void cmd_cat(int argc, char **argv) { int i; struct option longopts[] = { {"type", required_argument, 0, 't'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; int c; transfer_mode_t mode = tmAscii; optind = 0; while((c = getopt_long(argc, argv, "t:h", longopts, 0)) != EOF) { switch(c) { case 't': if(strncmp(optarg, "ascii", strlen(optarg)) == 0) mode = tmAscii; else if(strncmp(optarg, "binary", strlen(optarg)) == 0) mode = tmBinary; else { fprintf(stderr, _("Invalid option argument --type=%s\n"), optarg); return; } break; case 'h': show_help(_("Print file(s) on standard output."), "cat [options] <file>...", _(" -t, --type=TYPE set transfer TYPE to ascii or binary\n")); return; case '?': optind = -1; return; } } minargs(optind); need_connected(); need_loggedin(); for(i = optind; i < argc; i++) { listitem *gli; list *gl = rglob_create(); stripslash(argv[i]); if(rglob_glob(gl, argv[i], true, false, 0) == -1) fprintf(stderr, _("%s: no matches found\n"), argv[i]); for(gli = gl->first; gli; gli=gli->next) { rfile *rf = (rfile *)gli->data; const char *fn = base_name_ptr(rf->path); if(strcmp(fn, ".") != 0 && strcmp(fn, "..") != 0) { ftp_receive(rf->path, stdout, mode, 0); fflush(stdout); } } rglob_destroy(gl); } }
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; }
rdirectory *ftp_get_directory(const char *path) { rdirectory *rdir; char *ap; ap = ftp_path_absolute(path); stripslash(ap); rdir = ftp_cache_get_directory(ap); if(!rdir) rdir = ftp_read_directory(ap); free(ap); return rdir; }
int ssh_rename(const char *oldname, const char *newname) { char* on = ftp_path_absolute(oldname); char* nn = ftp_path_absolute(newname); stripslash(on); stripslash(nn); int rc = sftp_rename(ftp->sftp_session, on, nn); if (rc != SSH_OK) { ftp_err(_("Couldn't rename file '%s' to '%s': %s\n"), on, nn, ssh_get_error(ftp->session)); free(on); free(nn); return -1; } ftp_cache_flush_mark_for(on); ftp_cache_flush_mark_for(nn); free(on); free(nn); return 0; }
int ssh_rename(const char *oldname, const char *newname) { Buffer msg; u_int status, id; char *on, *nn; buffer_init(&msg); on = ftp_path_absolute(oldname); nn = ftp_path_absolute(newname); stripslash(on); stripslash(nn); /* Send rename request */ id = ftp->ssh_id++; buffer_put_char(&msg, SSH2_FXP_RENAME); buffer_put_int(&msg, id); buffer_put_cstring(&msg, on); buffer_put_cstring(&msg, nn); ssh_cmd( &msg); buffer_free(&msg); status = ssh_get_status(id); if(status != SSH2_FX_OK) { ftp_err("Couldn't rename file \"%s\" to \"%s\": %s\n", on, nn, fx2txt(status)); free(on); free(nn); return -1; } ftp_cache_flush_mark_for(on); ftp_cache_flush_mark_for(nn); free(on); free(nn); return 0; }
int ftp_chdir(const char *path) { #ifdef HAVE_LIBSSH if (ftp->session) return ssh_chdir(path); #endif ftp_set_tmp_verbosity(vbCommand); ftp_cmd("CWD %s", path); if(ftp->code == ctComplete) { /* Now, try to be smart ;-) * Many ftp servers include the current directory in the CWD reply * try to parse it, so we don't need to issue a PWD command */ if(strncasecmp(ftp->reply, "250 Changed to ", 15) == 0) { /* this is what Troll-ftpd replies: 250 Changed to /foo/bar */ ftp_update_curdir_x(ftp->reply+15); ftp_trace("Parsed cwd '%s' from reply\n", ftp->curdir); } else if(strncasecmp(ftp->reply, "250 OK. Current directory is ", 29) == 0) { /* PureFTPd responds: "250 OK. Current directory is /foo/bar */ ftp_update_curdir_x(ftp->reply+29); ftp_trace("Parsed cwd '%s' from reply\n", ftp->curdir); } else if(strstr(ftp->reply, " is current directory") != 0) { /* WarFTPD answers: 250 "/foo/bar/" is current directory */ char *edq; char *sdq = strchr(ftp->reply, '\"'); if(sdq) { edq = strchr(sdq+1, '\"'); if(edq) { char *e = xstrndup(sdq+1, edq-sdq-1); stripslash(e); ftp_update_curdir_x(e); free(e); ftp_trace("Parsed cwd '%s' from reply\n", ftp->curdir); } } } else if(strncasecmp(ftp->reply, "250 Directory changed to ", 25) == 0) { /* Serv-U FTP Server for WinSock */ ftp_update_curdir_x(ftp->reply + 25); ftp_trace("Parsed cwd '%s' from reply\n", ftp->curdir); } else ftp_update_curdir(); return 0; } return -1; }
void cmd_ltag(int argc, char **argv) { int i; int c; struct option longopts[] = { {"clear", no_argument, 0, 'c'}, {"info", no_argument, 0, 'i'}, {"list", no_argument, 0, 'l'}, {"load", optional_argument, 0, 'L'}, {"save", optional_argument, 0, 's'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; optind = 0; while((c = getopt_long(argc, argv, "ciL::lhs::", longopts, 0)) != EOF) { switch(c) { case 'c': list_clear(gvLocalTagList); return; case 's': save_ltaglist(optarg); return; case 'l': show_ltaglist(); return; case 'L': load_ltaglist(true, true, optarg); return; case 'i': show_ltaglist_info(); return; case 'h': print_ltag_syntax(); /* fall through */ case '?': return; } } minargs(1); for(i=1;i<argc;i++) { stripslash(argv[i]); lglob_glob(gvLocalTagList, argv[i], true, &lglob_exclude_dotdirs); } }
int ssh_mkdir_verb(const char *path, verbose_t verb) { char* abspath = ftp_path_absolute(path); stripslash(abspath); int rc = sftp_mkdir(ftp->sftp_session, abspath, S_IRWXU); if (rc != SSH_OK && sftp_get_error(ftp->sftp_session) != SSH_FX_FILE_ALREADY_EXISTS) { ftp_err(_("Couldn't create directory: %s\n"), ssh_get_error(ftp->session)); free(abspath); return rc; } ftp_cache_flush_mark_for(abspath); free(abspath); return 0; }
int ssh_chdir(const char *path) { char* tmp = ftp_path_absolute(path); char *p = sftp_canonicalize_path(ftp->sftp_session, tmp); free(tmp); if (!p) { ftp_err("%s: %s\n", path, ssh_get_error(ftp->session)); return -1; } bool isdir = false; /* First check if this file is cached and is a directory, else we * need to stat the file to see if it really is a directory */ stripslash(p); isdir = (ftp_cache_get_directory(p) != 0); if(!isdir) { rfile *rf = ftp_cache_get_file(p); isdir = (rf && risdir(rf)); } if (!isdir) { sftp_attributes attrib = sftp_stat(ftp->sftp_session, p); if (!attrib) { ftp_err(_("Couldn't stat directory: %s\n"), ssh_get_error(ftp->session)); free(p); return -1; } if (!S_ISDIR(attrib->permissions)) { ftp_err(_("%s: not a directory\n"), p); sftp_attributes_free(attrib); free(p); return -1; } sftp_attributes_free(attrib); } ftp_update_curdir_x(p); free(p); return 0; }
int ssh_rmdir(const char *path) { char* abspath = ftp_path_absolute(path); stripslash(abspath); int rc = sftp_rmdir(ftp->sftp_session, abspath); if (rc != SSH_OK && sftp_get_error(ftp->sftp_session) != SSH_FX_NO_SUCH_FILE) { ftp_err(_("Couldn't remove directory: %s\n"), ssh_get_error(ftp->session)); free(abspath); return rc; } ftp_cache_flush_mark(abspath); ftp_cache_flush_mark_for(abspath); free(abspath); return 0; }
static int ftp_mkdir_verb(const char *path, verbose_t verb) { char *p; #ifdef HAVE_LIBSSH if(ftp->session) return ssh_mkdir_verb(path, verb); #endif p = xstrdup(path); stripslash(p); ftp_set_tmp_verbosity(verb); ftp_cmd("MKD %s", p); if(ftp->code == ctComplete) ftp_cache_flush_mark_for(p); free(p); return ftp->code == ctComplete ? 0 : -1; }
int ftp_rmdir(const char *path) { char *p; #ifdef HAVE_LIBSSH if(ftp->session) return ssh_rmdir(path); #endif p = xstrdup(path); stripslash(p); ftp_set_tmp_verbosity(vbError); ftp_cmd("RMD %s", p); if(ftp->code == ctComplete) { ftp_cache_flush_mark(p); ftp_cache_flush_mark_for(p); } free(p); return ftp->code == ctComplete ? 0 : -1; }
/* ensure dirname exists, creating it if necessary. */ int make_valid_path(char *dir, mode_t mode) { struct stat st; char *tmp=NULL, *path = stripslash(strdup(dir)); int retval; if (stat(path, &st) == 0) { /* file exists */ if (S_ISDIR(st.st_mode)) { retval=1; goto end; } else { retval=0; goto end; } /* not a directory. Oops. */ } /* Directory doesn't exist. Let's make it. */ /* Make parent first. */ if (!make_valid_path(tmp = dirname(path), mode)) { retval=0; goto end; } /* Now make this 'un. */ if (mkdir(path, mode) < 0) { retval=0; goto end; } /* Success. */ retval=1; end: if (tmp!=NULL) free(tmp); if (path!=NULL) free(path); return retval; }
/* 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 ssh_rmdir(const char *path) { char *p; u_int status, id; p = ftp_path_absolute(path); stripslash(p); id = ftp->ssh_id++; ssh_send_string_request(id, SSH2_FXP_RMDIR, p, strlen(p)); status = ssh_get_status(id); if(status != SSH2_FX_OK) { ftp_err("Couldn't remove directory: %s\n", fx2txt(status)); free(p); return -1; } ftp_cache_flush_mark(p); ftp_cache_flush_mark_for(p); free(p); return 0; }
int ssh_chdir(const char *path) { Attrib *aa; char *p = ftp_path_absolute(path); bool isdir = false; /* First check if this file is cached and is a directory, else we * need to stat the file to see if it really is a directory */ stripslash(p); isdir = (ftp_cache_get_directory(p) != 0); if(!isdir) { rfile *rf = ftp_cache_get_file(p); isdir = (rf && risdir(rf)); } if(!isdir) { if ((aa = ssh_stat(p)) == 0) { free(p); return -1; } if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { ftp_err("Can't change directory: Can't check target"); free(p); return -1; } if (!S_ISDIR(aa->perm)) { ftp_err("%s: not a directory\n", p); free(p); return -1; } } ftp_update_curdir_x(p); return 0; }
rdirectory *ftp_read_directory(const char *path) { FILE *fp = 0; rdirectory *rdir; bool is_curdir = false; bool _failed = false; char *dir; bool is_mlsd = false; #ifdef HAVE_LIBSSH if(ftp->session) return ssh_read_directory(path); #endif dir = ftp_path_absolute(path); stripslash(dir); is_curdir = (strcmp(dir, ftp->curdir) == 0); if((fp = tmpfile()) == NULL) { /* can't create a tmpfile */ ftp_err("Unable to create temp file: %s\n", strerror(errno)); free(dir); return 0; } /* we do a "CWD" before the listing, because: we want a listing of * the directory contents, not the directory itself, and some * servers misunderstand this. If the target is a link to a * directory, we have to do this. */ if(!is_curdir) { ftp_cmd("CWD %s", dir); if(ftp->code != ctComplete) goto failed; } if(ftp->has_mlsd_command) { is_mlsd = true; #if 0 /* PureFTPd (1.0.11) doesn't recognize directory arguments * with spaces, not even quoted, it just chops the argument * string after the first space, duh... so we have to CWD to * the directory... */ char *asdf; asprintf(&asdf, "%s/", dir); /* Hack to get around issue in PureFTPd (up to version 0.98.2): * doing a 'MLSD link-to-dir' on PureFTPd closes the control * connection, however, 'MLSD link-to-dir/' works fine. */ _failed = (ftp_list("MLSD", asdf, fp) != 0); free(asdf); #else _failed = (ftp_list("MLSD", 0, fp) != 0); #endif if(_failed && ftp->code == ctError) ftp->has_mlsd_command = false; } if(!ftp->has_mlsd_command) { _failed = (ftp_list("LIST", 0, fp) != 0); is_mlsd = false; } if(!is_curdir) ftp_cmd("CWD %s", ftp->curdir); if(_failed) goto failed; rewind(fp); rdir = rdir_create(); if(rdir_parse(rdir, fp, dir, is_mlsd) != 0) { rdir_destroy(rdir); goto failed; } fclose(fp); ftp_trace("added directory '%s' to cache\n", dir); list_additem(ftp->cache, rdir); free(dir); return rdir; failed: /* forgive me father, for I have goto'ed */ if (fp) fclose(fp); free(dir); 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; }
void cmd_get(int argc, char **argv) { list *gl; int opt=GET_VERBOSE, c; char *logfile = 0; pid_t pid; struct group *grp; char *get_output = 0; int stat_thresh = gvStatsThreshold; #ifdef HAVE_REGEX int ret; char get_rx_errbuf[129]; #endif struct option longopts[] = { {"append", no_argument, 0, 'a'}, {"chmod", required_argument, 0, 'c'}, {"chgrp", required_argument, 0, '2'}, {"no-dereference", no_argument, 0, 'd'}, {"delete-after", no_argument, 0, 'D'}, {"dir-mask", required_argument, 0, '3'}, #ifdef HAVE_REGEX {"dir-rx-mask", required_argument, 0, '4'}, #endif {"interactive", no_argument, 0, 'i'}, {"skip-empty", no_argument, 0, 'e'}, {"force", no_argument, 0, 'f'}, {"force-newer", no_argument, 0, 'F'}, {"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'}, {"nohup", no_argument, 0, 'H'}, {"verbose", no_argument, 0, 'v'}, {"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'}, {"stats", optional_argument, 0, 'S'}, {"tagged", no_argument, 0, 't'}, {"type", required_argument, 0, '1'}, {"unique", no_argument, 0, 'u'}, {"output", required_argument, 0, 'o'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}, }; if(cmod) { mode_free(cmod); cmod = 0; } if(get_glob_mask) { free(get_glob_mask); get_glob_mask = 0; } if(get_dir_glob_mask) { free(get_dir_glob_mask); get_dir_glob_mask = 0; } #ifdef HAVE_REGEX if(get_rx_mask_set) { regfree(&get_rx_mask); get_rx_mask_set = 0; } if(get_dir_rx_mask_set) { regfree(&get_dir_rx_mask); get_dir_rx_mask_set = 0; } #endif get_skip_empty = false; optind = 0; /* force getopt() to re-initialize */ while((c=getopt_long(argc, argv, "abHc:dDeio:fFL:tnpPvqrRsuT:m:M:", longopts, 0)) != EOF) { switch(c) { case 'a': opt |= GET_APPEND; break; case 'c': cmod = mode_compile(optarg, MODE_MASK_ALL); if(cmod == NULL) { fprintf(stderr, _("Invalid mode for --chmod: %s\n"), optarg); return; } opt |= GET_CHMOD; break; case '2': /* --chgrp */ grp = getgrnam(optarg); if(grp == 0) { fprintf(stderr, _("%s is not a valid group name\n"), optarg); return; } { int i; for(i=0; grp->gr_mem && grp->gr_mem[i]; i++) { if(strcmp(gvUsername, grp->gr_mem[i]) == 0) break; } if(!grp->gr_mem[i]) { fprintf(stderr, _("you are not a member of group %s\n"), optarg); return; } } group_change = grp->gr_gid; opt |= GET_CHGRP; break; case 'D': opt |= GET_DELETE_AFTER; break; case 'd': opt |= GET_NO_DEREFERENCE; break; case 'e': opt |= GET_SKIP_EMPTY; get_skip_empty = true; break; case '3': /* --dir-mask=GLOB */ free(get_dir_glob_mask); get_dir_glob_mask = xstrdup(optarg); unquote(get_dir_glob_mask); break; #ifdef HAVE_REGEX case '4': /* --dir-rx-mask=REGEXP */ if(get_dir_rx_mask_set) { regfree(&get_dir_rx_mask); get_dir_rx_mask_set = false; } unquote(optarg); ret = regcomp(&get_dir_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &get_dir_rx_mask, get_rx_errbuf, sizeof(get_rx_errbuf) - 1); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, get_rx_errbuf); return; } else get_dir_rx_mask_set = true; break; #endif case 'i': opt |= GET_INTERACTIVE; break; case 'f': opt |= GET_FORCE; break; case 'F': opt |= GET_FORCE_NEWER; break; case 'm': /* --mask */ free(get_glob_mask); get_glob_mask = xstrdup(optarg); unquote(get_glob_mask); break; #ifdef HAVE_REGEX case 'M': /* --rx-mask */ if(get_rx_mask_set) { regfree(&get_rx_mask); get_rx_mask_set = false; } unquote(optarg); ret = regcomp(&get_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &get_rx_mask, get_rx_errbuf, sizeof(get_rx_errbuf) - 1); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, get_rx_errbuf); return; } else get_rx_mask_set = true; break; #endif case 'o': get_output = tilde_expand_home(optarg, gvLocalHomeDir); /*stripslash(get_output);*/ unquote(get_output); break; case 'v': opt |= GET_VERBOSE; break; case 'p': opt |= GET_PRESERVE; break; case 'P': opt |= GET_PARENTS; break; case 'H': opt |= GET_NOHUP; break; case 'q': opt &= ~GET_VERBOSE; break; case 'r': opt |= GET_RECURSIVE; break; case 's': opt |= GET_SKIP_EXISTING; break; case 'S': stat_thresh = optarg ? atoi(optarg) : 0; break; case 'R': opt |= GET_RESUME; break; case '1': if(strncmp(optarg, "ascii", strlen(optarg)) == 0) opt |= GET_ASCII; else if(strncmp(optarg, "binary", strlen(optarg)) == 0) opt |= GET_BINARY; else { printf(_("Invalid option argument --type=%s\n"), optarg); return; } break; case 'u': opt |= GET_UNIQUE; break; case 'L': free(logfile); logfile = xstrdup(optarg); unquote(logfile); break; case 't': opt |= GET_TAGGED; break; case 'n': opt |= GET_NEWER; break; case 'h': print_get_syntax(); return; case '?': return; } } if(optind>=argc && !test(opt, GET_TAGGED)) { minargs(optind); return; } need_connected(); need_loggedin(); gl = rglob_create(); while(optind < argc) { stripslash(argv[optind]); if(rglob_glob(gl, argv[optind], true, true, get_exclude_func) == -1) fprintf(stderr, _("%s: no matches found\n"), argv[optind]); optind++; } if(list_numitem(gl) == 0 && !test(opt, GET_TAGGED)) { rglob_destroy(gl); return; } if(test(opt, GET_TAGGED) && (!ftp->taglist || list_numitem(ftp->taglist)==0)) { printf(_("no tagged files\n")); if(list_numitem(gl) == 0) { rglob_destroy(gl); return; } } get_quit = false; get_batch = get_owbatch = get_delbatch = test(opt, GET_FORCE); if(test(opt, GET_FORCE)) opt &= ~GET_INTERACTIVE; if(get_output && !test(opt, GET_RECURSIVE) && list_numitem(gl) + (test(opt, GET_TAGGED) ? list_numitem(ftp->taglist) : 0) == 1) { /* if the argument to --output ends with a slash, we assume the * user wants the destination to be a directory */ char *e = strrchr(get_output, 0); if(e && e[-1] != '/') opt |= GET_OUTPUT_FILE; } stats_reset(gvStatsTransfer); gvInTransfer = true; gvInterrupted = false; if(test(opt, GET_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, GET_FORCE) && !test(opt, GET_RESUME)) opt |= GET_UNIQUE; opt |= GET_FORCE; if(list_numitem(gl)) getfiles(gl, opt, get_output); rglob_destroy(gl); if(ftp->taglist && test(opt, GET_TAGGED)) getfiles(ftp->taglist, opt, get_output); free(get_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); } if(list_numitem(gl)) getfiles(gl, opt, get_output); rglob_destroy(gl); if(ftp->taglist && test(opt, GET_TAGGED)) getfiles(ftp->taglist, opt, get_output); free(get_output); mode_free(cmod); cmod = 0; gvInTransfer = false; stats_display(gvStatsTransfer, stat_thresh); }
/* 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; }
rdirectory *ssh_read_directory(const char *path) { char *p = ftp_path_absolute(path); stripslash(p); sftp_dir dir = sftp_opendir(ftp->sftp_session, p); if (!dir) { free(p); return 0; } ftp_trace("*** start parsing directory listing ***\n"); rdirectory* rdir = rdir_create(); sftp_attributes attrib = NULL; while ((attrib = sftp_readdir(ftp->sftp_session, dir)) != NULL) { ftp_trace("%s\n", attrib->longname); rfile* rf = rfile_create(); rf->perm = perm2string(attrib->permissions); rf->nhl = 0; // atoi(e); if (attrib->owner) rf->owner = xstrdup(attrib->owner); if (attrib->group) rf->group = xstrdup(attrib->group); if (asprintf(&rf->path, "%s/%s", p, attrib->name) == -1) { ftp_err(_("Failed to allocate memory.\n")); sftp_closedir(dir); free(p); rdir_destroy(rdir); rfile_destroy(rf); } rf->mtime = attrib->mtime; rf->date = time_to_string(rf->mtime); rf->size = attrib->size; rfile_parse_colors(rf); rf->link = NULL; if (rislink(rf) && ftp->ssh_version > 2) rf->link = sftp_readlink(ftp->sftp_session, rf->path); list_additem(rdir->files, (void *)rf); sftp_attributes_free(attrib); } ftp_trace("*** end parsing directory listing ***\n"); if (!sftp_dir_eof(dir)) { ftp_err(_("Couldn't list directory: %s\n"), ssh_get_error(ftp->session)); sftp_closedir(dir); free(p); rdir_destroy(rdir); return NULL; } sftp_closedir(dir); rdir->path = p; ftp_trace("added directory '%s' to cache\n", p); list_additem(ftp->cache, rdir); return rdir; }
void cmd_fxp(int argc, char **argv) { list *gl; listitem *fxp_tmp = 0; char *logfile = 0; char *fxp_output = 0; #ifdef HAVE_REGEX int ret; char fxp_rx_errbuf[129]; #endif int c, opt = FXP_VERBOSE; 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 {"force", no_argument, 0, 'f'}, {"force-newer", 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'}, {"target", required_argument, 0, 'T'}, {"type", required_argument, 0, '1'}, {"unique", no_argument, 0, 'u'}, {"verbose", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; if(fxp_glob_mask) { free(fxp_glob_mask); fxp_glob_mask = 0; } if(fxp_dir_glob_mask) { free(fxp_dir_glob_mask); fxp_dir_glob_mask = 0; } #ifdef HAVE_REGEX if(fxp_rx_mask_set) { fxp_rx_mask_set = 0; } if(fxp_dir_rx_mask_set) { regfree(&fxp_dir_rx_mask); fxp_dir_rx_mask_set = 0; } #endif if(list_numitem(gvFtpList) == 2) { fxp_tmp = gvFtpList->first; if(fxp_tmp->data == ftp) fxp_target = fxp_tmp->next->data; else fxp_target = fxp_tmp->data; } else fxp_target = 0; fxp_skip_empty = false; optind = 0; /* force getopt() to re-initialize */ while((c=getopt_long(argc, argv, "aDefHiL:M:no:pPqrRstT:uvh", longopts, 0)) != EOF) { switch(c) { case 'a': /* --append */ opt |= FXP_APPEND; break; case 'D': /* --delete-after */ opt |= FXP_DELETE_AFTER; break; case 'f': /* --force */ opt |= FXP_FORCE; break; case 'F': opt |= FXP_FORCE_NEWER; break; case 'e': /* --skip-empty */ opt |= FXP_SKIP_EMPTY; fxp_skip_empty = true; break; case '3': /* --dir-mask=GLOB */ free(fxp_dir_glob_mask); fxp_dir_glob_mask = xstrdup(optarg); unquote(fxp_dir_glob_mask); break; #ifdef HAVE_REGEX case '4': /* --dir-rx-mask=REGEXP */ if(fxp_dir_rx_mask_set) { regfree(&fxp_dir_rx_mask); fxp_dir_rx_mask_set = false; } unquote(optarg); ret = regcomp(&fxp_dir_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &fxp_dir_rx_mask, fxp_rx_errbuf, 128); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, fxp_rx_errbuf); return; } else fxp_dir_rx_mask_set = true; break; #endif case 'H': /* --nohup */ opt |= FXP_NOHUP; break; case 'i': /* --interactive */ opt |= FXP_INTERACTIVE; break; case 'L': /* --logfile=FILE */ free(logfile); logfile = xstrdup(optarg); unquote(logfile); break; case 'm': /* --mask=GLOB */ free(fxp_glob_mask); fxp_glob_mask = xstrdup(optarg); unquote(fxp_glob_mask); break; #ifdef HAVE_REGEX case 'M': /* --rx-mask=REGEXP */ if(fxp_rx_mask_set) { regfree(&fxp_rx_mask); fxp_rx_mask_set = false; } unquote(optarg); ret = regcomp(&fxp_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &fxp_rx_mask, fxp_rx_errbuf, 128); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, fxp_rx_errbuf); return; } else fxp_rx_mask_set = true; break; #endif case 'n': /* --newer */ opt |= FXP_NEWER; break; case 'o': /* --output=DIRECTORY */ if(fxp_target == 0) { printf(_("FxP target not set, use --target=NAME" " (as first option)\n")); return; } fxp_output = tilde_expand_home(optarg, fxp_target->homedir); stripslash(fxp_output); unquote(fxp_output); break; case 'p': /* --preserve */ opt |= FXP_PRESERVE; break; case 'P': /* --parents */ opt |= FXP_PARENTS; break; case 'q': /* --quiet */ opt &= ~FXP_VERBOSE; break; case 'r': /* --recursive */ opt |= FXP_RECURSIVE; break; case 'R': /* --resume */ opt |= FXP_RESUME; break; case 's': opt |= FXP_SKIP_EXISTING; break; case 't': /* --tagged */ opt |= FXP_TAGGED; break; case '1': /* --type=[ascii|binary] */ if(strncmp(optarg, "ascii", strlen(optarg)) == 0) opt |= FXP_ASCII; else if(strncmp(optarg, "binary", strlen(optarg)) == 0) opt |= FXP_BINARY; else { printf(_("Invalid option argument --type=%s\n"), optarg); return; } break; case 'T': /* --target=HOST */ fxp_tmp = ftplist_search(optarg); if(!fxp_tmp) return; fxp_target = (Ftp *)fxp_tmp->data; break; case 'u': /* --unique */ opt |= FXP_UNIQUE; break; case 'v': /* --verbose */ opt |= FXP_VERBOSE; break; case 'h': /* --help */ print_fxp_syntax(); return; case '?': default: return; } } if(optind >= argc && !test(opt, FXP_TAGGED)) { minargs(optind); return; } need_connected(); need_loggedin(); if(fxp_target == 0) { ftp_err(_("No target specified, try '%s --help'" " for more information\n"), argv[0]); return; } #ifdef HAVE_LIBSSH if(ftp->session || fxp_target->session) { ftp_err("FxP for SSH connections no implemented\n"); return; } #endif gl = rglob_create(); while(optind < argc) { stripslash(argv[optind]); if(rglob_glob(gl, argv[optind], true, true, fxp_exclude_func) == -1) fprintf(stderr, _("%s: no matches found\n"), argv[optind]); optind++; } if(list_numitem(gl) == 0 && !test(opt, FXP_TAGGED)) { rglob_destroy(gl); return; } if(test(opt, FXP_TAGGED) && (!ftp->taglist || list_numitem(ftp->taglist) == 0)) { printf(_("no tagged files\n")); if(list_numitem(gl) == 0) { rglob_destroy(gl); return; } } fxp_quit = false; fxp_batch = fxp_owbatch = fxp_delbatch = test(opt, FXP_FORCE); if(test(opt, FXP_FORCE)) opt &= ~FXP_INTERACTIVE; if(fxp_output && !test(opt, FXP_RECURSIVE) && list_numitem(gl) + (test(opt, FXP_TAGGED) ? list_numitem(ftp->taglist) : 0) == 1) { opt |= FXP_OUTPUT_FILE; } gvInTransfer = true; gvInterrupted = false; if(test(opt, FXP_NOHUP)) { int r = 0; pid_t 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, FXP_FORCE) && !test(opt, FXP_RESUME)) opt |= FXP_UNIQUE; opt |= FXP_FORCE; if(list_numitem(gl)) fxpfiles(gl, opt, fxp_output); rglob_destroy(gl); if(ftp->taglist && test(opt, FXP_TAGGED)) fxpfiles(ftp->taglist, opt, fxp_output); free(fxp_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); } if(list_numitem(gl)) fxpfiles(gl, opt, fxp_output); rglob_destroy(gl); if(ftp->taglist && test(opt, FXP_TAGGED)) fxpfiles(ftp->taglist, opt, fxp_output); free(fxp_output); gvInTransfer = false; }
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")); } } } }
rdirectory *ssh_read_directory(const char *path) { rdirectory *rdir; int i; SFTP_DIRENT **dir; char *p = ftp_path_absolute(path); stripslash(p); if(ssh_readdir(p, &dir) != 0) { free(p); return 0; } rdir = rdir_create(); ftp_trace("*** start parsing directory listing ***\n"); for(i = 0; dir[i]; i++) { rfile *rf; char *e, *cf = dir[i]->longname; ftp_trace("%s\n", dir[i]->longname); rf = rfile_create(); rf->perm = perm2string(dir[i]->a.perm); e = strqsep(&cf, ' '); /* skip permissions */ e = strqsep(&cf, ' '); /* nhl? */ /* if(ftp->ssh_version > 2) {*/ rf->nhl = atoi(e); /* } else*/ /* rf->nhl = 0;*/ #if 1 e = strqsep(&cf, ' '); rf->owner = xstrdup(e); e = strqsep(&cf, ' '); rf->group = xstrdup(e); #else asprintf(&rf->owner, "%d", dir[i]->a.uid); asprintf(&rf->group, "%d", dir[i]->a.gid); #endif asprintf(&rf->path, "%s/%s", p, dir[i]->filename); rf->mtime = dir[i]->a.mtime; if(rf->mtime == 0) { char *m, *d, *y; while(e && month_number(e) == -1) e = strqsep(&cf, ' '); if(e) { m = e; d = strqsep(&cf, ' '); y = strqsep(&cf, ' '); ftp_trace("parsing time: m:%s d:%s y:%s\n", m, d, y); rfile_parse_time(rf, m, d, y); } } rf->date = time_to_string(rf->mtime); rf->size = dir[i]->a.size; rfile_parse_colors(rf); rf->link = 0; if(rislink(rf) && ftp->ssh_version > 2) rf->link = ssh_readlink(rf->path); list_additem(rdir->files, (void *)rf); } ftp_trace("*** end parsing directory listing ***\n"); ssh_free_dirents(dir); rdir->path = p; ftp_trace("added directory '%s' to cache\n", p); list_additem(ftp->cache, rdir); return rdir; }