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

Reply via email to