int chirp_fs_local_resolve (const char *path, char resolved[CHIRP_PATH_MAX]) { char collapse[CHIRP_PATH_MAX]; char absolute[CHIRP_PATH_MAX]; path_collapse(path, collapse, 1); int n = snprintf(absolute, sizeof(absolute), "%s/%s", local_root, collapse); assert(n >= 0); /* this should never happen */ if ((size_t)n >= CHIRP_PATH_MAX) { errno = ENAMETOOLONG; return -1; } path_collapse(absolute, resolved, 1); return 0; }
static int resolve (confuga *C, const char *path, char resolved[CONFUGA_PATH_MAX]) { int rc; char collapse[CONFUGA_PATH_MAX]; char absolute[CONFUGA_PATH_MAX]; path_collapse(path, collapse, 1); CATCHUNIX(snprintf(absolute, sizeof(absolute), "%s/root/%s", C->root, collapse)); if ((size_t)rc >= CONFUGA_PATH_MAX) CATCH(ENAMETOOLONG); path_collapse(absolute, resolved, 1); rc = 0; goto out; out: return rc; }
/* returns a static buffer, overwritten with each call */ char *shortpath(const char *path, unsigned maxlen, const char *home) { char *e; static char tmp[PATH_MAX]; extern bool gvTilde; if(!path) return 0; strcpy(tmp, path); path_collapse(tmp); if(home && home[0] && strlen(home)>=3 && gvTilde) { if(strncmp(tmp, home, strlen(home)) == 0) { tmp[0] = '~'; strpull(tmp+1, strlen(home)-1); } } if(maxlen <= 3) return tmp; e = _shortpath(tmp, maxlen); return e; }
int chirp_acl_ticket_modify(const char *subject, const char *ticket_subject, const char *path, int flags) { char ticket_filename[CHIRP_PATH_MAX]; const char *digest; char *esubject; struct chirp_ticket ct; int status = 0; if(!chirp_ticket_isticketsubject(ticket_subject, &digest)) { errno = EINVAL; return -1; } /* Note about tickets making tickets: * We check whether the ticket has the rights associated with the mask in * the next line. So, a ticket can only make a ticket with rights it * already has. */ if(!chirp_acl_check_dir(path, subject, flags)) return -1; /* you don't have the rights for the mask */ if(!chirp_acl_whoami(subject, &esubject)) return -1; chirp_ticket_filename(ticket_filename, ticket_subject, NULL); if(!ticket_read(ticket_filename, &ct)) { free(esubject); return -1; } if(strcmp(esubject, ct.subject) == 0 || strcmp(chirp_super_user, subject) == 0) { size_t n; int replaced = 0; for(n = 0; n < ct.nrights; n++) { if(strcmp(ct.rights[n].directory, path) == 0) { free(ct.rights[n].acl); ct.rights[n].acl = xxstrdup(chirp_acl_flags_to_text(flags)); /* replace old acl mask */ replaced = 1; } } if(!replaced) { char directory[CHIRP_PATH_MAX]; assert(strlen(path)); ct.rights = xxrealloc(ct.rights, sizeof(*ct.rights) * (++ct.nrights) + 1); path_collapse(path, directory, 1); ct.rights[ct.nrights - 1].directory = xxstrdup(directory); ct.rights[ct.nrights - 1].acl = xxstrdup(chirp_acl_flags_to_text(flags)); } status = ticket_write(ticket_filename, &ct); } else { errno = EACCES; status = -1; } chirp_ticket_free(&ct); free(esubject); return status; }
static void complete_remote_path(const char *file, char *full_path) { char temp[CHIRP_PATH_MAX]; if(file[0] != '/') { sprintf(temp, "%s/%s", current_remote_dir, file); } else { strcpy(temp, file); } path_collapse(temp, full_path, 1); }
std::string pwd_full_ex (std::string rel, const std::string &path) { if (rel[0] != '/') { rel = path + rel; } // process '..' bool err = false; std::string r = path_collapse(rel, err); if (err) EXCEPT << "Path tries to escape game dir: \"" << rel << "\"" << ENDL; return r; }
std::string pwd_full_ex (std::string rel, const std::string &path, const std::string &def) { if (rel[0] != '/') { rel = path + rel; } // process '..' bool err = false; std::string r = path_collapse(rel, err); if (err) { CERR << "Path tries to escape game dir: \"" << rel << "\"" << std::endl; r = def; } return r; }
static int chirp_fs_hdfs_init(const char url[CHIRP_PATH_MAX]) { static const char *groups[] = { "supergroup" }; char *path; if(!hdfs_services) { if (hdfs_library_envinit() == -1) return -1; hdfs_services = hdfs_library_open(); if(!hdfs_services) return -1; } debug(D_CHIRP, "url: %s", url); assert(strprfx(url, "hdfs://")); strcpy(hdfs_host, url+strlen("hdfs://")); path = strchr(hdfs_host, '/'); if (path) { path_collapse(path, hdfs_root, 1); *path = '\0'; /* remove path from hdfs_host */ /* now hdfs_host holds 'host[:port]' */ } else { strcpy(hdfs_root, "/"); } if (strlen(hdfs_host) == 0) { /* use default */ strcpy(hdfs_host, "default"); hdfs_port = 0; } else if (strchr(hdfs_host, ':')) { hdfs_port = atoi(strchr(hdfs_host, ':')+1); *strchr(hdfs_host, ':') = '\0'; } else { hdfs_port = 50070; /* default namenode port */ } debug(D_HDFS, "connecting to hdfs://%s:%u%s as '%s'\n", hdfs_host, hdfs_port, hdfs_root, chirp_owner); assert(fs == NULL); fs = hdfs_services->connect_as_user(hdfs_host, hdfs_port, chirp_owner, groups, 1); if (fs == NULL) { errno = EIO; return -1; } memset(open_files, 0, sizeof(open_files)); return cfs_create_dir("/", 0711); }
static int chirp_fs_local_init(const char url[CHIRP_PATH_MAX]) { int i; char tmp[CHIRP_PATH_MAX]; if (strprfx(url, "local://") || strprfx(url, "file://")) strcpy(tmp, strstr(url, "//")+2); else strcpy(tmp, url); path_collapse(tmp, local_root, 1); for (i = 0; i < CHIRP_FILESYSTEM_MAXFD; i++) open_files[i].fd = -1; return cfs_create_dir("/", 0711); }
static INT64_T do_cd(int argc, char **argv) { char full_path[CHIRP_PATH_MAX]; struct chirp_stat info; complete_remote_path(argv[1], full_path); if(chirp_reli_stat(current_host, full_path, &info, stoptime) < 0) { return -1; } else { if(S_ISDIR(info.cst_mode)) { path_collapse(full_path, current_remote_dir, 1); return 0; } else { errno = ENOTDIR; return -1; } } }
static const char *chirp_fs_local_init(const char *url) { static char root[CHIRP_PATH_MAX]; char tmp[CHIRP_PATH_MAX]; if (strlen(url) >= CHIRP_PATH_MAX) { fatal("root path too long"); } if (strprfx(url, "local://") || strprfx(url, "file://")) strcpy(tmp, strstr(url, "//")+2); else strcpy(tmp, url); path_collapse(tmp, root, 1); return root; }
static int chirp_fs_local_init(const char url[CHIRP_PATH_MAX]) { PREAMBLE("init(`%s')", url); int i; char tmp[CHIRP_PATH_MAX]; for (i = 0; i < CHIRP_FILESYSTEM_MAXFD; i++) open_files[i].fd = -1; if (strprfx(url, "local://") || strprfx(url, "file://")) strcpy(tmp, strstr(url, "//")+2); else strcpy(tmp, url); path_collapse(tmp, local_root, 1); rc = create_dir(local_root, 0711); PROLOGUE }
static int do_chirp_acl_check(const char *filename, const char *subject, int flags, int follow_links) { char linkname[CHIRP_PATH_MAX]; char temp[CHIRP_PATH_MAX]; char dirname[CHIRP_PATH_MAX]; if(cfs->do_acl_check() == 0) return 1; /* Symbolic links require special handling. If requested, follow the link and look for rights in that directory. */ if(follow_links && flags != CHIRP_ACL_DELETE) { int length = cfs->readlink(filename, linkname, sizeof(linkname)); if(length > 0) { linkname[length] = 0; /* If the link is relative, construct a full path */ if(linkname[0] != '/') { sprintf(temp, "%s/../%s", filename, linkname); path_collapse(temp, linkname, 1); } /* Use the linkname now to look up the ACL */ debug(D_DEBUG, "symlink %s points to %s", filename, linkname); filename = linkname; } } /* If the file being checked is an ACL file, then it may be written with the admin flag, but never deleted. */ if(!strcmp(string_back(filename, CHIRP_ACL_BASE_LENGTH), CHIRP_ACL_BASE_NAME)) { if(flags & CHIRP_ACL_DELETE) { errno = EACCES; return 0; } if(flags & CHIRP_ACL_WRITE) { flags &= ~CHIRP_ACL_WRITE; flags |= CHIRP_ACL_ADMIN; } } /* Now get the name of the directory containing the file */ path_collapse(filename, temp, 1); if(!cfs_isdir(temp)) path_dirname(temp, dirname); else strcpy(dirname, temp); /* Perform the permissions check on that directory. */ return chirp_acl_check_dir(dirname, subject, flags); }
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)); } } }
/* store a local file on remote server */ void cmd_put(int argc, char **argv) { int c, opt=PUT_VERBOSE; list *gl; char *put_output = 0; char *logfile = 0; pid_t pid; #ifdef HAVE_REGEX int ret; char put_rx_errbuf[129]; #endif struct option longopts[] = { {"append", no_argument, 0, 'a'}, {"delete-after", no_argument, 0, 'D'}, {"dir-mask", required_argument, 0, '3'}, #ifdef HAVE_REGEX {"dir-rx-mask", required_argument, 0, '4'}, #endif {"skip-empty", no_argument, 0, 'e'}, {"force", no_argument, 0, 'f'}, {"nohup", no_argument, 0, 'H'}, {"interactive", no_argument, 0, 'i'}, {"logfile", required_argument, 0, 'L'}, {"mask", required_argument, 0, 'm'}, #ifdef HAVE_REGEX {"rx-mask", required_argument, 0, 'M'}, #endif {"newer", no_argument, 0, 'n'}, {"output", required_argument, 0, 'o'}, {"preserve", no_argument, 0, 'p'}, {"parents", no_argument, 0, 'P'}, {"quiet", no_argument, 0, 'q'}, {"recursive", no_argument, 0, 'r'}, {"resume", no_argument, 0, 'R'}, {"skip-existing", no_argument, 0, 's'}, {"tagged", no_argument, 0, 't'}, {"type", required_argument, 0, '1'}, {"verbose", no_argument, 0, 'v'}, {"unique", no_argument, 0, 'u'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}, }; if(put_glob_mask) { free(put_glob_mask); put_glob_mask = 0; } if(put_dir_glob_mask) { free(put_dir_glob_mask); put_dir_glob_mask = 0; } #ifdef HAVE_REGEX if(put_rx_mask_set) { regfree(&put_rx_mask); put_rx_mask_set = 0; } if(put_dir_rx_mask_set) { regfree(&put_dir_rx_mask); put_dir_rx_mask_set = 0; } #endif put_skip_empty = false; optind = 0; /* force getopt() to re-initialize */ while((c = getopt_long(argc, argv, "aDefHiL:no:pPqrRstvum:M:", longopts, 0)) != EOF) { switch(c) { case 'i': opt |= PUT_INTERACTIVE; break; case 'f': opt |= PUT_FORCE; break; case 'e': opt |= PUT_SKIP_EMPTY; put_skip_empty = true; break; case '3': /* --dir-mask=GLOB */ free(put_dir_glob_mask); put_dir_glob_mask = xstrdup(optarg); unquote(put_dir_glob_mask); break; #ifdef HAVE_REGEX case '4': /* --dir-rx-mask=REGEXP */ if(put_dir_rx_mask_set) { regfree(&put_dir_rx_mask); put_dir_rx_mask_set = false; } unquote(optarg); ret = regcomp(&put_dir_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &put_dir_rx_mask, put_rx_errbuf, 128); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, put_rx_errbuf); return; } else put_dir_rx_mask_set = true; break; #endif case 'o': put_output = tilde_expand_home(optarg, ftp->homedir); path_collapse(put_output); stripslash(put_output); break; case 'H': opt |= PUT_NOHUP; break; case 'L': free(logfile); logfile = xstrdup(optarg); unquote(logfile); break; case 'm': /* --mask */ free(put_glob_mask); put_glob_mask = xstrdup(optarg); break; #ifdef HAVE_REGEX case 'M': /* --rx-mask */ if(put_rx_mask_set) { regfree(&put_rx_mask); put_rx_mask_set = false; } ret = regcomp(&put_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &put_rx_mask, put_rx_errbuf, 128); ftp_err(_("Regexp '%s' failed: %s\n"), optind, put_rx_errbuf); return; } else put_rx_mask_set = true; break; #endif case 'n': opt |= PUT_NEWER; break; case 'v': opt |= PUT_VERBOSE; break; case 'q': opt &= ~PUT_VERBOSE; break; case 'a': opt |= PUT_APPEND; break; case 'D': opt |= PUT_DELETE_AFTER; break; case 'u': opt |= PUT_UNIQUE; if(!ftp->has_stou_command) { fprintf(stderr, _("Remote doesn't support the STOU" " (store unique) command\n")); return; } break; case 'r': opt |= PUT_RECURSIVE; break; case 's': opt |= PUT_SKIP_EXISTING; break; case 'R': opt |= PUT_RESUME; break; case 't': opt |= PUT_TAGGED; break; case '1': if(strncmp(optarg, "ascii", strlen(optarg)) == 0) opt |= PUT_ASCII; else if(strncmp(optarg, "binary", strlen(optarg)) == 0) opt |= PUT_BINARY; else { printf(_("Invalid option argument --type=%s\n"), optarg); return; } break; case 'p': opt |= PUT_PRESERVE; break; case 'P': opt |= PUT_PARENTS; break; case 'h': print_put_syntax();; return; case '?': return; } } if(optind>=argc && !test(opt, PUT_TAGGED)) { /* fprintf(stderr, _("missing argument, try 'put --help'"*/ /* " for more information\n"));*/ minargs(optind); return; } if(test(opt, PUT_APPEND) && test(opt, PUT_SKIP_EXISTING)) { printf("Can't use --append and --skip-existing simultaneously\n"); return; } need_connected(); need_loggedin(); gl = lglob_create(); while(optind < argc) { char *f; f = tilde_expand_home(argv[optind], gvLocalHomeDir); stripslash(f); lglob_glob(gl, f, true, put_exclude_func); optind++; } if(list_numitem(gl) == 0) { if(!test(opt, PUT_TAGGED)) { list_free(gl); return; } else if(list_numitem(gvLocalTagList) == 0) { printf(_("no tagged files\n")); list_free(gl); return; } } free(ftp->last_mkpath); ftp->last_mkpath = 0; put_quit = false; put_batch = put_owbatch = put_delbatch = test(opt, PUT_FORCE); if(test(opt, PUT_FORCE)) opt &= ~PUT_INTERACTIVE; if(put_output && !test(opt, PUT_RECURSIVE) && list_numitem(gl) + (test(opt, PUT_TAGGED) ? list_numitem(gvLocalTagList) : 0) == 1) { opt |= PUT_OUTPUT_FILE; } gvInTransfer = true; gvInterrupted = false; if(test(opt, PUT_NOHUP)) { int r = 0; pid = fork(); if(pid == 0) { r = transfer_init_nohup(logfile); if(r != 0) exit(0); } if(r != 0) return; if(pid == 0) { /* child process */ transfer_begin_nohup(argc, argv); if(!test(opt, PUT_FORCE) && !test(opt, PUT_RESUME)) opt |= PUT_UNIQUE; opt |= PUT_FORCE; putfiles(gl, opt, put_output); list_free(gl); if(test(opt, PUT_TAGGED)) { putfiles(gvLocalTagList, opt, put_output); list_clear(gvLocalTagList); } free(put_output); transfer_end_nohup(); } if(pid == -1) { perror("fork()"); return; } /* parent process */ sleep(1); printf("%d\n", pid); input_save_history(); gvars_destroy(); reset_xterm_title(); exit(0); } putfiles(gl, opt, put_output); list_free(gl); if(test(opt, PUT_TAGGED)) { putfiles(gvLocalTagList, opt, put_output); list_clear(gvLocalTagList); } free(put_output); gvInTransfer = false; }
/* creates path (and all elements in path) * PATH should be an absolute path * returns -1 on error, 0 if no directories created, else 1 */ int ftp_mkpath(const char *path) { bool one_created = false; char *p, *orgp, *e = 0; if(!path) return 0; /* check if we already has created this path */ if(ftp_path_part_of(path, ftp->last_mkpath)) return 0; /* check if this path is a part of current directory */ if(ftp_path_part_of(path, ftp->curdir)) return 0; orgp = p = xstrdup(path); path_collapse(p); unquote(p); if(*p == '/') { e = xmalloc(1); *e = 0; } while(true) { char *tmp, *foo; tmp = strqsep(&p, '/'); if(!tmp) break; if (e) { if (asprintf(&foo, "%s/%s", e, tmp) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); free(e); free(orgp); return -1; } } else foo = xstrdup(tmp); free(e); e = foo; /* check if we already has created this path */ if(ftp_path_part_of(e, ftp->last_mkpath)) continue; /* check if this path is a part of current directory */ if(ftp_path_part_of(e, ftp->curdir)) continue; if(strcmp(e, ".") != 0) { ftp_mkdir_verb(e, vbNone); one_created = (ftp->code == ctComplete); } } free(ftp->last_mkpath); ftp->last_mkpath = path_absolute(path, ftp->curdir, ftp->homedir); free(e); free(orgp); return one_created; }
static int do_chirp_acl_get(const char *dirname, const char *subject, int *totalflags) { CHIRP_FILE *aclfile; char aclsubject[CHIRP_LINE_MAX]; int aclflags; errno = 0; *totalflags = 0; /* if the subject is a ticket, then we need the rights we have for the * directory along with the rights of the subject in that directory */ const char *digest; if(chirp_ticket_isticketsubject(subject, &digest)) { /* open the ticket file, read the public key */ char ticket_filename[CHIRP_PATH_MAX]; struct chirp_ticket ct; chirp_ticket_filename(ticket_filename, subject, NULL); if(!ticket_read(ticket_filename, &ct)) return 0; if(!do_chirp_acl_get(dirname, ct.subject, totalflags)) { chirp_ticket_free(&ct); return 0; } size_t i; size_t longest = 0; int mask = 0; for(i = 0; i < ct.nrights; i++) { char where[CHIRP_PATH_MAX]; path_collapse(ct.rights[i].directory, where, 1); if(strncmp(dirname, where, strlen(where)) == 0) { if(strlen(where) > longest) { longest = strlen(where); mask = chirp_acl_text_to_flags(ct.rights[i].acl); } } } *totalflags &= mask; } else { aclfile = chirp_acl_open(dirname); if(aclfile) { while(chirp_acl_read(aclfile, aclsubject, &aclflags)) { if(string_match(aclsubject, subject)) { *totalflags |= aclflags; } else if(!strncmp(aclsubject, "group:", 6)) { if(chirp_group_lookup(aclsubject, subject)) { *totalflags |= aclflags; } } } chirp_acl_close(aclfile); } else { return 0; } } if(read_only_mode) { *totalflags &= CHIRP_ACL_READ | CHIRP_ACL_LIST; } return 1; }
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; }