Mercurial > gnulib
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 |
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 } |