diff options
author | Jim Meyering <jim@meyering.net> | 2000-04-27 12:23:59 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2000-04-27 12:23:59 +0000 |
commit | 4954d34c147a80932b3befe5ef5d922ee534f6ff (patch) | |
tree | 2f92b57788d7bbf89c10e80c640a645d8e06ad22 /src | |
parent | e9c9e0f9e5c93e9f6af1ce99da661a81bb17d492 (diff) | |
download | coreutils-4954d34c147a80932b3befe5ef5d922ee534f6ff.tar.xz |
(pop_dir): Remove through_symlink arg; use null cwd
for that purpose instead.
(count_entry): Also save the directory if we're saving more
than one level.
Fix file descriptor and memory leak when chdir fails.
Diffstat (limited to 'src')
-rw-r--r-- | src/du.c | 39 |
1 files changed, 24 insertions, 15 deletions
@@ -455,14 +455,14 @@ hash_insert (ino_t ino, dev_t dev) } /* Restore the previous working directory or exit. - If THROUGH_SYMLINK is non-zero, simply call `chdir ("..")'. Otherwise, + 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 void -pop_dir (int through_symlink, struct saved_cwd *cwd, const char *curr_dir_name) +pop_dir (struct saved_cwd *cwd, const char *curr_dir_name) { - if (through_symlink) + if (cwd) { if (restore_cwd (cwd, "..", curr_dir_name)) exit (1); @@ -513,8 +513,8 @@ count_entry (const char *ent, int top, dev_t last_dev, int depth) dev_t dir_dev; char *name_space; char *namep; - struct saved_cwd cwd; - int through_symlink; + struct saved_cwd *cwd; + struct saved_cwd cwd_buf; struct stat e_buf; dir_dev = stat_buf.st_dev; @@ -525,18 +525,27 @@ count_entry (const char *ent, int top, dev_t last_dev, int depth) #ifndef S_ISLNK # define S_ISLNK(s) 0 #endif - /* 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. */ - through_symlink = (xstat == stat - && lstat (ent, &e_buf) == 0 - && S_ISLNK (e_buf.st_mode)); - if (through_symlink && save_cwd (&cwd)) - exit (1); + /* 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. */ + if (strchr (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"), path->text); + if (cwd) + free_cwd (cwd); exit_status = 1; return 0; } @@ -548,7 +557,7 @@ count_entry (const char *ent, int top, dev_t last_dev, int depth) if (errno) { error (0, errno, "%s", path->text); - pop_dir (through_symlink, &cwd, path->text); + pop_dir (cwd, path->text); exit_status = 1; return 0; } @@ -572,7 +581,7 @@ count_entry (const char *ent, int top, dev_t last_dev, int depth) } free (name_space); - pop_dir (through_symlink, &cwd, path->text); + pop_dir (cwd, path->text); str_trunc (path, pathlen - 1); /* Remove the "/" we added. */ if (depth <= max_depth || top) |