Subject: Re: bug#17179: [PATCH] cp: use an invalid dev_t for an unknown device

From: Paul Eggert <[email-masked]>
Date: Thu, 03 Apr 2014 09:50:38 -0700

On 04/03/2014 09:38 AM, Pádraig Brady wrote:
> I'd be as much worried about
> a clash with (dev_t)-1 as 0 TBH?
Absolutely.  I installed the attached patch, which should work 
regardless of what dev_t values are found in the file system. This fixes 
just this particular bug, though; I wouldn't be surprised if there are 
others (and haven't looked for them).

>From ee96d171ddf584f9d8faad1830aa1daf89de2d55 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Thu, 3 Apr 2014 09:48:22 -0700
Subject: [PATCH] cp: don't reserve a device number

* src/copy.c (copy_internal): Replace dev_t arg DEVICE with struct
stat pointer arg PARENT.  All callers changed.  This removes an
unwarranted assumption that dev_t values of 0 cannot occur in file
systems.  See: http://bugs.gnu.org/17179
---
 src/copy.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/src/copy.c b/src/copy.c
index 781cc1e..d471a77 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -117,7 +117,7 @@ struct dir_list
 #define DEST_INFO_INITIAL_CAPACITY 61
 
 static bool copy_internal (char const *src_name, char const *dst_name,
-                           bool new_dst, dev_t device,
+                           bool new_dst, struct stat const *parent,
                            struct dir_list *ancestors,
                            const struct cp_options *x,
                            bool command_line_arg,
@@ -621,7 +621,7 @@ copy_dir (char const *src_name_in, char const *dst_name_in, bool new_dst,
       char *dst_name = file_name_concat (dst_name_in, namep, NULL);
       bool first_dir_created = *first_dir_created_per_command_line_arg;
 
-      ok &= copy_internal (src_name, dst_name, new_dst, src_sb->st_dev,
+      ok &= copy_internal (src_name, dst_name, new_dst, src_sb,
                            ancestors, &non_command_line_options, false,
                            &first_dir_created,
                            &local_copy_into_self, NULL);
@@ -1725,9 +1725,8 @@ should_dereference (const struct cp_options *x, bool command_line_arg)
 /* Copy the file SRC_NAME to the file DST_NAME.  The files may be of
    any type.  NEW_DST should be true if the file DST_NAME cannot
    exist because its parent directory was just created; NEW_DST should
-   be false if DST_NAME might already exist.  DEVICE is the device
-   number of the parent directory, or 0 if the parent of this file is
-   not known.  ANCESTORS points to a linked, null terminated list of
+   be false if DST_NAME might already exist.  A nonnull PARENT describes the
+   parent directory.  ANCESTORS points to a linked, null terminated list of
    devices and inodes of parent directories of SRC_NAME.  COMMAND_LINE_ARG
    is true iff SRC_NAME was specified on the command line.
    FIRST_DIR_CREATED_PER_COMMAND_LINE_ARG is both input and output.
@@ -1737,7 +1736,7 @@ should_dereference (const struct cp_options *x, bool command_line_arg)
 static bool
 copy_internal (char const *src_name, char const *dst_name,
                bool new_dst,
-               dev_t device,
+               struct stat const *parent,
                struct dir_list *ancestors,
                const struct cp_options *x,
                bool command_line_arg,
@@ -2434,7 +2433,7 @@ copy_internal (char const *src_name, char const *dst_name,
         }
 
       /* Decide whether to copy the contents of the directory.  */
-      if (x->one_file_system && device != 0 && device != src_sb.st_dev)
+      if (x->one_file_system && parent && parent->st_dev != src_sb.st_dev)
         {
           /* Here, we are crossing a file system boundary and cp's -x option
              is in effect: so don't copy the contents of this directory. */
@@ -2827,7 +2826,7 @@ copy (char const *src_name, char const *dst_name,
   top_level_dst_name = dst_name;
 
   bool first_dir_created_per_command_line_arg = false;
-  return copy_internal (src_name, dst_name, nonexistent_dst, 0, NULL,
+  return copy_internal (src_name, dst_name, nonexistent_dst, NULL, NULL,
                         options, true,
                         &first_dir_created_per_command_line_arg,
                         copy_into_self, rename_succeeded);
-- 
1.9.0