📄 ftp.c
字号:
fl = opt.output_document; } else fl = con->target; if (fl) touch (fl, f->tstamp); } else if (f->tstamp == -1) logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), con->target); if (f->perms && f->type == FT_PLAINFILE && dlthis) { if (opt.preserve_perm) chmod (con->target, f->perms); } else DEBUGP (("Unrecognized permissions for %s.\n", con->target)); xfree (con->target); con->target = old_target; url_set_file (u, ofile); xfree (ofile); /* Break on fatals. */ if (err == QUOTEXC || err == HOSTERR || err == FWRITEERR) break; con->cmd &= ~ (DO_CWD | DO_LOGIN); f = f->next; } /* We do not want to call ftp_retrieve_dirs here */ if (opt.recursive && !(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel)) err = ftp_retrieve_dirs (u, orig, con); else if (opt.recursive) DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"), depth, opt.reclevel)); --depth; return err;}/* Retrieve the directories given in a file list. This function works by simply going through the linked list and calling ftp_retrieve_glob on each directory entry. The function knows about excluded directories. */static uerr_tftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con){ char *container = NULL; int container_size = 0; for (; f; f = f->next) { int size; char *odir, *newdir; if (opt.quota && total_downloaded_bytes > opt.quota) break; if (f->type != FT_DIRECTORY) continue; /* Allocate u->dir off stack, but reallocate only if a larger string is needed. It's a pity there's no "realloca" for an item on the bottom of the stack. */ size = strlen (u->dir) + 1 + strlen (f->name) + 1; if (size > container_size) container = (char *)alloca (size); newdir = container; odir = u->dir; if (*odir == '\0' || (*odir == '/' && *(odir + 1) == '\0')) /* If ODIR is empty or just "/", simply append f->name to ODIR. (In the former case, to preserve u->dir being relative; in the latter case, to avoid double slash.) */ sprintf (newdir, "%s%s", odir, f->name); else /* Else, use a separator. */ sprintf (newdir, "%s/%s", odir, f->name); DEBUGP (("Composing new CWD relative to the initial directory.\n")); DEBUGP ((" odir = '%s'\n f->name = '%s'\n newdir = '%s'\n\n", odir, f->name, newdir)); if (!accdir (newdir)) { logprintf (LOG_VERBOSE, _("\Not descending to `%s' as it is excluded/not-included.\n"), escnonprint (newdir)); continue; } con->st &= ~DONE_CWD; odir = xstrdup (u->dir); /* because url_set_dir will free u->dir. */ url_set_dir (u, newdir); ftp_retrieve_glob (u, con, GLOB_GETALL); url_set_dir (u, odir); xfree (odir); /* Set the time-stamp? */ } if (opt.quota && total_downloaded_bytes > opt.quota) return QUOTEXC; else return RETROK;}/* Return true if S has a leading '/' or contains '../' */static boolhas_insecure_name_p (const char *s){ if (*s == '/') return true; if (strstr (s, "../") != 0) return true; return false;}/* A near-top-level function to retrieve the files in a directory. The function calls ftp_get_listing, to get a linked list of files. Then it weeds out the file names that do not match the pattern. ftp_retrieve_list is called with this updated list as an argument. If the argument ACTION is GLOB_GETONE, just download the file (but first get the listing, so that the time-stamp is heeded); if it's GLOB_GLOBALL, use globbing; if it's GLOB_GETALL, download the whole directory. */static uerr_tftp_retrieve_glob (struct url *u, ccon *con, int action){ struct fileinfo *f, *start; uerr_t res; con->cmd |= LEAVE_PENDING; res = ftp_get_listing (u, con, &start); if (res != RETROK) return res; /* First: weed out that do not conform the global rules given in opt.accepts and opt.rejects. */ if (opt.accepts || opt.rejects) { f = start; while (f) { if (f->type != FT_DIRECTORY && !acceptable (f->name)) { logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"), escnonprint (f->name)); f = delelement (f, &start); } else f = f->next; } } /* Remove all files with possible harmful names */ f = start; while (f) { if (has_insecure_name_p (f->name)) { logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"), escnonprint (f->name)); f = delelement (f, &start); } else f = f->next; } /* Now weed out the files that do not match our globbing pattern. If we are dealing with a globbing pattern, that is. */ if (*u->file) { if (action == GLOB_GLOBALL) { int (*matcher) (const char *, const char *, int) = opt.ignore_case ? fnmatch_nocase : fnmatch; int matchres = 0; f = start; while (f) { matchres = matcher (u->file, f->name, 0); if (matchres == -1) { logprintf (LOG_NOTQUIET, _("Error matching %s against %s: %s\n"), u->file, escnonprint (f->name), strerror (errno)); break; } if (matchres == FNM_NOMATCH) f = delelement (f, &start); /* delete the element from the list */ else f = f->next; /* leave the element in the list */ } if (matchres == -1) { freefileinfo (start); return RETRBADPATTERN; } } else if (action == GLOB_GETONE) { int (*cmp) (const char *, const char *) = opt.ignore_case ? strcasecmp : strcmp; f = start; while (f) { if (0 != cmp(u->file, f->name)) f = delelement (f, &start); else f = f->next; } } } if (start) { /* Just get everything. */ ftp_retrieve_list (u, start, con); } else { if (action == GLOB_GLOBALL) { /* No luck. */ /* #### This message SUCKS. We should see what was the reason that nothing was retrieved. */ logprintf (LOG_VERBOSE, _("No matches on pattern `%s'.\n"), escnonprint (u->file)); } else /* GLOB_GETONE or GLOB_GETALL */ { /* Let's try retrieving it anyway. */ con->st |= ON_YOUR_OWN; res = ftp_loop_internal (u, NULL, con); return res; } } freefileinfo (start); if (opt.quota && total_downloaded_bytes > opt.quota) return QUOTEXC; else /* #### Should we return `res' here? */ return RETROK;}/* The wrapper that calls an appropriate routine according to contents of URL. Inherently, its capabilities are limited on what can be encoded into a URL. */uerr_tftp_loop (struct url *u, int *dt, struct url *proxy, bool recursive, bool glob){ ccon con; /* FTP connection */ uerr_t res; *dt = 0; xzero (con); con.csock = -1; con.st = ON_YOUR_OWN; con.rs = ST_UNIX; con.id = NULL; con.proxy = proxy; /* If the file name is empty, the user probably wants a directory index. We'll provide one, properly HTML-ized. Unless opt.htmlify is 0, of course. :-) */ if (!*u->file && !recursive) { struct fileinfo *f; res = ftp_get_listing (u, &con, &f); if (res == RETROK) { if (opt.htmlify && !opt.spider) { char *filename = (opt.output_document ? xstrdup (opt.output_document) : (con.target ? xstrdup (con.target) : url_file_name (u))); res = ftp_index (filename, u, f); if (res == FTPOK && opt.verbose) { if (!opt.output_document) { struct_stat st; wgint sz; if (stat (filename, &st) == 0) sz = st.st_size; else sz = -1; logprintf (LOG_NOTQUIET, _("Wrote HTML-ized index to `%s' [%s].\n"), filename, number_to_static_string (sz)); } else logprintf (LOG_NOTQUIET, _("Wrote HTML-ized index to `%s'.\n"), filename); } xfree (filename); } freefileinfo (f); } } else { bool ispattern = false; if (glob) { /* Treat the URL as a pattern if the file name part of the URL path contains wildcards. (Don't check for u->file because it is unescaped and therefore doesn't leave users the option to escape literal '*' as %2A.) */ char *file_part = strrchr (u->path, '/'); if (!file_part) file_part = u->path; ispattern = has_wildcards_p (file_part); } if (ispattern || recursive || opt.timestamping) { /* ftp_retrieve_glob is a catch-all function that gets called if we need globbing, time-stamping or recursion. Its third argument is just what we really need. */ res = ftp_retrieve_glob (u, &con, ispattern ? GLOB_GLOBALL : GLOB_GETONE); } else res = ftp_loop_internal (u, NULL, &con); } if (res == FTPOK) res = RETROK; if (res == RETROK) *dt |= RETROKF; /* If a connection was left, quench it. */ if (con.csock != -1) fd_close (con.csock); xfree_null (con.id); con.id = NULL; xfree_null (con.target); con.target = NULL; return res;}/* Delete an element from the fileinfo linked list. Returns the address of the next element, or NULL if the list is exhausted. It can modify the start of the list. */static struct fileinfo *delelement (struct fileinfo *f, struct fileinfo **start){ struct fileinfo *prev = f->prev; struct fileinfo *next = f->next; xfree (f->name); xfree_null (f->linkto); xfree (f); if (next) next->prev = prev; if (prev) prev->next = next; else *start = next; return next;}/* Free the fileinfo linked list of files. */static voidfreefileinfo (struct fileinfo *f){ while (f) { struct fileinfo *next = f->next; xfree (f->name); if (f->linkto) xfree (f->linkto); xfree (f); f = next; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -