commit 1c08fc548ae9aafb91a00d878bf9cdc2273b2a4d from: Omar Polo date: Sun Aug 01 18:18:05 2021 UTC add a first draft of Twalk commit - d28f26dbb261d0995b727dfdf94a6abe0e17b4c7 commit + 1c08fc548ae9aafb91a00d878bf9cdc2273b2a4d blob - 27c12f77ce32b6470060ab6849edbc13b5ba261a blob + 5225246de656c0505c8745171fcd2d330cf0d908 --- client.c +++ client.c @@ -38,13 +38,6 @@ #define DEBUG_PACKETS 0 -#if HAVE_ARC4RANDOM -# define RANDID() arc4random() -#else -static uint32_t counter; -# define RANDID() counter++ -#endif - STAILQ_HEAD(qidhead, qid) qids; struct qid { /* definition of a qid */ @@ -55,12 +48,15 @@ struct qid { int fd; int refcount; + struct stat sb; + STAILQ_ENTRY(qid) entries; }; STAILQ_HEAD(fidhead, fid) fids; struct fid { uint32_t fid; + int iomode; struct qid *qid; STAILQ_ENTRY(fid) entries; }; @@ -79,6 +75,7 @@ static void client_privdrop(const char *, const char static int client_send_listener(int, const void *, uint16_t); +static int qid_update_stat(struct qid *); static struct qid *new_qid(int); static struct qid *qid_incref(struct qid *); static void qid_decref(struct qid *); @@ -99,6 +96,7 @@ static void np_version(uint16_t, uint32_t, const char static void np_attach(uint16_t, struct qid *); static void np_clunk(uint16_t); static void np_flush(uint16_t); +static void np_walk(uint16_t, int, struct qid *); static void np_error(uint16_t, const char *); static void np_errno(uint16_t); @@ -106,6 +104,7 @@ static void tversion(struct np_msg_header *, const uin static void tattach(struct np_msg_header *, const uint8_t *, size_t); static void tclunk(struct np_msg_header *, const uint8_t *, size_t); static void tflush(struct np_msg_header *, const uint8_t *, size_t); +static void twalk(struct np_msg_header *, const uint8_t *, size_t); static void handle_message(struct imsg *, size_t); void client_hexdump(const char *, uint8_t *data, size_t len); @@ -309,31 +308,41 @@ client_send_listener(int type, const void *data, uint1 return ret; } +static int +qid_update_stat(struct qid *qid) +{ + if (fstat(qid->fd, &qid->sb) == -1) + return -1; + + qid->path = qid->sb.st_ino; + + /* + * Theoretically (and hopefully!) this should be a 64 bit + * number. Unfortunately, 9P uses 32 bit timestamps. + */ + qid->vers = qid->sb.st_mtim.tv_sec; + + if (S_ISREG(qid->sb.st_mode)) + qid->type = QTFILE; + else if (S_ISDIR(qid->sb.st_mode)) + qid->type = QTDIR; + else if (S_ISLNK(qid->sb.st_mode)) + qid->type = QTSYMLINK; + + return 0; +} + /* creates a qid given a fd */ static struct qid * new_qid(int fd) { - struct stat sb; struct qid *qid; - if (fstat(fd, &sb) == -1) { - log_warn("fstat"); - return NULL; - } - if ((qid = calloc(1, sizeof(*qid))) == NULL) return NULL; qid->fd = fd; - - qid->path = RANDID(); - - if (S_ISREG(sb.st_mode)) - qid->type = QTFILE; - else if (S_ISDIR(sb.st_mode)) - qid->type = QTDIR; - else if (S_ISLNK(sb.st_mode)) - qid->type = QTSYMLINK; + qid_update_stat(qid); STAILQ_INSERT_HEAD(&qids, qid, entries); @@ -530,6 +539,19 @@ np_flush(uint16_t tag) } static void +np_walk(uint16_t tag, int nwqid, struct qid *wqid) +{ + int i; + + np_header(QIDSIZE * nwqid, Rwalk, tag); + + for (i = 0; i < nwqid; ++i) + np_qid(wqid + i); + + do_send(); +} + +static void np_error(uint16_t tag, const char *errstr) { uint16_t l; @@ -749,6 +771,144 @@ tflush(struct np_msg_header *hdr, const uint8_t *data, } static void +twalk(struct np_msg_header *hdr, const uint8_t *data, size_t len) +{ + struct qid *qid, wqid[MAXWELEM]; + struct fid *f, *nf; + uint32_t fid, newfid; + uint16_t nwname, sl; + int fd, nfd, nwqid = 0; + char path[PATH_MAX+1]; + + /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ + if (len < 10) { + log_warnx("Twalk with the wrong size: got %zu want %d", + len, 10); + goto err; + } + + memcpy(&fid, data, sizeof(fid)); + data += sizeof(fid); + len -= sizeof(fid); + fid = le32toh(fid); + + memcpy(&newfid, data, sizeof(newfid)); + data += sizeof(newfid); + len -= sizeof(newfid); + newfid = le32toh(newfid); + + memcpy(&nwname, data, sizeof(nwname)); + data += sizeof(nwname); + len -= sizeof(nwname); + nwname = le16toh(nwname); + + if (nwname > MAXWELEM) { + log_warnx("Twalk: more than %d path elements: %d", + MAXWELEM, nwname); + goto err; + } + + if ((f = fid_by_id(fid)) == NULL) { + np_error(hdr->tag, "invalid fid"); + return; + } + + if (fid == newfid) + nf = f; + else if ((nf = fid_by_id(newfid)) != NULL) { + np_error(hdr->tag, "newfid already in use"); + return; + } else + nf = NULL; + + /* duplicate fid */ + if (nwqid == 0) { + /* + * TODO: should we forbid fids duplication when fid == + * newfid? + */ + + if (nf == NULL) { + if ((nf = new_fid(f->qid, newfid))) + fatal("new_fid"); + } + + np_walk(hdr->tag, 1, f->qid); + return; + } + + memset(wqid, 0, sizeof(wqid)); + + qid = f->qid; + fd = qid->fd; + for (nwqid = 0; nwqid < nwname; nwqid++) { + if (len < 2) { + log_warnx("Twalk: not enough space for the %d-th " + "string length", nwqid); + goto err; + } + + memcpy(&sl, data, sizeof(sl)); + data += sizeof(sl); + len -= sizeof(sl); + sl = le16toh(sl); + + if (len < sl) { + log_warnx("Twalk: want %d bytes for the %d-th wname " + "but only %zu are remaining", sl, nwqid, len); + goto err; + } + + if (sl > PATH_MAX) { + np_error(hdr->tag, "wname too long"); + return; + } + + memcpy(path, data, sl); + data += sl; + len -= sl; + path[sl] = '\0'; + + if ((nfd = openat(fd, path, O_RDONLY)) == -1) { + if (nwqid == 0) + np_errno(hdr->tag); + else + np_walk(hdr->tag, nwqid, wqid); + if (fd != qid->fd) + close(fd); + return; + } + + wqid[nwqid].fd = nfd; + qid_update_stat(wqid + nwqid); + + if (fd != qid->fd) + close(fd); + fd = nfd; + } + + if ((qid = new_qid(fd)) == NULL) + fatal("new_qid"); + + if (nf == NULL) { + if ((nf = new_fid(qid, newfid)) == NULL) + fatal("new_fid"); + } else { + /* swap qid */ + qid_decref(nf->qid); + nf->qid = qid_incref(qid); + } + + np_walk(hdr->tag, nwqid, wqid); + + return; + +err: + client_send_listener(IMSG_CLOSE, NULL, 0); + client_shutdown(); +} + +static void handle_message(struct imsg *imsg, size_t len) { struct msg { @@ -759,6 +919,7 @@ handle_message(struct imsg *imsg, size_t len) {Tattach, tattach}, {Tclunk, tclunk}, {Tflush, tflush}, + {Twalk, twalk}, }; struct np_msg_header hdr; size_t i; blob - ddac5d726866908b39eaf6318250ba6d480d4625 blob + a06374de892d37e7ac1f6e68abfe20c93c4e4473 --- kamid.h +++ kamid.h @@ -150,6 +150,7 @@ struct np_msg_header { #define NOFID ((uint32_t)~0U) #define NOUID (-1) #define QIDSIZE 13 +#define MAXWELEM 16 /* bits in Qid.type */ #define QTDIR 0x80 /* type bit for directories */