@@ -33,6 +33,7 @@
#define P9_CMD_OPEN 112
#define P9_CMD_CREATE 114
#define P9_CMD_CLUNK 120
+#define P9_CMD_STAT 124
/* P9 protocol open flags. */
#define P9_OREAD 0 /* read */
@@ -59,6 +60,25 @@ struct p9_qid {
uint64_t path;
};
+struct p9_stat {
+ uint16_t size;
+ uint16_t type;
+ uint32_t dev;
+ struct p9_qid qid;
+ uint32_t mode;
+ uint32_t atime;
+ uint32_t mtime;
+ uint64_t length;
+ const char *name;
+ const char *uid;
+ const char *gid;
+ const char *muid;
+ const char *extension;
+ uint32_t n_uid;
+ uint32_t n_gid;
+ uint32_t n_muid;
+};
+
/*
* Note that the ring names "in" and "out" are from the frontend's
* perspective, so the "in" ring will be used for responses to the frontend,
@@ -1136,6 +1156,74 @@ static void p9_clunk(struct ring *ring, struct p9_header *hdr)
fill_buffer(ring, hdr->cmd + 1, hdr->tag, "");
}
+static void fill_p9_stat(struct p9_stat *p9s, struct stat *st, const char *name)
+{
+ memset(p9s, 0, sizeof(*p9s));
+ fill_qid(NULL, &p9s->qid, st);
+ p9s->mode = st->st_mode & 0777;
+ if ( S_ISDIR(st->st_mode) )
+ p9s->mode |= P9_CREATE_PERM_DIR;
+ p9s->atime = st->st_atime;
+ p9s->mtime = st->st_mtime;
+ p9s->length = st->st_size;
+ p9s->name = name;
+ p9s->uid = "";
+ p9s->gid = "";
+ p9s->muid = "";
+ p9s->extension = "";
+ p9s->n_uid = 0;
+ p9s->n_gid = 0;
+ p9s->n_muid = 0;
+
+ /*
+ * Size of individual fields without the size field, including 5 2-byte
+ * string length fields.
+ */
+ p9s->size = 71 + strlen(p9s->name);
+}
+
+static void p9_stat(struct ring *ring, struct p9_header *hdr)
+{
+ device *device = ring->device;
+ uint32_t fid;
+ struct p9_fid *fidp;
+ struct p9_stat p9s;
+ struct stat st;
+ uint16_t total_length;
+ int ret;
+
+ ret = fill_data(ring, "U", &fid);
+ if ( ret != 1 )
+ {
+ p9_error(ring, hdr->tag, EINVAL);
+ return;
+ }
+
+ fidp = get_fid_ref(device, fid);
+ if ( !fidp )
+ {
+ p9_error(ring, hdr->tag, ENOENT);
+ return;
+ }
+
+ if ( stat(fidp->path, &st) < 0 )
+ {
+ p9_error(ring, hdr->tag, errno);
+ goto out;
+ }
+ fill_p9_stat(&p9s, &st, strrchr(fidp->path, '/') + 1);
+
+ total_length = p9s.size + sizeof(p9s.size);
+ fill_buffer(ring, hdr->cmd + 1, hdr->tag, "uuuUQUUULSSSSSUUU",
+ &total_length, &p9s.size, &p9s.type, &p9s.dev, &p9s.qid,
+ &p9s.mode, &p9s.atime, &p9s.mtime, &p9s.length, p9s.name,
+ p9s.uid, p9s.gid, p9s.muid, p9s.extension, &p9s.n_uid,
+ &p9s.n_gid, &p9s.n_muid);
+
+ out:
+ free_fid(device, fidp);
+}
+
void *io_thread(void *arg)
{
struct ring *ring = arg;
@@ -1215,6 +1303,10 @@ void *io_thread(void *arg)
p9_clunk(ring, &hdr);
break;
+ case P9_CMD_STAT:
+ p9_stat(ring, &hdr);
+ break;
+
default:
syslog(LOG_DEBUG, "%u.%u sent unhandled command %u\n",
ring->device->domid, ring->device->devid, hdr.cmd);