Mercurial > hg > octave-lojdl > gnulib-hg
annotate lib/link.c @ 12086:1ef8293b6bbe
link: LoadLibrary is not needed.
* lib/link.c: Use GetModuleHandle.
author | Paolo Bonzini <bonzini@gnu.org> |
---|---|
date | Fri, 02 Oct 2009 03:04:16 +0200 |
parents | 00e8f52bdef4 |
children | e8d2c6fc33ad |
rev | line source |
---|---|
11041 | 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 #include <unistd.h> | |
22 | |
23 #include <errno.h> | |
11981 | 24 #include <stdlib.h> |
25 #include <string.h> | |
26 #include <sys/stat.h> | |
27 | |
28 #if !HAVE_LINK | |
29 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ | |
30 | |
31 # define WIN32_LEAN_AND_MEAN | |
32 # include <windows.h> | |
11041 | 33 |
11063
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
34 /* CreateHardLink was introduced only in Windows 2000. */ |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
35 typedef BOOL (WINAPI * CreateHardLinkFuncType) (LPCTSTR lpFileName, |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
36 LPCTSTR lpExistingFileName, |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
37 LPSECURITY_ATTRIBUTES lpSecurityAttributes); |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
38 static CreateHardLinkFuncType CreateHardLinkFunc = NULL; |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
39 static BOOL initialized = FALSE; |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
40 |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
41 static void |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
42 initialize (void) |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
43 { |
12086
1ef8293b6bbe
link: LoadLibrary is not needed.
Paolo Bonzini <bonzini@gnu.org>
parents:
12062
diff
changeset
|
44 HMODULE kernel32 = GetModuleHandle ("kernel32.dll"); |
11063
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
45 if (kernel32 != NULL) |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
46 { |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
47 CreateHardLinkFunc = |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
48 (CreateHardLinkFuncType) GetProcAddress (kernel32, "CreateHardLinkA"); |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
49 } |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
50 initialized = TRUE; |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
51 } |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
52 |
11041 | 53 int |
11981 | 54 link (const char *file1, const char *file2) |
11041 | 55 { |
11981 | 56 char *dir; |
57 size_t len1 = strlen (file1); | |
58 size_t len2 = strlen (file2); | |
11063
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
59 if (!initialized) |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
60 initialize (); |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
61 if (CreateHardLinkFunc == NULL) |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
62 { |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
63 /* System does not support hard links. */ |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
64 errno = EPERM; |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
65 return -1; |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
66 } |
11981 | 67 /* Reject trailing slashes on non-directories; mingw does not |
68 support hard-linking directories. */ | |
69 if ((len1 && (file1[len1 - 1] == '/' || file1[len1 - 1] == '\\')) | |
70 || (len2 && (file2[len2 - 1] == '/' || file2[len2 - 1] == '\\'))) | |
71 { | |
72 struct stat st; | |
73 if (stat (file1, &st) == 0 && S_ISDIR (st.st_mode)) | |
74 errno = EPERM; | |
75 else | |
76 errno = ENOTDIR; | |
77 return -1; | |
78 } | |
79 /* CreateHardLink("b/.","a",NULL) creates file "b", so we must check | |
80 that dirname(file2) exists. */ | |
81 dir = strdup (file2); | |
82 if (!dir) | |
83 return -1; | |
84 { | |
85 struct stat st; | |
86 char *p = strchr (dir, '\0'); | |
87 while (dir < p && (*--p != '/' && *p != '\\')); | |
88 *p = '\0'; | |
89 if (p != dir && stat (dir, &st) == -1) | |
90 { | |
91 int saved_errno = errno; | |
92 free (dir); | |
93 errno = saved_errno; | |
94 return -1; | |
95 } | |
96 free (dir); | |
97 } | |
98 /* Now create the link. */ | |
99 if (CreateHardLinkFunc (file2, file1, NULL) == 0) | |
11041 | 100 { |
101 /* It is not documented which errors CreateHardLink() can produce. | |
102 * The following conversions are based on tests on a Windows XP SP2 | |
103 * system. */ | |
104 DWORD err = GetLastError (); | |
105 switch (err) | |
106 { | |
107 case ERROR_ACCESS_DENIED: | |
108 errno = EACCES; | |
109 break; | |
110 | |
111 case ERROR_INVALID_FUNCTION: /* fs does not support hard links */ | |
112 errno = EPERM; | |
113 break; | |
114 | |
115 case ERROR_NOT_SAME_DEVICE: | |
116 errno = EXDEV; | |
117 break; | |
118 | |
119 case ERROR_PATH_NOT_FOUND: | |
120 case ERROR_FILE_NOT_FOUND: | |
121 errno = ENOENT; | |
122 break; | |
123 | |
124 case ERROR_INVALID_PARAMETER: | |
125 errno = ENAMETOOLONG; | |
126 break; | |
127 | |
128 case ERROR_TOO_MANY_LINKS: | |
129 errno = EMLINK; | |
130 break; | |
131 | |
132 case ERROR_ALREADY_EXISTS: | |
133 errno = EEXIST; | |
134 break; | |
135 | |
136 default: | |
137 errno = EIO; | |
138 } | |
139 return -1; | |
140 } | |
141 | |
142 return 0; | |
143 } | |
144 | |
11981 | 145 # else /* !Windows */ |
146 | |
147 # error "This platform lacks a link function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib." | |
148 | |
149 # endif /* !Windows */ | |
150 #else /* HAVE_LINK */ | |
151 | |
152 # undef link | |
11041 | 153 |
11981 | 154 /* Create a hard link from FILE1 to FILE2, working around platform bugs. */ |
155 int | |
156 rpl_link (char const *file1, char const *file2) | |
157 { | |
158 /* Reject trailing slashes on non-directories. */ | |
159 size_t len1 = strlen (file1); | |
160 size_t len2 = strlen (file2); | |
161 if ((len1 && file1[len1 - 1] == '/') | |
162 || (len2 && file2[len2 - 1] == '/')) | |
163 { | |
164 /* Let link() decide whether hard-linking directories is legal. | |
12062
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
165 If stat() fails, then link() should fail for the same reason |
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
166 (although on Solaris 9, link("file/","oops") mistakenly |
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
167 succeeds); if stat() succeeds, require a directory. */ |
11981 | 168 struct stat st; |
12062
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
169 if (stat (file1, &st)) |
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
170 return -1; |
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
171 if (!S_ISDIR (st.st_mode)) |
11981 | 172 { |
173 errno = ENOTDIR; | |
174 return -1; | |
175 } | |
176 } | |
177 else | |
178 { | |
179 /* Fix Cygwin 1.5.x bug where link("a","b/.") creates file "b". */ | |
180 char *dir = strdup (file2); | |
181 struct stat st; | |
182 char *p; | |
183 if (!dir) | |
184 return -1; | |
185 /* We already know file2 does not end in slash. Strip off the | |
186 basename, then check that the dirname exists. */ | |
187 p = strrchr (dir, '/'); | |
188 if (p) | |
189 { | |
190 *p = '\0'; | |
191 if (stat (dir, &st) == -1) | |
192 { | |
193 int saved_errno = errno; | |
194 free (dir); | |
195 errno = saved_errno; | |
196 return -1; | |
197 } | |
198 } | |
199 free (dir); | |
200 } | |
201 return link (file1, file2); | |
202 } | |
203 #endif /* HAVE_LINK */ |