Re: /bin/cp: overwrite symlink with file pointed to by symlink

2021-02-22 Thread Quentin Rameau
> Hi Quentin,

Hi Cristopher,

> Thank you for having a look.

You're welcome!

> I know I'm very late, but I still like your patch. So ok chrisz@ if you 
> want to commit it.

It didn't raise much passion at the time, we can just hope it gets a bit
more attention now!



Re: /bin/cp: overwrite symlink with file pointed to by symlink

2021-02-11 Thread Christopher Zimmermann



Hi Quentin,

Thank you for having a look.
I know I'm very late, but I still like your patch. So ok chrisz@ if you 
want to commit it.


Christopher


On Fri, Nov 01, 2019 at 08:46:51PM +0100, Quentin Rameau wrote:

If you're interested in adapting to POSIX, here's a proposition patch:

Index: bin/cp//cp.1
===
RCS file: /var/cvs/src/bin/cp/cp.1,v
retrieving revision 1.40
diff -u -r1.40 cp.1
--- bin/cp//cp.128 Jan 2019 18:58:42 -  1.40
+++ bin/cp//cp.11 Nov 2019 19:41:26 -
@@ -79,9 +79,8 @@
Same as
.Fl RpP .
.It Fl f
-For each existing destination pathname, remove it and
-create a new file, without prompting for confirmation,
-regardless of its permissions.
+For each existing destination pathname which cannot be opened, remove
+it and create a new file, without prompting for confirmation.
The
.Fl f
option overrides any previous
Index: bin/cp//utils.c
===
RCS file: /var/cvs/src/bin/cp/utils.c,v
retrieving revision 1.47
diff -u -r1.47 utils.c
--- bin/cp//utils.c 28 Jan 2019 18:58:42 -  1.47
+++ bin/cp//utils.c 1 Nov 2019 19:25:02 -
@@ -55,7 +55,7 @@
static char *buf;
static char *zeroes;
struct stat to_stat, *fs;
-   int from_fd, rcount, rval, to_fd, wcount;
+   int from_fd, rcount, rval, to_fd, wcount, create = 1;
#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
char *p;
#endif
@@ -79,26 +79,24 @@
fs = entp->fts_statp;

/*
-* In -f (force) mode, we always unlink the destination first
-* if it exists.  Note that -i and -f are mutually exclusive.
-*/
-   if (exists && fflag)
-   (void)unlink(to.p_path);
-
-   /*
 * If the file DNE, set the mode to be the from file, minus setuid
 * bits, modified by the umask; arguably wrong, but it makes copying
 * executables work right and it's been that way forever.  (The
 * other choice is 666 or'ed with the execute bits on the from file
 * modified by the umask.)
 */
-   if (exists && !fflag) {
-   if (!copy_overwrite()) {
+   if (exists) {
+   /* Note that -i and -f are mutually exclusive. */
+   if (!fflag && !copy_overwrite()) {
(void)close(from_fd);
return 2;
}
to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
-   } else
+   if (to_fd != -1 || fflag && unlink(to.p_path) == -1)
+   create = 0;
+   }
+
+   if (create)
to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
fs->st_mode & ~(S_ISTXT | S_ISUID | S_ISGID));




--
http://gmerlin.de
OpenPGP: http://gmerlin.de/christopher.pub
CB07 DA40 B0B6 571D 35E2  0DEF 87E2 92A7 13E5 DEE1



Re: /bin/cp: overwrite symlink with file pointed to by symlink

2019-11-15 Thread Quentin Rameau
Hello,

> > Now I had a look at our cp.c, our cp(1) and at POSIX:
> > 
> >  -f For each existing destination pathname, remove it and
> > create a new file, without prompting for confirmation, regardless of
> > its permissions.  The -f option overrides any previous -i options.
> > 
> > POSIX says cp must always first try to open(2)(O_TRUNC) the
> > destination and only if this fails AND -f was specified should it try
> > unlink(2).
> > 
> > At least regarding this special case our cp behaves according to
> > POSIX, not according to our manpage.
> > 
> > As long as we cannot change the POSIX standard I don't know whether
> > our manpage should mention this or cp.c be changed to use lstat(),
> > too. Maybe this is such a special case we could just ignore it...
> 
> If you're interested in adapting to POSIX, here's a proposition patch:

