1/* -*- buffer-read-only: t -*- vi: set ro: */ 2/* DO NOT EDIT! GENERATED AUTOMATICALLY! */ 3#line 1 4/* Emulate link on platforms that lack it, namely native Windows platforms. 5 6 Copyright (C) 2009, 2010 Free Software Foundation, Inc. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3, or (at your option) 11 any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software Foundation, 20 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 21 22#include <config.h> 23 24#include <unistd.h> 25 26#include <errno.h> 27#include <stdlib.h> 28#include <string.h> 29#include <sys/stat.h> 30 31#if !HAVE_LINK 32# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 33 34# define WIN32_LEAN_AND_MEAN 35# include <windows.h> 36 37/* CreateHardLink was introduced only in Windows 2000. */ 38typedef BOOL (WINAPI * CreateHardLinkFuncType) (LPCTSTR lpFileName, 39 LPCTSTR lpExistingFileName, 40 LPSECURITY_ATTRIBUTES lpSecurityAttributes); 41static CreateHardLinkFuncType CreateHardLinkFunc = NULL; 42static BOOL initialized = FALSE; 43 44static void 45initialize (void) 46{ 47 HMODULE kernel32 = GetModuleHandle ("kernel32.dll"); 48 if (kernel32 != NULL) 49 { 50 CreateHardLinkFunc = 51 (CreateHardLinkFuncType) GetProcAddress (kernel32, "CreateHardLinkA"); 52 } 53 initialized = TRUE; 54} 55 56int 57link (const char *file1, const char *file2) 58{ 59 char *dir; 60 size_t len1 = strlen (file1); 61 size_t len2 = strlen (file2); 62 if (!initialized) 63 initialize (); 64 if (CreateHardLinkFunc == NULL) 65 { 66 /* System does not support hard links. */ 67 errno = EPERM; 68 return -1; 69 } 70 /* Reject trailing slashes on non-directories; mingw does not 71 support hard-linking directories. */ 72 if ((len1 && (file1[len1 - 1] == '/' || file1[len1 - 1] == '\\')) 73 || (len2 && (file2[len2 - 1] == '/' || file2[len2 - 1] == '\\'))) 74 { 75 struct stat st; 76 if (stat (file1, &st) == 0 && S_ISDIR (st.st_mode)) 77 errno = EPERM; 78 else 79 errno = ENOTDIR; 80 return -1; 81 } 82 /* CreateHardLink("b/.","a",NULL) creates file "b", so we must check 83 that dirname(file2) exists. */ 84 dir = strdup (file2); 85 if (!dir) 86 return -1; 87 { 88 struct stat st; 89 char *p = strchr (dir, '\0'); 90 while (dir < p && (*--p != '/' && *p != '\\')); 91 *p = '\0'; 92 if (p != dir && stat (dir, &st) == -1) 93 { 94 int saved_errno = errno; 95 free (dir); 96 errno = saved_errno; 97 return -1; 98 } 99 free (dir); 100 } 101 /* Now create the link. */ 102 if (CreateHardLinkFunc (file2, file1, NULL) == 0) 103 { 104 /* It is not documented which errors CreateHardLink() can produce. 105 * The following conversions are based on tests on a Windows XP SP2 106 * system. */ 107 DWORD err = GetLastError (); 108 switch (err) 109 { 110 case ERROR_ACCESS_DENIED: 111 errno = EACCES; 112 break; 113 114 case ERROR_INVALID_FUNCTION: /* fs does not support hard links */ 115 errno = EPERM; 116 break; 117 118 case ERROR_NOT_SAME_DEVICE: 119 errno = EXDEV; 120 break; 121 122 case ERROR_PATH_NOT_FOUND: 123 case ERROR_FILE_NOT_FOUND: 124 errno = ENOENT; 125 break; 126 127 case ERROR_INVALID_PARAMETER: 128 errno = ENAMETOOLONG; 129 break; 130 131 case ERROR_TOO_MANY_LINKS: 132 errno = EMLINK; 133 break; 134 135 case ERROR_ALREADY_EXISTS: 136 errno = EEXIST; 137 break; 138 139 default: 140 errno = EIO; 141 } 142 return -1; 143 } 144 145 return 0; 146} 147 148# else /* !Windows */ 149 150# error "This platform lacks a link function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib." 151 152# endif /* !Windows */ 153#else /* HAVE_LINK */ 154 155# undef link 156 157/* Create a hard link from FILE1 to FILE2, working around platform bugs. */ 158int 159rpl_link (char const *file1, char const *file2) 160{ 161 /* Reject trailing slashes on non-directories. */ 162 size_t len1 = strlen (file1); 163 size_t len2 = strlen (file2); 164 if ((len1 && file1[len1 - 1] == '/') 165 || (len2 && file2[len2 - 1] == '/')) 166 { 167 /* Let link() decide whether hard-linking directories is legal. 168 If stat() fails, then link() should fail for the same reason 169 (although on Solaris 9, link("file/","oops") mistakenly 170 succeeds); if stat() succeeds, require a directory. */ 171 struct stat st; 172 if (stat (file1, &st)) 173 return -1; 174 if (!S_ISDIR (st.st_mode)) 175 { 176 errno = ENOTDIR; 177 return -1; 178 } 179 } 180 else 181 { 182 /* Fix Cygwin 1.5.x bug where link("a","b/.") creates file "b". */ 183 char *dir = strdup (file2); 184 struct stat st; 185 char *p; 186 if (!dir) 187 return -1; 188 /* We already know file2 does not end in slash. Strip off the 189 basename, then check that the dirname exists. */ 190 p = strrchr (dir, '/'); 191 if (p) 192 { 193 *p = '\0'; 194 if (stat (dir, &st) == -1) 195 { 196 int saved_errno = errno; 197 free (dir); 198 errno = saved_errno; 199 return -1; 200 } 201 } 202 free (dir); 203 } 204 return link (file1, file2); 205} 206#endif /* HAVE_LINK */ 207