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

📄 ls.c

📁 Linux下文件工具。
💻 C
📖 第 1 页 / 共 5 页
字号:
      && !strncmp (color_indicator[C_LINK].string, "target", 6))    color_symlink_as_referent = 1;}/* Request that the directory named NAME have its contents listed later.   If REALNAME is nonzero, it will be used instead of NAME when the   directory name is printed.  This allows symbolic links to directories   to be treated as regular directories but still be listed under their   real names.  NAME == NULL is used to insert a marker entry for the   directory named in REALNAME.   If F is non-NULL, we use its dev/ino information to save   a call to stat -- when doing a recursive (-R) traversal.  */static voidqueue_directory (const char *name, const char *realname){  struct pending *new;  new = XMALLOC (struct pending, 1);  new->realname = realname ? xstrdup (realname) : NULL;  new->name = name ? xstrdup (name) : NULL;  new->next = pending_dirs;  pending_dirs = new;}/* Read directory `name', and list the files in it.   If `realname' is nonzero, print its name instead of `name';   this is used for symbolic links to directories. */static voidprint_dir (const char *name, const char *realname){  register DIR *reading;  register struct dirent *next;  register uintmax_t total_blocks = 0;  static int first = 1;  errno = 0;  reading = opendir (name);  if (!reading)    {      error (0, errno, "%s", quotearg_colon (name));      exit_status = 1;      return;    }  if (LOOP_DETECT)    {      struct stat dir_stat;      int fd = dirfd (reading);      /* If dirfd failed, endure the overhead of using stat.  */      if ((0 <= fd	   ? fstat (fd, &dir_stat)	   : stat (name, &dir_stat)) < 0)	{	  error (0, errno, _("cannot determine device and inode of %s"),		 quotearg_colon (name));	  exit_status = 1;	  return;	}      /* If we've already visited this dev/inode pair, warn that	 we've found a loop, and do not process this directory.  */      if (visit_dir (dir_stat.st_dev, dir_stat.st_ino))	{	  error (0, 0, _("not listing already-listed directory: %s"),		 quotearg_colon (name));	  return;	}      DEV_INO_PUSH (dir_stat.st_dev, dir_stat.st_ino);    }  /* Read the directory entries, and insert the subfiles into the `files'     table.  */  clear_files ();  while ((next = readdir (reading)) != NULL)    if (file_interesting (next))      {	enum filetype type = unknown;#if HAVE_STRUCT_DIRENT_D_TYPE	if (next->d_type == DT_DIR || next->d_type == DT_CHR	    || next->d_type == DT_BLK || next->d_type == DT_SOCK	    || next->d_type == DT_FIFO)	  type = next->d_type;#endif	total_blocks += gobble_file (next->d_name, type, 0, name);      }  if (CLOSEDIR (reading))    {      error (0, errno, "%s", quotearg_colon (name));      exit_status = 1;      /* Don't return; print whatever we got. */    }  /* Sort the directory contents.  */  sort_files ();  /* If any member files are subdirectories, perhaps they should have their     contents listed rather than being mentioned here as files.  */  if (recursive)    extract_dirs_from_files (name, 1);  if (recursive || print_dir_name)    {      if (!first)	DIRED_PUTCHAR ('\n');      first = 0;      DIRED_INDENT ();      PUSH_CURRENT_DIRED_POS (&subdired_obstack);      dired_pos += quote_name (stdout, realname ? realname : name,			       dirname_quoting_options);      PUSH_CURRENT_DIRED_POS (&subdired_obstack);      DIRED_FPUTS_LITERAL (":\n", stdout);    }  if (format == long_format || print_block_size)    {      const char *p;      char buf[LONGEST_HUMAN_READABLE + 1];      DIRED_INDENT ();      p = _("total");      DIRED_FPUTS (p, stdout, strlen (p));      DIRED_PUTCHAR (' ');      p = human_readable_inexact (total_blocks, buf, ST_NBLOCKSIZE,				  output_block_size, human_ceiling);      DIRED_FPUTS (p, stdout, strlen (p));      DIRED_PUTCHAR ('\n');    }  if (files_index)    print_current_files ();}/* Add `pattern' to the list of patterns for which files that match are   not listed.  */static voidadd_ignore_pattern (const char *pattern){  register struct ignore_pattern *ignore;  ignore = XMALLOC (struct ignore_pattern, 1);  ignore->pattern = pattern;  /* Add it to the head of the linked list. */  ignore->next = ignore_patterns;  ignore_patterns = ignore;}/* Return nonzero if the file in `next' should be listed. */static intfile_interesting (const struct dirent *next){  register struct ignore_pattern *ignore;  for (ignore = ignore_patterns; ignore; ignore = ignore->next)    if (fnmatch (ignore->pattern, next->d_name, FNM_PERIOD) == 0)      return 0;  if (really_all_files      || next->d_name[0] != '.'      || (all_files	  && next->d_name[1] != '\0'	  && (next->d_name[1] != '.' || next->d_name[2] != '\0')))    return 1;  return 0;}/* Enter and remove entries in the table `files'.  *//* Empty the table of files. */static voidclear_files (void){  register int i;  for (i = 0; i < files_index; i++)    {      free (files[i].name);      if (files[i].linkname)	free (files[i].linkname);    }  files_index = 0;  block_size_size = 4;}/* Add a file to the current table of files.   Verify that the file exists, and print an error message if it does not.   Return the number of blocks that the file occupies.  */static uintmax_tgobble_file (const char *name, enum filetype type, int explicit_arg,	     const char *dirname){  register uintmax_t blocks;  register char *path;  if (files_index == nfiles)    {      nfiles *= 2;      files = XREALLOC (files, struct fileinfo, nfiles);    }  files[files_index].linkname = 0;  files[files_index].linkmode = 0;  files[files_index].linkok = 0;  /* FIXME: this use of ls: `mkdir a; touch a/{b,c,d}; ls -R a'     shouldn't require that ls stat b, c, and d -- at least     not on systems with usable d_type.  The problem is that     format_needs_stat is set, because of the -R.  */  if (explicit_arg || format_needs_stat      || (format_needs_type && type == unknown))    {      /* `path' is the absolute pathname of this file. */      int val;      if (name[0] == '/' || dirname[0] == 0)	path = (char *) name;      else	{	  path = (char *) alloca (strlen (name) + strlen (dirname) + 2);	  attach (path, dirname, name);	}      val = (DEREF_ALWAYS <= dereference + explicit_arg	     ? stat (path, &files[files_index].stat)	     : lstat (path, &files[files_index].stat));      if (val < 0)	{	  error (0, errno, "%s", quotearg_colon (path));	  exit_status = 1;	  return 0;	}#if HAVE_ACL      if (format == long_format)	{	  int n = file_has_acl (path, &files[files_index].stat);	  files[files_index].have_acl = (0 < n);	  if (n < 0)	    error (0, errno, "%s", quotearg_colon (path));	}#endif      if (S_ISLNK (files[files_index].stat.st_mode)	  && (format == long_format || check_symlink_color))	{	  char *linkpath;	  struct stat linkstats;	  get_link_name (path, &files[files_index]);	  linkpath = make_link_path (path, files[files_index].linkname);	  /* Avoid following symbolic links when possible, ie, when	     they won't be traced and when no indicator is needed. */	  if (linkpath	      && (indicator_style != none || check_symlink_color)	      && stat (linkpath, &linkstats) == 0)	    {	      files[files_index].linkok = 1;	      /* Symbolic links to directories that are mentioned on the	         command line are automatically traced if not being	         listed as files.  */	      if (explicit_arg && format != long_format		  && S_ISDIR (linkstats.st_mode))		{		  /* Substitute the linked-to directory's name, but		     save the real name in `linkname' for printing.  */		  if (!immediate_dirs)		    {		      const char *tempname = name;		      name = linkpath;		      linkpath = files[files_index].linkname;		      files[files_index].linkname = (char *) tempname;		    }		  files[files_index].stat = linkstats;		}	      else		{		  /* Get the linked-to file's mode for the filetype indicator		     in long listings.  */		  files[files_index].linkmode = linkstats.st_mode;		  files[files_index].linkok = 1;		}	    }	  if (linkpath)	    free (linkpath);	}      if (S_ISLNK (files[files_index].stat.st_mode))	files[files_index].filetype = symbolic_link;      else if (S_ISDIR (files[files_index].stat.st_mode))	{	  if (explicit_arg && !immediate_dirs)	    files[files_index].filetype = arg_directory;	  else	    files[files_index].filetype = directory;	}      else	files[files_index].filetype = normal;      blocks = ST_NBLOCKS (files[files_index].stat);      {	char buf[LONGEST_HUMAN_READABLE + 1];	int len = strlen (human_readable_inexact (blocks, buf, ST_NBLOCKSIZE,						  output_block_size,						  human_ceiling));	if (block_size_size < len)	  block_size_size = len < 7 ? len : 7;      }    }  else    {      files[files_index].filetype = type;#if HAVE_STRUCT_DIRENT_D_TYPE      files[files_index].stat.st_mode = DTTOIF (type);#endif      blocks = 0;    }  files[files_index].name = xstrdup (name);  files_index++;  return blocks;}#if HAVE_SYMLINKS/* Put the name of the file that `filename' is a symbolic link to   into the `linkname' field of `f'. */static voidget_link_name (const char *filename, struct fileinfo *f){  f->linkname = xreadlink (filename);  if (f->linkname == NULL)    {      error (0, errno, _("cannot read symbolic link %s"),	     quotearg_colon (filename));      exit_status = 1;    }}/* If `linkname' is a relative path and `path' contains one or more   leading directories, return `linkname' with those directories   prepended; otherwise, return a copy of `linkname'.   If `linkname' is zero, return zero. */static char *make_link_path (const char *path, const char *linkname){  char *linkbuf;  size_t bufsiz;  if (linkname == 0)    return 0;  if (*linkname == '/')    return xstrdup (linkname);  /* The link is to a relative path.  Prepend any leading path     in `path' to the link name. */  linkbuf = strrchr (path, '/');  if (linkbuf == 0)    return xstrdup (linkname);  bufsiz = linkbuf - path + 1;  linkbuf = xmalloc (bufsiz + strlen (linkname) + 1);  strncpy (linkbuf, path, bufsiz);  strcpy (linkbuf + bufsiz, linkname);  return linkbuf;}#endif/* Return nonzero if base_name (NAME) ends in `.' or `..'   This is so we don't try to recurse on `././././. ...' */static intbasename_is_dot_or_dotdot (const char *name){  char const *base = base_name (name);  return DOT_OR_DOTDOT (base);}/* Remove any entries from `files' that are for directories,   and queue them to be listed as directories instead.   `dirname' is the prefix to prepend to each dirname   to make it correct relative to ls's working dir.   If IGNORE_DOT_AND_DOT_DOT is nonzero don't treat `.' and `..' as dirs.   This is desirable when processing directories recursively.  */static voidextract_dirs_from_files (const char *dirname, int ignore_dot_and_dot_dot){  register int i, j;  if (*dirname && LOOP_DETECT)    {      /* Insert a marker entry first.  When we dequeue this marker entry,	 we'll know that DIRNAME has been processed and may be removed	 from the set of active directories.  */      queue_directory (NULL, dirname);    }  /* Queue the directories last one first, because queueing reverses the     order.  */  for (i = files_index - 1; i >= 0; i--)    if ((files[i].filetype == directory || files[i].filetype == arg_directory)	&& (!ignore_dot_and_dot_dot	    || !basename_is_dot_or_dotdot (files[i].name)))      {	if (files[i].name[0] == '/' || dirname[0] == 0)	  {	    queue_directory (files[i].name, files[i].linkname);	  }	else	  {	    char *path = path_concat (dirname, files[i].name, NULL);	    queue_directory (path, files[i].linkname);	    free (path);	  }	if (files[i].filetype == arg_directory)	  free (files[i].name);      }  /* Now delete the directories from the table, compacting all the remaining     entries.  */  for (i = 0, j = 0; i < files_index; i++)    if (files[i].filetype != arg_directory)      files[j++] = files[i];  files_index = j;}/* Use strcoll to compare strings in this locale.  If an error occurs,   report an error and longjmp to failed_strcoll.  */static jmp_buf failed_strcoll;static intxstrcoll (char const *a, char const *b){  int diff;  errno = 0;  diff = strcoll (a, b);  if (errno)    {      error (0, errno, _("cannot compare file names %s and %s"),	     quote_n (0, a), quote_n (1, b));      exit_status = 1;      longjmp (failed_strcoll, 1);    }  return diff;}/* Comparison routines for sorting the files. */typedef void const *V;static inline intcmp_ctime (struct fileinfo const *a, struct fileinfo const *b,	   int (*cmp) PARAMS ((char const *, char const *))){  int diff = CTIME_CMP (b->stat, a->stat);  return diff ? diff : cmp (a->name, b->name);}static int compare_ctime (V a, V b) { return cmp_ctime (a, b, xstrcoll); }static int compstr_ctime (V a, V b) { return cmp_ctime (a, b, strcmp); }static int rev_cmp_ctime (V a, V b) { return compare_ctime (b, a); }static int rev_str_ctime (V a, V b) { return compstr_ctime (b, a); }static inline intcmp_mtime (struct fileinfo const *a, struct fileinfo const *b,	   int (*cmp) PARAMS((char const *, char const *))){  int diff = MTIME_CMP (b->stat, a->stat);  return diff ? diff : cmp (a->name, b->name);}static int compare_mtime (V a, V b) { return cmp_mtime (a, b, xstrcoll); }static int compstr_mtime (V a, V b) { return cmp_mtime (a, b, strcmp); }static int rev_cmp_mtime (V a, V b) { return compare_mtime (b, a); }static int rev_str_mtime (V a, V b) { return compstr_mtime (b, a); }static inline intcmp_atime (struct fileinfo const *a, struct fileinfo const *b,	   int (*cmp) PARAMS ((char const *, char const

⌨️ 快捷键说明

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