Absolute File Name: | /home/opencoverage/opencoverage/guest-scripts/coreutils/src/src/ln.c |
Source code | Switch to Preprocessed file |
Line | Source | Count | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | /* 'ln' program to create links between files. | - | ||||||||||||||||||
2 | Copyright (C) 1986-2018 Free Software Foundation, Inc. | - | ||||||||||||||||||
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 <https://www.gnu.org/licenses/>. */ | - | ||||||||||||||||||
16 | - | |||||||||||||||||||
17 | /* Written by Mike Parker and David MacKenzie. */ | - | ||||||||||||||||||
18 | - | |||||||||||||||||||
19 | #include <config.h> | - | ||||||||||||||||||
20 | #include <stdio.h> | - | ||||||||||||||||||
21 | #include <sys/types.h> | - | ||||||||||||||||||
22 | #include <getopt.h> | - | ||||||||||||||||||
23 | - | |||||||||||||||||||
24 | #include "system.h" | - | ||||||||||||||||||
25 | #include "backupfile.h" | - | ||||||||||||||||||
26 | #include "die.h" | - | ||||||||||||||||||
27 | #include "error.h" | - | ||||||||||||||||||
28 | #include "filenamecat.h" | - | ||||||||||||||||||
29 | #include "file-set.h" | - | ||||||||||||||||||
30 | #include "force-link.h" | - | ||||||||||||||||||
31 | #include "hash.h" | - | ||||||||||||||||||
32 | #include "hash-triple.h" | - | ||||||||||||||||||
33 | #include "relpath.h" | - | ||||||||||||||||||
34 | #include "same.h" | - | ||||||||||||||||||
35 | #include "yesno.h" | - | ||||||||||||||||||
36 | #include "canonicalize.h" | - | ||||||||||||||||||
37 | - | |||||||||||||||||||
38 | /* The official name of this program (e.g., no 'g' prefix). */ | - | ||||||||||||||||||
39 | #define PROGRAM_NAME "ln" | - | ||||||||||||||||||
40 | - | |||||||||||||||||||
41 | #define AUTHORS \ | - | ||||||||||||||||||
42 | proper_name ("Mike Parker"), \ | - | ||||||||||||||||||
43 | proper_name ("David MacKenzie") | - | ||||||||||||||||||
44 | - | |||||||||||||||||||
45 | /* FIXME: document */ | - | ||||||||||||||||||
46 | static enum backup_type backup_type; | - | ||||||||||||||||||
47 | - | |||||||||||||||||||
48 | /* If true, make symbolic links; otherwise, make hard links. */ | - | ||||||||||||||||||
49 | static bool symbolic_link; | - | ||||||||||||||||||
50 | - | |||||||||||||||||||
51 | /* If true, make symbolic links relative */ | - | ||||||||||||||||||
52 | static bool relative; | - | ||||||||||||||||||
53 | - | |||||||||||||||||||
54 | /* If true, hard links are logical rather than physical. */ | - | ||||||||||||||||||
55 | static bool logical = !!LINK_FOLLOWS_SYMLINKS; | - | ||||||||||||||||||
56 | - | |||||||||||||||||||
57 | /* If true, ask the user before removing existing files. */ | - | ||||||||||||||||||
58 | static bool interactive; | - | ||||||||||||||||||
59 | - | |||||||||||||||||||
60 | /* If true, remove existing files unconditionally. */ | - | ||||||||||||||||||
61 | static bool remove_existing_files; | - | ||||||||||||||||||
62 | - | |||||||||||||||||||
63 | /* If true, list each file as it is moved. */ | - | ||||||||||||||||||
64 | static bool verbose; | - | ||||||||||||||||||
65 | - | |||||||||||||||||||
66 | /* If true, allow the superuser to *attempt* to make hard links | - | ||||||||||||||||||
67 | to directories. However, it appears that this option is not useful | - | ||||||||||||||||||
68 | in practice, since even the superuser is prohibited from hard-linking | - | ||||||||||||||||||
69 | directories on most existing systems (Solaris being an exception). */ | - | ||||||||||||||||||
70 | static bool hard_dir_link; | - | ||||||||||||||||||
71 | - | |||||||||||||||||||
72 | /* If nonzero, and the specified destination is a symbolic link to a | - | ||||||||||||||||||
73 | directory, treat it just as if it were a directory. Otherwise, the | - | ||||||||||||||||||
74 | command 'ln --force --no-dereference file symlink-to-dir' deletes | - | ||||||||||||||||||
75 | symlink-to-dir before creating the new link. */ | - | ||||||||||||||||||
76 | static bool dereference_dest_dir_symlinks = true; | - | ||||||||||||||||||
77 | - | |||||||||||||||||||
78 | /* This is a set of destination name/inode/dev triples for hard links | - | ||||||||||||||||||
79 | created by ln. Use this data structure to avoid data loss via a | - | ||||||||||||||||||
80 | sequence of commands like this: | - | ||||||||||||||||||
81 | rm -rf a b c; mkdir a b c; touch a/f b/f; ln -f a/f b/f c && rm -r a b */ | - | ||||||||||||||||||
82 | static Hash_table *dest_set; | - | ||||||||||||||||||
83 | - | |||||||||||||||||||
84 | /* Initial size of the dest_set hash table. */ | - | ||||||||||||||||||
85 | enum { DEST_INFO_INITIAL_CAPACITY = 61 }; | - | ||||||||||||||||||
86 | - | |||||||||||||||||||
87 | static struct option const long_options[] = | - | ||||||||||||||||||
88 | { | - | ||||||||||||||||||
89 | {"backup", optional_argument, NULL, 'b'}, | - | ||||||||||||||||||
90 | {"directory", no_argument, NULL, 'F'}, | - | ||||||||||||||||||
91 | {"no-dereference", no_argument, NULL, 'n'}, | - | ||||||||||||||||||
92 | {"no-target-directory", no_argument, NULL, 'T'}, | - | ||||||||||||||||||
93 | {"force", no_argument, NULL, 'f'}, | - | ||||||||||||||||||
94 | {"interactive", no_argument, NULL, 'i'}, | - | ||||||||||||||||||
95 | {"suffix", required_argument, NULL, 'S'}, | - | ||||||||||||||||||
96 | {"target-directory", required_argument, NULL, 't'}, | - | ||||||||||||||||||
97 | {"logical", no_argument, NULL, 'L'}, | - | ||||||||||||||||||
98 | {"physical", no_argument, NULL, 'P'}, | - | ||||||||||||||||||
99 | {"relative", no_argument, NULL, 'r'}, | - | ||||||||||||||||||
100 | {"symbolic", no_argument, NULL, 's'}, | - | ||||||||||||||||||
101 | {"verbose", no_argument, NULL, 'v'}, | - | ||||||||||||||||||
102 | {GETOPT_HELP_OPTION_DECL}, | - | ||||||||||||||||||
103 | {GETOPT_VERSION_OPTION_DECL}, | - | ||||||||||||||||||
104 | {NULL, 0, NULL, 0} | - | ||||||||||||||||||
105 | }; | - | ||||||||||||||||||
106 | - | |||||||||||||||||||
107 | /* Return true when the passed ERR implies | - | ||||||||||||||||||
108 | that a file does not or could not exist. */ | - | ||||||||||||||||||
109 | - | |||||||||||||||||||
110 | static bool | - | ||||||||||||||||||
111 | errno_nonexisting (int err) | - | ||||||||||||||||||
112 | { | - | ||||||||||||||||||
113 | return err == ENOENT || err == ENAMETOOLONG || err == ENOTDIR || err == ELOOP; executed 754 times by 1 test: return err == 2 || err == 36 || err == 20 || err == 40 ; Executed by:
| 754 | ||||||||||||||||||
114 | } | - | ||||||||||||||||||
115 | - | |||||||||||||||||||
116 | - | |||||||||||||||||||
117 | /* FILE is the last operand of this command. Return true if FILE is a | - | ||||||||||||||||||
118 | directory. But report an error if there is a problem accessing FILE, | - | ||||||||||||||||||
119 | or if FILE does not exist but would have to refer to an existing | - | ||||||||||||||||||
120 | directory if it referred to anything at all. */ | - | ||||||||||||||||||
121 | - | |||||||||||||||||||
122 | static bool | - | ||||||||||||||||||
123 | target_directory_operand (char const *file) | - | ||||||||||||||||||
124 | { | - | ||||||||||||||||||
125 | char const *b = last_component (file); | - | ||||||||||||||||||
126 | size_t blen = strlen (b); | - | ||||||||||||||||||
127 | bool looks_like_a_dir = (blen == 0 || ISSLASH (b[blen - 1]));
| 1-775 | ||||||||||||||||||
128 | struct stat st; | - | ||||||||||||||||||
129 | int stat_result = | - | ||||||||||||||||||
130 | (dereference_dest_dir_symlinks ? stat (file, &st) : lstat (file, &st));
| 46-730 | ||||||||||||||||||
131 | int err = (stat_result == 0 ? 0 : errno);
| 22-754 | ||||||||||||||||||
132 | bool is_a_dir = !err && S_ISDIR (st.st_mode);
| 11-754 | ||||||||||||||||||
133 | if (err && ! errno_nonexisting (errno))
| 0-754 | ||||||||||||||||||
134 | die (EXIT_FAILURE, err, _("failed to access %s"), quoteaf (file)); never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, err, dcgettext (((void *)0), \"failed to access %s\", 5), quotearg_style (shell_escape_always_quoting_style, file)), assume (false))" ")"); int _gl_dummy; })) ? ((error ( 1 , e...s_quoting_style, file)), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , err, dcgettext (((void *)0), "failed to access %s" , 5) , quotearg_style (shell_escape_always_quoting_style, file)), (( 0 ) ? (void) 0 : __builtin_unreachable ())))); | 0 | ||||||||||||||||||
135 | if (is_a_dir < looks_like_a_dir)
| 1-775 | ||||||||||||||||||
136 | die (EXIT_FAILURE, err, _("target %s is not a directory"), executed 1 time by 1 test: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, err, dcgettext (((void *)0), \"target %s is not a directory\", 5), quotearg_style (shell_escape_always_quoting_style, file)), assume (false))" ")"); int _gl_dummy; })) ? ((erro...style, file)), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , err, dcgettext (((void *)0), "target %s is not a directory" , 5) , quotearg_style (shell_escape_always_quoting_style, file)), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; Executed by:
| 1 | ||||||||||||||||||
137 | quoteaf (file)); executed 1 time by 1 test: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, err, dcgettext (((void *)0), \"target %s is not a directory\", 5), quotearg_style (shell_escape_always_quoting_style, file)), assume (false))" ")"); int _gl_dummy; })) ? ((erro...style, file)), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , err, dcgettext (((void *)0), "target %s is not a directory" , 5) , quotearg_style (shell_escape_always_quoting_style, file)), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; Executed by:
| 1 | ||||||||||||||||||
138 | return is_a_dir; executed 775 times by 1 test: return is_a_dir; Executed by:
| 775 | ||||||||||||||||||
139 | } | - | ||||||||||||||||||
140 | - | |||||||||||||||||||
141 | /* Return FROM represented as relative to the dir of TARGET. | - | ||||||||||||||||||
142 | The result is malloced. */ | - | ||||||||||||||||||
143 | - | |||||||||||||||||||
144 | static char * | - | ||||||||||||||||||
145 | convert_abs_rel (const char *from, const char *target) | - | ||||||||||||||||||
146 | { | - | ||||||||||||||||||
147 | /* Get dirname to generate paths relative to. We don't resolve | - | ||||||||||||||||||
148 | the full TARGET as the last component could be an existing symlink. */ | - | ||||||||||||||||||
149 | char *targetdir = dir_name (target); | - | ||||||||||||||||||
150 | - | |||||||||||||||||||
151 | char *realdest = canonicalize_filename_mode (targetdir, CAN_MISSING); | - | ||||||||||||||||||
152 | char *realfrom = canonicalize_filename_mode (from, CAN_MISSING); | - | ||||||||||||||||||
153 | - | |||||||||||||||||||
154 | char *relative_from = NULL; | - | ||||||||||||||||||
155 | if (realdest && realfrom)
| 0-5 | ||||||||||||||||||
156 | { | - | ||||||||||||||||||
157 | /* Write to a PATH_MAX buffer. */ | - | ||||||||||||||||||
158 | relative_from = xmalloc (PATH_MAX); | - | ||||||||||||||||||
159 | - | |||||||||||||||||||
160 | if (!relpath (realfrom, realdest, relative_from, PATH_MAX))
| 0-4 | ||||||||||||||||||
161 | { | - | ||||||||||||||||||
162 | free (relative_from); | - | ||||||||||||||||||
163 | relative_from = NULL; | - | ||||||||||||||||||
164 | } never executed: end of block | 0 | ||||||||||||||||||
165 | } executed 4 times by 1 test: end of block Executed by:
| 4 | ||||||||||||||||||
166 | - | |||||||||||||||||||
167 | free (targetdir); | - | ||||||||||||||||||
168 | free (realdest); | - | ||||||||||||||||||
169 | free (realfrom); | - | ||||||||||||||||||
170 | - | |||||||||||||||||||
171 | return relative_from ? relative_from : xstrdup (from); executed 5 times by 1 test: return relative_from ? relative_from : xstrdup (from); Executed by:
| 5 | ||||||||||||||||||
172 | } | - | ||||||||||||||||||
173 | - | |||||||||||||||||||
174 | /* Make a link DEST to the (usually) existing file SOURCE. | - | ||||||||||||||||||
175 | Symbolic links to nonexistent files are allowed. | - | ||||||||||||||||||
176 | Return true if successful. */ | - | ||||||||||||||||||
177 | - | |||||||||||||||||||
178 | static bool | - | ||||||||||||||||||
179 | do_link (const char *source, const char *dest) | - | ||||||||||||||||||
180 | { | - | ||||||||||||||||||
181 | struct stat source_stats; | - | ||||||||||||||||||
182 | struct stat dest_stats; | - | ||||||||||||||||||
183 | char *dest_backup = NULL; | - | ||||||||||||||||||
184 | char *rel_source = NULL; | - | ||||||||||||||||||
185 | bool dest_lstat_ok = false; | - | ||||||||||||||||||
186 | bool source_is_dir = false; | - | ||||||||||||||||||
187 | - | |||||||||||||||||||
188 | if (!symbolic_link)
| 89-691 | ||||||||||||||||||
189 | { | - | ||||||||||||||||||
190 | /* Which stat to use depends on whether linkat will follow the | - | ||||||||||||||||||
191 | symlink. We can't use the shorter | - | ||||||||||||||||||
192 | (logical?stat:lstat) (source, &source_stats) | - | ||||||||||||||||||
193 | since stat might be a function-like macro. */ | - | ||||||||||||||||||
194 | if ((logical ? stat (source, &source_stats)
| 1-88 | ||||||||||||||||||
195 | : lstat (source, &source_stats))
| 1-88 | ||||||||||||||||||
196 | != 0)
| 1-88 | ||||||||||||||||||
197 | { | - | ||||||||||||||||||
198 | error (0, errno, _("failed to access %s"), quoteaf (source)); | - | ||||||||||||||||||
199 | return false; executed 1 time by 1 test: return 0 ; Executed by:
| 1 | ||||||||||||||||||
200 | } | - | ||||||||||||||||||
201 | - | |||||||||||||||||||
202 | if (S_ISDIR (source_stats.st_mode))
| 2-86 | ||||||||||||||||||
203 | { | - | ||||||||||||||||||
204 | source_is_dir = true; | - | ||||||||||||||||||
205 | if (! hard_dir_link)
| 0-2 | ||||||||||||||||||
206 | { | - | ||||||||||||||||||
207 | error (0, 0, _("%s: hard link not allowed for directory"), | - | ||||||||||||||||||
208 | quotef (source)); | - | ||||||||||||||||||
209 | return false; executed 2 times by 1 test: return 0 ; Executed by:
| 2 | ||||||||||||||||||
210 | } | - | ||||||||||||||||||
211 | } never executed: end of block | 0 | ||||||||||||||||||
212 | } executed 86 times by 1 test: end of block Executed by:
| 86 | ||||||||||||||||||
213 | - | |||||||||||||||||||
214 | if (remove_existing_files || interactive || backup_type != no_backups)
| 0-719 | ||||||||||||||||||
215 | { | - | ||||||||||||||||||
216 | dest_lstat_ok = (lstat (dest, &dest_stats) == 0); | - | ||||||||||||||||||
217 | if (!dest_lstat_ok && errno != ENOENT)
| 0-43 | ||||||||||||||||||
218 | { | - | ||||||||||||||||||
219 | error (0, errno, _("failed to access %s"), quoteaf (dest)); | - | ||||||||||||||||||
220 | return false; never executed: return 0 ; | 0 | ||||||||||||||||||
221 | } | - | ||||||||||||||||||
222 | } executed 60 times by 1 test: end of block Executed by:
| 60 | ||||||||||||||||||
223 | - | |||||||||||||||||||
224 | /* If the current target was created as a hard link to another | - | ||||||||||||||||||
225 | source file, then refuse to unlink it. */ | - | ||||||||||||||||||
226 | if (dest_lstat_ok
| 17-760 | ||||||||||||||||||
227 | && dest_set != NULL
| 1-16 | ||||||||||||||||||
228 | && seen_file (dest_set, dest, &dest_stats))
| 0-1 | ||||||||||||||||||
229 | { | - | ||||||||||||||||||
230 | error (0, 0, | - | ||||||||||||||||||
231 | _("will not overwrite just-created %s with %s"), | - | ||||||||||||||||||
232 | quoteaf_n (0, dest), quoteaf_n (1, source)); | - | ||||||||||||||||||
233 | return false; executed 1 time by 1 test: return 0 ; Executed by:
| 1 | ||||||||||||||||||
234 | } | - | ||||||||||||||||||
235 | - | |||||||||||||||||||
236 | /* If --force (-f) has been specified without --backup, then before | - | ||||||||||||||||||
237 | making a link ln must remove the destination file if it exists. | - | ||||||||||||||||||
238 | (with --backup, it just renames any existing destination file) | - | ||||||||||||||||||
239 | But if the source and destination are the same, don't remove | - | ||||||||||||||||||
240 | anything and fail right here. */ | - | ||||||||||||||||||
241 | if ((remove_existing_files
| 57-719 | ||||||||||||||||||
242 | /* Ensure that "ln --backup f f" fails here, with the | - | ||||||||||||||||||
243 | "... same file" diagnostic, below. Otherwise, subsequent | - | ||||||||||||||||||
244 | code would give a misleading "file not found" diagnostic. | - | ||||||||||||||||||
245 | This case is different than the others handled here, since | - | ||||||||||||||||||
246 | the command in question doesn't use --force. */ | - | ||||||||||||||||||
247 | || (!symbolic_link && backup_type != no_backups))
| 2-637 | ||||||||||||||||||
248 | && dest_lstat_ok
| 16-43 | ||||||||||||||||||
249 | /* Allow 'ln -sf --backup k k' to succeed in creating the | - | ||||||||||||||||||
250 | self-referential symlink, but don't allow the hard-linking | - | ||||||||||||||||||
251 | equivalent: 'ln -f k k' (with or without --backup) to get | - | ||||||||||||||||||
252 | beyond this point, because the error message you'd get is | - | ||||||||||||||||||
253 | misleading. */ | - | ||||||||||||||||||
254 | && (backup_type == no_backups || !symbolic_link)
| 0-12 | ||||||||||||||||||
255 | && (!symbolic_link || stat (source, &source_stats) == 0)
| 4-12 | ||||||||||||||||||
256 | && SAME_INODE (source_stats, dest_stats)
| 0-5 | ||||||||||||||||||
257 | /* The following detects whether removing DEST will also remove | - | ||||||||||||||||||
258 | SOURCE. If the file has only one link then both are surely | - | ||||||||||||||||||
259 | the same link. Otherwise check whether they point to the same | - | ||||||||||||||||||
260 | name in the same directory. */ | - | ||||||||||||||||||
261 | && (source_stats.st_nlink == 1 || same_name (source, dest)))
| 0-3 | ||||||||||||||||||
262 | { | - | ||||||||||||||||||
263 | error (0, 0, _("%s and %s are the same file"), | - | ||||||||||||||||||
264 | quoteaf_n (0, source), quoteaf_n (1, dest)); | - | ||||||||||||||||||
265 | return false; executed 3 times by 1 test: return 0 ; Executed by:
| 3 | ||||||||||||||||||
266 | } | - | ||||||||||||||||||
267 | - | |||||||||||||||||||
268 | if (dest_lstat_ok)
| 13-760 | ||||||||||||||||||
269 | { | - | ||||||||||||||||||
270 | if (S_ISDIR (dest_stats.st_mode))
| 0-13 | ||||||||||||||||||
271 | { | - | ||||||||||||||||||
272 | error (0, 0, _("%s: cannot overwrite directory"), quotef (dest)); | - | ||||||||||||||||||
273 | return false; never executed: return 0 ; | 0 | ||||||||||||||||||
274 | } | - | ||||||||||||||||||
275 | if (interactive)
| 0-13 | ||||||||||||||||||
276 | { | - | ||||||||||||||||||
277 | fprintf (stderr, _("%s: replace %s? "), program_name, quoteaf (dest)); | - | ||||||||||||||||||
278 | if (!yesno ())
| 0 | ||||||||||||||||||
279 | return true; never executed: return 1 ; | 0 | ||||||||||||||||||
280 | remove_existing_files = true; | - | ||||||||||||||||||
281 | } never executed: end of block | 0 | ||||||||||||||||||
282 | - | |||||||||||||||||||
283 | if (backup_type != no_backups)
| 3-10 | ||||||||||||||||||
284 | { | - | ||||||||||||||||||
285 | dest_backup = find_backup_file_name (dest, backup_type); | - | ||||||||||||||||||
286 | if (rename (dest, dest_backup) != 0)
| 0-3 | ||||||||||||||||||
287 | { | - | ||||||||||||||||||
288 | int rename_errno = errno; | - | ||||||||||||||||||
289 | free (dest_backup); | - | ||||||||||||||||||
290 | dest_backup = NULL; | - | ||||||||||||||||||
291 | if (rename_errno != ENOENT)
| 0 | ||||||||||||||||||
292 | { | - | ||||||||||||||||||
293 | error (0, rename_errno, _("cannot backup %s"), | - | ||||||||||||||||||
294 | quoteaf (dest)); | - | ||||||||||||||||||
295 | return false; never executed: return 0 ; | 0 | ||||||||||||||||||
296 | } | - | ||||||||||||||||||
297 | } never executed: end of block | 0 | ||||||||||||||||||
298 | } executed 3 times by 1 test: end of block Executed by:
| 3 | ||||||||||||||||||
299 | } executed 13 times by 1 test: end of block Executed by:
| 13 | ||||||||||||||||||
300 | - | |||||||||||||||||||
301 | if (relative)
| 5-768 | ||||||||||||||||||
302 | source = rel_source = convert_abs_rel (source, dest); executed 5 times by 1 test: source = rel_source = convert_abs_rel (source, dest); Executed by:
| 5 | ||||||||||||||||||
303 | - | |||||||||||||||||||
304 | /* If the attempt to create a link fails and we are removing or | - | ||||||||||||||||||
305 | backing up destinations, unlink the destination and try again. | - | ||||||||||||||||||
306 | - | |||||||||||||||||||
307 | On the surface, POSIX describes an algorithm that states that | - | ||||||||||||||||||
308 | 'ln -f A B' will call unlink() on B before ever attempting | - | ||||||||||||||||||
309 | link() on A. But strictly following this has the counterintuitive | - | ||||||||||||||||||
310 | effect of losing the contents of B, if A does not exist. | - | ||||||||||||||||||
311 | Fortunately, POSIX 2008 clarified that an application is free | - | ||||||||||||||||||
312 | to fail early if it can prove that continuing onwards cannot | - | ||||||||||||||||||
313 | succeed, so we are justified in trying link() before blindly | - | ||||||||||||||||||
314 | removing B, thus sometimes calling link() a second time during | - | ||||||||||||||||||
315 | a successful 'ln -f A B'. | - | ||||||||||||||||||
316 | - | |||||||||||||||||||
317 | Try to unlink DEST even if we may have backed it up successfully. | - | ||||||||||||||||||
318 | In some unusual cases (when DEST and DEST_BACKUP are hard-links | - | ||||||||||||||||||
319 | that refer to the same file), rename succeeds and DEST remains. | - | ||||||||||||||||||
320 | If we didn't remove DEST in that case, the subsequent symlink or link | - | ||||||||||||||||||
321 | call would fail. */ | - | ||||||||||||||||||
322 | bool ok_to_remove = remove_existing_files || dest_backup;
| 1-718 | ||||||||||||||||||
323 | bool ok = 0 <= (symbolic_link
| 84-689 | ||||||||||||||||||
324 | ? force_symlinkat (source, AT_FDCWD, dest, ok_to_remove) | - | ||||||||||||||||||
325 | : force_linkat (AT_FDCWD, source, AT_FDCWD, dest, | - | ||||||||||||||||||
326 | logical ? AT_SYMLINK_FOLLOW : 0, | - | ||||||||||||||||||
327 | ok_to_remove)); | - | ||||||||||||||||||
328 | - | |||||||||||||||||||
329 | if (ok)
| 5-768 | ||||||||||||||||||
330 | { | - | ||||||||||||||||||
331 | /* Right after creating a hard link, do this: (note dest name and | - | ||||||||||||||||||
332 | source_stats, which are also the just-linked-destinations stats) */ | - | ||||||||||||||||||
333 | if (! symbolic_link)
| 82-686 | ||||||||||||||||||
334 | record_file (dest_set, dest, &source_stats); executed 82 times by 1 test: record_file (dest_set, dest, &source_stats); Executed by:
| 82 | ||||||||||||||||||
335 | - | |||||||||||||||||||
336 | if (verbose)
| 1-767 | ||||||||||||||||||
337 | { | - | ||||||||||||||||||
338 | if (dest_backup)
| 0-1 | ||||||||||||||||||
339 | printf ("%s ~ ", quoteaf (dest_backup)); never executed: printf ("%s ~ ", quotearg_style (shell_escape_always_quoting_style, dest_backup)); | 0 | ||||||||||||||||||
340 | printf ("%s %c> %s\n", quoteaf_n (0, dest), | - | ||||||||||||||||||
341 | (symbolic_link ? '-' : '='), quoteaf_n (1, source)); | - | ||||||||||||||||||
342 | } executed 1 time by 1 test: end of block Executed by:
| 1 | ||||||||||||||||||
343 | } executed 768 times by 1 test: end of block Executed by:
| 768 | ||||||||||||||||||
344 | else | - | ||||||||||||||||||
345 | { | - | ||||||||||||||||||
346 | error (0, errno, | - | ||||||||||||||||||
347 | (symbolic_link | - | ||||||||||||||||||
348 | ? (errno != ENAMETOOLONG && *source | - | ||||||||||||||||||
349 | ? _("failed to create symbolic link %s") | - | ||||||||||||||||||
350 | : _("failed to create symbolic link %s -> %s")) | - | ||||||||||||||||||
351 | : (errno == EMLINK && !source_is_dir | - | ||||||||||||||||||
352 | ? _("failed to create hard link to %.0s%s") | - | ||||||||||||||||||
353 | : (errno == EDQUOT || errno == EEXIST || errno == ENOSPC | - | ||||||||||||||||||
354 | || errno == EROFS) | - | ||||||||||||||||||
355 | ? _("failed to create hard link %s") | - | ||||||||||||||||||
356 | : _("failed to create hard link %s => %s"))), | - | ||||||||||||||||||
357 | quoteaf_n (0, dest), quoteaf_n (1, source)); | - | ||||||||||||||||||
358 | - | |||||||||||||||||||
359 | if (dest_backup)
| 0-5 | ||||||||||||||||||
360 | { | - | ||||||||||||||||||
361 | if (rename (dest_backup, dest) != 0)
| 0 | ||||||||||||||||||
362 | error (0, errno, _("cannot un-backup %s"), quoteaf (dest)); never executed: error (0, (*__errno_location ()) , dcgettext (((void *)0), "cannot un-backup %s" , 5) , quotearg_style (shell_escape_always_quoting_style, dest)); | 0 | ||||||||||||||||||
363 | } never executed: end of block | 0 | ||||||||||||||||||
364 | } executed 5 times by 1 test: end of block Executed by:
| 5 | ||||||||||||||||||
365 | - | |||||||||||||||||||
366 | free (dest_backup); | - | ||||||||||||||||||
367 | free (rel_source); | - | ||||||||||||||||||
368 | return ok; executed 773 times by 1 test: return ok; Executed by:
| 773 | ||||||||||||||||||
369 | } | - | ||||||||||||||||||
370 | - | |||||||||||||||||||
371 | void | - | ||||||||||||||||||
372 | usage (int status) | - | ||||||||||||||||||
373 | { | - | ||||||||||||||||||
374 | if (status != EXIT_SUCCESS)
| 3-28 | ||||||||||||||||||
375 | emit_try_help (); executed 3 times by 1 test: end of block Executed by:
| 3 | ||||||||||||||||||
376 | else | - | ||||||||||||||||||
377 | { | - | ||||||||||||||||||
378 | printf (_("\ | - | ||||||||||||||||||
379 | Usage: %s [OPTION]... [-T] TARGET LINK_NAME (1st form)\n\ | - | ||||||||||||||||||
380 | or: %s [OPTION]... TARGET (2nd form)\n\ | - | ||||||||||||||||||
381 | or: %s [OPTION]... TARGET... DIRECTORY (3rd form)\n\ | - | ||||||||||||||||||
382 | or: %s [OPTION]... -t DIRECTORY TARGET... (4th form)\n\ | - | ||||||||||||||||||
383 | "), | - | ||||||||||||||||||
384 | program_name, program_name, program_name, program_name); | - | ||||||||||||||||||
385 | fputs (_("\ | - | ||||||||||||||||||
386 | In the 1st form, create a link to TARGET with the name LINK_NAME.\n\ | - | ||||||||||||||||||
387 | In the 2nd form, create a link to TARGET in the current directory.\n\ | - | ||||||||||||||||||
388 | In the 3rd and 4th forms, create links to each TARGET in DIRECTORY.\n\ | - | ||||||||||||||||||
389 | Create hard links by default, symbolic links with --symbolic.\n\ | - | ||||||||||||||||||
390 | By default, each destination (name of new link) should not already exist.\n\ | - | ||||||||||||||||||
391 | When creating hard links, each TARGET must exist. Symbolic links\n\ | - | ||||||||||||||||||
392 | can hold arbitrary text; if later resolved, a relative link is\n\ | - | ||||||||||||||||||
393 | interpreted in relation to its parent directory.\n\ | - | ||||||||||||||||||
394 | "), stdout); | - | ||||||||||||||||||
395 | - | |||||||||||||||||||
396 | emit_mandatory_arg_note (); | - | ||||||||||||||||||
397 | - | |||||||||||||||||||
398 | fputs (_("\ | - | ||||||||||||||||||
399 | --backup[=CONTROL] make a backup of each existing destination file\n\ | - | ||||||||||||||||||
400 | -b like --backup but does not accept an argument\n\ | - | ||||||||||||||||||
401 | -d, -F, --directory allow the superuser to attempt to hard link\n\ | - | ||||||||||||||||||
402 | directories (note: will probably fail due to\n\ | - | ||||||||||||||||||
403 | system restrictions, even for the superuser)\n\ | - | ||||||||||||||||||
404 | -f, --force remove existing destination files\n\ | - | ||||||||||||||||||
405 | "), stdout); | - | ||||||||||||||||||
406 | fputs (_("\ | - | ||||||||||||||||||
407 | -i, --interactive prompt whether to remove destinations\n\ | - | ||||||||||||||||||
408 | -L, --logical dereference TARGETs that are symbolic links\n\ | - | ||||||||||||||||||
409 | -n, --no-dereference treat LINK_NAME as a normal file if\n\ | - | ||||||||||||||||||
410 | it is a symbolic link to a directory\n\ | - | ||||||||||||||||||
411 | -P, --physical make hard links directly to symbolic links\n\ | - | ||||||||||||||||||
412 | -r, --relative create symbolic links relative to link location\n\ | - | ||||||||||||||||||
413 | -s, --symbolic make symbolic links instead of hard links\n\ | - | ||||||||||||||||||
414 | "), stdout); | - | ||||||||||||||||||
415 | fputs (_("\ | - | ||||||||||||||||||
416 | -S, --suffix=SUFFIX override the usual backup suffix\n\ | - | ||||||||||||||||||
417 | -t, --target-directory=DIRECTORY specify the DIRECTORY in which to create\n\ | - | ||||||||||||||||||
418 | the links\n\ | - | ||||||||||||||||||
419 | -T, --no-target-directory treat LINK_NAME as a normal file always\n\ | - | ||||||||||||||||||
420 | -v, --verbose print name of each linked file\n\ | - | ||||||||||||||||||
421 | "), stdout); | - | ||||||||||||||||||
422 | fputs (HELP_OPTION_DESCRIPTION, stdout); | - | ||||||||||||||||||
423 | fputs (VERSION_OPTION_DESCRIPTION, stdout); | - | ||||||||||||||||||
424 | emit_backup_suffix_note (); | - | ||||||||||||||||||
425 | printf (_("\ | - | ||||||||||||||||||
426 | \n\ | - | ||||||||||||||||||
427 | Using -s ignores -L and -P. Otherwise, the last option specified controls\n\ | - | ||||||||||||||||||
428 | behavior when a TARGET is a symbolic link, defaulting to %s.\n\ | - | ||||||||||||||||||
429 | "), LINK_FOLLOWS_SYMLINKS ? "-L" : "-P"); | - | ||||||||||||||||||
430 | emit_ancillary_info (PROGRAM_NAME); | - | ||||||||||||||||||
431 | } executed 28 times by 1 test: end of block Executed by:
| 28 | ||||||||||||||||||
432 | exit (status); executed 31 times by 1 test: exit (status); Executed by:
| 31 | ||||||||||||||||||
433 | } | - | ||||||||||||||||||
434 | - | |||||||||||||||||||
435 | int | - | ||||||||||||||||||
436 | main (int argc, char **argv) | - | ||||||||||||||||||
437 | { | - | ||||||||||||||||||
438 | int c; | - | ||||||||||||||||||
439 | bool ok; | - | ||||||||||||||||||
440 | bool make_backups = false; | - | ||||||||||||||||||
441 | char const *backup_suffix = NULL; | - | ||||||||||||||||||
442 | char *version_control_string = NULL; | - | ||||||||||||||||||
443 | char const *target_directory = NULL; | - | ||||||||||||||||||
444 | bool no_target_directory = false; | - | ||||||||||||||||||
445 | int n_files; | - | ||||||||||||||||||
446 | char **file; | - | ||||||||||||||||||
447 | - | |||||||||||||||||||
448 | initialize_main (&argc, &argv); | - | ||||||||||||||||||
449 | set_program_name (argv[0]); | - | ||||||||||||||||||
450 | setlocale (LC_ALL, ""); | - | ||||||||||||||||||
451 | bindtextdomain (PACKAGE, LOCALEDIR); | - | ||||||||||||||||||
452 | textdomain (PACKAGE); | - | ||||||||||||||||||
453 | - | |||||||||||||||||||
454 | atexit (close_stdin); | - | ||||||||||||||||||
455 | - | |||||||||||||||||||
456 | symbolic_link = remove_existing_files = interactive = verbose | - | ||||||||||||||||||
457 | = hard_dir_link = false; | - | ||||||||||||||||||
458 | - | |||||||||||||||||||
459 | while ((c = getopt_long (argc, argv, "bdfinrst:vFLPS:T", long_options, NULL))
| 780-891 | ||||||||||||||||||
460 | != -1)
| 780-891 | ||||||||||||||||||
461 | { | - | ||||||||||||||||||
462 | switch (c) | - | ||||||||||||||||||
463 | { | - | ||||||||||||||||||
464 | case 'b': executed 6 times by 1 test: case 'b': Executed by:
| 6 | ||||||||||||||||||
465 | make_backups = true; | - | ||||||||||||||||||
466 | if (optarg)
| 3 | ||||||||||||||||||
467 | version_control_string = optarg; executed 3 times by 1 test: version_control_string = optarg; Executed by:
| 3 | ||||||||||||||||||
468 | break; executed 6 times by 1 test: break; Executed by:
| 6 | ||||||||||||||||||
469 | case 'd': executed 1 time by 1 test: case 'd': Executed by:
| 1 | ||||||||||||||||||
470 | case 'F': executed 2 times by 1 test: case 'F': Executed by:
| 2 | ||||||||||||||||||
471 | hard_dir_link = true; | - | ||||||||||||||||||
472 | break; executed 3 times by 1 test: break; Executed by:
| 3 | ||||||||||||||||||
473 | case 'f': executed 59 times by 1 test: case 'f': Executed by:
| 59 | ||||||||||||||||||
474 | remove_existing_files = true; | - | ||||||||||||||||||
475 | interactive = false; | - | ||||||||||||||||||
476 | break; executed 59 times by 1 test: break; Executed by:
| 59 | ||||||||||||||||||
477 | case 'i': executed 2 times by 1 test: case 'i': Executed by:
| 2 | ||||||||||||||||||
478 | remove_existing_files = false; | - | ||||||||||||||||||
479 | interactive = true; | - | ||||||||||||||||||
480 | break; executed 2 times by 1 test: break; Executed by:
| 2 | ||||||||||||||||||
481 | case 'L': executed 8 times by 1 test: case 'L': Executed by:
| 8 | ||||||||||||||||||
482 | logical = true; | - | ||||||||||||||||||
483 | break; executed 8 times by 1 test: break; Executed by:
| 8 | ||||||||||||||||||
484 | case 'n': executed 48 times by 1 test: case 'n': Executed by:
| 48 | ||||||||||||||||||
485 | dereference_dest_dir_symlinks = false; | - | ||||||||||||||||||
486 | break; executed 48 times by 1 test: break; Executed by:
| 48 | ||||||||||||||||||
487 | case 'P': executed 10 times by 1 test: case 'P': Executed by:
| 10 | ||||||||||||||||||
488 | logical = false; | - | ||||||||||||||||||
489 | break; executed 10 times by 1 test: break; Executed by:
| 10 | ||||||||||||||||||
490 | case 'r': executed 7 times by 1 test: case 'r': Executed by:
| 7 | ||||||||||||||||||
491 | relative = true; | - | ||||||||||||||||||
492 | break; executed 7 times by 1 test: break; Executed by:
| 7 | ||||||||||||||||||
493 | case 's': executed 693 times by 1 test: case 's': Executed by:
| 693 | ||||||||||||||||||
494 | symbolic_link = true; | - | ||||||||||||||||||
495 | break; executed 693 times by 1 test: break; Executed by:
| 693 | ||||||||||||||||||
496 | case 't': executed 3 times by 1 test: case 't': Executed by:
| 3 | ||||||||||||||||||
497 | if (target_directory)
| 0-3 | ||||||||||||||||||
498 | die (EXIT_FAILURE, 0, _("multiple target directories specified")); never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, 0, dcgettext (((void *)0), \"multiple target directories specified\", 5)), assume (false))" ")"); int _gl_dummy; })) ? ((error ( 1 , 0, dcgettext (((void *)0), "multiple target directories specified" , 5) ), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , 0, dcgettext (((void *)0), "multiple target directories specified" , 5) ), (( 0 ) ? (void) 0 : __builtin_unreachable ())))); | 0 | ||||||||||||||||||
499 | else | - | ||||||||||||||||||
500 | { | - | ||||||||||||||||||
501 | struct stat st; | - | ||||||||||||||||||
502 | if (stat (optarg, &st) != 0)
| 1-2 | ||||||||||||||||||
503 | die (EXIT_FAILURE, errno, _("failed to access %s"), executed 2 times by 1 test: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, (*__errno_location ()), dcgettext (((void *)0), \"failed to access %s\", 5), quotearg_style (shell_escape_always_quoting_style, optarg)), assume (false))" ")"); int _gl_dummy; ..., (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , (*__errno_location ()) , dcgettext (((void *)0), "failed to access %s" , 5) , quotearg_style (shell_escape_always_quoting_style, optarg)), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; Executed by:
| 2 | ||||||||||||||||||
504 | quoteaf (optarg)); executed 2 times by 1 test: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, (*__errno_location ()), dcgettext (((void *)0), \"failed to access %s\", 5), quotearg_style (shell_escape_always_quoting_style, optarg)), assume (false))" ")"); int _gl_dummy; ..., (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , (*__errno_location ()) , dcgettext (((void *)0), "failed to access %s" , 5) , quotearg_style (shell_escape_always_quoting_style, optarg)), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; Executed by:
| 2 | ||||||||||||||||||
505 | if (! S_ISDIR (st.st_mode))
| 0-1 | ||||||||||||||||||
506 | die (EXIT_FAILURE, 0, _("target %s is not a directory"), never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, 0, dcgettext (((void *)0), \"target %s is not a directory\", 5), quotearg_style (shell_escape_always_quoting_style, optarg)), assume (false))" ")"); int _gl_dummy; })) ? ((erro...yle, optarg)), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , 0, dcgettext (((void *)0), "target %s is not a directory" , 5) , quotearg_style (shell_escape_always_quoting_style, optarg)), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||
507 | quoteaf (optarg)); never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, 0, dcgettext (((void *)0), \"target %s is not a directory\", 5), quotearg_style (shell_escape_always_quoting_style, optarg)), assume (false))" ")"); int _gl_dummy; })) ? ((erro...yle, optarg)), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , 0, dcgettext (((void *)0), "target %s is not a directory" , 5) , quotearg_style (shell_escape_always_quoting_style, optarg)), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||
508 | } executed 1 time by 1 test: end of block Executed by:
| 1 | ||||||||||||||||||
509 | target_directory = optarg; | - | ||||||||||||||||||
510 | break; executed 1 time by 1 test: break; Executed by:
| 1 | ||||||||||||||||||
511 | case 'T': executed 3 times by 1 test: case 'T': Executed by:
| 3 | ||||||||||||||||||
512 | no_target_directory = true; | - | ||||||||||||||||||
513 | break; executed 3 times by 1 test: break; Executed by:
| 3 | ||||||||||||||||||
514 | case 'v': executed 3 times by 1 test: case 'v': Executed by:
| 3 | ||||||||||||||||||
515 | verbose = true; | - | ||||||||||||||||||
516 | break; executed 3 times by 1 test: break; Executed by:
| 3 | ||||||||||||||||||
517 | case 'S': executed 3 times by 1 test: case 'S': Executed by:
| 3 | ||||||||||||||||||
518 | make_backups = true; | - | ||||||||||||||||||
519 | backup_suffix = optarg; | - | ||||||||||||||||||
520 | break; executed 3 times by 1 test: break; Executed by:
| 3 | ||||||||||||||||||
521 | case_GETOPT_HELP_CHAR; never executed: break; executed 28 times by 1 test: case GETOPT_HELP_CHAR: Executed by:
| 0-28 | ||||||||||||||||||
522 | case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); executed 12 times by 1 test: exit ( 0 ); Executed by:
never executed: break; executed 12 times by 1 test: case GETOPT_VERSION_CHAR: Executed by:
| 0-12 | ||||||||||||||||||
523 | default: executed 3 times by 1 test: default: Executed by:
| 3 | ||||||||||||||||||
524 | usage (EXIT_FAILURE); | - | ||||||||||||||||||
525 | break; never executed: break; | 0 | ||||||||||||||||||
526 | } | - | ||||||||||||||||||
527 | } | - | ||||||||||||||||||
528 | - | |||||||||||||||||||
529 | n_files = argc - optind; | - | ||||||||||||||||||
530 | file = argv + optind; | - | ||||||||||||||||||
531 | - | |||||||||||||||||||
532 | if (n_files <= 0)
| 0-780 | ||||||||||||||||||
533 | { | - | ||||||||||||||||||
534 | error (0, 0, _("missing file operand")); | - | ||||||||||||||||||
535 | usage (EXIT_FAILURE); | - | ||||||||||||||||||
536 | } never executed: end of block | 0 | ||||||||||||||||||
537 | - | |||||||||||||||||||
538 | if (no_target_directory)
| 1-779 | ||||||||||||||||||
539 | { | - | ||||||||||||||||||
540 | if (target_directory)
| 0-1 | ||||||||||||||||||
541 | die (EXIT_FAILURE, 0, never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, 0, dcgettext (((void *)0), \"cannot combine --target-directory \" \"and --no-target-directory\", 5)), assume (false))" ")"); int _gl_dummy; })) ? ((error ( 1 , 0, dcgettext (((...ry " "and --no-target-directory" , 5) ), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , 0, dcgettext (((void *)0), "cannot combine --target-directory " "and --no-target-directory" , 5) ), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||
542 | _("cannot combine --target-directory " never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, 0, dcgettext (((void *)0), \"cannot combine --target-directory \" \"and --no-target-directory\", 5)), assume (false))" ")"); int _gl_dummy; })) ? ((error ( 1 , 0, dcgettext (((...ry " "and --no-target-directory" , 5) ), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , 0, dcgettext (((void *)0), "cannot combine --target-directory " "and --no-target-directory" , 5) ), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||
543 | "and --no-target-directory")); never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, 0, dcgettext (((void *)0), \"cannot combine --target-directory \" \"and --no-target-directory\", 5)), assume (false))" ")"); int _gl_dummy; })) ? ((error ( 1 , 0, dcgettext (((...ry " "and --no-target-directory" , 5) ), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , 0, dcgettext (((void *)0), "cannot combine --target-directory " "and --no-target-directory" , 5) ), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||
544 | if (n_files != 2)
| 0-1 | ||||||||||||||||||
545 | { | - | ||||||||||||||||||
546 | if (n_files < 2)
| 0 | ||||||||||||||||||
547 | error (0, 0, never executed: error (0, 0, dcgettext (((void *)0), "missing destination file operand after %s" , 5) , quotearg_style (shell_escape_always_quoting_style, file[0])); | 0 | ||||||||||||||||||
548 | _("missing destination file operand after %s"), never executed: error (0, 0, dcgettext (((void *)0), "missing destination file operand after %s" , 5) , quotearg_style (shell_escape_always_quoting_style, file[0])); | 0 | ||||||||||||||||||
549 | quoteaf (file[0])); never executed: error (0, 0, dcgettext (((void *)0), "missing destination file operand after %s" , 5) , quotearg_style (shell_escape_always_quoting_style, file[0])); | 0 | ||||||||||||||||||
550 | else | - | ||||||||||||||||||
551 | error (0, 0, _("extra operand %s"), quoteaf (file[2])); never executed: error (0, 0, dcgettext (((void *)0), "extra operand %s" , 5) , quotearg_style (shell_escape_always_quoting_style, file[2])); | 0 | ||||||||||||||||||
552 | usage (EXIT_FAILURE); | - | ||||||||||||||||||
553 | } never executed: end of block | 0 | ||||||||||||||||||
554 | } executed 1 time by 1 test: end of block Executed by:
| 1 | ||||||||||||||||||
555 | else if (!target_directory)
| 1-778 | ||||||||||||||||||
556 | { | - | ||||||||||||||||||
557 | if (n_files < 2)
| 2-776 | ||||||||||||||||||
558 | target_directory = "."; executed 2 times by 1 test: target_directory = "."; Executed by:
| 2 | ||||||||||||||||||
559 | else if (2 <= n_files && target_directory_operand (file[n_files - 1]))
| 0-776 | ||||||||||||||||||
560 | target_directory = file[--n_files]; executed 11 times by 1 test: target_directory = file[--n_files]; Executed by:
| 11 | ||||||||||||||||||
561 | else if (2 < n_files)
| 0-764 | ||||||||||||||||||
562 | die (EXIT_FAILURE, 0, _("target %s is not a directory"), never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, 0, dcgettext (((void *)0), \"target %s is not a directory\", 5), quotearg_style (shell_escape_always_quoting_style, file[n_files - 1])), assume (false))" ")"); int _gl_dummy; }...)), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , 0, dcgettext (((void *)0), "target %s is not a directory" , 5) , quotearg_style (shell_escape_always_quoting_style, file[n_files - 1])), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||
563 | quoteaf (file[n_files - 1])); never executed: ((!!sizeof (struct { _Static_assert ( 1 , "verify_expr (" "1" ", " "(error (1, 0, dcgettext (((void *)0), \"target %s is not a directory\", 5), quotearg_style (shell_escape_always_quoting_style, file[n_files - 1])), assume (false))" ")"); int _gl_dummy; }...)), (( 0 ) ? (void) 0 : __builtin_unreachable ()))) : ((error ( 1 , 0, dcgettext (((void *)0), "target %s is not a directory" , 5) , quotearg_style (shell_escape_always_quoting_style, file[n_files - 1])), (( 0 ) ? (void) 0 : __builtin_unreachable ())))) ; | 0 | ||||||||||||||||||
564 | } executed 777 times by 1 test: end of block Executed by:
| 777 | ||||||||||||||||||
565 | - | |||||||||||||||||||
566 | backup_type = (make_backups
| 4-775 | ||||||||||||||||||
567 | ? xget_version (_("backup type"), version_control_string) | - | ||||||||||||||||||
568 | : no_backups); | - | ||||||||||||||||||
569 | set_simple_backup_suffix (backup_suffix); | - | ||||||||||||||||||
570 | - | |||||||||||||||||||
571 | if (relative && !symbolic_link)
| 0-774 | ||||||||||||||||||
572 | { | - | ||||||||||||||||||
573 | die (EXIT_FAILURE, 0, | - | ||||||||||||||||||
574 | _("cannot do --relative without --symbolic")); | - | ||||||||||||||||||
575 | } never executed: end of block | 0 | ||||||||||||||||||
576 | - | |||||||||||||||||||
577 | - | |||||||||||||||||||
578 | if (target_directory)
| 14-765 | ||||||||||||||||||
579 | { | - | ||||||||||||||||||
580 | /* Create the data structure we'll use to record which hard links we | - | ||||||||||||||||||
581 | create. Used to ensure that ln detects an obscure corner case that | - | ||||||||||||||||||
582 | might result in user data loss. Create it only if needed. */ | - | ||||||||||||||||||
583 | if (2 <= n_files
| 1-13 | ||||||||||||||||||
584 | && remove_existing_files
| 0-1 | ||||||||||||||||||
585 | /* Don't bother trying to protect symlinks, since ln clobbering | - | ||||||||||||||||||
586 | a just-created symlink won't ever lead to real data loss. */ | - | ||||||||||||||||||
587 | && ! symbolic_link
| 0-1 | ||||||||||||||||||
588 | /* No destination hard link can be clobbered when making | - | ||||||||||||||||||
589 | numbered backups. */ | - | ||||||||||||||||||
590 | && backup_type != numbered_backups)
| 0-1 | ||||||||||||||||||
591 | - | |||||||||||||||||||
592 | { | - | ||||||||||||||||||
593 | dest_set = hash_initialize (DEST_INFO_INITIAL_CAPACITY, | - | ||||||||||||||||||
594 | NULL, | - | ||||||||||||||||||
595 | triple_hash, | - | ||||||||||||||||||
596 | triple_compare, | - | ||||||||||||||||||
597 | triple_free); | - | ||||||||||||||||||
598 | if (dest_set == NULL)
| 0-1 | ||||||||||||||||||
599 | xalloc_die (); never executed: xalloc_die (); | 0 | ||||||||||||||||||
600 | } executed 1 time by 1 test: end of block Executed by:
| 1 | ||||||||||||||||||
601 | - | |||||||||||||||||||
602 | ok = true; | - | ||||||||||||||||||
603 | for (int i = 0; i < n_files; ++i)
| 14-15 | ||||||||||||||||||
604 | { | - | ||||||||||||||||||
605 | char *dest_base; | - | ||||||||||||||||||
606 | char *dest = file_name_concat (target_directory, | - | ||||||||||||||||||
607 | last_component (file[i]), | - | ||||||||||||||||||
608 | &dest_base); | - | ||||||||||||||||||
609 | strip_trailing_slashes (dest_base); | - | ||||||||||||||||||
610 | ok &= do_link (file[i], dest); | - | ||||||||||||||||||
611 | free (dest); | - | ||||||||||||||||||
612 | } executed 15 times by 1 test: end of block Executed by:
| 15 | ||||||||||||||||||
613 | } executed 14 times by 1 test: end of block Executed by:
| 14 | ||||||||||||||||||
614 | else | - | ||||||||||||||||||
615 | ok = do_link (file[0], file[1]); executed 765 times by 1 test: ok = do_link (file[0], file[1]); Executed by:
| 765 | ||||||||||||||||||
616 | - | |||||||||||||||||||
617 | return ok ? EXIT_SUCCESS : EXIT_FAILURE; executed 779 times by 1 test: return ok ? 0 : 1 ; Executed by:
| 779 | ||||||||||||||||||
618 | } | - | ||||||||||||||||||
Source code | Switch to Preprocessed file |