Mercurial > hg > octave-shane > gnulib-hg
annotate lib/renameat.c @ 17480:f40b3156a43e
selinux-at: omit unnecessary include
* lib/selinux-at.c: Don't include dosname.h; not needed, since
this source file doesn't use its macros, and subsidiary files that
use the macros already include it.
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Fri, 23 Aug 2013 13:53:46 -0700 |
parents | e542fd46ad6f |
children | 344018b6e5d7 |
rev | line source |
---|---|
12099 | 1 /* Rename a file relative to open directories. |
17249
e542fd46ad6f
maint: update all copyright year number ranges
Eric Blake <eblake@redhat.com>
parents:
16201
diff
changeset
|
2 Copyright (C) 2009-2013 Free Software Foundation, Inc. |
12099 | 3 |
4 This program is free software: you can redistribute it and/or modify | |
5 it under the terms of the GNU General Public License as published by | |
6 the Free Software Foundation; either version 3 of the License, or | |
7 (at your option) any later version. | |
8 | |
9 This program is distributed in the hope that it will be useful, | |
10 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 GNU General Public License for more details. | |
13 | |
14 You should have received a copy of the GNU General Public License | |
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
16 | |
17 /* written by Eric Blake */ | |
18 | |
19 #include <config.h> | |
20 | |
21 #include <stdio.h> | |
22 | |
12100 | 23 #if HAVE_RENAMEAT |
24 | |
25 # include <errno.h> | |
26 # include <stdbool.h> | |
27 # include <stdlib.h> | |
28 # include <string.h> | |
29 # include <sys/stat.h> | |
30 | |
31 # include "dirname.h" | |
32 # include "openat.h" | |
33 | |
34 # undef renameat | |
35 | |
36 /* renameat does not honor trailing / on Solaris 10. Solve it in a | |
37 similar manner to rename. No need to worry about bugs not present | |
38 on Solaris, since all other systems either lack renameat or honor | |
39 trailing slash correctly. */ | |
40 | |
41 int | |
42 rpl_renameat (int fd1, char const *src, int fd2, char const *dst) | |
43 { | |
44 size_t src_len = strlen (src); | |
45 size_t dst_len = strlen (dst); | |
46 char *src_temp = (char *) src; | |
47 char *dst_temp = (char *) dst; | |
48 bool src_slash; | |
49 bool dst_slash; | |
50 int ret_val = -1; | |
51 int rename_errno = ENOTDIR; | |
52 struct stat src_st; | |
53 struct stat dst_st; | |
54 | |
55 /* Let strace see any ENOENT failure. */ | |
56 if (!src_len || !dst_len) | |
57 return renameat (fd1, src, fd2, dst); | |
58 | |
59 src_slash = src[src_len - 1] == '/'; | |
60 dst_slash = dst[dst_len - 1] == '/'; | |
61 if (!src_slash && !dst_slash) | |
62 return renameat (fd1, src, fd2, dst); | |
63 | |
64 /* Presence of a trailing slash requires directory semantics. If | |
65 the source does not exist, or if the destination cannot be turned | |
66 into a directory, give up now. Otherwise, strip trailing slashes | |
67 before calling rename. */ | |
68 if (lstatat (fd1, src, &src_st)) | |
69 return -1; | |
70 if (lstatat (fd2, dst, &dst_st)) | |
71 { | |
72 if (errno != ENOENT || !S_ISDIR (src_st.st_mode)) | |
73 return -1; | |
74 } | |
75 else if (!S_ISDIR (dst_st.st_mode)) | |
76 { | |
77 errno = ENOTDIR; | |
78 return -1; | |
79 } | |
80 else if (!S_ISDIR (src_st.st_mode)) | |
81 { | |
82 errno = EISDIR; | |
83 return -1; | |
84 } | |
85 | |
86 # if RENAME_TRAILING_SLASH_SOURCE_BUG | |
87 /* See the lengthy comment in rename.c why Solaris 9 is forced to | |
88 GNU behavior, while Solaris 10 is left with POSIX behavior, | |
89 regarding symlinks with trailing slash. */ | |
90 if (src_slash) | |
91 { | |
92 src_temp = strdup (src); | |
93 if (!src_temp) | |
94 { | |
95 /* Rather than rely on strdup-posix, we set errno ourselves. */ | |
96 rename_errno = ENOMEM; | |
97 goto out; | |
98 } | |
99 strip_trailing_slashes (src_temp); | |
100 if (lstatat (fd1, src_temp, &src_st)) | |
101 { | |
102 rename_errno = errno; | |
103 goto out; | |
104 } | |
105 if (S_ISLNK (src_st.st_mode)) | |
106 goto out; | |
107 } | |
108 if (dst_slash) | |
109 { | |
110 dst_temp = strdup (dst); | |
111 if (!dst_temp) | |
112 { | |
113 rename_errno = ENOMEM; | |
114 goto out; | |
115 } | |
116 strip_trailing_slashes (dst_temp); | |
117 if (lstatat (fd2, dst_temp, &dst_st)) | |
118 { | |
119 if (errno != ENOENT) | |
120 { | |
121 rename_errno = errno; | |
122 goto out; | |
123 } | |
124 } | |
125 else if (S_ISLNK (dst_st.st_mode)) | |
126 goto out; | |
127 } | |
128 # endif /* RENAME_TRAILING_SLASH_SOURCE_BUG */ | |
129 | |
130 ret_val = renameat (fd1, src_temp, fd2, dst_temp); | |
131 rename_errno = errno; | |
132 out: | |
133 if (src_temp != src) | |
134 free (src_temp); | |
135 if (dst_temp != dst) | |
136 free (dst_temp); | |
137 errno = rename_errno; | |
138 return ret_val; | |
139 } | |
140 | |
141 #else /* !HAVE_RENAMEAT */ | |
142 | |
143 # include "openat-priv.h" | |
12099 | 144 |
145 /* Rename FILE1, in the directory open on descriptor FD1, to FILE2, in | |
146 the directory open on descriptor FD2. If possible, do it without | |
147 changing the working directory. Otherwise, resort to using | |
148 save_cwd/fchdir, then rename/restore_cwd. If either the save_cwd or | |
149 the restore_cwd fails, then give a diagnostic and exit nonzero. */ | |
150 | |
151 int | |
152 renameat (int fd1, char const *file1, int fd2, char const *file2) | |
153 { | |
154 return at_func2 (fd1, file1, fd2, file2, rename); | |
155 } | |
12100 | 156 |
157 #endif /* !HAVE_RENAMEAT */ |