coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] cp: always detect copy-into-self: avoid infloop w/large PATH_MAX


From: Jim Meyering
Subject: [PATCH] cp: always detect copy-into-self: avoid infloop w/large PATH_MAX
Date: Sat, 02 Apr 2011 16:14:28 +0200

FYI,

>From b368d453ff27820c769564b4170f0c81b1558b2f Mon Sep 17 00:00:00 2001
From: Jim Meyering <address@hidden>
Date: Mon, 28 Mar 2011 09:14:31 +0200
Subject: [PATCH] cp: always detect copy-into-self: avoid infloop w/large
 PATH_MAX

When running the erroneous command, cp -rl A D D, and depending on the
structure of directories A and D and the file system type (because that
changes order of dir. entry traversal), cp would sometimes fail to
detect that D was being copied into D, and would create D/D/D/D/D/...
until it hit PATH_MAX or exhausted some resource.
I noticed this via the occasional failure of the cp/into-self test
when run using a ZFS file system.  It is occasional because the bug
is dependent on the order in which directory entries are traversed,
and that is apparently indeterminate with ZFS.
Technically, with the current recursive implementation, there is no
risk of an infinite loop, due to stack limitations, but with an
eventual fts-based implementation, it might have iterated until
disk space or inodes are exhausted.
* src/copy.c (copy_dir): Avoid copy-into-self interminable loop on
systems with large PATH_MAX.  On other systems, diagnose the copy-into-
self error consistently.  Handle the parameter,
first_dir_created_per_command_line_arg, correctly when there are two
or more sub-directories.
---
 src/copy.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/copy.c b/src/copy.c
index 05f92b3..d479b9c 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -566,8 +566,11 @@ copy_attr (char const *src_path ATTRIBUTE_UNUSED,
    DST_NAME_IN is a directory that was created previously in the
    recursion.   SRC_SB and ANCESTORS describe SRC_NAME_IN.
    Set *COPY_INTO_SELF if SRC_NAME_IN is a parent of
-   FIRST_DIR_CREATED_PER_COMMAND_LINE_ARG  FIXME
    (or the same as) DST_NAME_IN; otherwise, clear it.
+   Propagate *FIRST_DIR_CREATED_PER_COMMAND_LINE_ARG from
+   caller to each invocation of copy_internal.  Be careful to
+   pass the address of a temporary, and to update
+   *FIRST_DIR_CREATED_PER_COMMAND_LINE_ARG only upon completion.
    Return true if successful.  */

 static bool
@@ -596,16 +599,18 @@ copy_dir (char const *src_name_in, char const 
*dst_name_in, bool new_dst,
   if (x->dereference == DEREF_COMMAND_LINE_ARGUMENTS)
     non_command_line_options.dereference = DEREF_NEVER;

+  bool new_first_dir_created = false;
   namep = name_space;
   while (*namep != '\0')
     {
       bool local_copy_into_self;
       char *src_name = file_name_concat (src_name_in, namep, NULL);
       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,
                            ancestors, &non_command_line_options, false,
-                           first_dir_created_per_command_line_arg,
+                           &first_dir_created,
                            &local_copy_into_self, NULL);
       *copy_into_self |= local_copy_into_self;

@@ -618,9 +623,12 @@ copy_dir (char const *src_name_in, char const 
*dst_name_in, bool new_dst,
       if (local_copy_into_self)
         break;

+      new_first_dir_created |= first_dir_created;
       namep += strlen (namep) + 1;
     }
   free (name_space);
+  *first_dir_created_per_command_line_arg = new_first_dir_created;
+
   return ok;
 }

--
1.7.4.2.662.gcbd0



reply via email to

[Prev in Thread] Current Thread [Next in Thread]