link.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /* Emulate link on platforms that lack it, namely native Windows platforms.
  2. Copyright (C) 2009-2021 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program 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. int saved_errno = errno;
  101. free (dir);
  102. errno = saved_errno;
  103. return -1;
  104. }
  105. free (dir);
  106. }
  107. /* Now create the link. */
  108. if (CreateHardLinkFunc (file2, file1, NULL) == 0)
  109. {
  110. /* It is not documented which errors CreateHardLink() can produce.
  111. * The following conversions are based on tests on a Windows XP SP2
  112. * system. */
  113. DWORD err = GetLastError ();
  114. switch (err)
  115. {
  116. case ERROR_ACCESS_DENIED:
  117. errno = EACCES;
  118. break;
  119. case ERROR_INVALID_FUNCTION: /* fs does not support hard links */
  120. errno = EPERM;
  121. break;
  122. case ERROR_NOT_SAME_DEVICE:
  123. errno = EXDEV;
  124. break;
  125. case ERROR_PATH_NOT_FOUND:
  126. case ERROR_FILE_NOT_FOUND:
  127. errno = ENOENT;
  128. break;
  129. case ERROR_INVALID_PARAMETER:
  130. errno = ENAMETOOLONG;
  131. break;
  132. case ERROR_TOO_MANY_LINKS:
  133. errno = EMLINK;
  134. break;
  135. case ERROR_ALREADY_EXISTS:
  136. errno = EEXIST;
  137. break;
  138. default:
  139. errno = EIO;
  140. }
  141. return -1;
  142. }
  143. return 0;
  144. }
  145. # else /* !Windows */
  146. # error "This platform lacks a link function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib."
  147. # endif /* !Windows */
  148. #else /* HAVE_LINK */
  149. # undef link
  150. /* Create a hard link from FILE1 to FILE2, working around platform bugs. */
  151. int
  152. rpl_link (char const *file1, char const *file2)
  153. {
  154. size_t len1;
  155. size_t len2;
  156. struct stat st;
  157. /* Don't allow IRIX to dereference dangling file2 symlink. */
  158. if (lstat (file2, &st) == 0 || errno == EOVERFLOW)
  159. {
  160. errno = EEXIST;
  161. return -1;
  162. }
  163. /* Reject trailing slashes on non-directories. */
  164. len1 = strlen (file1);
  165. len2 = strlen (file2);
  166. if ((len1 && file1[len1 - 1] == '/')
  167. || (len2 && file2[len2 - 1] == '/'))
  168. {
  169. /* Let link() decide whether hard-linking directories is legal.
  170. If stat() fails, then link() should fail for the same reason
  171. (although on Solaris 9, link("file/","oops") mistakenly
  172. succeeds); if stat() succeeds, require a directory. */
  173. if (stat (file1, &st))
  174. return -1;
  175. if (!S_ISDIR (st.st_mode))
  176. {
  177. errno = ENOTDIR;
  178. return -1;
  179. }
  180. }
  181. else
  182. {
  183. /* Fix Cygwin 1.5.x bug where link("a","b/.") creates file "b". */
  184. char *dir = strdup (file2);
  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) != 0 && errno != EOVERFLOW)
  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 */