Subject: cp -P and cp -R
To: None <tech-userlevel@netbsd.org>
From: Jan Schaumann <jschauma@netmeister.org>
List: tech-userlevel
Date: 07/03/2006 13:33:58
--dc+cDN39EJAMEtIO
Content-Type: multipart/mixed; boundary="n8g4imXOkfNTN/H1"
Content-Disposition: inline
--n8g4imXOkfNTN/H1
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
Hi,
I've noticed a discrepancy between the cp(1) manual page and it's actual
usage. The manual page states:
-R [...] Created directories have the same mode as the corre-
sponding source directory, unmodified by the process' umask.
This does however not seem to be the case:
(lapdog) umask
077
(lapdog) ls -la dir1
total 7
drwx------ 3 jschauma wheel 512 Jul 3 13:17 .
drwxrwxrwt 30 root wheel 1536 Jul 3 13:18 ..
-rw------- 1 jschauma wheel 7 Jul 3 13:17 file
drwxrwxrwx 2 jschauma wheel 512 Jul 3 13:17 subdir1
lrwx------ 1 jschauma wheel 6 Jul 3 13:17 symlink -> target
-rw------- 1 jschauma wheel 6 Jul 3 13:17 target
(lapdog) cp -R dir1 dir2
(lapdog) ls -la dir2
total 7
drwx------ 3 jschauma wheel 512 Jul 3 13:18 .
drwxrwxrwt 31 root wheel 1536 Jul 3 13:18 ..
-rw------- 1 jschauma wheel 7 Jul 3 13:18 file
drwx------ 2 jschauma wheel 512 Jul 3 13:18 subdir1
lrwx------ 1 jschauma wheel 6 Jul 3 13:18 symlink -> target
-rw------- 1 jschauma wheel 6 Jul 3 13:18 target
(lapdog)=20
Note that dir2/subdir1 was created with permissions modified by my
umask. This is because the variable 'dne' is reset to 0 during file
traversal before the directory is visited the second time.
Another thing I noticed is that there currently is no way to copy a file
to a symbolic link (ie overwriting the symbolic link). One can copy a
symbolic link to a file (ie turning the file into a symbolic link with
the same target) by using '-R', but that is non-intuitive.
Ie:
(lapdog) ls -la
total 7
drwx------ 3 jschauma wheel 512 Jul 3 13:17 .
drwxrwxrwt 31 root wheel 1536 Jul 3 13:18 ..
-rw------- 1 jschauma wheel 7 Jul 3 13:17 file
drwxrwxrwx 2 jschauma wheel 512 Jul 3 13:17 subdir1
lrwx------ 1 jschauma wheel 6 Jul 3 13:17 symlink -> target
-rw------- 1 jschauma wheel 6 Jul 3 13:17 target
(lapdog) cp symlink file
(lapdog) ls -la
total 7
drwx------ 3 jschauma wheel 512 Jul 3 13:17 .
drwxrwxrwt 31 root wheel 1536 Jul 3 13:18 ..
-rw------- 1 jschauma wheel 6 Jul 3 13:22 file
drwxrwxrwx 2 jschauma wheel 512 Jul 3 13:17 subdir1
lrwx------ 1 jschauma wheel 6 Jul 3 13:17 symlink -> target
-rw------- 1 jschauma wheel 6 Jul 3 13:17 target
(lapdog) cp -R symlink file
(lapdog) ls -la
total 6
drwx------ 3 jschauma wheel 512 Jul 3 13:22 .
drwxrwxrwt 31 root wheel 1536 Jul 3 13:18 ..
lrwx------ 1 jschauma wheel 6 Jul 3 13:22 file -> target
drwxrwxrwx 2 jschauma wheel 512 Jul 3 13:17 subdir1
lrwx------ 1 jschauma wheel 6 Jul 3 13:17 symlink -> target
-rw------- 1 jschauma wheel 6 Jul 3 13:17 target
(lapdog)=20
It seemed to me that using '-P' (no symbolic links are followed) could
also be used when '-R' is _not_ specified to allow a user to copy a file
over a symbolic link or a symbolic link over a file, like so:
(lapdog) ls -la
total 7
drwx------ 3 jschauma wheel 512 Jul 3 13:24 .
drwxrwxrwt 31 root wheel 1536 Jul 3 13:18 ..
-rw------- 1 jschauma wheel 6 Jul 3 13:24 file
drwxrwxrwx 2 jschauma wheel 512 Jul 3 13:17 subdir1
lrwx------ 1 jschauma wheel 6 Jul 3 13:17 symlink -> target
-rw------- 1 jschauma wheel 6 Jul 3 13:17 target
(lapdog) /usr/src/bin/cp/obj/cp -P symlink file
(lapdog) ls -la
total 6
drwx------ 3 jschauma wheel 512 Jul 3 13:24 .
drwxrwxrwt 31 root wheel 1536 Jul 3 13:18 ..
lrwx------ 1 jschauma wheel 6 Jul 3 13:24 file -> target
drwxrwxrwx 2 jschauma wheel 512 Jul 3 13:17 subdir1
lrwx------ 1 jschauma wheel 6 Jul 3 13:17 symlink -> target
-rw------- 1 jschauma wheel 6 Jul 3 13:17 target
(lapdog) rm file
(lapdog) echo hello > file
(lapdog) /usr/src/bin/cp/obj/cp -P file symlink
(lapdog) ls -la
total 8
drwx------ 3 jschauma wheel 512 Jul 3 13:27 .
drwxrwxrwt 31 root wheel 1536 Jul 3 13:18 ..
-rw------- 1 jschauma wheel 6 Jul 3 13:27 file
drwxrwxrwx 2 jschauma wheel 512 Jul 3 13:17 subdir1
-rw------- 1 jschauma wheel 6 Jul 3 13:27 symlink
-rw------- 1 jschauma wheel 6 Jul 3 13:17 target
(lapdog)=20
The attached patch fixes those problem, but I have to admit I'm not
entirely sure if this goes against old conventions or if this just adds
confusion. Any thoughts?
-Jan
--=20
In the beginning the Universe was created. This has made a lot=20
of people very angry and been widely regarded as a bad move.
--n8g4imXOkfNTN/H1
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="cp.diff"
Content-Transfer-Encoding: quoted-printable
Index: cp.1
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/cp/cp.1,v
retrieving revision 1.26
diff -b -u -r1.26 cp.1
--- cp.1 10 Sep 2005 21:51:57 -0000 1.26
+++ cp.1 3 Jul 2006 17:09:19 -0000
@@ -42,18 +42,18 @@
.Nm
.Oo
.Fl R
-.Op Fl H | Fl L | Fl P
+.Op Fl H | Fl L
.Oc
.Op Fl f | i
-.Op Fl Npv
+.Op Fl NpPv
.Ar source_file target_file
.Nm cp
.Oo
.Fl R
-.Op Fl H | Fl L | Fl P
+.Op Fl H | Fl L
.Oc
.Op Fl f | i
-.Op Fl Npv
+.Op Fl NpPv
.Ar source_file ... target_directory
.Sh DESCRIPTION
In the first synopsis form, the
@@ -105,9 +105,7 @@
.Fl p ,
don't copy file flags.
.It Fl P
-If the
-.Fl R
-option is specified, no symbolic links are followed.
+No symbolic links are followed.
.It Fl p
Causes
.Nm
@@ -138,7 +136,7 @@
.Nm
to create special files rather than copying them as normal files.
Created directories have the same mode as the corresponding source
-directory, unmodified by the process' umask.
+directory, unmodified by the process's umask.
.It Fl v
Cause
.Nm
@@ -178,16 +176,17 @@
flag is set, in which case symbolic links are not followed, by default.
The
.Fl H
-or
+and
.Fl L
flags (in conjunction with the
.Fl R
-flag) cause symbolic links to be followed as described above.
+flag), as well as the
+.Fl P
+flag cause symbolic links to be followed as described above.
The
.Fl H ,
-.Fl L
and
-.Fl P
+.Fl L
options are ignored unless the
.Fl R
option is specified.
Index: cp.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/cp/cp.c,v
retrieving revision 1.41
diff -b -u -r1.41 cp.c
--- cp.c 17 Mar 2006 06:22:30 -0000 1.41
+++ cp.c 3 Jul 2006 17:09:19 -0000
@@ -85,7 +85,7 @@
PATH_T to =3D { to.p_path, empty };
=20
uid_t myuid;
-int Rflag, fflag, iflag, pflag, rflag, vflag, Nflag;
+int Hflag, Lflag, Rflag, Pflag, fflag, iflag, pflag, rflag, vflag, Nflag;
mode_t myumask;
=20
enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
@@ -99,7 +99,7 @@
{
struct stat to_stat, tmp_stat;
enum op type;
- int Hflag, Lflag, Pflag, ch, fts_options, r, have_trailing_slash;
+ int ch, fts_options, r, have_trailing_slash;
char *target, **src;
=20
(void)setlocale(LC_ALL, "");
@@ -168,6 +168,7 @@
fts_options &=3D ~FTS_PHYSICAL;
fts_options |=3D FTS_LOGICAL;
}
+
if (Rflag) {
if (Hflag)
fts_options |=3D FTS_COMFOLLOW;
@@ -175,7 +176,7 @@
fts_options &=3D ~FTS_PHYSICAL;
fts_options |=3D FTS_LOGICAL;
}
- } else {
+ } else if (!Pflag) {
fts_options &=3D ~FTS_PHYSICAL;
fts_options |=3D FTS_LOGICAL | FTS_COMFOLLOW;
}
@@ -213,7 +214,10 @@
*
* In (2), the real target is not directory, but "directory/source".
*/
+ if (rflag || (Rflag && (Lflag || Hflag)))
r =3D stat(to.p_path, &to_stat);
+ else
+ r =3D lstat(to.p_path, &to_stat);
if (r =3D=3D -1 && errno !=3D ENOENT) {
err(EXIT_FAILURE, "%s", to.p_path);
/* NOTREACHED */
@@ -282,10 +286,11 @@
struct stat to_stat;
FTS *ftsp;
FTSENT *curr;
- int base, dne, rval;
+ int base, dne, rval, sval;
size_t nlen;
char *p, *target_mid;
=20
+ dne =3D 0;
base =3D 0; /* XXX gcc -Wuninitialized (see comment below) */
=20
if ((ftsp =3D fts_open(argv, fts_options, mastercmp)) =3D=3D NULL)
@@ -370,8 +375,10 @@
STRIP_TRAILING_SLASH(to);
}
=20
+ sval =3D (rflag || (Rflag && (Lflag || Hflag))) ?
+ stat(to.p_path, &to_stat) : lstat(to.p_path, &to_stat);
/* Not an error but need to remember it happened */
- if (stat(to.p_path, &to_stat) =3D=3D -1)
+ if (sval =3D=3D -1)
dne =3D 1;
else {
if (to_stat.st_dev =3D=3D curr->fts_statp->st_dev &&
@@ -390,6 +397,7 @@
rval =3D 1;
continue;
}
+ if (!S_ISDIR(curr->fts_statp->st_mode))
dne =3D 0;
}
=20
Index: extern.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/cp/extern.h,v
retrieving revision 1.12
diff -b -u -r1.12 extern.h
--- extern.h 15 Oct 2005 18:22:18 -0000 1.12
+++ extern.h 3 Jul 2006 17:09:19 -0000
@@ -42,7 +42,7 @@
=20
extern PATH_T to;
extern uid_t myuid;
-extern int fflag, iflag, pflag, Nflag;
+extern int Rflag, rflag, Hflag, Lflag, Pflag, fflag, iflag, pflag, Nflag;
extern mode_t myumask;
=20
#include <sys/cdefs.h>
Index: utils.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/cp/utils.c,v
retrieving revision 1.29
diff -b -u -r1.29 utils.c
--- utils.c 15 Oct 2005 18:22:18 -0000 1.29
+++ utils.c 3 Jul 2006 17:09:19 -0000
@@ -74,7 +74,7 @@
{
static char buf[MAXBSIZE];
struct stat to_stat, *fs;
- int ch, checkch, from_fd, rcount, rval, to_fd, wcount;
+ int ch, checkch, from_fd, rcount, rval, to_fd, tolnk, wcount;
char *p;
=09
if ((from_fd =3D open(entp->fts_path, O_RDONLY, 0)) =3D=3D -1) {
@@ -82,7 +82,9 @@
return (1);
}
=20
+ to_fd =3D -1;
fs =3D entp->fts_statp;
+ tolnk =3D ((Rflag && !(Lflag || Hflag)) || Pflag);
=20
/*
* If the file exists and we're interactive, verify with the user.
@@ -93,6 +95,9 @@
* modified by the umask.)
*/
if (!dne) {
+ struct stat sb;
+ int sval;
+
if (iflag) {
(void)fprintf(stderr, "overwrite %s? ", to.p_path);
checkch =3D ch =3D getchar();
@@ -103,13 +108,21 @@
return (0);
}
}
- /* overwrite existing destination file name */
+
+ sval =3D tolnk ?
+ lstat(to.p_path, &sb) : stat(to.p_path, &sb);
+ if (sval =3D=3D -1) {
+ warn("stat: %s", to.p_path);
+ return (1);
+ }
+
+ if (!(tolnk && S_ISLNK(sb.st_mode)))
to_fd =3D open(to.p_path, O_WRONLY | O_TRUNC, 0);
} else
to_fd =3D open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
fs->st_mode & ~(S_ISUID | S_ISGID));
=20
- if (to_fd =3D=3D -1 && fflag) {
+ if (to_fd =3D=3D -1 && (fflag || tolnk)) {
/*
* attempt to remove existing destination file name and
* create a new file
--n8g4imXOkfNTN/H1--
--dc+cDN39EJAMEtIO
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (NetBSD)
iD8DBQFEqVUGfFtkr68iakwRAsztAJ9Yw3pFppnhc0srMgnoT68ogiLPjgCgu4iC
SRIYle7V9q7L8Tzpeb93va8=
=5UzJ
-----END PGP SIGNATURE-----
--dc+cDN39EJAMEtIO--