GNU bug report logs - #78509
Coreutils' mv and cp 9.5 do not work properly on old PPC Mac OS X 10.4.11, Tiger

Previous Next

Package: coreutils;

Reported by: Peter Dyballa <Peter_Dyballa <at> Web.DE>

Date: Tue, 20 May 2025 16:13:04 UTC

Severity: normal

Done: Paul Eggert <eggert <at> cs.ucla.edu>

Full log


View this message in rfc822 format

From: Peter Dyballa <Peter_Dyballa <at> Web.DE>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: 78509 <at> debbugs.gnu.org
Subject: bug#78509: Coreutils' mv and cp 9.5 do not work properly on old PPC Mac OS X 10.4.11, Tiger
Date: Fri, 23 May 2025 13:27:44 +0200
When using Gdb I skip in mv.c's main() function over the first few calls and come to the while loop, line #344. It is entered and

    378           target_directory = optarg;.

is – visited? The name "out" contains a "t" which is also listed in the list of command line options. After the while loop target_directory is still 0x0. It also "visits" line #386 because of "u". But this too does not seem to change anything…

But then the if at line

    431   if (no_target_directory)

is reached. no_target_directory is false, so

    443   else if (target_directory)

is reached. target_directory is still 0x0, the "nullptr", so we come to line

    450   else

and then to an if on line

    457       if (x.rename_errno != 0)

x.rename_errno is 17 and therefore != 0, so the if expression is true and its block entered:

    458         {
    459           int fd = target_directory_operand (lastfile, &sb);
    460           if (target_dirfd_valid (fd))
    461             {
    462               x.rename_errno = -1;
    463               target_dirfd = fd;
    464               target_directory = lastfile;
    465               n_files--;
    466             }
    467           else
    468             {
    ...  
    484             }
    485         }

Here x.rename_errno is (re)set to -1 although already != 0, and most importantly target_directory receives value "out". So from now on mv might be sure that something needs to be moved into a *directory* "out", and we come to

    519   if (target_directory)
    520     {
    521       /* Initialize the hash table only if we'll need it.
    522          The problem it is used to detect can arise only if there are
    523          two or more files to move.  */
    524       if (2 <= n_files)
    525         dest_info_init (&x);
    526  
    527       ok = true;
    528       for (int i = 0; i < n_files; ++i)
    529         {
    530           x.last_file = i + 1 == n_files;
    531           char const *source = file[i];
    532           char const *source_basename = last_component (source);
    533           char *dest_relname;
    534           char *dest = file_name_concat (target_directory, source_basename,
    535                                          &dest_relname);
    536           strip_trailing_slashes (dest_relname);
    537           ok &= do_move (source, dest, target_dirfd, dest_relname, &x);
    538           free (dest);
    539         }
    540     }

target_directory is "out" and therefore we enter the true block. n_files has been decremented on line #365, so dest_info_init() is not called and we enter the for loop to do our job…

The cause for faulty behaviour is the value of x.rename_errno. It receives its value from

    450   else
    451     {
    452       char const *lastfile = file[n_files - 1];
    453       if (n_files == 2 && !x.exchange)
    454         x.rename_errno = (renameatu (AT_FDCWD, file[0], AT_FDCWD, lastfile,
    455                                      RENAME_NOREPLACE)
    456                           ? errno : 0);
    457       if (x.rename_errno != 0)

On line # 453 n_files is 2, and x.exchange is false, so we have if( true && true) and renameatu() is called, with:

	renameatu (fd1=-3041965, src=0xbfffd607 "k", fd2=-3041965, dst=0xbfffd609 "out", flags=1) at lib/renameatu.c:257

    254 #else /* !HAVE_RENAMEAT */
    255 
    256   /* RENAME_NOREPLACE is the only flag currently supported.  */
    257   if (flags & ~RENAME_NOREPLACE)
    258     return errno_fail (ENOTSUP);
    259   return at_func2 (fd1, src, fd2, dst, flags ? rename_noreplace : rename);
    260  
    261 #endif /* !HAVE_RENAMEAT */

Mac OS X 10.4, Tiger, does not have the renameat() system call, so not much is used from the GNUlib function.

The if clause on line #257 is false, so renameatu() returns, calling at_func2():

	at_func2 (fd1=-3041965, file1=0xbfffd607 "k", fd2=-3041965, file2=0xbfffd609 "out", func=0x25270 <rename_noreplace>) at lib/at-func2.c:77

     77   if ((fd1 == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file1))
     78       && (fd2 == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file2)))
     79     return func (file1, file2); /* Case 0-2, 4-6, 8-10.  */

Here the if clause on lines #77/78 is true and func() is called:

	rename_noreplace (src=0xbfffd607 "k", dst=0xbfffd609 "out") at lib/renameatu.c:55

     39 #if HAVE_RENAMEAT
     40       41 # include <stdlib.h>
     42 # include <string.h>
     43       44 # include "dirname.h"
     45 # include "openat.h"
     46       47 #else
     48 # include "openat-priv.h"
     49       50 static int
     51 rename_noreplace (char const *src, char const *dst)
     52 {
     53   /* This has a race between the call to lstat and the call to rename.  */
     54   struct stat st;
     55   return (lstat (dst, &st) == 0 || errno == EOVERFLOW ? errno_fail (EEXIST)
     56           : errno == ENOENT ? rename (src, dst)
     57           : -1);
     58 }
     59 #endif

Isn't calling rename_noreplace() already faulty? Shouldn't it be rename_and_do_replace_and/or_remove()?

The faulty behaviour starts here in mv.c:

    454         x.rename_errno = (renameatu (AT_FDCWD, file[0], AT_FDCWD, lastfile,
    455                                      RENAME_NOREPLACE)

RENAME_NOREPLACE should not be passed to the function here. Anyway, lib/renameatu.c is divided into two parts, one for systems with renameat() family of library functions and another one without them. And this part might behave differently and take the last parameter as a target directory.

I checked on my up-to-date Mac coreutils 9.7: mv -v k out just works! So I should start to debug here too to understand what produces the different behaviour – but first I need a working version of Gdb!


--
Greetings

  Pete

Clovis' Consideration of an Atmospheric Anomaly:
        The perversity of nature is nowhere better demonstrated than by the fact that, when exposed to the same atmosphere, bread becomes hard while crackers become soft





This bug report was last modified 9 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.