int ssh_send(const char *path, FILE *fp, putmode_t how, transfer_mode_t mode, ftp_transfer_func hookf) { uint64_t offset = ftp->restart_offset; reset_transfer_info(); ftp->ti.size = ftp->ti.restart_size = offset; ftp->restart_offset = 0L; ftp->ti.transfer_is_put = true; if(how == putUnique) { ftp_err(_("Unique put with SSH not implemented yet\n")); return -1; } char* p = ftp_path_absolute(path); stripslash(p); ftp_cache_flush_mark_for(p); if(how == putAppend) { ftp_set_tmp_verbosity(vbNone); offset = ftp_filesize(p); } int r = do_write(p, fp, hookf, offset); free(p); transfer_finished(); return r; }
int ssh_send(const char *path, FILE *fp, putmode_t how, transfer_mode_t mode, ftp_transfer_func hookf) { int r; long offset = ftp->restart_offset; char *p; reset_transfer_info(); ftp->ti.size = ftp->ti.restart_size = offset; ftp->restart_offset = 0L; ftp->ti.transfer_is_put = true; if(how == putUnique) { ftp_err("Unique put with SSH not implemented yet\n"); return -1; #if 0 /* try to figure out remote filename */ char *e = strstr(ftp->reply, " for "); if(e) { int l; e += 5; l = strlen(e); if(l) { free(ftp->ti.local_name); if(*e == '\'') ftp->ti.local_name = xstrndup(e+1, l-3); else ftp->ti.local_name = xstrndup(e, l-1); ftp_trace("parsed unique filename as '%s'\n", ftp->ti.local_name); } } #endif } p = ftp_path_absolute(path); stripslash(p); ftp_cache_flush_mark_for(p); if(how == putAppend) { ftp_set_tmp_verbosity(vbNone); offset = ftp_filesize(p); } r = ssh_send_binary(p, fp, hookf, offset); free(p); transfer_finished(); return 0; }
/* 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; }
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)); } } }
/* transfers SRCFILE on SRCFTP to DESTFILE on DESTFTP * using pasv mode on SRCFTP and port mode on DESTFTP * */ int ftp_fxpfile(Ftp *srcftp, const char *srcfile, Ftp *destftp, const char *destfile, fxpmode_t how, transfer_mode_t mode) { int r; unsigned int old_reply_timeout; Ftp *thisftp; unsigned char addr[6]; /* printf("FxP: %s -> %s\n", srcftp->url->hostname, destftp->url->hostname);*/ if(srcftp == destftp) { ftp_err(_("FxP between same hosts\n")); return -1; } #ifdef HAVE_LIBSSH if(ftp->session) { ftp_err("FxP with SSH not implemented\n"); return -1; } #endif thisftp = ftp; /* save currently active connection */ /* setup source side */ ftp_use(srcftp); ftp_type(mode); // TODO: IPv6 support if(!ftp_pasv(false, addr, NULL)) { ftp_use(thisftp); return -1; } ftp->ti.total_size = -1; /* setup destination side */ ftp_use(destftp); ftp_type(mode); ftp_cmd("PORT %d,%d,%d,%d,%d,%d", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); if(ftp->code != ctComplete) { ftp_use(thisftp); return -1; } ftp->ti.total_size = -1; ftp_use(destftp); if(how == fxpResume) { rfile *f; f = ftp_get_file(destfile); if(f && f->size != (unsigned long long)-1) ftp->restart_offset = f->size; else { ftp->restart_offset = ftp_filesize(destfile); if(ftp->restart_offset == (unsigned long long)-1) { ftp_err(_("unable to get remote filesize of '%s'," " unable to resume\n"), destfile); ftp->restart_offset = 0L; } } } else ftp->restart_offset = 0L; if(ftp->restart_offset) { /* RESTart on destftp */ ftp_cmd("REST %ld", ftp->restart_offset); if(ftp->code != ctContinue) return -1; ftp_use(srcftp); ftp_cmd("REST %ld", ftp->restart_offset); if(ftp->code != ctContinue) return -1; } /* issue a STOR command on DESTFTP */ ftp_use(destftp); switch(how) { case fxpUnique: if(ftp->has_stou_command) { ftp_cmd("STOU %s", destfile); if(ftp->fullcode == 502) ftp->has_stou_command = false; } else { ftp->code = ctError; ftp->fullcode = 502; } break; case fxpAppend: ftp_cmd("APPE %s", destfile); break; case fxpNormal: default: ftp_cmd("STOR %s", destfile); break; } ftp_cache_flush_mark_for(destfile); if(ftp->code != ctPrelim) { ftp_use(thisftp); return -1; } /* issue a RETR command on SRCFTP */ ftp_use(srcftp); ftp_cmd("RETR %s", srcfile); if(ftp->code != ctPrelim) { ftp_use(destftp); ftp_abort(NULL); ftp_use(thisftp); return -1; } ftp_use(destftp); old_reply_timeout = ftp->reply_timeout; ftp_reply_timeout(0); ftp_read_reply(); ftp_reply_timeout(old_reply_timeout); r = (ftp->code == ctComplete ? 0 : -1); ftp_use(srcftp); old_reply_timeout = ftp->reply_timeout; ftp_reply_timeout(0); ftp_read_reply(); ftp_reply_timeout(old_reply_timeout); ftp_use(thisftp); return r; }
int ftp_putfile(const char *infile, const char *outfile, putmode_t how, transfer_mode_t mode, ftp_transfer_func hookf) { FILE *fp; int r; struct stat statbuf; if(stat(infile, &statbuf) != 0) { perror(infile); return -1; } if(S_ISDIR(statbuf.st_mode)) { ftp_err(_("%s: is a directory\n"), infile); return -1; } fp = fopen(infile, "r"); if(fp == 0) { perror(infile); return -1; } ftp->ti.total_size = statbuf.st_size; free(ftp->ti.remote_name); free(ftp->ti.local_name); ftp->ti.remote_name = xstrdup(infile); /* actually local file, or _target_ */ ftp->ti.local_name = xstrdup(outfile); /* actually remote file, or _source_ */ if(how == putResume) { rfile *f; f = ftp_get_file(outfile); if(f && f->size != (unsigned long long)-1) ftp->restart_offset = f->size; else { ftp->restart_offset = ftp_filesize(outfile); if(ftp->restart_offset == (unsigned long long)-1) { ftp_err(_("unable to get remote filesize of '%s'," " unable to resume\n"), outfile); ftp->restart_offset = 0L; } } } else ftp->restart_offset = 0L; if(ftp->restart_offset > 0L) { if(fseek(fp, ftp->restart_offset, SEEK_SET) != 0) { ftp_err(_("%s: %s, transfer cancelled\n"), outfile, strerror(errno)); fclose(fp); return -1; } } foo_hookf = hookf; #ifdef HAVE_LIBSSH if(ftp->session) r = ssh_send(outfile, fp, how, mode, hookf); else #endif r = ftp_send(outfile, fp, how, mode, hookf); fclose(fp); return r; }