Hard-link directory SRCDIR's file SRCNAME to directory DSTDIR's file DSTNAME, using linkat-style FLAGS to control the linking. If FORCE and DSTNAME already exists, replace it atomically. If LINKAT_ERRNO is 0, the hard link is already done; if positive, the hard link was tried and failed with errno == LINKAT_ERRNO. Return -1 if successful and DSTNAME already existed, 0 if success
| 92 | 0 if successful and DSTNAME did not already exist, and |
| 93 | a positive errno value on failure. */ |
| 94 | extern int |
| 95 | force_linkat (int srcdir, char const *srcname, |
| 96 | int dstdir, char const *dstname, int flags, bool force, |
| 97 | int linkat_errno) |
| 98 | { |
| 99 | if (linkat_errno < 0) |
| 100 | linkat_errno = (linkat (srcdir, srcname, dstdir, dstname, flags) == 0 |
| 101 | ? 0 : errno); |
| 102 | if (!force || linkat_errno != EEXIST) |
| 103 | return linkat_errno; |
| 104 | |
| 105 | char buf[smallsize]; |
| 106 | char *dsttmp = samedir_template (dstname, buf); |
| 107 | if (! dsttmp) |
| 108 | return errno; |
| 109 | struct link_arg arg = { srcdir, srcname, dstdir, flags }; |
| 110 | int err; |
| 111 | |
| 112 | if (try_tempname_len (dsttmp, 0, &arg, try_link, x_suffix_len) != 0) |
| 113 | err = errno; |
| 114 | else |
| 115 | { |
| 116 | err = renameat (dstdir, dsttmp, dstdir, dstname) == 0 ? -1 : errno; |
| 117 | /* Unlink DSTTMP even if renameat succeeded, in case DSTTMP |
| 118 | and DSTNAME were already the same hard link and renameat |
| 119 | was a no-op. */ |
| 120 | unlinkat (dstdir, dsttmp, 0); |
| 121 | } |
| 122 | |
| 123 | if (dsttmp != buf) |
| 124 | free (dsttmp); |
| 125 | return err; |
| 126 | } |
| 127 | |
| 128 | |
| 129 | /* Auxiliaries for force_symlinkat. */ |
no test coverage detected