📄 ls.c
字号:
case 2: /* Second label character */ if (*p) { label[1] = *(p++); state = 3; } else state = -1; /* Error */ break; case 3: /* Equal sign after indicator label */ state = -1; /* Assume failure... */ if (*(p++) == '=')/* It *should* be... */ { for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no) { if (STREQ (label, indicator_name[ind_no])) { color_indicator[ind_no].string = buf; state = ((color_indicator[ind_no].len = get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1); break; } } if (state == -1) error (0, 0, _("unrecognized prefix: %s"), quotearg (label)); } break; case 4: /* Equal sign after *.ext */ if (*(p++) == '=') { ext->seq.string = buf; state = (ext->seq.len = get_funky_string (&buf, &p, 0)) < 0 ? -1 : 1; } else state = -1; break; } } if (state < 0) { struct color_ext_type *e; struct color_ext_type *e2; error (0, 0, _("unparsable value for LS_COLORS environment variable")); free (color_buf); for (e = color_ext_list; e != NULL; /* empty */) { e2 = e; e = e->next; free (e2); } print_with_color = 0; } if (color_indicator[C_LINK].len == 6 && !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 *dirp; register struct dirent *next; register uintmax_t total_blocks = 0; static int first = 1; errno = 0; dirp = opendir (name); if (!dirp) { error (0, errno, "%s", quotearg_colon (name)); exit_status = 1; return; } if (LOOP_DETECT) { struct stat dir_stat; int fd = dirfd (dirp); /* 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 (1) { /* Set errno to zero so we can distinguish between a readdir failure and when readdir simply finds that there are no more entries. */ errno = 0; if ((next = readdir (dirp)) == NULL) { if (errno) { /* Save/restore errno across closedir call. */ int e = errno; closedir (dirp); errno = e; /* Arrange to give a diagnostic after exiting this loop. */ dirp = NULL; } break; } if (file_interesting (next)) { enum filetype type = unknown;#if HAVE_STRUCT_DIRENT_D_TYPE if (next->d_type == DT_BLK || next->d_type == DT_CHR || next->d_type == DT_DIR || next->d_type == DT_FIFO || next->d_type == DT_LNK || next->d_type == DT_REG || next->d_type == DT_SOCK) type = next->d_type;#endif total_blocks += gobble_file (next->d_name, type, 0, name); } } if (dirp == NULL || CLOSEDIR (dirp)) { error (0, errno, _("reading directory %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, NULL); 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 (total_blocks, buf, human_output_opts, ST_NBLOCKSIZE, output_block_size); 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; if (explicit_arg || format_needs_stat || (format_needs_type && (type == unknown /* FIXME: remove this disjunct. I don't think we care about symlinks here, but for now this won't make a big performance difference. */ || type == symbolic_link /* --indicator-style=classify (aka -F) requires that we stat each regular file to see if it's executable. */ || (type == normal && (indicator_style == classify /* This is so that --color ends up highlighting files with the executable bit set even when options like -F are not specified. */ || print_with_color))))) { /* `path' is the absolute pathname of this file. */ int err; if (name[0] == '/' || dirname[0] == 0) path = (char *) name; else { path = (char *) alloca (strlen (name) + strlen (dirname) + 2); attach (path, dirname, name); } switch (dereference) { case DEREF_ALWAYS: err = stat (path, &files[files_index].stat); break; case DEREF_COMMAND_LINE_ARGUMENTS: case DEREF_COMMAND_LINE_SYMLINK_TO_DIR: if (explicit_arg) { int need_lstat; err = stat (path, &files[files_index].stat); if (dereference == DEREF_COMMAND_LINE_ARGUMENTS) break; need_lstat = (err < 0 ? errno == ENOENT : ! S_ISDIR (files[files_index].stat.st_mode)); if (!need_lstat) break; /* stat failed because of ENOENT, maybe indicating a dangling symlink. Or stat succeeded, PATH does not refer to a directory, and --dereference-command-line-symlink-to-dir is in effect. Fall through so that we call lstat instead. */ } default: /* DEREF_NEVER */ err = lstat (path, &files[files_index].stat); break; } if (err < 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)) { /* 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 (blocks, buf, human_output_opts, ST_NBLOCKSIZE, output_block_size)); 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;}#ifdef S_ISLNK/* 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 *n
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -