/* appends char * items in list LP matching MASK * EXCLUDE_FUNC (if not 0) is called for each path found * and that path is excluded if EXCLUDE_FUNC returns true * * returns 0 if successful, -1 if failure */ int lglob_glob(list *gl, const char *mask, bool ignore_multiples, lglobfunc exclude_func) { struct dirent *de; DIR *dp; char *directory; char tmp[PATH_MAX]; bool added = false, found = false; directory = base_dir_xptr(mask); if((dp = opendir(directory ? directory : ".")) == 0) { ftp_err("Unable to read directory %s\n", directory ? directory : "."); return -1; } if (!getcwd(tmp, PATH_MAX)) { if (ERANGE == errno) { ftp_err("cwd too long\n"); } else { ftp_err("getcwd(): %s\n", strerror(errno)); } return -1; } while((de = readdir(dp)) != 0) { char *path; asprintf(&path, "%s/%s", directory ? directory : ".", de->d_name); if(fnmatch(base_name_ptr(mask), de->d_name, 0) == 0) { if(!(exclude_func && exclude_func(path))) { char *p; bool ignore_item; p = path_absolute(path, tmp, gvLocalHomeDir); ignore_item = (ignore_multiples && (list_search(gl, (listsearchfunc)strcmp, p) != 0)); if(!ignore_item) { list_additem(gl, p); added = true; } } found = true; } free(path); } closedir(dp); if(!found) { ftp_err("%s: no matches found\n", mask); return -1; } return added ? 0 : -1; }
/* returns the rfile at PATH * if it's not in the cache, reads the directory * returns 0 if not found */ rfile *ftp_get_file(const char *path) { rfile *f; char *ap; if(!path) return 0; ap = ftp_path_absolute(path); stripslash(ap); f = ftp_cache_get_file(ap); if(!f) { char *p = base_dir_xptr(ap); rdirectory *rdir = ftp_get_directory(p); free(p); if(rdir) f = rdir_get_file(rdir, base_name_ptr(ap)); } free(ap); return f; }
int ftp_maybe_isdir(rfile *fp) { if(risdir(fp)) return 1; if(rislink(fp)) { /* found a link; if the link is in the cache, * check if it's a directory, else we don't * read the directory just to check if it's a * directory */ char *adir = base_dir_xptr(fp->path); char *ap = path_absolute(fp->link, adir, ftp->homedir); rfile *lnfp = ftp_cache_get_file(ap); free(adir); free(ap); if(lnfp) return risdir(lnfp) ? 1 : 0; else /* return maybe ;-) */ return 2; } return 0; }
static char *remote_completion_function(const char *text, int state) { static int len; /* length of unquoted */ static char *dir = NULL; /* any initial directory in text */ static char *unquoted = NULL; /* the unquoted filename (or beginning of it) */ static listitem *lip = NULL; static rdirectory *rdir = NULL; /* the cached remote directory */ static char merge_fmt[] = "%s/%s"; if (!ftp_loggedin()) return 0; /* this is not really true, this is for local filename completion, * but it works here too (sort of), and it looks nicer, since * the whole path is not printed by readline, ie * only foo is printed and not /bar/fu/foo (if cwd == /bar/fu) * readline appends a class character (ie /,@,*) in _local_ filenames */ rl_filename_completion_desired = 1; #ifndef HAVE_LIBEDIT rl_filename_quoting_desired = 1; #endif if (!state) { dir = base_dir_xptr(text); if (dir) { stripslash(dir); char* e = strchr(dir, 0); if (e[-1]=='\"') e[-1] = '\0'; unquote(dir); if (strcmp(dir, "/") == 0) strlcpy(merge_fmt, "%s%s", sizeof(merge_fmt)); else strlcpy(merge_fmt, "%s/%s", sizeof(merge_fmt)); } #ifndef HAVE_LIBEDIT if(gvWaitingDots) { rl_insert_text("..."); /* show dots while waiting, like ncftp */ rl_redisplay(); } #endif char* ap = ftp_path_absolute(dir); rdir = ftp_cache_get_directory(ap); const bool dir_is_cached = (rdir != 0); if (!rdir) rdir = ftp_read_directory(ap); free(ap); #ifndef HAVE_LIBEDIT if (gvWaitingDots) rl_do_undo(); /* remove the dots */ #endif if (!dir_is_cached && ftp_get_verbosity() >= vbCommand) rl_forced_update_display(); if (!rdir) { free(dir); return 0; } unquoted = dequote_filename(base_name_ptr(text), 0); if (!unquoted) unquoted = (char *)xmalloc(1); len = strlen(unquoted); lip = rdir->files->first; } while (lip) { rfile* fp = (rfile *)lip->data; lip = lip->next; /* 0 = not dir, 1 = dir, 2 = link (maybe dir) */ const int isdir = ftp_maybe_isdir(fp); if (remote_dir_only && isdir == 0) continue; const char* name = base_name_ptr(fp->path); /* skip dotdirs in completion */ if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue; if (strncmp(name, unquoted, len) == 0) { char *ret; if (dir) { if (asprintf(&ret, merge_fmt, dir, name) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); free(unquoted); free(dir); return NULL; } } else ret = xstrdup(name); if (isdir == 1) { rl_completion_append_character = '/'; } else { rl_completion_append_character = ' '; } return ret; } } free(unquoted); free(dir); return NULL; }
static void getfiles(list *gl, unsigned int opt, const char *output) { listitem *li; rfile *fp, *lnfp; const char *opath, *ofile; char *link = 0; list_sort(gl, get_sort_func, false); li = gl->first; while(li && !get_quit) { fp = (rfile *)li->data; if(!ftp_connected()) return; if(gvSighupReceived) { if(!test(opt, GET_RESUME)) opt |= GET_UNIQUE; opt |= GET_FORCE; } opath = fp->path; ofile = base_name_ptr(opath); if(strcmp(ofile, ".")==0 || strcmp(ofile, "..")==0) { transfer_nextfile(gl, &li, true); continue; } if(test(opt, GET_INTERACTIVE) && !get_batch && !gvSighupReceived) { char* sp = shortpath(opath, 42, ftp->homedir); int a = ask(ASKYES|ASKNO|ASKCANCEL|ASKALL, ASKYES, _("Get '%s'?"), sp); free(sp); if(a == ASKNO) { transfer_nextfile(gl, &li, true); continue; } if(a == ASKCANCEL) { get_quit = true; break; } if(a == ASKALL) get_batch = true; /* else a==ASKYES */ } if(rislink(fp)) { link_to_link__duh: if(test(opt, GET_NO_DEREFERENCE)) { /* link the file, don't copy */ const int r = getfile(fp, opt, output, ofile); transfer_nextfile(gl, &li, r == 0); continue; } { char *xcurdir = base_dir_xptr(opath); link = path_absolute(fp->link, xcurdir, ftp->homedir); stripslash(link); free(xcurdir); ftp_trace("found link: '%s' -> '%s'\n", opath, link); } lnfp = ftp_get_file(link); if(lnfp == 0) { /* couldn't dereference the link, try to RETR it */ ftp_trace("unable to dereference link\n"); const int r = getfile(fp, opt, output, ofile); transfer_nextfile(gl, &li, r == 0); continue; } if(strncmp(opath, lnfp->path, strlen(lnfp->path)) == 0) { ftp_trace("opath == '%s', lnfp->path == '%s'\n", opath, lnfp->path); char* sp = shortpath(lnfp->path, 42, ftp->homedir); fprintf(stderr, _("%s: circular link -- skipping\n"), sp); free(sp); transfer_nextfile(gl, &li, true); continue; } fp = lnfp; if(rislink(fp)) /* found a link pointing to another link */ /* forgive me father, for I have goto'ed */ goto link_to_link__duh; } if(risdir(fp)) { if(test(opt, GET_RECURSIVE)) { char *recurs_output; char *recurs_mask; list *rgl; if((get_dir_glob_mask && fnmatch(get_dir_glob_mask, base_name_ptr(fp->path), FNM_EXTMATCH) == FNM_NOMATCH) #ifdef HAVE_REGEX || (get_dir_rx_mask_set && regexec(&get_dir_rx_mask, base_name_ptr(fp->path), 0, 0, 0) == REG_NOMATCH) #endif ) { } else { char *q_recurs_mask; bool success = true; if(!test(opt, GET_PARENTS)) success = asprintf(&recurs_output, "%s/%s", output ? output : ".", ofile) != -1; else success = asprintf(&recurs_output, "%s", output ? output : ".") != -1; if (!success) { fprintf(stderr, _("Failed to allocate memory.\n")); transfer_nextfile(gl, &li, true); continue; } if (asprintf(&recurs_mask, "%s/*", opath) == -1) { free(recurs_output); fprintf(stderr, _("Failed to allocate memory.\n")); transfer_nextfile(gl, &li, true); continue; } rgl = rglob_create(); q_recurs_mask = backslash_quote(recurs_mask); rglob_glob(rgl, q_recurs_mask, true, true, get_exclude_func); free(q_recurs_mask); if(list_numitem(rgl) > 0) getfiles(rgl, opt, recurs_output); if(test(opt, GET_PRESERVE)) get_preserve_attribs(fp, recurs_output); rglob_destroy(rgl); free(recurs_output); } } else if(test(opt, GET_VERBOSE)) { char* sp = shortpath(opath, 42, ftp->homedir); fprintf(stderr, _("%s: omitting directory\n"), sp); free(sp); } transfer_nextfile(gl, &li, true); continue; } if(!risreg(fp)) { if(test(opt, GET_VERBOSE)) { char* sp = shortpath(opath, 42, ftp->homedir); fprintf(stderr, _("%s: not a regular file\n"), sp); free(sp); } transfer_nextfile(gl, &li, true); continue; } const int r = getfile(fp, opt, output, ofile); transfer_nextfile(gl, &li, r == 0); if(gvInterrupted) { gvInterrupted = false; if(li && !get_quit && ftp_connected() && !gvSighupReceived) { int a = ask(ASKYES|ASKNO, ASKYES, _("Continue transfer?")); if(a == ASKNO) { get_quit = true; break; } /* else a == ASKYES */ fprintf(stderr, _("Excellent!!!\n")); } } } }
/* returns: * 0 ok, remove file from list * -1 failure */ static int getfile(const rfile *fi, unsigned int opt, const char *output, const char *destname) { struct stat sb; char* dest = NULL; getmode_t how = getNormal; bool mkunique = false; int r, ret = -1; if((get_glob_mask && fnmatch(get_glob_mask, base_name_ptr(fi->path), FNM_EXTMATCH) == FNM_NOMATCH) #ifdef HAVE_REGEX || (get_rx_mask_set && regexec(&get_rx_mask, base_name_ptr(fi->path), 0, 0, 0) == REG_NOMATCH) #endif ) { return 0; } if(!output) output = "."; if(test(opt, GET_PARENTS)) { char *apath = base_dir_xptr(fi->path); if (asprintf(&dest, "%s%s/%s", output, apath, destname) == -1) { free(apath); fprintf(stderr, _("Failed to allocate memory.\n")); return -1; } free(apath); } else { /* check if -o option is given, if GET_OUTPUT_FILE is set, we only * transfer one file and output is set to the filename. However, if * the destination already exists and is a directory, we assume * that the user meant a directory */ int dest_is_file = test(opt, GET_OUTPUT_FILE); if(stat(output, &sb) == 0) { if(S_ISDIR(sb.st_mode)) { dest_is_file = false; } } if(dest_is_file) dest = xstrdup(output); else if (asprintf(&dest, "%s/%s", output, destname) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); return -1; } } /* make sure destination directory exists */ { char *destdir = base_dir_xptr(dest); if(destdir) { bool r = make_path(destdir); if(!r) { if (errno == EEXIST) ftp_err("`%s' exists but is not a directory\n", destdir); else ftp_err("%s: %s\n", destdir, strerror(errno)); transfer_mail_msg(_("Couldn't create directory: %s\n"), destdir); free(destdir); return -1; } /* change permission and group, if requested */ if(test(opt, GET_CHMOD)) { if(stat(destdir, &sb) == 0) { mode_t m = sb.st_mode; m = mode_adjust(m, cmod); if(chmod(destdir, m) != 0) perror(destdir); } } if(test(opt, GET_CHGRP)) { if(chown(destdir, -1, group_change) != 0) perror(dest); } free(destdir); } } /* check if destination file exists */ if(stat(dest, &sb) == 0) { if(test(opt, GET_SKIP_EXISTING)) { if(test(opt, GET_VERBOSE)) { char* sp = shortpath(dest, 42, gvLocalHomeDir); fprintf(stderr, _("Local file '%s' exists, skipping...\n"), sp); stats_file(STATS_SKIP, 0); free(sp); } return 0; } if(test(opt, GET_UNIQUE)) mkunique = true; else if(test(opt, GET_APPEND)) how = getAppend; else if(test(opt, GET_NEWER)) { struct tm *fan = gmtime(&sb.st_mtime); time_t ft = ftp_filetime(fi->path, test(opt, GET_FORCE_NEWER)); sb.st_mtime = gmt_mktime(fan); ftp_trace("get -n: remote file: %s", ctime(&ft)); ftp_trace("get -n: local file: %s\n", ctime(&sb.st_mtime)); if(sb.st_mtime >= ft && ft != (time_t)-1) { if(test(opt, GET_VERBOSE)) { char* sp = shortpath(dest, 30, gvLocalHomeDir); ftp_err(_( "Local file '%s' is newer than remote, skipping...\n"), sp); stats_file(STATS_SKIP, 0); free(sp); } return 0; } } else if(!test(opt, GET_RESUME)) { if(!get_owbatch && !gvSighupReceived) { struct tm *fan = gmtime(&sb.st_mtime); time_t ft = ftp_filetime(fi->path, test(opt, GET_FORCE_NEWER)); int a; char *e; sb.st_mtime = gmt_mktime(fan); e = xstrdup(ctime(&sb.st_mtime)); char* sp = shortpath(dest, 42, gvLocalHomeDir); a = ask(ASKYES|ASKNO|ASKUNIQUE|ASKCANCEL|ASKALL|ASKRESUME, ASKRESUME, _("Local file '%s' exists\nLocal: %lld bytes, %sRemote: %lld bytes, %sOverwrite?"), sp, (unsigned long long) sb.st_size, e ? e : "unknown date\n", ftp_filesize(fi->path), ctime(&ft)); free(sp); free(e); if(a == ASKCANCEL) { get_quit = true; return 0; } else if(a == ASKNO) return 0; else if(a == ASKUNIQUE) mkunique = true; else if(a == ASKALL) { get_owbatch = true; } else if(a == ASKRESUME) opt |= GET_RESUME; /* for this file only */ /* else a == ASKYES */ } } if(test(opt, GET_RESUME)) how = getResume; } if(mkunique) { char* newdest = make_unique_filename(dest); free(dest); dest = newdest; } /* the file doesn't exist or we choosed to overwrite it, or changed dest */ if(rislink(fi) && test(opt, GET_NO_DEREFERENCE)) { /* remove any existing destination */ unlink(dest); ftp_err(_("symlinking '%s' to '%s'\n"), dest, fi->link); if(symlink(fi->link, dest) != 0) perror(dest); ret = 0; } else { r = do_the_get(fi->path, dest, how, opt); if(r == 0) { stats_file(STATS_SUCCESS, ftp->ti.total_size); ret = 0; if(test(opt, GET_PRESERVE)) get_preserve_attribs(fi, dest); if(test(opt, GET_CHMOD)) { mode_t m = rfile_getmode(fi); m = mode_adjust(m, cmod); if(chmod(dest, m) != 0) perror(dest); } if(test(opt, GET_CHGRP)) { if(chown(dest, -1, group_change) != 0) perror(dest); } if(test(opt, GET_DELETE_AFTER)) { bool dodel = false; char* sp = shortpath(fi->path, 42, ftp->homedir); if(!test(opt, GET_FORCE) && !get_delbatch && !gvSighupReceived) { int a = ask(ASKYES|ASKNO|ASKCANCEL|ASKALL, ASKYES, _("Delete remote file '%s'?"), sp); if(a == ASKALL) { get_delbatch = true; dodel = true; } else if(a == ASKCANCEL) get_quit = true; else if(a != ASKNO) dodel = true; } else dodel = true; if(dodel) { ftp_unlink(fi->path); if(ftp->code == ctComplete) fprintf(stderr, _("%s: deleted\n"), sp); else fprintf(stderr, _("error deleting '%s': %s\n"), sp, ftp_getreply(false)); } free(sp); } } else { stats_file(STATS_FAIL, 0); ret = -1; } } free(dest); return ret; }
/* appends rglob items in list LP matching MASK * EXCLUDE_FUNC (if not 0) is called for each fileinfo item found * and that file is excluded if EXCLUDE_FUNC returns true * returns 0 if successful, -1 if failure (no files found) * * if ignore_multiples is true, a file isn't added to the list * if it already exists in the list * * any spaces or other strange characters in MASK should be backslash-quoted */ int rglob_glob(list *gl, const char *mask, bool cpifnomatch, bool ignore_multiples, rglobfunc exclude_func) { char *path; char *dep, *mp; rdirectory *rdir; listitem *lip; rfile *fi = 0, *nfi; char *d; int found = 0; path = tilde_expand_home(mask, ftp->homedir); dep = strrchr(path, '/'); if(!dep) dep = path; else dep++; mp = xstrdup(dep); if(mp) unquote(mp); /* note: mp might be NULL here, treat it like mp == "*" */ /* read the directory */ d = base_dir_xptr(path); if(!d) d = xstrdup(ftp->curdir); else unquote(d); rdir = ftp_get_directory(d); free(d); if(rdir) { lip = rdir->files->first; while(lip) { fi = (rfile *)lip->data; lip = lip->next; /* check if the mask includes this file */ if(mp == 0 || fnmatch(mp, base_name_ptr(fi->path), 0) != FNM_NOMATCH) { bool ignore_item; found++; /* call the exclude function, if any, and skip file if the function returns true */ if(exclude_func && exclude_func(fi)) ignore_item = true; else ignore_item = (ignore_multiples && (list_search(gl, (listsearchfunc)rfile_search_path, fi->path) != 0)); if(!ignore_item) { nfi = rfile_clone(fi); list_additem(gl, (void *)nfi); } else ftp_trace("ignoring file '%s'\n", fi->path); } } } if(found == 0) { char *p; bool ignore_item; if(!cpifnomatch || mp == 0 || *mp == 0) { free(mp); return -1; } p = ftp_path_absolute(path); unquote(p); /* disallow multiples of the same file */ ignore_item = (ignore_multiples && (list_search(gl, (listsearchfunc)rfile_search_path, p)) != 0); if(!ignore_item) { nfi = rfile_create(); rfile_fake(nfi, p); list_additem(gl, (void *)nfi); } free(p); } free(mp); free(path); return 0; }
static void putfile(const char *path, struct stat *sb, unsigned opt, const char *output) { putmode_t how = putNormal; bool file_exists = false; char *dest, *dpath; int r; bool dir_created; char *dest_dir, *q_dest_dir; if((put_glob_mask && fnmatch(put_glob_mask, base_name_ptr(path), FNM_EXTMATCH) == FNM_NOMATCH) #ifdef HAVE_REGEX || (put_rx_mask_set && regexec(&put_rx_mask, base_name_ptr(path), 0, 0, 0) == REG_NOMATCH) #endif ) return; if(!output) output = "."; if(test(opt, PUT_PARENTS)) { char *p = base_dir_xptr(path); asprintf(&dest, "%s/%s/%s", output, p, base_name_ptr(path)); free(p); } else if(test(opt, PUT_OUTPUT_FILE)) dest = xstrdup(output); else asprintf(&dest, "%s/%s", output, base_name_ptr(path)); path_collapse(dest); /* make sure destination directory exists */ dpath = base_dir_xptr(dest); dest_dir = ftp_path_absolute(dpath); q_dest_dir = bash_backslash_quote(dest_dir); r = ftp_mkpath(q_dest_dir); free(q_dest_dir); free(dest_dir); if(r == -1) { transfer_mail_msg(_("failed to create directory %s\n"), dest_dir); free(dpath); free(dest); return; } dir_created = (r == 1); if(!dir_created && !test(opt, PUT_UNIQUE) && !test(opt, PUT_FORCE)) { rfile *f; f = ftp_get_file(dest); file_exists = (f != 0); if(f && risdir(f)) { /* can't overwrite a directory */ printf(_("%s: is a directory\n"), dest); free(dest); return; } } if(test(opt, PUT_APPEND)) { how = putAppend; } else if(file_exists) { if(test(opt, PUT_SKIP_EXISTING)) { printf(_("Remote file '%s' exists, skipping...\n"), shortpath(dest, 42, ftp->homedir)); free(dest); return; } else if(test(opt, PUT_NEWER)) { time_t ft = ftp_filetime(dest); if(ft != (time_t)-1 && ft >= sb->st_mtime) { printf(_("Remote file '%s' is newer than local, skipping...\n"), shortpath(dest, 42, ftp->homedir)); free(dest); return; } } else if(!test(opt, PUT_RESUME)) { if(!put_owbatch) { struct tm *fan = gmtime(&sb->st_mtime); time_t ft; int a; rfile *f; char *e; f = ftp_get_file(dest); ft = ftp_filetime(f->path); sb->st_mtime = gmt_mktime(fan); e = xstrdup(ctime(&sb->st_mtime)); a = ask(ASKYES|ASKNO|ASKUNIQUE|ASKCANCEL|ASKALL|ASKRESUME, ASKRESUME, _("Remote file '%s' exists\nLocal: %lld bytes, %sRemote: %lld bytes, %sOverwrite?"), shortpath(dest, 42, ftp->homedir), (unsigned long long) sb->st_size, e ? e : "unknown size", ftp_filesize(f->path), ctime(&ft)); free(e); if(a == ASKCANCEL) { put_quit = true; free(dest); return; } else if(a == ASKNO) { free(dest); return; } else if(a == ASKUNIQUE) opt |= PUT_UNIQUE; /* for this file only */ else if(a == ASKALL) put_owbatch = true; else if(a == ASKRESUME) opt |= PUT_RESUME; /* for this file only */ /* else a == ASKYES */ } } } if(test(opt, PUT_RESUME)) how = putResume; if(test(opt, PUT_UNIQUE)) how = putUnique; r = do_the_put(path, dest, how, opt); free(dest); if(r != 0) return; if(test(opt, PUT_PRESERVE)) { if(ftp->has_site_chmod_command) ftp_chmod(ftp->ti.local_name, get_mode_string(sb->st_mode)); } if(test(opt, PUT_DELETE_AFTER)) { bool dodel = false; if(!test(opt, PUT_FORCE) && !put_delbatch) { int a = ask(ASKYES|ASKNO|ASKCANCEL|ASKALL, ASKYES, _("Delete local file '%s'?"), shortpath(path, 42, gvLocalHomeDir)); if(a == ASKALL) { put_delbatch = true; dodel = true; } else if(a == ASKCANCEL) put_quit = true; else if(a != ASKNO) dodel = true; } else dodel = true; if(dodel) { if(unlink(path) == 0) printf(_("%s: deleted\n"), shortpath(path, 42, gvLocalHomeDir)); else printf(_("error deleting '%s': %s\n"), shortpath(path, 42, gvLocalHomeDir), strerror(errno)); } } }
static int fxpfile(const rfile *fi, unsigned int opt, const char *output, const char *destname) { fxpmode_t how = fxpNormal; bool file_exists = false; char *dest, *dpath; bool dir_created; char *dest_dir, *q_dest_dir; Ftp *thisftp = ftp; if((fxp_glob_mask && fnmatch(fxp_glob_mask, base_name_ptr(fi->path), 0) == FNM_NOMATCH) #ifdef HAVE_REGEX || (fxp_rx_mask_set && regexec(&fxp_rx_mask, base_name_ptr(fi->path), 0, 0, 0) == REG_NOMATCH) #endif ) return 0; if(!output) output = "."; if(test(opt, FXP_PARENTS)) { char *p = base_dir_xptr(fi->path); if (asprintf(&dest, "%s/%s/%s", output, p, base_name_ptr(fi->path)) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); free(p); return -1; } free(p); } else if(test(opt, FXP_OUTPUT_FILE)) dest = xstrdup(output); else if (asprintf(&dest, "%s/%s", output, base_name_ptr(fi->path)) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); return -1; } path_collapse(dest); ftp_use(fxp_target); /* make sure destination directory exists */ dpath = base_dir_xptr(dest); dest_dir = ftp_path_absolute(dpath); q_dest_dir = backslash_quote(dest_dir); int r = ftp_mkpath(q_dest_dir); free(q_dest_dir); free(dest_dir); if(r == -1) { transfer_mail_msg(_("Couldn't create directory: %s\n"), dest_dir); free(dpath); free(dest); ftp_use(thisftp); return -1; } dir_created = (r == 1); if(!dir_created && !test(opt, FXP_UNIQUE) && !test(opt, FXP_FORCE)) { rfile *f; f = ftp_get_file(dest); file_exists = (f != 0); if(f && risdir(f)) { /* can't overwrite a directory */ printf(_("%s: is a directory\n"), dest); free(dest); return 0; } } if(test(opt, FXP_APPEND)) { how = fxpAppend; } else if(file_exists) { if(test(opt, FXP_SKIP_EXISTING)) { char* sp = shortpath(dest, 42, ftp->homedir); printf(_("Remote file '%s' exists, skipping...\n"), sp); free(sp); free(dest); ftp_use(thisftp); return 0; } else if(test(opt, FXP_NEWER)) { time_t src_ft; time_t dst_ft; ftp_use(thisftp); src_ft = ftp_filetime(fi->path, test(opt, FXP_FORCE_NEWER)); ftp_use(fxp_target); dst_ft = ftp_filetime(dest, test(opt, FXP_FORCE_NEWER)); if(src_ft != (time_t)-1 && dst_ft != (time_t)-1 && dst_ft >= src_ft) { char* sp = shortpath(dest, 42, ftp->homedir); printf(_("Remote file '%s' is newer than local, skipping...\n"), sp); free(sp); free(dest); ftp_use(thisftp); return 0; } } else if(!test(opt, FXP_RESUME)) { if(!fxp_owbatch) { char* sp = shortpath(dest, 42, ftp->homedir); int a = ask(ASKYES|ASKNO|ASKUNIQUE|ASKCANCEL|ASKALL|ASKRESUME, ASKRESUME, _("File '%s' exists, overwrite?"), sp); free(sp); if(a == ASKCANCEL) { fxp_quit = true; free(dest); ftp_use(thisftp); return 0; } else if(a == ASKNO) { free(dest); ftp_use(thisftp); return 0; } else if(a == ASKUNIQUE) opt |= FXP_UNIQUE; /* for this file only */ else if(a == ASKALL) fxp_owbatch = true; else if(a == ASKRESUME) opt |= FXP_RESUME; /* for this file only */ /* else a == ASKYES */ } } } if(test(opt, FXP_RESUME)) how = fxpResume; if(test(opt, FXP_UNIQUE)) how = fxpUnique; r = do_the_fxp(thisftp, fi->path, fxp_target, dest, how, opt); free(dest); if(r != 0) { ftp_use(thisftp); return -1; } if(test(opt, FXP_PRESERVE)) fxp_preserve_attribs(fi, dest); if(test(opt, FXP_DELETE_AFTER)) { bool dodel = false; ftp_use(thisftp); if(!test(opt, FXP_FORCE) && !fxp_delbatch && !gvSighupReceived) { char* sp = shortpath(fi->path, 42, ftp->homedir); int a = ask(ASKYES|ASKNO|ASKCANCEL|ASKALL, ASKYES, _("Delete remote file '%s'?"), sp); free(sp); if(a == ASKALL) { fxp_delbatch = true; dodel = true; } else if(a == ASKCANCEL) fxp_quit = true; else if(a != ASKNO) dodel = true; } else dodel = true; if(dodel) { ftp_unlink(fi->path); char* sp = shortpath(fi->path, 42, ftp->homedir); if(ftp->code == ctComplete) fprintf(stderr, _("%s: deleted\n"), sp); else fprintf(stderr, _("error deleting '%s': %s\n"), sp, ftp_getreply(false)); free(sp); } } ftp_use(thisftp); return 0; }