@@ -298,11 +298,12 @@ static int free_fid(V9fsState *s, int32_t fid)
#define P9_STAT_MODE_SETGID 0x00040000
#define P9_STAT_MODE_SETVTX 0x00010000
-#define P9_STAT_MODE_SPECIAL (P9_STAT_MODE_NAMED_PIPE | \
- P9_STAT_MODE_SYMLINK | \
- P9_STAT_MODE_LINK | \
- P9_STAT_MODE_DEVICE)
-
+#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \
+ P9_STAT_MODE_SYMLINK | \
+ P9_STAT_MODE_LINK | \
+ P9_STAT_MODE_DEVICE | \
+ P9_STAT_MODE_NAMED_PIPE | \
+ P9_STAT_MODE_SOCKET)
/* This is the algorithm from ufs in spfs */
static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
@@ -1842,6 +1843,7 @@ typedef struct V9fsWstatState
int16_t unused;
V9fsStat v9stat;
V9fsFidState *fidp;
+ struct stat stbuf;
V9fsString nname;
} V9fsWstatState;
@@ -2034,6 +2036,37 @@ static int donttouch_stat(V9fsStat *stat)
return 0;
}
+static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
+{
+ uint32_t v9_mode;
+
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ v9_mode = stat_to_v9mode(&vs->stbuf);
+
+ if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
+ (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
+ /* Attempting to change the type */
+ err = -EIO;
+ goto out;
+ }
+
+ if (posix_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
+ &vs->v9stat.extension))) {
+ err = -errno;
+ }
+ v9fs_wstat_post_chmod(s, vs, err);
+ return;
+
+out:
+ v9fs_stat_free(&vs->v9stat);
+ complete_pdu(s, vs->pdu, err);
+ qemu_free(vs);
+}
+
static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
{
int32_t fid;
@@ -2060,16 +2093,9 @@ static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
}
if (vs->v9stat.mode != -1) {
- if (vs->v9stat.mode & P9_STAT_MODE_DIR && vs->fidp->dir == NULL) {
- err = -EIO;
- goto out;
- }
-
- if (posix_chmod(s, &vs->fidp->path,
- v9mode_to_mode(vs->v9stat.mode,
- &vs->v9stat.extension))) {
- err = -errno;
- }
+ err = posix_lstat(s, &vs->fidp->path, &vs->stbuf);
+ v9fs_wstat_post_lstat(s, vs, err);
+ return;
}
v9fs_wstat_post_chmod(s, vs, err);