Mercurial > hg > octave-lojdl > gnulib-hg
annotate lib/link.c @ 17476:6057744acd2c default tip master
autoupdate
author | Karl Berry <karl@freefriends.org> |
---|---|
date | Fri, 16 Aug 2013 06:32:22 -0700 |
parents | e542fd46ad6f |
children |
rev | line source |
---|---|
11041 | 1 /* Emulate link on platforms that lack it, namely native Windows platforms. |
2 | |
17249
e542fd46ad6f
maint: update all copyright year number ranges
Eric Blake <eblake@redhat.com>
parents:
16366
diff
changeset
|
3 Copyright (C) 2009-2013 Free Software Foundation, Inc. |
11041 | 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 | |
16366
bb182ee4a09d
maint: replace FSF snail-mail addresses with URLs
Paul Eggert <eggert@cs.ucla.edu>
parents:
16201
diff
changeset
|
16 along with this program; if not, see <http://www.gnu.org/licenses/>. */ |
11041 | 17 |
18 #include <config.h> | |
19 | |
20 #include <unistd.h> | |
21 | |
22 #include <errno.h> | |
11981 | 23 #include <stdlib.h> |
24 #include <string.h> | |
25 #include <sys/stat.h> | |
26 | |
27 #if !HAVE_LINK | |
28 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ | |
29 | |
30 # define WIN32_LEAN_AND_MEAN | |
31 # include <windows.h> | |
11041 | 32 |
11063
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
33 /* 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
|
34 typedef BOOL (WINAPI * CreateHardLinkFuncType) (LPCTSTR lpFileName, |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
35 LPCTSTR lpExistingFileName, |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
36 LPSECURITY_ATTRIBUTES lpSecurityAttributes); |
11063
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
37 static CreateHardLinkFuncType CreateHardLinkFunc = NULL; |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
38 static BOOL initialized = FALSE; |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
39 |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
40 static void |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
41 initialize (void) |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
42 { |
12086
1ef8293b6bbe
link: LoadLibrary is not needed.
Paolo Bonzini <bonzini@gnu.org>
parents:
12062
diff
changeset
|
43 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
|
44 if (kernel32 != NULL) |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
45 { |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
46 CreateHardLinkFunc = |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
47 (CreateHardLinkFuncType) GetProcAddress (kernel32, "CreateHardLinkA"); |
11063
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
48 } |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
49 initialized = TRUE; |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
50 } |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
51 |
11041 | 52 int |
11981 | 53 link (const char *file1, const char *file2) |
11041 | 54 { |
11981 | 55 char *dir; |
56 size_t len1 = strlen (file1); | |
57 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
|
58 if (!initialized) |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
59 initialize (); |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
60 if (CreateHardLinkFunc == NULL) |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
61 { |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
62 /* 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
|
63 errno = EPERM; |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
64 return -1; |
2921cdaa1164
Make the 'link' module link on Windows NT 4.
Bruno Haible <bruno@clisp.org>
parents:
11041
diff
changeset
|
65 } |
11981 | 66 /* Reject trailing slashes on non-directories; mingw does not |
67 support hard-linking directories. */ | |
68 if ((len1 && (file1[len1 - 1] == '/' || file1[len1 - 1] == '\\')) | |
69 || (len2 && (file2[len2 - 1] == '/' || file2[len2 - 1] == '\\'))) | |
70 { | |
71 struct stat st; | |
72 if (stat (file1, &st) == 0 && S_ISDIR (st.st_mode)) | |
73 errno = EPERM; | |
74 else | |
75 errno = ENOTDIR; | |
76 return -1; | |
77 } | |
78 /* CreateHardLink("b/.","a",NULL) creates file "b", so we must check | |
79 that dirname(file2) exists. */ | |
80 dir = strdup (file2); | |
81 if (!dir) | |
82 return -1; | |
83 { | |
84 struct stat st; | |
85 char *p = strchr (dir, '\0'); | |
86 while (dir < p && (*--p != '/' && *p != '\\')); | |
87 *p = '\0'; | |
88 if (p != dir && stat (dir, &st) == -1) | |
89 { | |
90 int saved_errno = errno; | |
91 free (dir); | |
92 errno = saved_errno; | |
93 return -1; | |
94 } | |
95 free (dir); | |
96 } | |
97 /* Now create the link. */ | |
98 if (CreateHardLinkFunc (file2, file1, NULL) == 0) | |
11041 | 99 { |
100 /* It is not documented which errors CreateHardLink() can produce. | |
101 * The following conversions are based on tests on a Windows XP SP2 | |
102 * system. */ | |
103 DWORD err = GetLastError (); | |
104 switch (err) | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
105 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
106 case ERROR_ACCESS_DENIED: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
107 errno = EACCES; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
108 break; |
11041 | 109 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
110 case ERROR_INVALID_FUNCTION: /* fs does not support hard links */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
111 errno = EPERM; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
112 break; |
11041 | 113 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
114 case ERROR_NOT_SAME_DEVICE: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
115 errno = EXDEV; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
116 break; |
11041 | 117 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
118 case ERROR_PATH_NOT_FOUND: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
119 case ERROR_FILE_NOT_FOUND: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
120 errno = ENOENT; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
121 break; |
11041 | 122 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
123 case ERROR_INVALID_PARAMETER: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
124 errno = ENAMETOOLONG; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
125 break; |
11041 | 126 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
127 case ERROR_TOO_MANY_LINKS: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
128 errno = EMLINK; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
129 break; |
11041 | 130 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
131 case ERROR_ALREADY_EXISTS: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
132 errno = EEXIST; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
133 break; |
11041 | 134 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
135 default: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
136 errno = EIO; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
137 } |
11041 | 138 return -1; |
139 } | |
140 | |
141 return 0; | |
142 } | |
143 | |
11981 | 144 # else /* !Windows */ |
145 | |
146 # error "This platform lacks a link function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib." | |
147 | |
148 # endif /* !Windows */ | |
149 #else /* HAVE_LINK */ | |
150 | |
151 # undef link | |
11041 | 152 |
11981 | 153 /* Create a hard link from FILE1 to FILE2, working around platform bugs. */ |
154 int | |
155 rpl_link (char const *file1, char const *file2) | |
156 { | |
15313
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
157 size_t len1; |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
158 size_t len2; |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
159 struct stat st; |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
160 |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
161 /* Don't allow IRIX to dereference dangling file2 symlink. */ |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
162 if (!lstat (file2, &st)) |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
163 { |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
164 errno = EEXIST; |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
165 return -1; |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
166 } |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
167 |
11981 | 168 /* Reject trailing slashes on non-directories. */ |
15313
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
169 len1 = strlen (file1); |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
170 len2 = strlen (file2); |
11981 | 171 if ((len1 && file1[len1 - 1] == '/') |
172 || (len2 && file2[len2 - 1] == '/')) | |
173 { | |
174 /* 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
|
175 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
|
176 (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
|
177 succeeds); if stat() succeeds, require a directory. */ |
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
178 if (stat (file1, &st)) |
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
179 return -1; |
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
180 if (!S_ISDIR (st.st_mode)) |
11981 | 181 { |
182 errno = ENOTDIR; | |
183 return -1; | |
184 } | |
185 } | |
186 else | |
187 { | |
188 /* Fix Cygwin 1.5.x bug where link("a","b/.") creates file "b". */ | |
189 char *dir = strdup (file2); | |
190 char *p; | |
191 if (!dir) | |
192 return -1; | |
193 /* We already know file2 does not end in slash. Strip off the | |
194 basename, then check that the dirname exists. */ | |
195 p = strrchr (dir, '/'); | |
196 if (p) | |
197 { | |
198 *p = '\0'; | |
199 if (stat (dir, &st) == -1) | |
200 { | |
201 int saved_errno = errno; | |
202 free (dir); | |
203 errno = saved_errno; | |
204 return -1; | |
205 } | |
206 } | |
207 free (dir); | |
208 } | |
209 return link (file1, file2); | |
210 } | |
211 #endif /* HAVE_LINK */ |