Mercurial > hg > octave-lojdl > gnulib-hg
annotate lib/link.c @ 16358:a712776b11ce
maint: spelling fixes
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Sun, 05 Feb 2012 13:42:03 -0800 |
parents | 8250f2777afc |
children | bb182ee4a09d |
rev | line source |
---|---|
11041 | 1 /* Emulate link on platforms that lack it, namely native Windows platforms. |
2 | |
16201
8250f2777afc
maint: update all copyright year number ranges
Jim Meyering <meyering@redhat.com>
parents:
15313
diff
changeset
|
3 Copyright (C) 2009-2012 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 | |
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, |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
36 LPCTSTR lpExistingFileName, |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
37 LPSECURITY_ATTRIBUTES lpSecurityAttributes); |
11063
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 = |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
48 (CreateHardLinkFuncType) GetProcAddress (kernel32, "CreateHardLinkA"); |
11063
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) | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
106 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
107 case ERROR_ACCESS_DENIED: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
108 errno = EACCES; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
109 break; |
11041 | 110 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
111 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
|
112 errno = EPERM; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
113 break; |
11041 | 114 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
115 case ERROR_NOT_SAME_DEVICE: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
116 errno = EXDEV; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
117 break; |
11041 | 118 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
119 case ERROR_PATH_NOT_FOUND: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
120 case ERROR_FILE_NOT_FOUND: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
121 errno = ENOENT; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
122 break; |
11041 | 123 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
124 case ERROR_INVALID_PARAMETER: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
125 errno = ENAMETOOLONG; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
126 break; |
11041 | 127 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
128 case ERROR_TOO_MANY_LINKS: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
129 errno = EMLINK; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
130 break; |
11041 | 131 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
132 case ERROR_ALREADY_EXISTS: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
133 errno = EEXIST; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
134 break; |
11041 | 135 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
136 default: |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
137 errno = EIO; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
12086
diff
changeset
|
138 } |
11041 | 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 { | |
15313
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
158 size_t len1; |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
159 size_t len2; |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
160 struct stat st; |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
161 |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
162 /* Don't allow IRIX to dereference dangling file2 symlink. */ |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
163 if (!lstat (file2, &st)) |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
164 { |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
165 errno = EEXIST; |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
166 return -1; |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
167 } |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
168 |
11981 | 169 /* Reject trailing slashes on non-directories. */ |
15313
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
170 len1 = strlen (file1); |
8dfa469e2ba8
link: work around IRIX bug
Eric Blake <eblake@redhat.com>
parents:
14079
diff
changeset
|
171 len2 = strlen (file2); |
11981 | 172 if ((len1 && file1[len1 - 1] == '/') |
173 || (len2 && file2[len2 - 1] == '/')) | |
174 { | |
175 /* 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
|
176 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
|
177 (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
|
178 succeeds); if stat() succeeds, require a directory. */ |
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
179 if (stat (file1, &st)) |
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
180 return -1; |
00e8f52bdef4
link: fix test failure on Solaris 9
Eric Blake <ebb9@byu.net>
parents:
11981
diff
changeset
|
181 if (!S_ISDIR (st.st_mode)) |
11981 | 182 { |
183 errno = ENOTDIR; | |
184 return -1; | |
185 } | |
186 } | |
187 else | |
188 { | |
189 /* Fix Cygwin 1.5.x bug where link("a","b/.") creates file "b". */ | |
190 char *dir = strdup (file2); | |
191 char *p; | |
192 if (!dir) | |
193 return -1; | |
194 /* We already know file2 does not end in slash. Strip off the | |
195 basename, then check that the dirname exists. */ | |
196 p = strrchr (dir, '/'); | |
197 if (p) | |
198 { | |
199 *p = '\0'; | |
200 if (stat (dir, &st) == -1) | |
201 { | |
202 int saved_errno = errno; | |
203 free (dir); | |
204 errno = saved_errno; | |
205 return -1; | |
206 } | |
207 } | |
208 free (dir); | |
209 } | |
210 return link (file1, file2); | |
211 } | |
212 #endif /* HAVE_LINK */ |