bug-gnulib
[Top][All Lists]
Advanced

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

Re: renameat


From: Jim Meyering
Subject: Re: renameat
Date: Fri, 02 Oct 2009 18:26:04 +0200

Eric Blake wrote:
> According to Jim Meyering on 10/1/2009 1:28 PM:
>>> Here's the current state of the series, finally ready for review.  If we
>>> check it in as-is, then coreutils will have everything it needs to ensure
>>> consistent behavior of 'mv -T a b/' on every platform it already supports
>>> except for cygwin 1.5 (which has never been a show-stopper for coreutils
>>
>> I've skimmed through all of that.
>> Considering I spent only 20 minutes, I can't have
>> done it justice, but didn't spot any problems, either.
>
> I've completed these three additional patches to fix the outstanding
> issues, and am now doing a sanity check that my rebasing worked before
> pushing to savannah.  Expect it soon.

Thanks!
A couple of minor suggestions below:

>>From 0eb9ddbf689cb195763848c52507685ebb07834d Mon Sep 17 00:00:00 2001
> From: Eric Blake <address@hidden>
> Date: Thu, 1 Oct 2009 11:57:47 -0600
> Subject: [PATCH 1/3] rename: fix another cygwin 1.5 bug
...

>>From 984235b49cd5dd2f2bcfe26a4988c1c8a2253b97 Mon Sep 17 00:00:00 2001
> From: Eric Blake <address@hidden>
> Date: Thu, 1 Oct 2009 15:31:32 -0600
> Subject: [PATCH 2/3] renameat: fix Solaris bugs
...

>>From 9b631e0590832e7a1739fe053c30c97fa4d1aa77 Mon Sep 17 00:00:00 2001
> From: Eric Blake <address@hidden>
> Date: Thu, 1 Oct 2009 16:46:08 -0600
> Subject: [PATCH 3/3] rename: fix mingw bugs
>
> Copy various workarounds from cygwin 1.5: rename("dir/.","name"),
> rename("dir","file"), rename("dir1","dir2").  Amazingly,
> even though mingw stat() has no way to identify hard linked
> files, and even though rename("hard1","hard2") destroys the
> hard link, the lower-level MoveFileEx does the right thing!
> So the only testsuite relaxation is for rename("dir","dir/sub")
> giving EACCES instead of EINVAL when "dir/sub" does not exist.
>
> * lib/rename.c (rpl_rename) [W32]: Fix trailing slash and
> directory overwrite bugs.
> * tests/test-rename.h (test_rename): Relax test.
...

> diff --git a/lib/rename.c b/lib/rename.c
...
> +  /* Presence of a trailing slash requires directory semantics.  If
> +     the source does not exist, or if the destination cannot be turned
> +     into a directory, give up now.  Otherwise, strip trailing slashes
> +     before calling rename.  There are no symlinks on mingw, so stat
> +     works instead of lstat.  */
> +  src_slash = ISSLASH (src[src_len - 1]);
> +  dst_slash = ISSLASH (dst[dst_len - 1]);
> +  if (stat (src, &src_st))
> +    return -1;
> +  if (stat (dst, &dst_st))
> +    {
> +      if (errno != ENOENT || (!S_ISDIR (src_st.st_mode) && dst_slash))
> +        return -1;
> +      dst_exists = false;
> +    }
> +  else
> +    {
> +      if (S_ISDIR (dst_st.st_mode) != S_ISDIR (src_st.st_mode))
> +     {

The odd indentation highlights the fact there's a TAB on this line
and on the three following.  If you use spaces, the code will
render readably regardless of quoting.

> +       errno = S_ISDIR (dst_st.st_mode) ? EISDIR : ENOTDIR;
> +       return -1;
> +     }
> +      dst_exists = true;
> +    }
> +
> +  /* There are no symlinks, so if a file existed with a trailing
> +     slash, it must be a directory, and we don't have to worry about
> +     stripping strip trailing slash.  However, mingw refuses to
> +     replace an existing empty directory, so we have to help it out.
> +     And canonicalize_file_name is not yet ported to mingw; however,
> +     for directories, getcwd works as a viable alternative.  Ensure
> +     that we can get back to where we started before using it.  */
> +  if (dst_exists && S_ISDIR (dst_st.st_mode))
> +    {
> +      char *cwd = getcwd (NULL, 0);

Don't you want to handle getcwd failure here?
Otherwise, the chdir below dereferences NULL.

> +      char *src_temp;
> +      char *dst_temp;
> +      if (chdir (cwd))
> +        return -1;
> +      if (IS_ABSOLUTE_FILE_NAME (src))
> +        {
> +          dst_temp = chdir (dst) ? NULL : getcwd (NULL, 0);
> +          src_temp = chdir (src) ? NULL : getcwd (NULL, 0);
> +        }
> +      else
> +        {
> +          src_temp = chdir (src) ? NULL : getcwd (NULL, 0);
> +          if (!IS_ABSOLUTE_FILE_NAME (dst))
> +            chdir (cwd);

This chdir may fail.

> +          dst_temp = chdir (dst) ? NULL : getcwd (NULL, 0);
> +        }
> +      chdir (cwd);

Same here.  Neither failure may be ignored.

> +      free (cwd);
> +      if (!src_temp || !dst_temp)
> +        {
> +          free (src_temp);
> +          free (dst_temp);
> +          errno = ENOMEM;
> +          return -1;
> +        }
> +      src_len = strlen (src_temp);
> +      if (strncmp (src_temp, dst_temp, src_len) == 0
> +          && (ISSLASH (dst_temp[src_len]) || dst_temp[src_len] == '\0'))
> +        {
> +          error = dst_temp[src_len];
> +          free (src_temp);
> +          free (dst_temp);
> +          if (error)
> +            {
> +              errno = EINVAL;
> +              return -1;
> +            }
> +          return 0;
> +        }
> +      if (rmdir (dst))
> +        {
> +          error = errno;
> +          free (src_temp);
> +          free (dst_temp);
> +          errno = error;
> +          return -1;
> +        }
> +      free (src_temp);
> +      free (dst_temp);
> +    }
...




reply via email to

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