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

📄 utils.c

📁 wget (command line browser) source code
💻 C
📖 第 1 页 / 共 4 页
字号:
remove_link (const char *file){  int err = 0;  struct stat st;  if (lstat (file, &st) == 0 && S_ISLNK (st.st_mode))    {      DEBUGP (("Unlinking %s (symlink).\n", file));      err = unlink (file);      if (err != 0)	logprintf (LOG_VERBOSE, _("Failed to unlink symlink `%s': %s\n"),		   file, strerror (errno));    }  return err;}/* Does FILENAME exist?  This is quite a lousy implementation, since   it supplies no error codes -- only a yes-or-no answer.  Thus it   will return that a file does not exist if, e.g., the directory is   unreadable.  I don't mind it too much currently, though.  The   proper way should, of course, be to have a third, error state,   other than true/false, but that would introduce uncalled-for   additional complexity to the callers.  */intfile_exists_p (const char *filename){#ifdef HAVE_ACCESS  return access (filename, F_OK) >= 0;#else  struct stat buf;  return stat (filename, &buf) >= 0;#endif}/* Returns 0 if PATH is a directory, 1 otherwise (any kind of file).   Returns 0 on error.  */intfile_non_directory_p (const char *path){  struct stat buf;  /* Use lstat() rather than stat() so that symbolic links pointing to     directories can be identified correctly.  */  if (lstat (path, &buf) != 0)    return 0;  return S_ISDIR (buf.st_mode) ? 0 : 1;}/* Return the size of file named by FILENAME, or -1 if it cannot be   opened or seeked into. */longfile_size (const char *filename){  long size;  /* We use fseek rather than stat to determine the file size because     that way we can also verify whether the file is readable.     Inspired by the POST patch by Arnaud Wylie.  */  FILE *fp = fopen (filename, "rb");  if (!fp)    return -1;  fseek (fp, 0, SEEK_END);  size = ftell (fp);  fclose (fp);  return size;}/* stat file names named PREFIX.1, PREFIX.2, etc., until one that   doesn't exist is found.  Return a freshly allocated copy of the   unused file name.  */static char *unique_name_1 (const char *prefix){  int count = 1;  int plen = strlen (prefix);  char *template = (char *)alloca (plen + 1 + 24);  char *template_tail = template + plen;  memcpy (template, prefix, plen);  *template_tail++ = '.';  do    number_to_string (template_tail, count++);  while (file_exists_p (template));  return xstrdup (template);}/* Return a unique file name, based on FILE.   More precisely, if FILE doesn't exist, it is returned unmodified.   If not, FILE.1 is tried, then FILE.2, etc.  The first FILE.<number>   file name that doesn't exist is returned.   The resulting file is not created, only verified that it didn't   exist at the point in time when the function was called.   Therefore, where security matters, don't rely that the file created   by this function exists until you open it with O_EXCL or   something.   If ALLOW_PASSTHROUGH is 0, it always returns a freshly allocated   string.  Otherwise, it may return FILE if the file doesn't exist   (and therefore doesn't need changing).  */char *unique_name (const char *file, int allow_passthrough){  /* If the FILE itself doesn't exist, return it without     modification. */  if (!file_exists_p (file))    return allow_passthrough ? (char *)file : xstrdup (file);  /* Otherwise, find a numeric suffix that results in unused file name     and return it.  */  return unique_name_1 (file);}/* Create DIRECTORY.  If some of the pathname components of DIRECTORY   are missing, create them first.  In case any mkdir() call fails,   return its error status.  Returns 0 on successful completion.   The behaviour of this function should be identical to the behaviour   of `mkdir -p' on systems where mkdir supports the `-p' option.  */intmake_directory (const char *directory){  int quit = 0;  int i;  int ret = 0;  char *dir;  /* Make a copy of dir, to be able to write to it.  Otherwise, the     function is unsafe if called with a read-only char *argument.  */  STRDUP_ALLOCA (dir, directory);  /* If the first character of dir is '/', skip it (and thus enable     creation of absolute-pathname directories.  */  for (i = (*dir == '/'); 1; ++i)    {      for (; dir[i] && dir[i] != '/'; i++)	;      if (!dir[i])	quit = 1;      dir[i] = '\0';      /* Check whether the directory already exists.  Allow creation of	 of intermediate directories to fail, as the initial path components	 are not necessarily directories!  */      if (!file_exists_p (dir))	ret = mkdir (dir, 0777);      else	ret = 0;      if (quit)	break;      else	dir[i] = '/';    }  return ret;}/* Merge BASE with FILE.  BASE can be a directory or a file name, FILE   should be a file name.   file_merge("/foo/bar", "baz")  => "/foo/baz"   file_merge("/foo/bar/", "baz") => "/foo/bar/baz"   file_merge("foo", "bar")       => "bar"   In other words, it's a simpler and gentler version of uri_merge_1.  */char *file_merge (const char *base, const char *file){  char *result;  const char *cut = (const char *)strrchr (base, '/');  if (!cut)    return xstrdup (file);  result = (char *)xmalloc (cut - base + 1 + strlen (file) + 1);  memcpy (result, base, cut - base);  result[cut - base] = '/';  strcpy (result + (cut - base) + 1, file);  return result;}static int in_acclist PARAMS ((const char *const *, const char *, int));/* Determine whether a file is acceptable to be followed, according to   lists of patterns to accept/reject.  */intacceptable (const char *s){  int l = strlen (s);  while (l && s[l] != '/')    --l;  if (s[l] == '/')    s += (l + 1);  if (opt.accepts)    {      if (opt.rejects)	return (in_acclist ((const char *const *)opt.accepts, s, 1)		&& !in_acclist ((const char *const *)opt.rejects, s, 1));      else	return in_acclist ((const char *const *)opt.accepts, s, 1);    }  else if (opt.rejects)    return !in_acclist ((const char *const *)opt.rejects, s, 1);  return 1;}/* Compare S1 and S2 frontally; S2 must begin with S1.  E.g. if S1 is   `/something', frontcmp() will return 1 only if S2 begins with   `/something'.  Otherwise, 0 is returned.  */intfrontcmp (const char *s1, const char *s2){  for (; *s1 && *s2 && (*s1 == *s2); ++s1, ++s2);  return !*s1;}/* Iterate through STRLIST, and return the first element that matches   S, through wildcards or front comparison (as appropriate).  */static char *proclist (char **strlist, const char *s, enum accd flags){  char **x;  for (x = strlist; *x; x++)    if (has_wildcards_p (*x))      {	if (fnmatch (*x, s, FNM_PATHNAME) == 0)	  break;      }    else      {	char *p = *x + ((flags & ALLABS) && (**x == '/')); /* Remove '/' */	if (frontcmp (p, s))	  break;      }  return *x;}/* Returns whether DIRECTORY is acceptable for download, wrt the   include/exclude lists.   If FLAGS is ALLABS, the leading `/' is ignored in paths; relative   and absolute paths may be freely intermixed.  */intaccdir (const char *directory, enum accd flags){  /* Remove starting '/'.  */  if (flags & ALLABS && *directory == '/')    ++directory;  if (opt.includes)    {      if (!proclist (opt.includes, directory, flags))	return 0;    }  if (opt.excludes)    {      if (proclist (opt.excludes, directory, flags))	return 0;    }  return 1;}/* Return non-zero if STRING ends with TAIL.  For instance:   match_tail ("abc", "bc", 0)  -> 1   match_tail ("abc", "ab", 0)  -> 0   match_tail ("abc", "abc", 0) -> 1   If FOLD_CASE_P is non-zero, the comparison will be   case-insensitive.  */intmatch_tail (const char *string, const char *tail, int fold_case_p){  int i, j;  /* We want this to be fast, so we code two loops, one with     case-folding, one without. */  if (!fold_case_p)    {      for (i = strlen (string), j = strlen (tail); i >= 0 && j >= 0; i--, j--)	if (string[i] != tail[j])	  break;    }  else    {      for (i = strlen (string), j = strlen (tail); i >= 0 && j >= 0; i--, j--)	if (TOLOWER (string[i]) != TOLOWER (tail[j]))	  break;    }  /* If the tail was exhausted, the match was succesful.  */  if (j == -1)    return 1;  else    return 0;}/* Checks whether string S matches each element of ACCEPTS.  A list   element are matched either with fnmatch() or match_tail(),   according to whether the element contains wildcards or not.   If the BACKWARD is 0, don't do backward comparison -- just compare   them normally.  */static intin_acclist (const char *const *accepts, const char *s, int backward){  for (; *accepts; accepts++)    {      if (has_wildcards_p (*accepts))	{	  /* fnmatch returns 0 if the pattern *does* match the	     string.  */	  if (fnmatch (*accepts, s, 0) == 0)	    return 1;	}      else	{	  if (backward)	    {	      if (match_tail (s, *accepts, 0))		return 1;	    }	  else	    {	      if (!strcmp (s, *accepts))		return 1;	    }	}    }  return 0;}/* Return the location of STR's suffix (file extension).  Examples:   suffix ("foo.bar")       -> "bar"   suffix ("foo.bar.baz")   -> "baz"   suffix ("/foo/bar")      -> NULL   suffix ("/foo.bar/baz")  -> NULL  */char *suffix (const char *str){  int i;  for (i = strlen (str); i && str[i] != '/' && str[i] != '.'; i--)    ;  if (str[i++] == '.')    return (char *)str + i;  else    return NULL;}/* Return non-zero if S contains globbing wildcards (`*', `?', `[' or   `]').  */inthas_wildcards_p (const char *s){  for (; *s; s++)    if (*s == '*' || *s == '?' || *s == '[' || *s == ']')      return 1;  return 0;}/* Return non-zero if FNAME ends with a typical HTML suffix.  The   following (case-insensitive) suffixes are presumed to be HTML files:        html     htm     ?html (`?' matches one character)   #### CAVEAT.  This is not necessarily a good indication that FNAME   refers to a file that contains HTML!  */inthas_html_suffix_p (const char *fname){  char *suf;  if ((suf = suffix (fname)) == NULL)    return 0;  if (!strcasecmp (suf, "html"))    return 1;  if (!strcasecmp (suf, "htm"))    return 1;  if (suf[0] && !strcasecmp (suf + 1, "html"))    return 1;  return 0;}/* Read a line from FP and return the pointer to freshly allocated   storage.  The storage space is obtained through malloc() and should   be freed with free() when it is no longer needed.   The length of the line is not limited, except by available memory.   The newline character at the end of line is retained.  The line is   terminated with a zero character.   After end-of-file is encountered without anything being read, NULL   is returned.  NULL is also returned on error.  To distinguish   between these two cases, use the stdio function ferror().  */char *read_whole_line (FILE *fp){  int length = 0;  int bufsize = 82;  char *line = (char *)xmalloc (bufsize);  while (fgets (line + length, bufsize - length, fp))    {      length += strlen (line + length);      if (length == 0)	/* Possible for example when reading from a binary file where	   a line begins with \0.  */	continue;      if (line[length - 1] == '\n')	break;      /* fgets() guarantees to read the whole line, or to use up the         space we've given it.  We can double the buffer         unconditionally.  */      bufsize <<= 1;      line = xrealloc (line, bufsize);    }  if (length == 0 || ferror (fp))    {      xfree (line);      return NULL;    }  if (length + 1 < bufsize)    /* Relieve the memory from our exponential greediness.  We say       `length + 1' because the terminating \0 is not included in       LENGTH.  We don't need to zero-terminate the string ourselves,       though, because fgets() does that.  */    line = xrealloc (line, length + 1);  return line;}/* Read FILE into memory.  A pointer to `struct file_memory' are   returned; use struct element `content' to access file contents, and   the element `length' to know the file length.  `content' is *not*   zero-terminated, and you should *not* read or write beyond the [0,   length) range of characters.   After you are done with the file contents, call read_file_free to   release the memory.   Depending on the operating system and the type of file that is   being read, read_file() either mmap's the file into memory, or   reads the file into the core using read().   If file is named "-", fileno(stdin) is used for reading instead.   If you want to read from a real file named "-", use "./-" instead.  */struct file_memory *read_file (const char *file){  int fd;  struct file_memory *fm;  long size;  int inhibit_close = 0;  /* Some magic in the finest tradition of Perl and its kin: if FILE     is "-", just use stdin.  */  if (HYPHENP (file))    {      fd = fileno (stdin);      inhibit_close = 1;      /* Note that we don't inhibit mmap() in this case.  If stdin is         redirected from a regular file, mmap() will still work.  */    }  else    fd = open (file, O_RDONLY);  if (fd < 0)    return NULL;  fm = xmalloc (sizeof (struct file_memory));#ifdef HAVE_MMAP  {    struct stat buf;    if (fstat (fd, &buf) < 0)      goto mmap_lose;    fm->length = buf.st_size;    /* NOTE: As far as I know, the callers of this function never       modify the file text.  Relying on this would enable us to       specify PROT_READ and MAP_SHARED for a marginal gain in       efficiency, but at some cost to generality.  */    fm->content = mmap (NULL, fm->length, PROT_READ | PROT_WRITE,			MAP_PRIVATE, fd, 0);    if (fm->content == (char *)MAP_FAILED)      goto mmap_lose;    if (!inhibit_close)      close (fd);    fm->mmap_p = 1;    return fm;  } mmap_lose:  /* The most common reason why mmap() fails is that FD does not point     to a plain file.  However, it's also possible that mmap() doesn't     work for a particular type of file.  Therefore, whenever mmap()     fails, we just fall back to the regular method.  */#endif /* HAVE_MMAP */  fm->length = 0;  size = 512;			/* number of bytes fm->contents can                                   hold at any given time. */  fm->content = xmalloc (size);  while (1)    {      long nread;      if (fm->length > size / 2)	{	  /* #### I'm not sure whether the whole exponential-growth             thing makes sense with kernel read.  On Linux at least,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -