commit 01fb39ab76a8b3d6e6f1300b5ef3c5e0fac912c9 from: Omar Polo date: Sun Jan 16 11:08:21 2022 UTC new `put' command to upload a file commit - 1bb1bfca8878efcab2568f1f41e010e0be1f5e24 commit + 01fb39ab76a8b3d6e6f1300b5ef3c5e0fac912c9 blob - 7b2755a8c648c74994efabb1de0a73f70ef6e010 blob + 965d864515ce22d55ef06113ed961162c48674eb --- kamiftp/ftp.c +++ kamiftp/ftp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -454,7 +455,26 @@ do_open(uint32_t fid, uint8_t mode) do_send(); recv_msg(); expect2(Ropen, iota_tag); + + np_read_qid(buf, &qid); + iounit = np_read32(buf); + + ASSERT_EMPTYBUF(); + + return iounit; +} + +static uint32_t +do_create(uint32_t fid, const char *name, uint32_t perm, uint8_t mode) +{ + struct qid qid; + uint32_t iounit; + tcreate(fid, name, perm, mode); + do_send(); + recv_msg(); + expect2(Rcreate, iota_tag); + np_read_qid(buf, &qid); iounit = np_read32(buf); @@ -572,6 +592,24 @@ do_read(int fid, uint64_t off, uint32_t count, void *d return r; } +static size_t +do_write(int fid, uint64_t off, uint32_t count, void *data) +{ + uint32_t r; + + twrite(fid, off, data, count); + do_send(); + recv_msg(); + expect2(Rwrite, iota_tag); + + r = np_read32(buf); + assert(r <= count); + + ASSERT_EMPTYBUF(); + + return r; +} + static void draw_progress(const char *pre, const struct progress *p) { @@ -654,7 +692,50 @@ fetch_fid(int fid, int fd, const char *name) } putchar('\n'); + + do_clunk(fid); +} + +static void +send_fid(int fid, const char *fnam, int fd, const char *name) +{ + struct progress p = {0}; + struct stat sb; + ssize_t r; + size_t w; + char buf[BUFSIZ]; + + if (fstat(fd, &sb) == -1) + err(1, "fstat"); + + if (fnam != NULL) + do_create(fid, fnam, 0644, KOWRITE); + else + do_open(fid, KOWRITE); + + p.max = sb.st_size; + for (;;) { + r = read(fd, buf, sizeof(buf)); + if (r == 0) + break; + if (r == -1) + err(1, "read"); + w = do_write(fid, p.done, r, buf); + p.done += w; + + draw_progress(name, &p); + +#if 0 + /* throttle, for debugging purpose */ + { + struct timespec ts = { 0, 500000000 }; + nanosleep(&ts, NULL); + } +#endif + } + + putchar('\n'); do_clunk(fid); } @@ -1002,6 +1083,88 @@ cmd_page(int argc, const char **argv) close(tmpfd); spawn("less", sfn, NULL); unlink(sfn); +} + +static void +cmd_put(int argc, const char **argv) +{ + struct qid qid; + const char *l, *n = NULL; + char *errstr; + int nfid, fd, miss; + + if (argc != 1 && argc != 2) { + printf("usage: put local-file [remote-file]\n"); + return; + } + + if (argc == 2) + l = argv[1]; + else if ((l = strrchr(argv[0], '/')) != NULL) + l++; /* skip / */ + else + l = argv[0]; + + nfid = pwdfid+1; + errstr = walk_path(pwdfid, nfid, l, &miss, &qid); + if (errstr != NULL && miss > 1) { + printf("%s: %s\n", l, errstr); + free(errstr); + return; + } + + if (errstr != NULL || miss == 1) { + char p[PATH_MAX], *dn; + + /* + * If it's only one component missing (the file name), walk + * to the parent directory and try to create the file. + */ + + if (strlcpy(p, l, sizeof(p)) >= sizeof(p)) { + printf("path too long: %s\n", l); + return; + } + dn = dirname(p); + + if (!strcmp(dn, ".")) { + errstr = dup_fid(pwdfid, nfid); + miss = 0; + } else + errstr = walk_path(pwdfid, nfid, dn, &miss, &qid); + + if (errstr != NULL) { + printf("%s: %s\n", dn, errstr); + free(errstr); + return; + } + + if (miss != 0) { + printf("%s: not a directory\n", dn); + return; + } + + if ((n = strrchr(l, '/')) != NULL) + n++; + else + n = l; + } + + free(errstr); + + if (miss > 1) { + printf("can't create %s: missing %d path component(s)\n", + l, miss); + return; + } + + if ((fd = open(argv[0], O_RDONLY)) == -1) { + warn("%s", argv[0]); + return; + } + + send_fid(nfid, n, fd, argv[0]); + close(fd); } static void @@ -1050,6 +1213,7 @@ excmd(int argc, const char **argv) {"lpwd", cmd_lpwd}, {"ls", cmd_ls}, {"page", cmd_page}, + {"put", cmd_put}, {"quit", cmd_bye}, {"verbose", cmd_verbose}, };