commit baa405044968a73fd6a257a3504efe7dc5fe7443 from: Omar Polo date: Wed Dec 15 10:08:02 2021 UTC first half of the tread implementation done, no new tests yet commit - d4e438158258d53a0d22189b432537b22300dd2e commit + baa405044968a73fd6a257a3504efe7dc5fe7443 blob - 8237f9706cffd481702b8272b3a7d4f2e6a9fab9 blob + f364ea6c67cb4d786641bd038be514c72f697c00 --- client.c +++ client.c @@ -18,6 +18,8 @@ #include +#include +#include #include #include #include @@ -36,6 +38,12 @@ #define DEBUG_PACKETS 0 +/* straight outta /src/usr.bin/ssh/scp.c */ +#define TYPE_OVERFLOW(type, val) \ + ((sizeof(type) == 4 && (val) > INT32_MAX) || \ + (sizeof(type) == 8 && (val) > INT64_MAX) || \ + (sizeof(type) != 4 && sizeof(type) != 8)) + STAILQ_HEAD(qidhead, qid) qids; struct qid { /* definition of a qid */ @@ -67,6 +75,9 @@ struct fid { * file descriptor. */ int fd; + DIR *dir; + struct evbuffer *evb; + uint64_t offset; struct qid *qid; STAILQ_ENTRY(fid) entries; @@ -111,6 +122,7 @@ static void np_clunk(uint16_t); static void np_flush(uint16_t); static void np_walk(uint16_t, int, struct qid *); static void np_open(uint16_t, struct qid *, uint32_t); +static void np_read(uint16_t, uint32_t, void *); static void np_error(uint16_t, const char *); static void np_errno(uint16_t); @@ -120,6 +132,8 @@ static int np_read16(const char *, const char *, uint1 const uint8_t **, size_t *); static int np_read32(const char *, const char *, uint32_t *, const uint8_t **, size_t *); +static int np_read64(const char *, const char *, uint64_t *, + const uint8_t **, size_t *); #define READSTRERR -1 #define READSTRTRUNC -2 @@ -129,6 +143,7 @@ static int np_readstr(const char *, const char *, char #define NPREAD8(f, dst, src, len) np_read8(__func__, f, dst, src, len) #define NPREAD16(f, dst, src, len) np_read16(__func__, f, dst, src, len) #define NPREAD32(f, dst, src, len) np_read32(__func__, f, dst, src, len) +#define NPREAD64(f, dst, src, len) np_read64(__func__, f, dst, src, len) #define NPREADSTR(f, b, bl, src, len) np_readstr(__func__, f, b, bl, src, len) @@ -138,6 +153,7 @@ static void tclunk(struct np_msg_header *, const uint8 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 topen(struct np_msg_header *, const uint8_t *, size_t); +static void tread(struct np_msg_header *, const uint8_t *, size_t); static void handle_message(struct imsg *, size_t); ATTR_DEAD void @@ -446,8 +462,19 @@ fid_by_id(uint32_t fid) static void free_fid(struct fid *f) { + int r; + if (f->fd != -1) { - close(f->fd); + if (f->dir != NULL) + r = closedir(f->dir); + else + r = close(f->fd); + + if (r == -1) + fatal("can't close fid %d", f->fid); + + evbuffer_free(f->evb); + /* try to honour ORCLOSE if requested */ if (f->iomode & O_CLOEXEC) unlinkat(f->qid->fd, f->qid->fpath, 0); @@ -501,6 +528,12 @@ np_write32(uint32_t x) { x = htole32(x); evbuffer_add(evb, &x, sizeof(x)); +} + +static void +np_writebuf(size_t len, void *data) +{ + evbuffer_add(evb, data, len); } static void @@ -617,6 +650,15 @@ np_open(uint16_t tag, struct qid *qid, uint32_t iounit } static void +np_read(uint16_t tag, uint32_t count, void *data) +{ + np_header(sizeof(count) + count, Rread, tag); + np_write32(count); + np_writebuf(count, data); + do_send(); +} + +static void np_error(uint16_t tag, const char *errstr) { uint16_t l; @@ -691,6 +733,24 @@ np_read32(const char *t, const char *f, uint32_t *dst, *src += sizeof(*dst); *len -= sizeof(*dst); *dst = le32toh(*dst); + + return 1; +} + +static int +np_read64(const char *t, const char *f, uint64_t *dst, const uint8_t **src, + size_t *len) +{ + if (*len < sizeof(*dst)) { + log_warnx("%s: wanted %zu bytes for the %s field but only " + "%zu are available.", t, sizeof(*dst), f, *len); + return -1; + } + + memcpy(dst, *src, sizeof(*dst)); + *src += sizeof(*dst); + *len -= sizeof(*dst); + *dst = le64toh(*dst); return 1; } @@ -1091,11 +1151,72 @@ topen(struct np_msg_header *hdr, const uint8_t *data, if (fstat(f->fd, &sb) == -1) fatal("fstat"); + if (S_ISDIR(sb.st_mode)) { + assert(f->qid->type & QTDIR); + if ((f->dir = fdopendir(f->fd)) == NULL) { + np_errno(hdr->tag); + close(f->fd); + f->fd = -1; + return; + } + } + + if ((f->evb = evbuffer_new()) == NULL) { + np_errno(hdr->tag); + closedir(f->dir); + f->dir = NULL; + f->fd = -1; + } + + f->offset = 0; + qid_update_from_sb(&qid, &sb); np_open(hdr->tag, &qid, sb.st_blksize); } static void +tread(struct np_msg_header *hdr, const uint8_t *data, size_t len) +{ + struct fid *f; + ssize_t r; + uint64_t off; + uint32_t fid, count; + char buf[2048]; + + /* fid[4] offset[8] count[4] */ + if (!NPREAD32("fid", &fid, &data, &len) || + !NPREAD64("offset", &off, &data, &len) || + !NPREAD32("count", &count, &data, &len)) { + client_send_listener(IMSG_CLOSE, NULL, 0); + client_shutdown(); + return; + } + + if ((f = fid_by_id(fid)) == NULL || f->fd != -1) { + np_error(hdr->tag, "invalid fid"); + return; + } + + if (TYPE_OVERFLOW(off_t, off)) { + log_warnx("unexpected size_t size"); + np_error(hdr->tag, "invalid offset"); + return; + } + + if (f->dir == NULL) { + /* read a file */ + r = pread(f->fd, buf, sizeof(buf), (off_t)off); + if (r == -1) + np_errno(hdr->tag); + else + np_read(hdr->tag, r, buf); + } else { + /* read dirents */ + np_error(hdr->tag, "not implemented yet"); + } +} + +static void handle_message(struct imsg *imsg, size_t len) { struct msg { @@ -1108,6 +1229,7 @@ handle_message(struct imsg *imsg, size_t len) {Tflush, tflush}, {Twalk, twalk}, {Topen, topen}, + {Tread, tread}, }; struct np_msg_header hdr; size_t i;