Any comment on making cp more “POSIXy” there?



Re: /bin/cp: overwrite symlink with file pointed to by symlink

2019-11-01 Thread Quentin Rameau
> Hi,

Hello Christopher,

> I admit this is a very special case, but anyway this is what I hit:
> 
> $ touch blub; ln -s blub blab; ls -l; cp -f blub blab
> total 0
> lrwxr-xr-x  1 madroach  wheel  4 Oct 30 17:39 blab -> blub
> -rw-r--r--  1 madroach  wheel  0 Oct 30 17:39 blub
> cp: blab and blub are identical (not copied).

This is expected behaviour, blab and blub are indeed the same file and
so copy should be skipped.

From POSIX:

“If source_file references the same file as dest_file, cp may write a
diagnostic message to standard error; it shall do nothing more with
source_file and shall go on to any remaining files.”

> Now I had a look at our cp.c, our cp(1) and at POSIX:
> 
>  -f   For each existing destination pathname, remove it and
> create a new file, without prompting for confirmation, regardless of
> its permissions.  The -f option overrides any previous -i options.
> 
> POSIX says cp must always first try to open(2)(O_TRUNC) the
> destination and only if this fails AND -f was specified should it try
> unlink(2).
> 
> At least regarding this special case our cp behaves according to
> POSIX, not according to our manpage.
> 
> As long as we cannot change the POSIX standard I don't know whether
> our manpage should mention this or cp.c be changed to use lstat(),
> too. Maybe this is such a special case we could just ignore it...

If you're interested in adapting to POSIX, here's a proposition patch:

Index: bin/cp//cp.1
===
RCS file: /var/cvs/src/bin/cp/cp.1,v
retrieving revision 1.40
diff -u -r1.40 cp.1
--- bin/cp//cp.128 Jan 2019 18:58:42 -  1.40
+++ bin/cp//cp.11 Nov 2019 19:41:26 -
@@ -79,9 +79,8 @@
 Same as
 .Fl RpP .
 .It Fl f
-For each existing destination pathname, remove it and
-create a new file, without prompting for confirmation,
-regardless of its permissions.
+For each existing destination pathname which cannot be opened, remove
+it and create a new file, without prompting for confirmation.
 The
 .Fl f
 option overrides any previous
Index: bin/cp//utils.c
===
RCS file: /var/cvs/src/bin/cp/utils.c,v
retrieving revision 1.47
diff -u -r1.47 utils.c
--- bin/cp//utils.c 28 Jan 2019 18:58:42 -  1.47
+++ bin/cp//utils.c 1 Nov 2019 19:25:02 -
@@ -55,7 +55,7 @@
static char *buf;
static char *zeroes;
struct stat to_stat, *fs;
-   int from_fd, rcount, rval, to_fd, wcount;
+   int from_fd, rcount, rval, to_fd, wcount, create = 1;
 #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
char *p;
 #endif
@@ -79,26 +79,24 @@
fs = entp->fts_statp;
 
/*
-* In -f (force) mode, we always unlink the destination first
-* if it exists.  Note that -i and -f are mutually exclusive.
-*/
-   if (exists && fflag)
-   (void)unlink(to.p_path);
-
-   /*
 * If the file DNE, set the mode to be the from file, minus setuid
 * bits, modified by the umask; arguably wrong, but it makes copying
 * executables work right and it's been that way forever.  (The
 * other choice is 666 or'ed with the execute bits on the from file
 * modified by the umask.)
 */
-   if (exists && !fflag) {
-   if (!copy_overwrite()) {
+   if (exists) {
+   /* Note that -i and -f are mutually exclusive. */
+   if (!fflag && !copy_overwrite()) {
(void)close(from_fd);
return 2;
}
to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
-   } else
+   if (to_fd != -1 || fflag && unlink(to.p_path) == -1)
+   create = 0;
+   }
+
+   if (create)
to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
fs->st_mode & ~(S_ISTXT | S_ISUID | S_ISGID));