maint: add doc/coverage to .gitignore
[coreutils.git] / src / force-link.c
blob4ed04aa7c13e7a566652115a5f0563e65b1a26b1
1 /* Implement ln -f "atomically"
3 Copyright 2017 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 /* Written by Paul Eggert. */
20 /* A naive "ln -f A B" unlinks B and then links A to B. This module
21 instead links A to a randomly-named temporary T in B's directory,
22 and then renames T to B. This approach has a window with a
23 randomly-named temporary, which is safer for many applications than
24 a window where B does not exist. */
26 #include <config.h>
27 #include "system.h"
29 #include "force-link.h"
31 #include <tempname.h>
33 /* A basename pattern suitable for a temporary file. It should work
34 even on file systems like FAT that support only short names.
35 "Cu" is short for "Coreutils" or for "Changeable unstable",
36 take your pick.... */
38 static char const simple_pattern[] = "CuXXXXXX";
39 enum { x_suffix_len = sizeof "XXXXXX" - 1 };
41 /* A size for smallish buffers containing file names. Longer file
42 names can use malloc. */
44 enum { smallsize = 256 };
46 /* Return a template for a file in the same directory as DSTNAME.
47 Use BUF if the template fits, otherwise use malloc and return NULL
48 (setting errno) if unsuccessful. */
50 static char *
51 samedir_template (char const *dstname, char buf[smallsize])
53 ptrdiff_t dstdirlen = last_component (dstname) - dstname;
54 size_t dsttmpsize = dstdirlen + sizeof simple_pattern;
55 char *dsttmp;
56 if (dsttmpsize <= smallsize)
57 dsttmp = buf;
58 else
60 dsttmp = malloc (dsttmpsize);
61 if (!dsttmp)
62 return dsttmp;
64 strcpy (mempcpy (dsttmp, dstname, dstdirlen), simple_pattern);
65 return dsttmp;
69 /* Auxiliaries for force_linkat. */
71 struct link_arg
73 int srcdir;
74 char const *srcname;
75 int dstdir;
76 int flags;
79 static int
80 try_link (char *dest, void *arg)
82 struct link_arg *a = arg;
83 return linkat (a->srcdir, a->srcname, a->dstdir, dest, a->flags);
86 /* Hard-link directory SRCDIR's file SRCNAME to directory DSTDIR's
87 file DSTNAME, using linkat-style FLAGS to control the linking.
88 If FORCE and DSTNAME already exists, replace it atomically. Return
89 1 if successful and DSTNAME already existed,
90 0 if successful and DSTNAME did not already exist, and
91 -1 (setting errno) on failure. */
92 extern int
93 force_linkat (int srcdir, char const *srcname,
94 int dstdir, char const *dstname, int flags, bool force)
96 int r = linkat (srcdir, srcname, dstdir, dstname, flags);
97 if (!force || r == 0 || errno != EEXIST)
98 return r;
100 char buf[smallsize];
101 char *dsttmp = samedir_template (dstname, buf);
102 if (! dsttmp)
103 return -1;
104 struct link_arg arg = { srcdir, srcname, dstdir, flags };
105 int err;
107 if (try_tempname_len (dsttmp, 0, &arg, try_link, x_suffix_len) != 0)
108 err = errno;
109 else
111 err = renameat (dstdir, dsttmp, dstdir, dstname) == 0 ? 0 : errno;
112 /* Unlink DSTTMP even if renameat succeeded, in case DSTTMP
113 and DSTNAME were already the same hard link and renameat
114 was a no-op. */
115 unlinkat (dstdir, dsttmp, 0);
118 if (dsttmp != buf)
119 free (dsttmp);
120 if (!err)
121 return 1;
122 errno = err;
123 return -1;
127 /* Auxiliaries for force_symlinkat. */
129 struct symlink_arg
131 char const *srcname;
132 int dstdir;
135 static int
136 try_symlink (char *dest, void *arg)
138 struct symlink_arg *a = arg;
139 return symlinkat (a->srcname, a->dstdir, dest);
142 /* Create a symlink containing SRCNAME in directory DSTDIR's file DSTNAME.
143 If FORCE and DSTNAME already exists, replace it atomically. Return
144 1 if successful and DSTNAME already existed,
145 0 if successful and DSTNAME did not already exist, and
146 -1 (setting errno) on failure. */
147 extern int
148 force_symlinkat (char const *srcname, int dstdir, char const *dstname,
149 bool force)
151 int r = symlinkat (srcname, dstdir, dstname);
152 if (!force || r == 0 || errno != EEXIST)
153 return r;
155 char buf[smallsize];
156 char *dsttmp = samedir_template (dstname, buf);
157 if (!dsttmp)
158 return -1;
159 struct symlink_arg arg = { srcname, dstdir };
160 int err;
162 if (try_tempname_len (dsttmp, 0, &arg, try_symlink, x_suffix_len) != 0)
163 err = errno;
164 else if (renameat (dstdir, dsttmp, dstdir, dstname) != 0)
166 err = errno;
167 unlinkat (dstdir, dsttmp, 0);
169 else
171 /* Don't worry about renameat being a no-op, since DSTTMP is
172 newly created. */
173 err = 0;
176 if (dsttmp != buf)
177 free (dsttmp);
178 if (!err)
179 return 1;
180 errno = err;
181 return -1;