commit - 4b022e455ca08c0eb4bcbde2adc4f55af451e044
commit + 1bf47a19d4d917370f706fc996d61f03b5bba45f
blob - 77f7810b6c2e520c3347b838a944f3670d6ba767
blob + ebe01ee35020648e7c84e1fad5340f1bcdf3cbf9
--- client.c
+++ client.c
int refcount;
int fd;
- char fpath[PATH_MAX];
STAILQ_ENTRY(qid) entries;
};
struct fid {
uint32_t fid;
+ char fpath[PATH_MAX];
+
/*
* 0 when the fid was not yet opened for I/O otherwise set to
* the flags passed to open(2). O_CLOEXEC means ORCLOSE, that
static int client_send_listener(int, const void *, uint16_t);
static void qid_update_from_sb(struct qid *, struct stat *);
-static struct qid *qid_from_fd(int, const char *, struct stat *);
+static struct qid *qid_from_fd(int, struct stat *);
static struct qid *qid_incref(struct qid *);
static void qid_decref(struct qid *);
-static struct fid *new_fid(struct qid *, uint32_t);
+static struct fid *new_fid(struct qid *, uint32_t, const char *);
static struct fid *fid_by_id(uint32_t);
static void free_fid(struct fid *);
/* creates a qid given a fd */
static struct qid *
-qid_from_fd(int fd, const char *path, struct stat *s)
+qid_from_fd(int fd, struct stat *s)
{
struct qid *qid;
struct stat sb;
- int r;
if ((qid = calloc(1, sizeof(*qid))) == NULL)
return NULL;
-
- if (path != NULL)
- strlcpy(qid->fpath, path, sizeof(qid->fpath));
qid->fd = fd;
if (s == NULL) {
s = &sb;
- if (path == NULL)
- r = fstat(fd, s);
- else
- r = fstatat(fd, path, s, 0);
- if (r == -1) {
- free(qid);
- return NULL;
- }
+ if (fstat(fd, &sb) == -1)
+ fatal("fstat");
}
qid_update_from_sb(qid, s);
}
static struct fid *
-new_fid(struct qid *qid, uint32_t fid)
+new_fid(struct qid *qid, uint32_t fid, const char *path)
{
struct fid *f;
f->qid = qid_incref(qid);
f->fid = fid;
f->fd = -1;
+
+ if (path != NULL)
+ strlcpy(f->fpath, path, sizeof(f->fpath));
STAILQ_INSERT_HEAD(&fids, f, entries);
/* try to honour ORCLOSE if requested */
if (f->iomode & O_CLOEXEC)
- unlinkat(f->qid->fd, f->qid->fpath, 0);
+ unlinkat(f->qid->fd, f->fpath, 0);
}
qid_decref(f->qid);
if ((fd = open(aname, O_RDONLY|O_DIRECTORY)) == -1)
goto fail;
- if ((qid = qid_from_fd(fd, NULL, NULL)) == NULL)
+ if ((qid = qid_from_fd(fd, NULL)) == NULL)
goto fail;
log_debug("attached %s to %d", aname, fid);
- if ((f = new_fid(qid, fid)) == NULL) {
+ if ((f = new_fid(qid, fid, aname)) == NULL) {
qid_decref(qid);
goto fail;
}
* TODO: should we forbid fids duplication when fid ==
* newfid?
*/
- if (nf == NULL && (nf = new_fid(f->qid, newfid)) == NULL)
+ if (nf == NULL &&
+ (nf = new_fid(f->qid, newfid, f->fpath)) == NULL)
fatal("new_fid duplication");
np_walk(hdr->tag, 0, NULL);
oldfd = fd;
}
- /*
- * There can be two possibilities: fd == -1 means that we've
- * reached a file and we should save BOTH the dirfd (oldfd)
- * and the path (wnam); or we just reached another directory,
- * in which case we can just create a new qid using fd.
- */
- if (fd == -1)
- qid = qid_from_fd(oldfd, wnam, &sb);
+ /*
+ * If fd is -1 we've reached a file, otherwise we've just
+ * reached another directory. We must pay attention to what
+ * file descriptor we use to create the qid, because if we've
+ * reached a file and oldfd is f->qid->fd then we *must* share
+ * the same qid (it was a walk of one path from a directory to a
+ * file, otherwise fun is bound to happen as soon as the client
+ * closes the fid for the directory but keeps the one for the
+ * file.
+ */
+ if (fd == -1 && oldfd == f->qid->fd)
+ qid = f->qid;
+ else if (fd == -1)
+ qid = qid_from_fd(oldfd, NULL);
else
- qid = qid_from_fd(oldfd, NULL, &sb);
+ qid = qid_from_fd(fd, &sb);
+
if (qid == NULL)
fatal("qid_from_fd");
if (nf == NULL) {
- if ((nf = new_fid(qid, newfid)) == NULL)
- fatal("new_fid");
+ const char *fnam = NULL;
+
+ /* reached the file wnam */
+ if (fd == -1)
+ fnam = wnam;
+
+ if ((nf = new_fid(qid, newfid, fnam)) == NULL)
+ fatal("new fid");
} else {
- /* swap qid */
+ /* update the qid */
qid_decref(nf->qid);
nf->qid = qid_incref(qid);
}
return;
}
- if (f->qid->type & QTDIR &&
- (f->iomode & O_WRONLY || f->iomode & O_RDWR)) {
- np_error(hdr->tag, "can't open directory for writing");
- return;
- }
-
- path = f->qid->fpath;
+ path = f->fpath;
if (*path == '\0')
path = ".";
struct evbuffer *evb;
struct stat sb;
struct fid *f;
- const char *fname;
int r;
uint32_t fid;
if ((evb = evbuffer_new()) == NULL)
fatal("evbuffer_new");
- if (f->qid->type & QTDIR) {
- fname = ".";
- r = fstat(f->qid->fd, &sb);
- } else {
- fname = f->qid->fpath;
- r = fstatat(f->qid->fd, f->qid->fpath, &sb, 0);
- }
+ if (f->fd != -1)
+ r = fstat(f->fd, &sb);
+ else
+ r = fstatat(f->qid->fd, f->fpath, &sb, 0);
if (r == -1) {
np_errno(hdr->tag);
return;
}
- serialize_stat(fname, &sb, evb);
+ serialize_stat(f->fpath, &sb, evb);
np_stat(hdr->tag, EVBUFFER_LENGTH(evb), EVBUFFER_DATA(evb));
evbuffer_free(evb);
}
}
if (f->fd == -1 || f->dir == NULL) /* unlink file */
- r = unlinkat(f->qid->fd, f->qid->fpath, 0);
+ r = unlinkat(f->qid->fd, f->fpath, 0);
else /* directory */
- r = unlinkat(f->qid->fd, f->qid->fpath, AT_REMOVEDIR);
+ r = unlinkat(f->qid->fd, f->fpath, AT_REMOVEDIR);
if (r == -1)
np_errno(hdr->tag);