annotate lib/renameatu.c @ 39898:6b8c2cbdd8b0

renameatu: prefer renameat2 to syscall * lib/renameatu.c (renameatu) [HAVE_RENAMEAT2]: Use renameat2 instead of syscall (Bug#32796). * m4/renameat.m4 (gl_FUNC_RENAMEAT): Check for renameat2.
author Andreas Henriksson <andreas@fatal.se>
date Sun, 07 Oct 2018 15:01:07 -0700
parents c05640d27ca2
children b06060465f09
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
39738
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
1 /* Rename a file relative to open directories.
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
2 Copyright (C) 2009-2018 Free Software Foundation, Inc.
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
3
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
4 This program is free software: you can redistribute it and/or modify
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
5 it under the terms of the GNU General Public License as published by
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
6 the Free Software Foundation; either version 3 of the License, or
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
7 (at your option) any later version.
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
8
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
9 This program is distributed in the hope that it will be useful,
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
12 GNU General Public License for more details.
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
13
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
14 You should have received a copy of the GNU General Public License
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
16
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
17 /* written by Eric Blake and Paul Eggert */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
18
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
19 #include <config.h>
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
20
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
21 #include "renameatu.h"
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
22
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
23 #include <errno.h>
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
24 #include <stdio.h>
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
25 #include <sys/stat.h>
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
26 #include <unistd.h>
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
27
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
28 #ifdef __linux__
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
29 # include <sys/syscall.h>
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
30 #endif
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
31
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
32 static int
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
33 errno_fail (int e)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
34 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
35 errno = e;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
36 return -1;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
37 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
38
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
39 #if HAVE_RENAMEAT
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
40
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
41 # include <stdbool.h>
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
42 # include <stdlib.h>
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
43 # include <string.h>
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
44
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
45 # include "dirname.h"
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
46 # include "openat.h"
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
47
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
48 #else
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
49 # include "openat-priv.h"
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
50
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
51 static int
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
52 rename_noreplace (char const *src, char const *dst)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
53 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
54 /* This has a race between the call to lstat and the call to rename. */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
55 struct stat st;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
56 return (lstat (dst, &st) == 0 || errno == EOVERFLOW ? errno_fail (EEXIST)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
57 : errno == ENOENT ? rename (src, dst)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
58 : -1);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
59 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
60 #endif
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
61
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
62 #undef renameat
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
63
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
64 /* Rename FILE1, in the directory open on descriptor FD1, to FILE2, in
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
65 the directory open on descriptor FD2. If possible, do it without
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
66 changing the working directory. Otherwise, resort to using
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
67 save_cwd/fchdir, then rename/restore_cwd. If either the save_cwd or
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
68 the restore_cwd fails, then give a diagnostic and exit nonzero.
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
69
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
70 Obey FLAGS when doing the renaming. If FLAGS is zero, this
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
71 function is equivalent to renameat (FD1, SRC, FD2, DST).
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
72 Otherwise, attempt to implement FLAGS even if the implementation is
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
73 not atomic; this differs from the GNU/Linux native renameat2,
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
74 which fails if it cannot guarantee atomicity. */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
75
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
76 int
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
77 renameatu (int fd1, char const *src, int fd2, char const *dst,
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
78 unsigned int flags)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
79 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
80 int ret_val = -1;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
81 int err = EINVAL;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
82
39898
6b8c2cbdd8b0 renameatu: prefer renameat2 to syscall
Andreas Henriksson <andreas@fatal.se>
parents: 39738
diff changeset
83 #ifdef HAVE_RENAMEAT2
6b8c2cbdd8b0 renameatu: prefer renameat2 to syscall
Andreas Henriksson <andreas@fatal.se>
parents: 39738
diff changeset
84 ret_val = renameat2 (fd1, src, fd2, dst, flags);
6b8c2cbdd8b0 renameatu: prefer renameat2 to syscall
Andreas Henriksson <andreas@fatal.se>
parents: 39738
diff changeset
85 err = errno;
6b8c2cbdd8b0 renameatu: prefer renameat2 to syscall
Andreas Henriksson <andreas@fatal.se>
parents: 39738
diff changeset
86 #elif defined SYS_renameat2
39738
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
87 ret_val = syscall (SYS_renameat2, fd1, src, fd2, dst, flags);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
88 err = errno;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
89 #elif defined RENAME_EXCL
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
90 if (! (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE)))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
91 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
92 ret_val = renameatx_np (fd1, src, fd2, dst,
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
93 ((flags & RENAME_EXCHANGE ? RENAME_SWAP : 0)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
94 | (flags & RENAME_NOREPLACE ? RENAME_EXCL : 0)));
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
95 err = errno;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
96 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
97 #endif
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
98
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
99 if (! (ret_val < 0 && (err == EINVAL || err == ENOSYS || err == ENOTSUP)))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
100 return ret_val;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
101
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
102 #if HAVE_RENAMEAT
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
103 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
104 size_t src_len;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
105 size_t dst_len;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
106 char *src_temp = (char *) src;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
107 char *dst_temp = (char *) dst;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
108 bool src_slash;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
109 bool dst_slash;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
110 int rename_errno = ENOTDIR;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
111 struct stat src_st;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
112 struct stat dst_st;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
113 bool dst_found_nonexistent = false;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
114
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
115 if (flags != 0)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
116 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
117 /* RENAME_NOREPLACE is the only flag currently supported. */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
118 if (flags & ~RENAME_NOREPLACE)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
119 return errno_fail (ENOTSUP);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
120 else
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
121 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
122 /* This has a race between the call to lstatat and the calls to
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
123 renameat below. */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
124 if (lstatat (fd2, dst, &dst_st) == 0 || errno == EOVERFLOW)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
125 return errno_fail (EEXIST);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
126 if (errno != ENOENT)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
127 return -1;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
128 dst_found_nonexistent = true;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
129 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
130 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
131
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
132 /* Let strace see any ENOENT failure. */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
133 src_len = strlen (src);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
134 dst_len = strlen (dst);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
135 if (!src_len || !dst_len)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
136 return renameat (fd1, src, fd2, dst);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
137
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
138 src_slash = src[src_len - 1] == '/';
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
139 dst_slash = dst[dst_len - 1] == '/';
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
140 if (!src_slash && !dst_slash)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
141 return renameat (fd1, src, fd2, dst);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
142
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
143 /* Presence of a trailing slash requires directory semantics. If
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
144 the source does not exist, or if the destination cannot be turned
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
145 into a directory, give up now. Otherwise, strip trailing slashes
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
146 before calling rename. */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
147 if (lstatat (fd1, src, &src_st))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
148 return -1;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
149 if (dst_found_nonexistent)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
150 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
151 if (!S_ISDIR (src_st.st_mode))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
152 return errno_fail (ENOENT);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
153 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
154 else if (lstatat (fd2, dst, &dst_st))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
155 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
156 if (errno != ENOENT || !S_ISDIR (src_st.st_mode))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
157 return -1;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
158 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
159 else if (!S_ISDIR (dst_st.st_mode))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
160 return errno_fail (ENOTDIR);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
161 else if (!S_ISDIR (src_st.st_mode))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
162 return errno_fail (EISDIR);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
163
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
164 # if RENAME_TRAILING_SLASH_SOURCE_BUG
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
165 /* See the lengthy comment in rename.c why Solaris 9 is forced to
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
166 GNU behavior, while Solaris 10 is left with POSIX behavior,
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
167 regarding symlinks with trailing slash. */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
168 ret_val = -1;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
169 if (src_slash)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
170 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
171 src_temp = strdup (src);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
172 if (!src_temp)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
173 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
174 /* Rather than rely on strdup-posix, we set errno ourselves. */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
175 rename_errno = ENOMEM;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
176 goto out;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
177 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
178 strip_trailing_slashes (src_temp);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
179 if (lstatat (fd1, src_temp, &src_st))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
180 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
181 rename_errno = errno;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
182 goto out;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
183 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
184 if (S_ISLNK (src_st.st_mode))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
185 goto out;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
186 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
187 if (dst_slash)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
188 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
189 dst_temp = strdup (dst);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
190 if (!dst_temp)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
191 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
192 rename_errno = ENOMEM;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
193 goto out;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
194 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
195 strip_trailing_slashes (dst_temp);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
196 if (lstatat (fd2, dst_temp, &dst_st))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
197 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
198 if (errno != ENOENT)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
199 {
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
200 rename_errno = errno;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
201 goto out;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
202 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
203 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
204 else if (S_ISLNK (dst_st.st_mode))
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
205 goto out;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
206 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
207 # endif /* RENAME_TRAILING_SLASH_SOURCE_BUG */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
208
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
209 /* renameat does not honor trailing / on Solaris 10. Solve it in a
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
210 similar manner to rename. No need to worry about bugs not present
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
211 on Solaris, since all other systems either lack renameat or honor
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
212 trailing slash correctly. */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
213
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
214 ret_val = renameat (fd1, src_temp, fd2, dst_temp);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
215 rename_errno = errno;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
216 goto out;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
217 out:
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
218 if (src_temp != src)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
219 free (src_temp);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
220 if (dst_temp != dst)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
221 free (dst_temp);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
222 errno = rename_errno;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
223 return ret_val;
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
224 }
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
225 #else /* !HAVE_RENAMEAT */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
226
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
227 /* RENAME_NOREPLACE is the only flag currently supported. */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
228 if (flags & ~RENAME_NOREPLACE)
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
229 return errno_fail (ENOTSUP);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
230 return at_func2 (fd1, src, fd2, dst, flags ? rename_noreplace : rename);
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
231
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
232 #endif /* !HAVE_RENAMEAT */
c05640d27ca2 renameatu: rename from renameat2
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
233 }