commit 053e2652121f9aa3477d7ae1433bc63b52aac02b from: Omar Polo date: Sun Aug 01 21:42:06 2021 UTC improve qid implementation qid now aren't *always* associated with a fd. They are associated with a path instead. The may be associated with a fd if the client preared a fid for I/O. At Tattach time we don't necessarily open the directory, we just stat it. Same during Twalk. commit - 913eba5cda7629102a8a71f2e07500c359786ed0 commit + 053e2652121f9aa3477d7ae1433bc63b52aac02b blob - 7a6fb3c0506bec785c5aa23e0925117f416e65f8 blob + 8b7272ee9473f3d04f30ce314639e74336426582 --- client.c +++ client.c @@ -48,6 +48,7 @@ struct qid { int fd; int refcount; + char fpath[PATH_MAX]; struct stat sb; STAILQ_ENTRY(qid) entries; @@ -75,8 +76,11 @@ static void client_privdrop(const char *, const char static int client_send_listener(int, const void *, uint16_t); +static void qid_set_from_sb(struct qid *); static int qid_update_stat(struct qid *); +static struct qid *qid_from_copy(const struct qid *); static struct qid *qid_from_fd(int); +static struct qid *qid_from_path(const char *); static struct qid *qid_incref(struct qid *); static void qid_decref(struct qid *); @@ -326,12 +330,10 @@ client_send_listener(int type, const void *data, uint1 return ret; } -static int -qid_update_stat(struct qid *qid) +/* set qid fields from the sb field */ +static void +qid_set_from_sb(struct qid *qid) { - if (fstat(qid->fd, &qid->sb) == -1) - return -1; - qid->path = qid->sb.st_ino; /* @@ -346,10 +348,39 @@ qid_update_stat(struct qid *qid) qid->type = QTDIR; else if (S_ISLNK(qid->sb.st_mode)) qid->type = QTSYMLINK; +} +/* update qid info */ +static int +qid_update_stat(struct qid *qid) +{ + if (fstat(qid->fd, &qid->sb) == -1) + return -1; + + qid_set_from_sb(qid); return 0; } +/* create a new qid by copying info from an existing one */ +static struct qid * +qid_from_copy(const struct qid *qid) +{ + struct qid *q; + + if ((q = calloc(1, sizeof(*q))) == NULL) + return NULL; + q->fd = -1; + + memcpy(q->fpath, qid->fpath, sizeof(q->fpath)); + + memcpy(&q->sb, &qid->sb, sizeof(q->sb)); + memcpy(&q->path, &qid->path, sizeof(q->path)); + memcpy(&q->vers, &qid->vers, sizeof(q->vers)); + memcpy(&q->type, &qid->type, sizeof(q->type)); + + return q; +} + /* creates a qid given a fd */ static struct qid * qid_from_fd(int fd) @@ -362,12 +393,34 @@ qid_from_fd(int fd) qid->fd = fd; qid_update_stat(qid); - STAILQ_INSERT_HEAD(&qids, qid, entries); + STAILQ_INSERT_HEAD(&qids, qid, entries); return qid; } static struct qid * +qid_from_path(const char *path) +{ + struct qid *qid; + + if ((qid = calloc(1, sizeof(*qid))) == NULL) + return NULL; + + qid->fd = -1; + + if (stat(path, &qid->sb) == -1) { + free(qid); + return NULL; + } + + qid_set_from_sb(qid); + + STAILQ_INSERT_HEAD(&qids, qid, entries); + + return qid; +} + +static struct qid * qid_incref(struct qid *qid) { qid->refcount++; @@ -720,7 +773,6 @@ tattach(struct np_msg_header *hdr, const uint8_t *data struct qid *qid; struct fid *f; uint32_t fid, afid; - int fd; char aname[PATH_MAX]; if (attached) { @@ -751,22 +803,15 @@ tattach(struct np_msg_header *hdr, const uint8_t *data return; } - if ((fd = open(aname, O_DIRECTORY)) == -1) { + if ((qid = qid_from_path(aname)) == NULL) { np_errno(hdr->tag); log_debug("failed to attach %s: %s", aname, strerror(errno)); return; } log_debug("attached %s", aname); - - if ((qid = qid_from_fd(fd)) == NULL) { - close(fd); - np_error(hdr->tag, "no memory"); - return; - } if ((f = new_fid(qid, fid)) == NULL) { - close(qid->fd); - free(qid); + qid_decref(qid); np_error(hdr->tag, "no memory"); return; } @@ -827,12 +872,12 @@ 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 qid *qid, wqid[MAXWELEM] = {0}; struct fid *f, *nf; uint32_t fid, newfid; uint16_t nwname; - int fd, nfd, nwqid = 0; - char path[PATH_MAX+1]; + int nwqid = 0; + char wnam[PATH_MAX+1], path[PATH_MAX+1]; /* fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ if (len < 10) { @@ -881,12 +926,20 @@ twalk(struct np_msg_header *hdr, const uint8_t *data, return; } - memset(wqid, 0, sizeof(wqid)); - - qid = f->qid; - fd = qid->fd; + if (f->iomode != 0) { + np_error(hdr->tag, "fid already opened for I/O"); + return; + } + + if (f->qid->type != QTDIR) { + np_error(hdr->tag, "fid doesn't represent a directory"); + return; + } + + strlcpy(path, f->qid->fpath, sizeof(path)); + for (nwqid = 0; nwqid < nwname; nwqid++) { - switch (NPREADSTR("wname", path, sizeof(path), &data, &len)) { + switch (NPREADSTR("wname", wnam, sizeof(wnam), &data, &len)) { case READSTRERR: goto err; case READSTRTRUNC: @@ -894,25 +947,19 @@ twalk(struct np_msg_header *hdr, const uint8_t *data, return; } - if ((nfd = openat(fd, path, O_RDONLY)) == -1) { + strlcat(path, "/", sizeof(path)); + strlcat(path, wnam, sizeof(path)); + + if (stat(path, &wqid[nwqid].sb) == -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 = qid_from_fd(fd)) == NULL) + if ((qid = qid_from_path(path)) == NULL) fatal("qid_from_fd"); if (nf == NULL) {