link.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /* Emulate link on platforms that lack it, namely native Windows platforms.
  2. Copyright (C) 2009-2014 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 <http://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 __WIN32__) && ! defined __CYGWIN__
  21. # define WIN32_LEAN_AND_MEAN
  22. # include <windows.h>
  23. /* CreateHardLink was introduced only in Windows 2000. */
  24. typedef BOOL (WINAPI * CreateHardLinkFuncType) (LPCTSTR lpFileName,
  25. LPCTSTR lpExistingFileName,
  26. LPSECURITY_ATTRIBUTES lpSecurityAttributes);
  27. static CreateHardLinkFuncType CreateHardLinkFunc = NULL;
  28. static BOOL initialized = FALSE;
  29. static void
  30. initialize (void)
  31. {
  32. HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
  33. if (kernel32 != NULL)
  34. {
  35. CreateHardLinkFunc =
  36. (CreateHardLinkFuncType) GetProcAddress (kernel32, "CreateHardLinkA");
  37. }
  38. initialized = TRUE;
  39. }
  40. int
  41. link (const char *file1, const char *file2)
  42. {
  43. char *dir;
  44. size_t len1 = strlen (file1);
  45. size_t len2 = strlen (file2);
  46. if (!initialized)
  47. initialize ();
  48. if (CreateHardLinkFunc == NULL)
  49. {
  50. /* System does not support hard links. */
  51. errno = EPERM;
  52. return -1;
  53. }
  54. /* Reject trailing slashes on non-directories; mingw does not
  55. support hard-linking directories. */
  56. if ((len1 && (file1[len1 - 1] == '/' || file1[len1 - 1] == '\\'))
  57. || (len2 && (file2[len2 - 1] == '/' || file2[len2 - 1] == '\\')))
  58. {
  59. struct stat st;
  60. if (stat (file1, &st) == 0 && S_ISDIR (st.st_mode))
  61. errno = EPERM;
  62. else
  63. errno = ENOTDIR;
  64. return -1;
  65. }
  66. /* CreateHardLink("b/.","a",NULL) creates file "b", so we must check
  67. that dirname(file2) exists. */
  68. dir = strdup (file2);
  69. if (!dir)
  70. return -1;
  71. {
  72. struct stat st;
  73. char *p = strchr (dir, '\0');
  74. while (dir < p && (*--p != '/' && *p != '\\'));
  75. *p = '\0';
  76. if (p != dir && stat (dir, &st) == -1)
  77. {
  78. int saved_errno = errno;
  79. free (dir);
  80. errno = saved_errno;
  81. return -1;
  82. }
  83. free (dir);
  84. }
  85. /* Now create the link. */
  86. if (CreateHardLinkFunc (file2, file1, NULL) == 0)
  87. {
  88. /* It is not documented which errors CreateHardLink() can produce.
  89. * The following conversions are based on tests on a Windows XP SP2
  90. * system. */
  91. DWORD err = GetLastError ();
  92. switch (err)
  93. {
  94. case ERROR_ACCESS_DENIED:
  95. errno = EACCES;
  96. break;
  97. case ERROR_INVALID_FUNCTION: /* fs does not support hard links */
  98. errno = EPERM;
  99. break;
  100. case ERROR_NOT_SAME_DEVICE:
  101. errno = EXDEV;
  102. break;
  103. case ERROR_PATH_NOT_FOUND:
  104. case ERROR_FILE_NOT_FOUND:
  105. errno = ENOENT;
  106. break;
  107. case ERROR_INVALID_PARAMETER:
  108. errno = ENAMETOOLONG;
  109. break;
  110. case ERROR_TOO_MANY_LINKS:
  111. errno = EMLINK;
  112. break;
  113. case ERROR_ALREADY_EXISTS:
  114. errno = EEXIST;
  115. break;
  116. default:
  117. errno = EIO;
  118. }
  119. return -1;
  120. }
  121. return 0;
  122. }
  123. # else /* !Windows */
  124. # error "This platform lacks a link function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib."
  125. # endif /* !Windows */
  126. #else /* HAVE_LINK */
  127. # undef link
  128. /* Create a hard link from FILE1 to FILE2, working around platform bugs. */
  129. int
  130. rpl_link (char const *file1, char const *file2)
  131. {
  132. size_t len1;
  133. size_t len2;
  134. struct stat st;
  135. /* Don't allow IRIX to dereference dangling file2 symlink. */
  136. if (!lstat (file2, &st))
  137. {
  138. errno = EEXIST;
  139. return -1;
  140. }
  141. /* Reject trailing slashes on non-directories. */
  142. len1 = strlen (file1);
  143. len2 = strlen (file2);
  144. if ((len1 && file1[len1 - 1] == '/')
  145. || (len2 && file2[len2 - 1] == '/'))
  146. {
  147. /* Let link() decide whether hard-linking directories is legal.
  148. If stat() fails, then link() should fail for the same reason
  149. (although on Solaris 9, link("file/","oops") mistakenly
  150. succeeds); if stat() succeeds, require a directory. */
  151. if (stat (file1, &st))
  152. return -1;
  153. if (!S_ISDIR (st.st_mode))
  154. {
  155. errno = ENOTDIR;
  156. return -1;
  157. }
  158. }
  159. else
  160. {
  161. /* Fix Cygwin 1.5.x bug where link("a","b/.") creates file "b". */
  162. char *dir = strdup (file2);
  163. char *p;
  164. if (!dir)
  165. return -1;
  166. /* We already know file2 does not end in slash. Strip off the
  167. basename, then check that the dirname exists. */
  168. p = strrchr (dir, '/');
  169. if (p)
  170. {
  171. *p = '\0';
  172. if (stat (dir, &st) == -1)
  173. {
  174. int saved_errno = errno;
  175. free (dir);
  176. errno = saved_errno;
  177. return -1;
  178. }
  179. }
  180. free (dir);
  181. }
  182. return link (file1, file2);
  183. }
  184. #endif /* HAVE_LINK */