⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftp.c

📁 Wget很好的处理了http和ftp的下载,很值得学习的经典代码
💻 C
📖 第 1 页 / 共 5 页
字号:
                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 + -