link.c 6.2 KB

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