commit 9c48f915c93a4d5ad0f7aa91b62f047f68054089 from: Omar Polo date: Sun Jan 16 14:11:10 2022 UTC add `edit' command refactor the "write or create file" code into a function (woc_file) to share it with the `put' command. commit - 64d8db89b9ae1d0770f75cd7638f1ac14d4bb677 commit + 9c48f915c93a4d5ad0f7aa91b62f047f68054089 blob - d01b9d73af35372622b0075071ffbd6c108fa4d0 blob + 25002f0aacbc119a06152d97e75906764bb8ad7e --- kamiftp/ftp.c +++ kamiftp/ftp.c @@ -740,6 +740,71 @@ send_fid(int fid, const char *fnam, int fd, const char putchar('\n'); do_clunk(fid); +} + +static int +woc_file(int fd, const char *prompt, const char *path) +{ + struct qid qid; + const char *n = NULL; + char *errstr; + int nfid, miss; + + nfid = pwdfid+1; + errstr = walk_path(pwdfid, nfid, path, &miss, &qid); + if (errstr != NULL && miss > 1) { + printf("%s: %s\n", path, errstr); + free(errstr); + return -1; + } + + 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, path, sizeof(p)) >= sizeof(p)) { + printf("path too long: %s\n", path); + return -1; + } + 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 -1; + } + + if (miss != 0) { + printf("%s: not a directory\n", dn); + return -1; + } + + if ((n = strrchr(path, '/')) != NULL) + n++; + else + n = path; + } + + free(errstr); + + if (miss > 1) { + printf("can't create %s: missing %d path component(s)\n", + path, miss); + return -1; + } + + send_fid(nfid, n, fd, prompt); + return 0; } static void @@ -926,6 +991,69 @@ cmd_cd(int argc, const char **argv) } static void +cmd_edit(int argc, const char **argv) +{ + struct qid qid; + int nfid, tmpfd, miss; + char sfn[TMPFSTRLEN], p[PATH_MAX], *name, *errstr; + const char *ed; + + if (argc != 1) { + puts("usage: edit file"); + return; + } + + if ((ed = getenv("VISUAL")) == NULL && + (ed = getenv("EDITOR")) == NULL) + ed = "ed"; + + nfid = pwdfid+1; + errstr = walk_path(pwdfid, nfid, *argv, &miss, &qid); + if (errstr != NULL) { + printf("%s: %s\n", *argv, errstr); + free(errstr); + return; + } + + if (miss != 0 || qid.type != 0) { + printf("%s: not a file\n", *argv); + if (miss == 0) + do_clunk(nfid); + return; + } + + if ((tmpfd = tmp_file(sfn)) == -1) { + do_clunk(nfid); + return; + } + + strlcpy(p, *argv, sizeof(p)); + name = basename(p); + + fetch_fid(nfid, tmpfd, name); + close(tmpfd); + + spawn(ed, sfn, NULL); + + /* + * Re-open the file because it's not guaranteed that the + * file descriptor tmpfd is still associated with the file + * pointed by sfn: it's not uncommon for editor to write + * a backup file and then rename(2) it to the file name. + */ + if ((tmpfd = open(sfn, O_RDONLY)) == -1) { + warn("can't open %s", sfn); + goto end; + } + + woc_file(tmpfd, *argv, name); + close(tmpfd); + +end: + unlink(sfn); +} + +static void cmd_get(int argc, const char **argv) { struct qid qid; @@ -1104,9 +1232,8 @@ static void cmd_put(int argc, const char **argv) { struct qid qid; - const char *l, *n = NULL; - char *errstr; - int nfid, fd, miss; + const char *l; + int fd; if (argc != 1 && argc != 2) { printf("usage: put local-file [remote-file]\n"); @@ -1119,66 +1246,13 @@ cmd_put(int argc, const char **argv) 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]); + woc_file(fd, argv[0], l); close(fd); } @@ -1223,6 +1297,7 @@ excmd(int argc, const char **argv) {"bell", cmd_bell}, {"bye", cmd_bye}, {"cd", cmd_cd}, + {"edit", cmd_edit}, {"get", cmd_get}, {"lcd", cmd_lcd}, {"lpwd", cmd_lpwd},