Mercurial > hg > octave-nkf > gnulib-hg
annotate lib/linkat.c @ 12559:c2cbabec01dd
update nearly all FSF copyright year lists to include 2010
Use the same procedure as for 2009, outlined in
http://thread.gmane.org/gmane.comp.lib.gnulib.bugs/20081
author | Jim Meyering <meyering@redhat.com> |
---|---|
date | Fri, 01 Jan 2010 10:31:12 +0100 (2010-01-01) |
parents | e81e96b1161c |
children | 6154fce586b6 |
rev | line source |
---|---|
12068 | 1 /* Create a hard link relative to open directories. |
12559
c2cbabec01dd
update nearly all FSF copyright year lists to include 2010
Jim Meyering <meyering@redhat.com>
parents:
12136
diff
changeset
|
2 Copyright (C) 2009-2010 Free Software Foundation, Inc. |
12068 | 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 <unistd.h> | |
22 | |
23 #include <errno.h> | |
24 #include <fcntl.h> | |
25 #include <limits.h> | |
12121
49d6e6e49816
linkat: avoid compilation failure
Jim Meyering <meyering@redhat.com>
parents:
12120
diff
changeset
|
26 #include <stdint.h> |
12120 | 27 #include <stdlib.h> |
28 #include <string.h> | |
12068 | 29 #include <sys/stat.h> |
30 | |
31 #include "areadlink.h" | |
32 #include "dirname.h" | |
33 #include "filenamecat.h" | |
34 #include "openat-priv.h" | |
35 | |
36 #if HAVE_SYS_PARAM_H | |
37 # include <sys/param.h> | |
38 #endif | |
39 #ifndef MAXSYMLINKS | |
40 # ifdef SYMLOOP_MAX | |
41 # define MAXSYMLINKS SYMLOOP_MAX | |
42 # else | |
43 # define MAXSYMLINKS 20 | |
44 # endif | |
45 #endif | |
46 | |
12120 | 47 #if !HAVE_LINKAT |
48 | |
12068 | 49 /* Create a link. If FILE1 is a symlink, either create a hardlink to |
50 that symlink, or fake it by creating an identical symlink. */ | |
12120 | 51 # if LINK_FOLLOWS_SYMLINKS == 0 |
52 # define link_immediate link | |
53 # else | |
12068 | 54 static int |
55 link_immediate (char const *file1, char const *file2) | |
56 { | |
57 char *target = areadlink (file1); | |
58 if (target) | |
59 { | |
60 /* A symlink cannot be modified in-place. Therefore, creating | |
61 an identical symlink behaves like a hard link to a symlink, | |
62 except for incorrect st_ino and st_nlink. However, we must | |
63 be careful of EXDEV. */ | |
64 struct stat st1; | |
65 struct stat st2; | |
66 char *dir = mdir_name (file2); | |
67 if (!dir) | |
68 { | |
69 free (target); | |
70 errno = ENOMEM; | |
71 return -1; | |
72 } | |
73 if (lstat (file1, &st1) == 0 && stat (dir, &st2) == 0) | |
74 { | |
75 if (st1.st_dev == st2.st_dev) | |
76 { | |
77 int result = symlink (target, file2); | |
78 int saved_errno = errno; | |
79 free (target); | |
80 free (dir); | |
81 errno = saved_errno; | |
82 return result; | |
83 } | |
84 free (target); | |
85 free (dir); | |
86 errno = EXDEV; | |
87 return -1; | |
88 } | |
89 free (target); | |
90 free (dir); | |
91 } | |
92 if (errno == ENOMEM) | |
93 return -1; | |
94 return link (file1, file2); | |
95 } | |
12120 | 96 # endif /* LINK_FOLLOWS_SYMLINKS == 0 */ |
12068 | 97 |
98 /* Create a link. If FILE1 is a symlink, create a hardlink to the | |
99 canonicalized file. */ | |
12120 | 100 # if 0 < LINK_FOLLOWS_SYMLINKS |
101 # define link_follow link | |
102 # else | |
12068 | 103 static int |
104 link_follow (char const *file1, char const *file2) | |
105 { | |
106 char *name = (char *) file1; | |
107 char *target; | |
108 int result; | |
109 int i = MAXSYMLINKS; | |
110 | |
111 /* Using realpath or canonicalize_file_name is too heavy-handed: we | |
112 don't need an absolute name, and we don't need to resolve | |
113 intermediate symlinks, just the basename of each iteration. */ | |
114 while (i-- && (target = areadlink (name))) | |
115 { | |
116 if (IS_ABSOLUTE_FILE_NAME (target)) | |
117 { | |
118 if (name != file1) | |
119 free (name); | |
120 name = target; | |
121 } | |
122 else | |
123 { | |
124 char *dir = mdir_name (name); | |
125 if (name != file1) | |
126 free (name); | |
127 if (!dir) | |
128 { | |
129 free (target); | |
130 errno = ENOMEM; | |
131 return -1; | |
132 } | |
133 name = mfile_name_concat (dir, target, NULL); | |
134 free (dir); | |
135 free (target); | |
136 if (!name) | |
137 { | |
138 errno = ENOMEM; | |
139 return -1; | |
140 } | |
141 } | |
142 } | |
143 if (i < 0) | |
144 { | |
145 target = NULL; | |
146 errno = ELOOP; | |
147 } | |
148 if (!target && errno != EINVAL) | |
149 { | |
150 if (name != file1) | |
151 { | |
152 int saved_errno = errno; | |
153 free (name); | |
154 errno = saved_errno; | |
155 } | |
156 return -1; | |
157 } | |
158 result = link (name, file2); | |
159 if (name != file1) | |
160 { | |
161 int saved_errno = errno; | |
162 free (name); | |
163 errno = saved_errno; | |
164 } | |
165 return result; | |
166 } | |
12120 | 167 # endif /* 0 < LINK_FOLLOWS_SYMLINKS */ |
12068 | 168 |
169 /* Create a link to FILE1, in the directory open on descriptor FD1, to FILE2, | |
170 in the directory open on descriptor FD2. If FILE1 is a symlink, FLAG | |
171 controls whether to dereference FILE1 first. If possible, do it without | |
172 changing the working directory. Otherwise, resort to using | |
173 save_cwd/fchdir, then rename/restore_cwd. If either the save_cwd or | |
174 the restore_cwd fails, then give a diagnostic and exit nonzero. */ | |
175 | |
176 int | |
177 linkat (int fd1, char const *file1, int fd2, char const *file2, int flag) | |
178 { | |
179 if (flag & ~AT_SYMLINK_FOLLOW) | |
180 { | |
181 errno = EINVAL; | |
182 return -1; | |
183 } | |
184 return at_func2 (fd1, file1, fd2, file2, | |
185 flag ? link_follow : link_immediate); | |
186 } | |
12120 | 187 |
188 #else /* HAVE_LINKAT */ | |
189 | |
190 # undef linkat | |
191 | |
192 /* Create a link. If FILE1 is a symlink, create a hardlink to the | |
193 canonicalized file. */ | |
194 | |
195 static int | |
196 linkat_follow (int fd1, char const *file1, int fd2, char const *file2) | |
197 { | |
198 char *name = (char *) file1; | |
199 char *target; | |
200 int result; | |
201 int i = MAXSYMLINKS; | |
202 | |
203 /* There is no realpathat. */ | |
204 while (i-- && (target = areadlinkat (fd1, name))) | |
205 { | |
206 if (IS_ABSOLUTE_FILE_NAME (target)) | |
207 { | |
208 if (name != file1) | |
209 free (name); | |
210 name = target; | |
211 } | |
212 else | |
213 { | |
214 char *dir = mdir_name (name); | |
215 if (name != file1) | |
216 free (name); | |
217 if (!dir) | |
218 { | |
219 free (target); | |
220 errno = ENOMEM; | |
221 return -1; | |
222 } | |
223 name = mfile_name_concat (dir, target, NULL); | |
224 free (dir); | |
225 free (target); | |
226 if (!name) | |
227 { | |
228 errno = ENOMEM; | |
229 return -1; | |
230 } | |
231 } | |
232 } | |
233 if (i < 0) | |
234 { | |
235 target = NULL; | |
236 errno = ELOOP; | |
237 } | |
238 if (!target && errno != EINVAL) | |
239 { | |
240 if (name != file1) | |
241 { | |
242 int saved_errno = errno; | |
243 free (name); | |
244 errno = saved_errno; | |
245 } | |
246 return -1; | |
247 } | |
248 result = linkat (fd1, name, fd2, file2, 0); | |
249 if (name != file1) | |
250 { | |
251 int saved_errno = errno; | |
252 free (name); | |
253 errno = saved_errno; | |
254 } | |
255 return result; | |
256 } | |
257 | |
258 | |
259 /* Like linkat, but guarantee that AT_SYMLINK_FOLLOW works even on | |
260 older Linux kernels. */ | |
261 | |
262 int | |
263 rpl_linkat (int fd1, char const *file1, int fd2, char const *file2, int flag) | |
264 { | |
265 if (!flag) | |
266 return linkat (fd1, file1, fd2, file2, flag); | |
267 if (flag & ~AT_SYMLINK_FOLLOW) | |
268 { | |
269 errno = EINVAL; | |
270 return -1; | |
271 } | |
272 | |
273 /* Cache the information on whether the system call really works. */ | |
274 { | |
275 static int have_follow_really; /* 0 = unknown, 1 = yes, -1 = no */ | |
276 if (0 <= have_follow_really) | |
277 { | |
278 int result = linkat (fd1, file1, fd2, file2, flag); | |
279 if (!(result == -1 && errno == EINVAL)) | |
280 { | |
281 have_follow_really = 1; | |
282 return result; | |
283 } | |
284 have_follow_really = -1; | |
285 } | |
286 } | |
287 return linkat_follow (fd1, file1, fd2, file2); | |
288 } | |
289 | |
290 #endif /* HAVE_LINKAT */ |