]>
Commit | Line | Data |
---|---|---|
a500fbcd | 1 | /* Copyright (C) 1992,93,94,95,96,97,99,2001 Free Software Foundation, Inc. |
c84142e8 | 2 | This file is part of the GNU C Library. |
28f540f4 | 3 | |
c84142e8 | 4 | The GNU C Library is free software; you can redistribute it and/or |
41bdb6e2 AJ |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
28f540f4 | 8 | |
c84142e8 UD |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 12 | Lesser General Public License for more details. |
28f540f4 | 13 | |
41bdb6e2 AJ |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, write to the Free | |
16 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
17 | 02111-1307 USA. */ | |
28f540f4 RM |
18 | |
19 | #include <hurd.h> | |
2948fc64 | 20 | #include <hurd/lookup.h> |
28f540f4 | 21 | #include <string.h> |
28f540f4 | 22 | #include <fcntl.h> |
28f540f4 RM |
23 | |
24 | ||
25 | /* Translate the error from dir_lookup into the error the user sees. */ | |
26 | static inline error_t | |
27 | lookup_error (error_t error) | |
28 | { | |
29 | switch (error) | |
30 | { | |
31 | case EOPNOTSUPP: | |
32 | case MIG_BAD_ID: | |
33 | /* These indicate that the server does not understand dir_lookup | |
34 | at all. If it were a directory, it would, by definition. */ | |
35 | return ENOTDIR; | |
36 | default: | |
37 | return error; | |
38 | } | |
39 | } | |
40 | ||
41 | error_t | |
2948fc64 RM |
42 | __hurd_file_name_lookup (error_t (*use_init_port) |
43 | (int which, error_t (*operate) (file_t)), | |
44 | file_t (*get_dtable_port) (int fd), | |
92ea4fec MB |
45 | error_t (*lookup) |
46 | (file_t dir, char *name, int flags, mode_t mode, | |
47 | retry_type *do_retry, string_t retry_name, | |
48 | mach_port_t *result), | |
28f540f4 RM |
49 | const char *file_name, int flags, mode_t mode, |
50 | file_t *result) | |
51 | { | |
52 | error_t err; | |
53 | enum retry_type doretry; | |
54 | char retryname[1024]; /* XXX string_t LOSES! */ | |
791cfdb7 | 55 | int startport; |
28f540f4 | 56 | |
92ea4fec | 57 | error_t lookup_op (mach_port_t startdir) |
2948fc64 | 58 | { |
92ea4fec MB |
59 | return lookup_error ((*lookup) (startdir, file_name, flags, mode, |
60 | &doretry, retryname, result)); | |
2948fc64 | 61 | } |
28f540f4 | 62 | |
92ea4fec MB |
63 | if (! lookup) |
64 | lookup = __dir_lookup; | |
65 | ||
3220cade RM |
66 | if (file_name[0] == '\0') |
67 | return ENOENT; | |
68 | ||
791cfdb7 RM |
69 | startport = (file_name[0] == '/') ? INIT_PORT_CRDIR : INIT_PORT_CWDIR; |
70 | while (file_name[0] == '/') | |
71 | file_name++; | |
72 | ||
5c7665dc | 73 | if (flags & O_NOFOLLOW) /* See lookup-retry.c about O_NOFOLLOW. */ |
791cfdb7 RM |
74 | flags |= O_NOTRANS; |
75 | ||
76 | if (flags & O_DIRECTORY) | |
77 | { | |
78 | /* The caller wants to require that the file we look up is a directory. | |
79 | We can do this without an extra RPC by appending a trailing slash | |
80 | to the file name we look up. */ | |
81 | size_t len = strlen (file_name); | |
82 | if (len == 0) | |
83 | file_name = "/"; | |
84 | else if (file_name[len - 1] != '/') | |
85 | { | |
86 | char *n = alloca (len + 2); | |
87 | memcpy (n, file_name, len); | |
88 | n[len] = '/'; | |
89 | n[len + 1] = '\0'; | |
90 | file_name = n; | |
91 | } | |
92 | } | |
93 | ||
94 | err = (*use_init_port) (startport, &lookup_op); | |
2948fc64 | 95 | if (! err) |
791cfdb7 RM |
96 | err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port, |
97 | lookup, doretry, retryname, | |
98 | flags, mode, result); | |
28f540f4 | 99 | |
2948fc64 | 100 | return err; |
28f540f4 RM |
101 | } |
102 | weak_alias (__hurd_file_name_lookup, hurd_file_name_lookup) | |
103 | ||
28f540f4 | 104 | error_t |
2948fc64 RM |
105 | __hurd_file_name_split (error_t (*use_init_port) |
106 | (int which, error_t (*operate) (file_t)), | |
107 | file_t (*get_dtable_port) (int fd), | |
92ea4fec MB |
108 | error_t (*lookup) |
109 | (file_t dir, char *name, int flags, mode_t mode, | |
110 | retry_type *do_retry, string_t retry_name, | |
111 | mach_port_t *result), | |
28f540f4 RM |
112 | const char *file_name, |
113 | file_t *dir, char **name) | |
114 | { | |
2948fc64 RM |
115 | error_t addref (file_t crdir) |
116 | { | |
117 | *dir = crdir; | |
787e4db9 | 118 | return __mach_port_mod_refs (__mach_task_self (), |
2948fc64 RM |
119 | crdir, MACH_PORT_RIGHT_SEND, +1); |
120 | } | |
121 | ||
122 | const char *lastslash = strrchr (file_name, '/'); | |
28f540f4 | 123 | |
28f540f4 RM |
124 | if (lastslash != NULL) |
125 | { | |
126 | if (lastslash == file_name) | |
127 | { | |
128 | /* "/foobar" => crdir + "foobar". */ | |
129 | *name = (char *) file_name + 1; | |
2948fc64 | 130 | return (*use_init_port) (INIT_PORT_CRDIR, &addref); |
28f540f4 RM |
131 | } |
132 | else | |
133 | { | |
134 | /* "/dir1/dir2/.../file". */ | |
135 | char dirname[lastslash - file_name + 1]; | |
136 | memcpy (dirname, file_name, lastslash - file_name); | |
137 | dirname[lastslash - file_name] = '\0'; | |
138 | *name = (char *) lastslash + 1; | |
92ea4fec MB |
139 | return |
140 | __hurd_file_name_lookup (use_init_port, get_dtable_port, lookup, | |
141 | dirname, 0, 0, dir); | |
28f540f4 RM |
142 | } |
143 | } | |
144 | else | |
145 | { | |
146 | /* "foobar" => cwdir + "foobar". */ | |
147 | *name = (char *) file_name; | |
2948fc64 | 148 | return (*use_init_port) (INIT_PORT_CWDIR, &addref); |
28f540f4 RM |
149 | } |
150 | } | |
151 | weak_alias (__hurd_file_name_split, hurd_file_name_split) | |
152 | ||
0bd01927 RM |
153 | /* This is the same as hurd_file_name_split, except that it ignores |
154 | trailing slashes (so *NAME is never ""). */ | |
155 | error_t | |
156 | __hurd_directory_name_split (error_t (*use_init_port) | |
157 | (int which, error_t (*operate) (file_t)), | |
158 | file_t (*get_dtable_port) (int fd), | |
159 | error_t (*lookup) | |
160 | (file_t dir, char *name, int flags, mode_t mode, | |
161 | retry_type *do_retry, string_t retry_name, | |
162 | mach_port_t *result), | |
163 | const char *file_name, | |
164 | file_t *dir, char **name) | |
165 | { | |
166 | error_t addref (file_t crdir) | |
167 | { | |
168 | *dir = crdir; | |
169 | return __mach_port_mod_refs (__mach_task_self (), | |
170 | crdir, MACH_PORT_RIGHT_SEND, +1); | |
171 | } | |
172 | ||
173 | const char *lastslash = strrchr (file_name, '/'); | |
174 | ||
175 | if (lastslash != NULL && lastslash[1] == '\0') | |
176 | { | |
177 | /* Trailing slash doesn't count. Look back further. */ | |
178 | ||
179 | /* Back up over all trailing slashes. */ | |
180 | while (lastslash > file_name && *lastslash == '/') | |
181 | --lastslash; | |
182 | ||
183 | /* Find the last one earlier in the string, before the trailing ones. */ | |
184 | #if __GLIBC__ > 2 || __GLIBC_MINOR__ >= 2 | |
185 | lastslash = __memrchr (file_name, '/', lastslash - file_name); | |
186 | #else | |
187 | /* Keep backing up, looking for a slash. */ | |
188 | do | |
189 | if (lastslash == file_name) | |
190 | { | |
191 | /* Hit the start with no slash. */ | |
192 | lastslash = NULL; | |
193 | break; | |
194 | } | |
195 | while (*lastslash-- != '/'); | |
196 | #endif | |
197 | } | |
198 | ||
199 | if (lastslash != NULL) | |
200 | { | |
201 | if (lastslash == file_name) | |
202 | { | |
203 | /* "/foobar" => crdir + "foobar". */ | |
204 | *name = (char *) file_name + 1; | |
205 | return (*use_init_port) (INIT_PORT_CRDIR, &addref); | |
206 | } | |
207 | else | |
208 | { | |
209 | /* "/dir1/dir2/.../file". */ | |
210 | char dirname[lastslash - file_name + 1]; | |
211 | memcpy (dirname, file_name, lastslash - file_name); | |
212 | dirname[lastslash - file_name] = '\0'; | |
213 | *name = (char *) lastslash + 1; | |
214 | return | |
215 | __hurd_file_name_lookup (use_init_port, get_dtable_port, lookup, | |
216 | dirname, 0, 0, dir); | |
217 | } | |
218 | } | |
219 | else | |
220 | { | |
221 | /* "foobar" => cwdir + "foobar". */ | |
222 | *name = (char *) file_name; | |
223 | return (*use_init_port) (INIT_PORT_CWDIR, &addref); | |
224 | } | |
225 | } | |
226 | weak_alias (__hurd_directory_name_split, hurd_directory_name_split) | |
227 | ||
28f540f4 RM |
228 | \f |
229 | file_t | |
230 | __file_name_lookup (const char *file_name, int flags, mode_t mode) | |
231 | { | |
232 | error_t err; | |
2948fc64 | 233 | file_t result; |
28f540f4 | 234 | |
92ea4fec | 235 | err = __hurd_file_name_lookup (&_hurd_ports_use, &__getdport, 0, |
dc825f85 | 236 | file_name, flags, mode & ~_hurd_umask, |
28f540f4 RM |
237 | &result); |
238 | ||
2948fc64 | 239 | return err ? (__hurd_fail (err), MACH_PORT_NULL) : result; |
28f540f4 RM |
240 | } |
241 | weak_alias (__file_name_lookup, file_name_lookup) | |
242 | ||
243 | ||
244 | file_t | |
245 | __file_name_split (const char *file_name, char **name) | |
246 | { | |
247 | error_t err; | |
2948fc64 RM |
248 | file_t result; |
249 | ||
92ea4fec | 250 | err = __hurd_file_name_split (&_hurd_ports_use, &__getdport, 0, |
2948fc64 | 251 | file_name, &result, name); |
28f540f4 | 252 | |
2948fc64 RM |
253 | return err ? (__hurd_fail (err), MACH_PORT_NULL) : result; |
254 | } | |
255 | weak_alias (__file_name_split, file_name_split) | |
28f540f4 | 256 | |
0bd01927 RM |
257 | file_t |
258 | __directory_name_split (const char *directory_name, char **name) | |
259 | { | |
260 | error_t err; | |
261 | file_t result; | |
262 | ||
263 | err = __hurd_directory_name_split (&_hurd_ports_use, &__getdport, 0, | |
264 | directory_name, &result, name); | |
265 | ||
266 | return err ? (__hurd_fail (err), MACH_PORT_NULL) : result; | |
267 | } | |
268 | weak_alias (__directory_name_split, directory_name_split) | |
269 | ||
28f540f4 | 270 | |
2948fc64 RM |
271 | file_t |
272 | __file_name_lookup_under (file_t startdir, | |
273 | const char *file_name, int flags, mode_t mode) | |
274 | { | |
275 | error_t err; | |
276 | file_t result; | |
28f540f4 | 277 | |
2948fc64 | 278 | error_t use_init_port (int which, error_t (*operate) (mach_port_t)) |
28f540f4 | 279 | { |
2948fc64 RM |
280 | return (which == INIT_PORT_CWDIR ? (*operate) (startdir) : |
281 | _hurd_ports_use (which, operate)); | |
28f540f4 | 282 | } |
2948fc64 | 283 | |
92ea4fec | 284 | err = __hurd_file_name_lookup (&use_init_port, &__getdport, 0, |
dc825f85 | 285 | file_name, flags, mode & ~_hurd_umask, |
2948fc64 RM |
286 | &result); |
287 | ||
288 | return err ? (__hurd_fail (err), MACH_PORT_NULL) : result; | |
28f540f4 | 289 | } |
2948fc64 | 290 | weak_alias (__file_name_lookup_under, file_name_lookup_under) |