📄 du.c
字号:
/* Print N_BLOCKS followed by STRING on a line. NBLOCKS is the number of ST_NBLOCKSIZE-byte blocks; convert it to OUTPUT_BLOCK_SIZE units before printing. If OUTPUT_BLOCK_SIZE is negative, use a human readable notation instead. */static voidprint_size (uintmax_t n_blocks, const char *string){ char buf[LONGEST_HUMAN_READABLE + 1]; printf ("%s\t%s\n", human_readable_inexact (n_blocks, buf, ST_NBLOCKSIZE, output_block_size, human_ceiling), string); fflush (stdout);}/* Restore the previous working directory or exit. If CWD is null, simply call `chdir ("..")'. Otherwise, use CWD and free it. CURR_DIR_NAME is the name of the current directory and is used solely in failure diagnostics. */static voidpop_dir (struct saved_cwd *cwd, const char *curr_dir_name){ if (cwd) { if (restore_cwd (cwd, "..", curr_dir_name)) exit (1); free_cwd (cwd); } else if (chdir ("..") < 0) { error (1, errno, _("cannot change to `..' from directory %s"), quote (curr_dir_name)); }}/* Print (if appropriate) the size (in units determined by `output_block_size') of file or directory ENT. Return the size of ENT in units of 512-byte blocks. TOP is one for external calls, zero for recursive calls. LAST_DEV is the device that the parent directory of ENT is on. DEPTH is the number of levels (in hierarchy) down from a command line argument. Don't print if DEPTH > max_depth. An important invariant is that when this function returns, the current working directory is the same as when it was called. */static uintmax_tcount_entry (const char *ent, int top, dev_t last_dev, int depth){ uintmax_t size; struct stat stat_buf; if (((top && opt_dereference_arguments) ? stat (ent, &stat_buf) : (*xstat) (ent, &stat_buf)) < 0) { error (0, errno, "%s", quote (path->text)); exit_status = 1; return 0; } if (!opt_count_all && stat_buf.st_nlink > 1 && hash_ins (stat_buf.st_ino, stat_buf.st_dev)) return 0; /* Have counted this already. */ size = ST_NBLOCKS (stat_buf); tot_size += size; if (S_ISDIR (stat_buf.st_mode)) { unsigned pathlen; dev_t dir_dev; char *name_space; char *namep; struct saved_cwd *cwd; struct saved_cwd cwd_buf; struct stat e_buf; dir_dev = stat_buf.st_dev; /* Return `0' here, not SIZE, since the SIZE bytes would reside in the new filesystem. */ if (opt_one_file_system && !top && last_dev != dir_dev) return 0; /* Don't enter a new file system. */#ifndef S_ISLNK# define S_ISLNK(s) 0#endif /* If we're traversing more than one level, or if we're dereferencing symlinks and we're about to chdir through a symlink, remember the current directory so we can return to it later. In other cases, chdir ("..") works fine. Treat `.' and `..' like multi-level paths, since `chdir ("..")' wont't restore the current working directory after a `chdir' to one of those. */ if (strchr (ent, '/') || DOT_OR_DOTDOT (ent) || (xstat == stat && lstat (ent, &e_buf) == 0 && S_ISLNK (e_buf.st_mode))) { if (save_cwd (&cwd_buf)) exit (1); cwd = &cwd_buf; } else cwd = NULL; if (chdir (ent) < 0) { error (0, errno, _("cannot change to directory %s"), quote (path->text)); if (cwd) free_cwd (cwd); exit_status = 1; /* Do return SIZE, here, since even though we can't chdir into ENT, we *can* count the blocks used by its directory entry. */ return opt_separate_dirs ? 0 : size; } name_space = savedir ("."); if (name_space == NULL) { error (0, errno, "%s", quote (path->text)); pop_dir (cwd, path->text); exit_status = 1; /* Do count the SIZE bytes. */ return opt_separate_dirs ? 0 : size; } /* Remember the current path. */ str_concatc (path, "/"); pathlen = path->length; for (namep = name_space; *namep; namep += strlen (namep) + 1) { if (!excluded_filename (exclude, namep)) { str_concatc (path, namep); size += count_entry (namep, 0, dir_dev, depth + 1); str_trunc (path, pathlen); } } free (name_space); pop_dir (cwd, path->text); str_trunc (path, pathlen - 1); /* Remove the "/" we added. */ if (depth <= max_depth || top) print_size (size, path->length > 0 ? path->text : "/"); return opt_separate_dirs ? 0 : size; } else if ((opt_all && depth <= max_depth) || top) { /* FIXME: make this an option. */ int print_only_dir_size = 0; if (!print_only_dir_size) print_size (size, path->length > 0 ? path->text : "/"); } return size;}/* Recursively print the sizes of the directories (and, if selected, files) named in FILES, the last entry of which is NULL. */static voiddu_files (char **files){ int i; /* Index in FILES. */ for (i = 0; files[i]; i++) { char *arg; int s; arg = files[i]; /* Delete final slash in the argument, unless the slash is alone. */ s = strlen (arg) - 1; if (s != 0) { if (arg[s] == '/') arg[s] = 0; str_copyc (path, arg); } else if (arg[0] == '/') str_trunc (path, 0); /* Null path for root directory. */ else str_copyc (path, arg); if (!print_totals) hash_clear (htab); count_entry (arg, 1, 0, 0); } if (print_totals) print_size (tot_size, _("total"));}intmain (int argc, char **argv){ int c; char *cwd_only[2]; int max_depth_specified = 0; /* If nonzero, display only a total for each argument. */ int opt_summarize_only = 0; cwd_only[0] = "."; cwd_only[1] = NULL; program_name = argv[0]; setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); atexit (close_stdout); exclude = new_exclude (); xstat = lstat; human_block_size (getenv ("DU_BLOCK_SIZE"), 0, &output_block_size); while ((c = getopt_long (argc, argv, "abchHklmsxB:DLSX:", long_options, NULL)) != -1) { long int tmp_long; switch (c) { case 0: /* Long option. */ break; case 'a': opt_all = 1; break; case 'b': output_block_size = 1; break; case 'c': print_totals = 1; break; case 'h': output_block_size = -1024; break; case 'H': output_block_size = -1000; break; case 'k': output_block_size = 1024; break; case MAX_DEPTH_OPTION: /* --max-depth=N */ if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK || tmp_long < 0 || tmp_long > INT_MAX) error (1, 0, _("invalid maximum depth %s"), quote (optarg)); max_depth_specified = 1; max_depth = (int) tmp_long; break; case 'm': /* obsolescent */ output_block_size = 1024 * 1024; break; case 'l': opt_count_all = 1; break; case 's': opt_summarize_only = 1; break; case 'x': opt_one_file_system = 1; break; case 'B': human_block_size (optarg, 1, &output_block_size); break; case 'D': opt_dereference_arguments = 1; break; case 'L': xstat = stat; break; case 'S': opt_separate_dirs = 1; break; case 'X': if (add_exclude_file (add_exclude, exclude, optarg, EXCLUDE_WILDCARDS, '\n')) error (1, errno, "%s", quote (optarg)); break; case EXCLUDE_OPTION: add_exclude (exclude, optarg, EXCLUDE_WILDCARDS); break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); default: usage (1); } } if (opt_all && opt_summarize_only) { error (0, 0, _("cannot both summarize and show all entries")); usage (1); } if (opt_summarize_only && max_depth_specified && max_depth == 0) { error (0, 0, _("warning: summarizing is the same as using --max-depth=0")); } if (opt_summarize_only && max_depth_specified && max_depth != 0) { error (0, 0, _("warning: summarizing conflicts with --max-depth=%d"), max_depth); usage (1); } if (opt_summarize_only) max_depth = 0; /* Initialize the hash structure for inode numbers. */ hash_init (); str_init (&path, INITIAL_PATH_SIZE); du_files (optind == argc ? cwd_only : argv + optind); exit (exit_status);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -