/*********************************************************************\ * Copyright (c) 1991 by Wen-King Su (wen-king@vlsi.cs.caltech.edu) * * Copyright (c) 1993 by Phil Richards (pgr@prg.ox.ac.uk) * * * * You may copy or modify this file in any manner you wish, provided * * that this notice is always included, and that you hold the author * * harmless for any loss or damage resulting from the installation or * * use of this software. * \*********************************************************************/ /* ---INFOBEGIN--- * DO NOT DELETE THIS COMMENT BLOCK!!! COMMAND get remote "download files from the remote system" * ---INFOEND--- */ #include "client.h" #include "table.h" #include #ifdef HAVE_UTIME_H # include #else # ifdef HAVE_UTIMES_H # include # define utime utimes # else # define NO_UTIME # endif #endif static unsigned int baselen, cwdlen; static char *abscwd; static int recursive; typedef enum { GET_WHOLE, GET_HEAD, GET_MIDDLE, GET_TAIL } GetOp; static GetOp _getmode; static int get_file(char *name, struct stat *sbufp, int depth) { char *basename, *path, *remname; char *tmpname, *openname; const char *modedesc; int fd, mode, retval = 0; unsigned pathlen,dirlen; if (!validate_operation(name, UTIL_DOWNLOAD)) return -1; basename = strrchr(name, '/'); if (basename) basename++; else basename = name; if (recursive) path = name + baselen; else path = basename; pathlen = strlen(path); tmpname = (char *)malloc(5 + pathlen); if (recursive) { dirlen = (int)(basename - path); (void)strncpy(tmpname, path, dirlen); (void)strcpy(tmpname + dirlen, ".in."); (void)strcpy(tmpname + dirlen + 4, basename); } else { (void)strcpy(tmpname, ".in."); (void)strcpy(tmpname + 4, path); } if (baselen > cwdlen && strncmp(abscwd, name, cwdlen) == 0) remname = name + cwdlen + 1; else remname = name; switch (_getmode) { case GET_WHOLE: if (access(path, W_OK) == 0) { openname = path; mode = O_WRONLY | O_CREAT | O_APPEND; modedesc = "update"; } else if (access(tmpname, W_OK) == 0) { openname = tmpname; mode = O_WRONLY | O_CREAT | O_APPEND; modedesc = "update"; } else { openname = tmpname; mode = O_WRONLY | O_CREAT | O_TRUNC; modedesc = "writing"; } break; case GET_HEAD: case GET_MIDDLE: case GET_TAIL: openname = tmpname; mode = O_WRONLY | O_CREAT | O_TRUNC; modedesc = "writing"; break; } if ((fd = open(openname, mode, 0644)) < 0) { retval = 1; ffprintf(STDERR, "?get: cannot open local `%s' for %s: %s\n", path, modedesc, strerror(errno)); } else { int can_rename = 1, bytes; unsigned int pos = 0; struct stat lbuf; if (openname != tmpname && rename(path, tmpname) < 0) { ffprintf(STDERR, "?get: failed to rename `%s' to `%s': %s\n", path, tmpname, strerror(errno)); can_rename = 0; } (void)fstat(fd, &lbuf); if (S_ISREG(lbuf.st_mode)) { if ((pos = lseek(fd, 0L, SEEK_END)) > 0 && askprompt && STDPROMPT) { char result, buf[256]; ffprintf(STDPROMPT, "`%s' already contains %d bytes; continue or restart [cr]? ", openname, pos); (void)my_fgets(buf, 256, STDIN); /* if ^C was hit, then return immediately */ if (buf[0] == '\0') { (void)free(tmpname); return 0; } if (sscanf(buf, " %c", &result) != 1 || strchr("rRnN", result)) { pos = 0; (void)ftruncate(fd, 0L); (void)lseek(fd, 0L, SEEK_SET); } } } if (client_trace >= 2) { if (pos >= sbufp->st_size) ffprintf(STDINFO, "nothing to download for `%s' -- skipping\n", remname); else if (pos > 0) ffprintf(STDINFO, "resuming `%s' (%d bytes remaining)\n", remname, sbufp->st_size - pos); else ffprintf(STDINFO, "downloading `%s' (%d bytes)\n", remname, sbufp->st_size); } bytes = util_download(remname, fd, pos, sbufp->st_size - pos); if (bytes < 0) { retval = 1; (void)close(fd); (void)unlink(can_rename? tmpname: path); } else { (void)close(fd); if (bytes < sbufp->st_size - pos) ffprintf(STDERR, "?failed to get %d bytes -- file truncated\n", sbufp->st_size - pos - bytes); if (can_rename && rename(tmpname, path) < 0) ffprintf(STDERR, "?get: failed to rename `%s' to `%s': %s\n", tmpname, path, strerror(errno)); #ifndef NO_UTIME else if (datestamp) { struct stat rfstat; if (util_stat(name, &rfstat) < 0) ffprintf(STDERR, "?can't get times for file `%s': %s\n", name, strerror(errno)); else { struct utimbuf lftimes; lftimes.actime = rfstat.st_atime; lftimes.modtime = rfstat.st_mtime; if (utime(path, &lftimes) < 0) ffprintf(STDERR, "?can't date stamp file `%s': %s\n", path, strerror(errno)); } } #endif } (void)free(tmpname); } return -retval; } static int make_dir(char *name, int depth, char **pdata) { struct stat sbuf; if (stat(name + baselen, &sbuf) == 0) { /* check if the directory already exists... */ if (S_ISDIR(sbuf.st_mode)) return 0; /* the directory doesn't exist, but *something* does... urgh! */ ffprintf(STDERR, "?local file `%s' is not a directory\n", name + baselen); return -1; } /* nothing exists by this name -- try to create it */ if (mkdir(name + baselen, 0755) < 0) { ffprintf(STDERR, "?can't make directory `%s': %s\n", name + baselen, strerror(errno)); return -1; } return 0; } static int do_get(char *name) { char *dirname; if (!validate_operation(name, UTIL_PROCESS_FILE | UTIL_STAT)) return -1; dirname = util_abs_path(name); /* util_abs_path() is guaranteed to return path with a '/' */ baselen = strrchr(dirname, '/') - dirname + 1; (void)free(dirname); return util_process_file(name, recursive, 0, get_file, make_dir, 0); } /* ARGSUSED */ int rget_main(int argc, char *const*argv, char **envp) { int retval, errcnt, ch; recursive = 0; optind = 0; opterr = 0; errcnt = 0; #ifdef HAVE_OPTRESET optreset = 1; optind = 1; #endif if (strcmp(argv[0], "head") == 0) _getmode = GET_HEAD; else if (strcmp(argv[0], "tail") == 0) _getmode = GET_TAIL; else _getmode = GET_WHOLE; while ((ch = getopt(argc, argv, "ftnr")) != EOF) switch (ch) { case 'f': case 'r': recursive = MAXRECURSION; break; default: errcnt++; break; } if (errcnt > 0) return 1; #if 0 if (_getmode == GET_WHOLE && (frompos != 0 || getlen XXX)) ; #endif abscwd = util_abs_path(env_dir); cwdlen = strlen(abscwd); /* special case "/" */ if (cwdlen == 1) cwdlen = 0; if (argc > optind) retval = -util_process_arglist(argv + optind, do_get); else { #define INBUF_SIZE 1024 char *argbuf[2], buf[INBUF_SIZE]; argbuf[0] = buf; argbuf[1] = 0; retval = 0; while (client_intr_state < 2) { char *eofn; ffprintf(STDPROMPT, "(get) "); if (!my_fgets(buf, INBUF_SIZE, STDIN) || !buf[0] || buf[0] == '\n') break; eofn = strrchr(buf, '\n'); if (eofn) *eofn = 0; retval |= (util_process_arglist(argbuf, do_get) < 0); } } (void)free(abscwd); client_done(); return retval; }