Hi, I've implemented symlink dereferencing flags for -H, -L and -P to most the tools that support traversing directories as required by the standard.
I don't think changing the permissions symlinks works on linux, but does anyone have a platform where this is actually supported? This relates to the, as yet, unimplemented -h flag. Cheers, Ralph
From 912441f70fac4dafb7babadcfd2f028e80a42b2d Mon Sep 17 00:00:00 2001 From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com> Date: Mon, 9 Feb 2015 22:22:32 +0000 Subject: [PATCH 8/8] du.1: add symlink dereferencing flags to manpage --- du.1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/du.1 b/du.1 index 2639fde..8eee211 100644 --- a/du.1 +++ b/du.1 @@ -8,6 +8,8 @@ .Nm .Op Fl a | s .Op Fl d Ar depth +.Op Fl H +.Op Fl L .Op Fl h .Op Fl k .Op Ar file ... @@ -26,6 +28,11 @@ is displayed. Display an entry for each file in the file hierarchy. .It Fl d Ar depth Maximum directory depth to print files and directories. +.It Fl H +Only dereference symbolic links that are passed as command line arguments when +recursively traversing directories. +.It Fl L +Always dereference symbolic links while recursively traversing directories. .It Fl h Enable human-readable output. .It Fl k -- 2.3.0
From 9801e16c4b79fe4cafc40a573bac139767333942 Mon Sep 17 00:00:00 2001 From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com> Date: Mon, 9 Feb 2015 22:18:49 +0000 Subject: [PATCH 7/8] du.c: add symlink dereferencing flags -H and -L --- du.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/du.c b/du.c index 6d96190..e18bae0 100644 --- a/du.c +++ b/du.c @@ -21,6 +21,7 @@ static int dflag = 0; static int sflag = 0; static int kflag = 0; static int hflag = 0; +static char HLflag = 'P'; static char * xrealpath(const char *pathname, char *resolved) @@ -68,7 +69,7 @@ nblks(struct stat *st) } static size_t -du(const char *path) +du(const char *path, char follow) { struct dirent *dent; struct stat st; @@ -81,9 +82,13 @@ du(const char *path) eprintf("stat: %s:", path); n = nblks(&st); - if (!S_ISDIR(st.st_mode)) + if (!(S_ISDIR(st.st_mode) || + (follow != 'P' && S_ISLNK(st.st_mode) && + stat(path, &st) == 0 && S_ISDIR(st.st_mode)))) goto done; + follow = follow == 'H' ? 'P' : follow; + dp = opendir(path); if (!dp) { weprintf("opendir %s:", path); @@ -97,10 +102,12 @@ du(const char *path) continue; if (lstat(dent->d_name, &st) < 0) eprintf("stat: %s:", dent->d_name); - if (S_ISDIR(st.st_mode)) { + if (S_ISDIR(st.st_mode) || + (follow != 'P' && S_ISLNK(st.st_mode) && + stat(dent->d_name, &st) == 0 && S_ISDIR(st.st_mode))) { t = curdepth; curdepth++; - n += du(dent->d_name); + n += du(dent->d_name, follow); curdepth = t; continue; } @@ -157,6 +164,10 @@ main(int argc, char *argv[]) case 'h': hflag = 1; break; + case 'H': + case 'L': + HLflag = ARGC(); + break; default: usage(); } ARGEND; @@ -172,13 +183,13 @@ main(int argc, char *argv[]) blksize = 1024; if (argc < 1) { - n = du("."); + n = du(".", HLflag); if (sflag) print(n, xrealpath(".", file)); } else { for (; argc > 0; argc--, argv++) { curdepth = 0; - n = du(argv[0]); + n = du(argv[0], HLflag); if (sflag) print(n, xrealpath(argv[0], file)); } -- 2.3.0
From 44cf96ca1eec0bf09240d92a4008dd33eb9723e2 Mon Sep 17 00:00:00 2001 From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com> Date: Mon, 9 Feb 2015 21:42:56 +0000 Subject: [PATCH 6/8] tar.1: add symbolic link dereferencing to manpage --- tar.1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tar.1 b/tar.1 index 2d9e087..6e0ec56 100644 --- a/tar.1 +++ b/tar.1 @@ -12,11 +12,13 @@ .Op Fl f Ar file .Nm .Op Fl C Ar dir +.Op Fl h .Op Fl j | Fl z .Fl c Ar dir .Op Fl f Ar file .Nm .Op Fl C Ar dir +.Op Fl h .Op Fl j | Fl z .Fl cf .Ar file Ar dir @@ -42,6 +44,8 @@ Do not preserve modification time. List all files in the archive. .It Fl x Extract archive. +.It Fl h +Always dereference symbolic links while recursively traversing directories. .It Fl j | Fl z Use bzip2 | gzip compression. The .Xr bzip2 1 | -- 2.3.0
From 8305b0e0e23c4ed8867a057660d33eae633c8f87 Mon Sep 17 00:00:00 2001 From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com> Date: Mon, 9 Feb 2015 21:29:11 +0000 Subject: [PATCH 5/8] chgrp.1: note exception of -h flag unsupported --- chgrp.1 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/chgrp.1 b/chgrp.1 index 7e24699..4981b93 100644 --- a/chgrp.1 +++ b/chgrp.1 @@ -1,4 +1,4 @@ -.Dd January 30, 2015 +.Dd February 9, 2015 .Dt CHGRP 1 .Os sbase .Sh NAME @@ -37,3 +37,10 @@ Don't dereference symbolic links (default). .Xr chmod 2 , .Xr chown 2 , .Xr getgrnam 3 +.El +.Sh STANDARDS +The +.Nm +utility is compliant with the +.St -p1003.1-2008 +specification except from the -h flag. -- 2.3.0
From 85ec7d832b3c05bb26611469216f76d800ddc040 Mon Sep 17 00:00:00 2001 From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com> Date: Mon, 9 Feb 2015 21:26:53 +0000 Subject: [PATCH 4/8] chgrp.1: add symlink derefencing flags to manpage --- chgrp.1 | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/chgrp.1 b/chgrp.1 index c9a0573..7e24699 100644 --- a/chgrp.1 +++ b/chgrp.1 @@ -7,6 +7,9 @@ .Sh SYNOPSIS .Nm .Op Fl R +.Op Fl H +.Op Fl L +.Op Fl P .Ar groupname .Op Ar file... .Sh DESCRIPTION @@ -15,10 +18,18 @@ sets the group id of the files specified by .Ar file to the gid of the group named .Ar group. -If the -.Fl R -flag is specified, this process is recursively applied to -everything in +.El +.Sh OPTIONS +.Bl -tag -width Ds +.It Fl R +Change file group ownership recursively. +.It Fl H +Only dereference symbolic links that are passed as command line arguments when +recursively traversing directories. +.It Fl L +Always dereference symbolic links while recursively traversing directories. +.It Fl P +Don't dereference symbolic links (default). .Ar file . .Sh SEE ALSO .Xr chmod 1 , -- 2.3.0
From 0b95a838a0e14790275179035259d9fd7cc4c189 Mon Sep 17 00:00:00 2001 From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com> Date: Mon, 9 Feb 2015 21:25:58 +0000 Subject: [PATCH 3/8] chown.1: add symlink dereferencing flags to manpage --- chown.1 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/chown.1 b/chown.1 index d27f5cd..1365c07 100644 --- a/chown.1 +++ b/chown.1 @@ -7,6 +7,9 @@ .Sh SYNOPSIS .Nm .Op Fl Rr +.Op Fl H +.Op Fl L +.Op Fl P .Op Ar owner Op Ar :group .Op Ar file ... .Sh DESCRIPTION @@ -19,6 +22,13 @@ changes the user or group ownership for the given Equivalent to \-r. .It Fl r Change directory ownership recursively. +.It Fl H +Only dereference symbolic links that are passed as command line arguments when +recursively traversing directories. +.It Fl L +Always dereference symbolic links while recursively traversing directories. +.It Fl P +Don't dereference symbolic links (default). .El .Sh SEE ALSO .Xr chown 2 -- 2.3.0
From 57a0d77d5311a355e56e16a186a5cc964c5df4bf Mon Sep 17 00:00:00 2001 From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com> Date: Mon, 9 Feb 2015 21:11:06 +0000 Subject: [PATCH 2/8] cp.1: symlink dereferencing flags --- cp.1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cp.1 b/cp.1 index 070ec47..9434d18 100644 --- a/cp.1 +++ b/cp.1 @@ -34,6 +34,12 @@ and .Fl r . .It Fl f If an existing destination file cannot be opened, remove it and try again. +.It Fl H +Only dereference symbolic links that are passed as command line arguments when +recursively traversing directories. +.It Fl L +Always dereference symbolic links while recursively traversing directories +(default). .It Fl P Don't dereference symbolic links. .It Fl p -- 2.3.0
From 4c66bb4696d98a1ce2dc18c1ee58c79065deaf9a Mon Sep 17 00:00:00 2001 From: Tai Chi Minh Ralph Eastwood <tcmreastw...@gmail.com> Date: Mon, 9 Feb 2015 20:56:23 +0000 Subject: [PATCH 1/8] cp: add symlink deref flags -H and -L for cp and mv --- cp.c | 15 +++++++++------ fs.h | 4 ++-- libutil/cp.c | 10 +++++----- libutil/enmasse.c | 6 +++--- libutil/fnck.c | 5 +++-- mv.c | 8 ++++---- util.h | 4 ++-- 7 files changed, 28 insertions(+), 24 deletions(-) diff --git a/cp.c b/cp.c index f3b91f1..25fc07e 100644 --- a/cp.c +++ b/cp.c @@ -19,10 +19,8 @@ main(int argc, char *argv[]) ARGBEGIN { case 'a': /* implies -dpr */ - cp_aflag = cp_Pflag = cp_pflag = cp_rflag = 1; - break; - case 'P': - cp_Pflag = 1; + cp_HLPflag = 'P'; + cp_aflag = cp_pflag = cp_rflag = 1; break; case 'p': cp_pflag = 1; @@ -30,10 +28,15 @@ main(int argc, char *argv[]) case 'f': cp_fflag = 1; break; - case 'R': case 'r': + case 'R': cp_rflag = 1; break; + case 'H': + case 'L': + case 'P': + cp_HLPflag = ARGC(); + break; case 'v': cp_vflag = 1; break; @@ -46,6 +49,6 @@ main(int argc, char *argv[]) if (argc > 2 && !(stat(argv[argc-1], &st) == 0 && S_ISDIR(st.st_mode))) eprintf("%s: not a directory\n", argv[argc-1]); - enmasse(argc, argv, cp); + enmasse(argc, argv, cp, cp_HLPflag); return cp_status; } diff --git a/fs.h b/fs.h index c6535d7..d9faeac 100644 --- a/fs.h +++ b/fs.h @@ -1,15 +1,15 @@ /* See LICENSE file for copyright and license details. */ extern int cp_aflag; extern int cp_fflag; -extern int cp_Pflag; extern int cp_pflag; extern int cp_rflag; extern int cp_vflag; +extern char cp_HLPflag; extern int cp_status; extern int rm_fflag; extern int rm_rflag; extern int rm_status; -int cp(const char *, const char *); +int cp(const char *, const char *, char); void rm(const char *); diff --git a/libutil/cp.c b/libutil/cp.c index d252e52..7e0cd3a 100644 --- a/libutil/cp.c +++ b/libutil/cp.c @@ -17,14 +17,14 @@ int cp_aflag = 0; int cp_fflag = 0; -int cp_Pflag = 0; int cp_pflag = 0; int cp_rflag = 0; int cp_vflag = 0; int cp_status = 0; +char cp_HLPflag = 'L'; int -cp(const char *s1, const char *s2) +cp(const char *s1, const char *s2, char ff) { FILE *f1, *f2; char *ns1, *ns2; @@ -39,9 +39,9 @@ cp(const char *s1, const char *s2) if (cp_vflag) printf("'%s' -> '%s'\n", s1, s2); - r = cp_Pflag ? lstat(s1, &st) : stat(s1, &st); + r = ff == 'P' ? lstat(s1, &st) : stat(s1, &st); if (r < 0) { - weprintf("%s %s:", cp_Pflag ? "lstat" : "stat", s1); + weprintf("%s %s:", ff == 'P' ? "lstat" : "stat", s1); cp_status = 1; return 0; } @@ -83,7 +83,7 @@ cp(const char *s1, const char *s2) eprintf("%s/%s: filename too long\n", s2, d->d_name); } - fnck(ns1, ns2, cp); + fnck(ns1, ns2, cp, ff == 'H' ? 'P' : ff); } } closedir(dp); diff --git a/libutil/enmasse.c b/libutil/enmasse.c index 7a2fa2a..6281b79 100644 --- a/libutil/enmasse.c +++ b/libutil/enmasse.c @@ -9,7 +9,7 @@ #include "../util.h" void -enmasse(int argc, char *argv[], int (*fn)(const char *, const char *)) +enmasse(int argc, char *argv[], int (*fn)(const char *, const char *, char), char ff) { char *buf, *dir; int i, len; @@ -18,7 +18,7 @@ enmasse(int argc, char *argv[], int (*fn)(const char *, const char *)) size_t dlen; if (argc == 2 && !(stat(argv[1], &st) == 0 && S_ISDIR(st.st_mode))) { - fnck(argv[0], argv[1], fn); + fnck(argv[0], argv[1], fn, ff); return; } else { dir = (argc == 1) ? "." : argv[--argc]; @@ -35,7 +35,7 @@ enmasse(int argc, char *argv[], int (*fn)(const char *, const char *)) eprintf("%s/%s: filename too long\n", dir, basename(argv[i])); } - fnck(argv[i], buf, fn); + fnck(argv[i], buf, fn, ff); } free(buf); } diff --git a/libutil/fnck.c b/libutil/fnck.c index 3085ab7..8afc4b1 100644 --- a/libutil/fnck.c +++ b/libutil/fnck.c @@ -4,7 +4,8 @@ #include "../util.h" void -fnck(const char *a, const char *b, int (*fn)(const char *, const char *)) +fnck(const char *a, const char *b, + int (*fn)(const char *, const char *, char), char ff) { struct stat sta, stb; @@ -15,6 +16,6 @@ fnck(const char *a, const char *b, int (*fn)(const char *, const char *)) eprintf("%s -> %s: same file\n", a, b); } - if (fn(a, b) < 0) + if (fn(a, b, ff) < 0) eprintf("%s -> %s:", a, b); } diff --git a/mv.c b/mv.c index ff29a8a..605e9d8 100644 --- a/mv.c +++ b/mv.c @@ -11,14 +11,14 @@ static int mv_status = 0; static int -mv(const char *s1, const char *s2) +mv(const char *s1, const char *s2, char ff) { if (rename(s1, s2) == 0) return (mv_status = 0); if (errno == EXDEV) { - cp_rflag = 1; + cp_aflag = cp_rflag = cp_pflag = 1; rm_rflag = 1; - cp(s1, s2); + cp(s1, s2, ff); rm(s1); return (mv_status = cp_status || rm_status); } @@ -50,7 +50,7 @@ main(int argc, char *argv[]) if (argc > 3 && !(stat(argv[argc-1], &st) == 0 && S_ISDIR(st.st_mode))) eprintf("%s: not a directory\n", argv[argc-1]); - enmasse(argc, &argv[0], mv); + enmasse(argc, &argv[0], mv, 'P'); return mv_status; } diff --git a/util.h b/util.h index 1f1c229..2688848 100644 --- a/util.h +++ b/util.h @@ -48,8 +48,8 @@ int enregcomp(int, regex_t *, const char *, int); int eregcomp(regex_t *, const char *, int); /* misc */ -void enmasse(int, char **, int (*)(const char *, const char *)); -void fnck(const char *, const char *, int (*)(const char *, const char *)); +void enmasse(int, char **, int (*)(const char *, const char *, char), char); +void fnck(const char *, const char *, int (*)(const char *, const char *, char), char); mode_t getumask(void); char *humansize(double); mode_t parsemode(const char *, mode_t, mode_t); -- 2.3.0