Make the 'link' module link on Windows NT 4.
[gnulib.git] / lib / link.c
1 /* Emulate link on platforms that lack it, namely native Windows platforms.
2
3    Copyright (C) 2009 Free Software Foundation, Inc.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18
19 #include <config.h>
20
21 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
22
23 #define WIN32_LEAN_AND_MEAN
24 #include <unistd.h>
25 #include <windows.h>
26
27 #include <errno.h>
28
29 /* CreateHardLink was introduced only in Windows 2000.  */
30 typedef BOOL (WINAPI * CreateHardLinkFuncType) (LPCTSTR lpFileName,
31                                                 LPCTSTR lpExistingFileName,
32                                                 LPSECURITY_ATTRIBUTES lpSecurityAttributes);
33 static CreateHardLinkFuncType CreateHardLinkFunc = NULL;
34 static BOOL initialized = FALSE;
35
36 static void
37 initialize (void)
38 {
39   HMODULE kernel32 = LoadLibrary ("kernel32.dll");
40   if (kernel32 != NULL)
41     {
42       CreateHardLinkFunc =
43         (CreateHardLinkFuncType) GetProcAddress (kernel32, "CreateHardLinkA");
44     }
45   initialized = TRUE;
46 }
47
48 int
49 link (const char *path1, const char *path2)
50 {
51   if (!initialized)
52     initialize ();
53   if (CreateHardLinkFunc == NULL)
54     {
55       /* System does not support hard links.  */
56       errno = EPERM;
57       return -1;
58     }
59   if (CreateHardLinkFunc (path2, path1, NULL) == 0)
60     {
61       /* It is not documented which errors CreateHardLink() can produce.
62        * The following conversions are based on tests on a Windows XP SP2
63        * system. */
64       DWORD err = GetLastError ();
65       switch (err)
66         {
67         case ERROR_ACCESS_DENIED:
68           errno = EACCES;
69           break;
70
71         case ERROR_INVALID_FUNCTION:    /* fs does not support hard links */
72           errno = EPERM;
73           break;
74
75         case ERROR_NOT_SAME_DEVICE:
76           errno = EXDEV;
77           break;
78
79         case ERROR_PATH_NOT_FOUND:
80         case ERROR_FILE_NOT_FOUND:
81           errno = ENOENT;
82           break;
83
84         case ERROR_INVALID_PARAMETER:
85           errno = ENAMETOOLONG;
86           break;
87
88         case ERROR_TOO_MANY_LINKS:
89           errno = EMLINK;
90           break;
91
92         case ERROR_ALREADY_EXISTS:
93           errno = EEXIST;
94           break;
95
96         default:
97           errno = EIO;
98         }
99       return -1;
100     }
101
102   return 0;
103 }
104
105 #else /* !Windows */
106
107 #error "This platform lacks a link function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib."
108
109 #endif /* !Windows */