1/* Create a hard link relative to open directories. 2 Copyright (C) 2009-2010 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 <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> 26#include <stdint.h> 27#include <stdlib.h> 28#include <string.h> 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 47#if !HAVE_LINKAT 48 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. */ 51# if LINK_FOLLOWS_SYMLINKS == 0 52# define link_immediate link 53# else 54static int 55link_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} 96# endif /* LINK_FOLLOWS_SYMLINKS == 0 */ 97 98/* Create a link. If FILE1 is a symlink, create a hardlink to the 99 canonicalized file. */ 100# if 0 < LINK_FOLLOWS_SYMLINKS 101# define link_follow link 102# else 103static int 104link_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} 167# endif /* 0 < LINK_FOLLOWS_SYMLINKS */ 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 176int 177linkat (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} 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 195static int 196linkat_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 262int 263rpl_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 */ 291