]>
Commit | Line | Data |
---|---|---|
dc825f85 | 1 | /* Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. |
28f540f4 RM |
2 | This file is part of the GNU C Library. |
3 | ||
4 | The GNU C Library is free software; you can redistribute it and/or | |
5 | modify it under the terms of the GNU Library General Public License as | |
6 | published by the Free Software Foundation; either version 2 of the | |
7 | License, or (at your option) any later version. | |
8 | ||
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 | |
12 | Library General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU Library General Public | |
15 | License along with the GNU C Library; see the file COPYING.LIB. If | |
16 | not, write to the Free Software Foundation, Inc., 675 Mass Ave, | |
17 | Cambridge, MA 02139, USA. */ | |
18 | ||
19 | #include <hurd.h> | |
2948fc64 | 20 | #include <hurd/lookup.h> |
28f540f4 RM |
21 | #include <string.h> |
22 | #include <limits.h> | |
23 | #include <fcntl.h> | |
cabcc273 | 24 | #include "stdio-common/_itoa.h" |
28f540f4 RM |
25 | #include <hurd/term.h> |
26 | ||
27 | ||
28 | /* Translate the error from dir_lookup into the error the user sees. */ | |
29 | static inline error_t | |
30 | lookup_error (error_t error) | |
31 | { | |
32 | switch (error) | |
33 | { | |
34 | case EOPNOTSUPP: | |
35 | case MIG_BAD_ID: | |
36 | /* These indicate that the server does not understand dir_lookup | |
37 | at all. If it were a directory, it would, by definition. */ | |
38 | return ENOTDIR; | |
39 | default: | |
40 | return error; | |
41 | } | |
42 | } | |
43 | ||
44 | error_t | |
2948fc64 RM |
45 | __hurd_file_name_lookup (error_t (*use_init_port) |
46 | (int which, error_t (*operate) (file_t)), | |
47 | file_t (*get_dtable_port) (int fd), | |
92ea4fec MB |
48 | error_t (*lookup) |
49 | (file_t dir, char *name, int flags, mode_t mode, | |
50 | retry_type *do_retry, string_t retry_name, | |
51 | mach_port_t *result), | |
28f540f4 RM |
52 | const char *file_name, int flags, mode_t mode, |
53 | file_t *result) | |
54 | { | |
55 | error_t err; | |
56 | enum retry_type doretry; | |
57 | char retryname[1024]; /* XXX string_t LOSES! */ | |
28f540f4 | 58 | |
92ea4fec | 59 | error_t lookup_op (mach_port_t startdir) |
2948fc64 RM |
60 | { |
61 | while (file_name[0] == '/') | |
62 | file_name++; | |
28f540f4 | 63 | |
92ea4fec MB |
64 | return lookup_error ((*lookup) (startdir, file_name, flags, mode, |
65 | &doretry, retryname, result)); | |
2948fc64 | 66 | } |
28f540f4 | 67 | |
92ea4fec MB |
68 | if (! lookup) |
69 | lookup = __dir_lookup; | |
70 | ||
2948fc64 RM |
71 | err = (*use_init_port) (file_name[0] == '/' |
72 | ? INIT_PORT_CRDIR : INIT_PORT_CWDIR, | |
92ea4fec | 73 | &lookup_op); |
2948fc64 | 74 | if (! err) |
92ea4fec | 75 | err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port, lookup, |
2948fc64 RM |
76 | doretry, retryname, flags, mode, |
77 | result); | |
28f540f4 | 78 | |
2948fc64 | 79 | return err; |
28f540f4 RM |
80 | } |
81 | weak_alias (__hurd_file_name_lookup, hurd_file_name_lookup) | |
82 | ||
83 | error_t | |
2948fc64 RM |
84 | __hurd_file_name_lookup_retry (error_t (*use_init_port) |
85 | (int which, error_t (*operate) (file_t)), | |
86 | file_t (*get_dtable_port) (int fd), | |
92ea4fec MB |
87 | error_t (*lookup) |
88 | (file_t dir, char *name, int flags, mode_t mode, | |
89 | retry_type *do_retry, string_t retry_name, | |
90 | mach_port_t *result), | |
28f540f4 RM |
91 | enum retry_type doretry, |
92 | char retryname[1024], | |
93 | int flags, mode_t mode, | |
94 | file_t *result) | |
95 | { | |
96 | error_t err; | |
28f540f4 | 97 | char *file_name; |
28f540f4 RM |
98 | int nloops; |
99 | ||
92ea4fec | 100 | error_t lookup_op (file_t startdir) |
2948fc64 RM |
101 | { |
102 | while (file_name[0] == '/') | |
103 | file_name++; | |
104 | ||
92ea4fec MB |
105 | return lookup_error ((*lookup) (startdir, file_name, flags, mode, |
106 | &doretry, retryname, result)); | |
2948fc64 RM |
107 | } |
108 | error_t reauthenticate (file_t unauth) | |
109 | { | |
110 | error_t err; | |
111 | mach_port_t ref = __mach_reply_port (); | |
112 | error_t reauth (auth_t auth) | |
113 | { | |
8f0c527e | 114 | return __auth_user_authenticate (auth, ref, |
2948fc64 RM |
115 | MACH_MSG_TYPE_MAKE_SEND, |
116 | result); | |
117 | } | |
118 | err = __io_reauthenticate (unauth, ref, MACH_MSG_TYPE_MAKE_SEND); | |
119 | if (! err) | |
120 | err = (*use_init_port) (INIT_PORT_AUTH, &reauth); | |
121 | __mach_port_destroy (__mach_task_self (), ref); | |
122 | __mach_port_deallocate (__mach_task_self (), unauth); | |
123 | return err; | |
124 | } | |
125 | ||
92ea4fec MB |
126 | if (! lookup) |
127 | lookup = __dir_lookup; | |
128 | ||
28f540f4 RM |
129 | nloops = 0; |
130 | err = 0; | |
2948fc64 | 131 | do |
28f540f4 | 132 | { |
2948fc64 RM |
133 | file_t startdir = MACH_PORT_NULL; |
134 | int dirport = INIT_PORT_CWDIR; | |
28f540f4 RM |
135 | |
136 | switch (doretry) | |
137 | { | |
138 | case FS_RETRY_REAUTH: | |
2948fc64 | 139 | if (err = reauthenticate (*result)) |
28f540f4 | 140 | return err; |
28f540f4 RM |
141 | /* Fall through. */ |
142 | ||
143 | case FS_RETRY_NORMAL: | |
144 | #ifdef SYMLOOP_MAX | |
145 | if (nloops++ >= SYMLOOP_MAX) | |
146 | return ELOOP; | |
147 | #endif | |
148 | ||
149 | /* An empty RETRYNAME indicates we have the final port. */ | |
4ca84cff RM |
150 | if (retryname[0] == '\0' && |
151 | /* If reauth'd, we must do one more retry on "" to give the new | |
152 | translator a chance to make a new port for us. */ | |
153 | doretry == FS_RETRY_NORMAL) | |
28f540f4 RM |
154 | { |
155 | /* We got a successful translation. Now apply any open-time | |
156 | action flags we were passed. */ | |
157 | if (flags & O_EXLOCK) | |
158 | ; /* XXX */ | |
159 | if (!err && (flags & O_SHLOCK)) | |
160 | ; /* XXX */ | |
161 | if (!err && (flags & O_TRUNC)) | |
aa910907 | 162 | err = __file_set_size (*result, 0); |
28f540f4 RM |
163 | |
164 | if (err) | |
165 | __mach_port_deallocate (__mach_task_self (), *result); | |
166 | return err; | |
167 | } | |
168 | ||
169 | startdir = *result; | |
28f540f4 RM |
170 | file_name = retryname; |
171 | break; | |
172 | ||
173 | case FS_RETRY_MAGICAL: | |
174 | switch (retryname[0]) | |
175 | { | |
176 | case '/': | |
2948fc64 | 177 | dirport = INIT_PORT_CRDIR; |
28f540f4 RM |
178 | if (*result != MACH_PORT_NULL) |
179 | __mach_port_deallocate (__mach_task_self (), *result); | |
180 | file_name = &retryname[1]; | |
181 | break; | |
182 | ||
183 | case 'f': | |
184 | if (retryname[1] == 'd' && retryname[2] == '/') | |
185 | { | |
186 | int fd; | |
187 | char *end; | |
188 | int save = errno; | |
189 | errno = 0; | |
4d049a8b | 190 | fd = (int) strtol (&retryname[3], &end, 10); |
28f540f4 RM |
191 | if (end == NULL || errno || /* Malformed number. */ |
192 | /* Check for excess text after the number. A slash | |
193 | is valid; it ends the component. Anything else | |
194 | does not name a numeric file descriptor. */ | |
195 | (*end != '/' && *end != '\0')) | |
196 | { | |
197 | errno = save; | |
198 | return ENOENT; | |
199 | } | |
2948fc64 RM |
200 | if (! get_dtable_port) |
201 | err = EGRATUITOUS; | |
202 | else | |
28f540f4 | 203 | { |
2948fc64 RM |
204 | *result = (*get_dtable_port) (fd); |
205 | if (*result == MACH_PORT_NULL) | |
206 | { | |
207 | /* If the name was a proper number, but the file | |
208 | descriptor does not exist, we return EBADF instead | |
209 | of ENOENT. */ | |
210 | err = errno; | |
211 | errno = save; | |
212 | } | |
28f540f4 RM |
213 | } |
214 | errno = save; | |
2948fc64 RM |
215 | if (err) |
216 | return err; | |
28f540f4 RM |
217 | if (*end == '\0') |
218 | return 0; | |
219 | else | |
220 | { | |
221 | /* Do a normal retry on the remaining components. */ | |
222 | startdir = *result; | |
28f540f4 RM |
223 | file_name = end + 1; /* Skip the slash. */ |
224 | break; | |
225 | } | |
226 | } | |
227 | else | |
228 | goto bad_magic; | |
229 | break; | |
230 | ||
231 | case 'm': | |
232 | if (retryname[1] == 'a' && retryname[2] == 'c' && | |
233 | retryname[3] == 'h' && retryname[4] == 't' && | |
234 | retryname[5] == 'y' && retryname[6] == 'p' && | |
235 | retryname[7] == 'e') | |
236 | { | |
237 | error_t err; | |
238 | struct host_basic_info hostinfo; | |
239 | mach_msg_type_number_t hostinfocnt = HOST_BASIC_INFO_COUNT; | |
240 | char *p; | |
2948fc64 | 241 | /* XXX want client's host */ |
28f540f4 RM |
242 | if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO, |
243 | (natural_t *) &hostinfo, | |
244 | &hostinfocnt)) | |
245 | return err; | |
246 | if (hostinfocnt != HOST_BASIC_INFO_COUNT) | |
247 | return EGRATUITOUS; | |
248 | p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0); | |
249 | *--p = '/'; | |
250 | p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0); | |
251 | if (p < retryname) | |
252 | abort (); /* XXX write this right if this ever happens */ | |
253 | if (p > retryname) | |
254 | strcpy (retryname, p); | |
255 | startdir = *result; | |
28f540f4 RM |
256 | } |
257 | else | |
258 | goto bad_magic; | |
259 | break; | |
260 | ||
261 | case 't': | |
262 | if (retryname[1] == 't' && retryname[2] == 'y') | |
263 | switch (retryname[3]) | |
264 | { | |
265 | error_t opentty (file_t *result) | |
266 | { | |
267 | error_t err; | |
2948fc64 | 268 | error_t ctty_open (file_t port) |
28f540f4 | 269 | { |
787e4db9 RM |
270 | if (port == MACH_PORT_NULL) |
271 | return ENXIO; /* No controlling terminal. */ | |
2948fc64 RM |
272 | return __termctty_open_terminal (port, |
273 | flags, | |
274 | result); | |
28f540f4 | 275 | } |
2948fc64 RM |
276 | err = (*use_init_port) (INIT_PORT_CTTYID, &ctty_open); |
277 | if (! err) | |
278 | err = reauthenticate (*result); | |
28f540f4 RM |
279 | return err; |
280 | } | |
281 | ||
282 | case '\0': | |
283 | return opentty (result); | |
284 | case '/': | |
285 | if (err = opentty (&startdir)) | |
286 | return err; | |
28f540f4 RM |
287 | strcpy (retryname, &retryname[4]); |
288 | break; | |
289 | default: | |
290 | goto bad_magic; | |
291 | } | |
292 | else | |
293 | goto bad_magic; | |
294 | break; | |
295 | ||
296 | default: | |
297 | bad_magic: | |
298 | return EGRATUITOUS; | |
299 | } | |
787e4db9 | 300 | break; |
28f540f4 RM |
301 | |
302 | default: | |
303 | return EGRATUITOUS; | |
304 | } | |
305 | ||
2948fc64 RM |
306 | if (startdir != MACH_PORT_NULL) |
307 | { | |
92ea4fec | 308 | err = lookup_op (startdir); |
2948fc64 RM |
309 | __mach_port_deallocate (__mach_task_self (), startdir); |
310 | startdir = MACH_PORT_NULL; | |
311 | } | |
312 | else | |
92ea4fec | 313 | err = (*use_init_port) (dirport, &lookup_op); |
2948fc64 RM |
314 | } while (! err); |
315 | ||
316 | return err; | |
28f540f4 RM |
317 | } |
318 | weak_alias (__hurd_file_name_lookup_retry, hurd_file_name_lookup_retry) | |
319 | ||
320 | error_t | |
2948fc64 RM |
321 | __hurd_file_name_split (error_t (*use_init_port) |
322 | (int which, error_t (*operate) (file_t)), | |
323 | file_t (*get_dtable_port) (int fd), | |
92ea4fec MB |
324 | error_t (*lookup) |
325 | (file_t dir, char *name, int flags, mode_t mode, | |
326 | retry_type *do_retry, string_t retry_name, | |
327 | mach_port_t *result), | |
28f540f4 RM |
328 | const char *file_name, |
329 | file_t *dir, char **name) | |
330 | { | |
2948fc64 RM |
331 | error_t addref (file_t crdir) |
332 | { | |
333 | *dir = crdir; | |
787e4db9 | 334 | return __mach_port_mod_refs (__mach_task_self (), |
2948fc64 RM |
335 | crdir, MACH_PORT_RIGHT_SEND, +1); |
336 | } | |
337 | ||
338 | const char *lastslash = strrchr (file_name, '/'); | |
28f540f4 | 339 | |
28f540f4 RM |
340 | if (lastslash != NULL) |
341 | { | |
342 | if (lastslash == file_name) | |
343 | { | |
344 | /* "/foobar" => crdir + "foobar". */ | |
345 | *name = (char *) file_name + 1; | |
2948fc64 | 346 | return (*use_init_port) (INIT_PORT_CRDIR, &addref); |
28f540f4 RM |
347 | } |
348 | else | |
349 | { | |
350 | /* "/dir1/dir2/.../file". */ | |
351 | char dirname[lastslash - file_name + 1]; | |
352 | memcpy (dirname, file_name, lastslash - file_name); | |
353 | dirname[lastslash - file_name] = '\0'; | |
354 | *name = (char *) lastslash + 1; | |
92ea4fec MB |
355 | return |
356 | __hurd_file_name_lookup (use_init_port, get_dtable_port, lookup, | |
357 | dirname, 0, 0, dir); | |
28f540f4 RM |
358 | } |
359 | } | |
360 | else | |
361 | { | |
362 | /* "foobar" => cwdir + "foobar". */ | |
363 | *name = (char *) file_name; | |
2948fc64 | 364 | return (*use_init_port) (INIT_PORT_CWDIR, &addref); |
28f540f4 RM |
365 | } |
366 | } | |
367 | weak_alias (__hurd_file_name_split, hurd_file_name_split) | |
368 | ||
369 | \f | |
370 | file_t | |
371 | __file_name_lookup (const char *file_name, int flags, mode_t mode) | |
372 | { | |
373 | error_t err; | |
2948fc64 | 374 | file_t result; |
28f540f4 | 375 | |
92ea4fec | 376 | err = __hurd_file_name_lookup (&_hurd_ports_use, &__getdport, 0, |
dc825f85 | 377 | file_name, flags, mode & ~_hurd_umask, |
28f540f4 RM |
378 | &result); |
379 | ||
2948fc64 | 380 | return err ? (__hurd_fail (err), MACH_PORT_NULL) : result; |
28f540f4 RM |
381 | } |
382 | weak_alias (__file_name_lookup, file_name_lookup) | |
383 | ||
384 | ||
385 | file_t | |
386 | __file_name_split (const char *file_name, char **name) | |
387 | { | |
388 | error_t err; | |
2948fc64 RM |
389 | file_t result; |
390 | ||
92ea4fec | 391 | err = __hurd_file_name_split (&_hurd_ports_use, &__getdport, 0, |
2948fc64 | 392 | file_name, &result, name); |
28f540f4 | 393 | |
2948fc64 RM |
394 | return err ? (__hurd_fail (err), MACH_PORT_NULL) : result; |
395 | } | |
396 | weak_alias (__file_name_split, file_name_split) | |
28f540f4 | 397 | |
28f540f4 | 398 | |
2948fc64 RM |
399 | file_t |
400 | __file_name_lookup_under (file_t startdir, | |
401 | const char *file_name, int flags, mode_t mode) | |
402 | { | |
403 | error_t err; | |
404 | file_t result; | |
28f540f4 | 405 | |
2948fc64 | 406 | error_t use_init_port (int which, error_t (*operate) (mach_port_t)) |
28f540f4 | 407 | { |
2948fc64 RM |
408 | return (which == INIT_PORT_CWDIR ? (*operate) (startdir) : |
409 | _hurd_ports_use (which, operate)); | |
28f540f4 | 410 | } |
2948fc64 | 411 | |
92ea4fec | 412 | err = __hurd_file_name_lookup (&use_init_port, &__getdport, 0, |
dc825f85 | 413 | file_name, flags, mode & ~_hurd_umask, |
2948fc64 RM |
414 | &result); |
415 | ||
416 | return err ? (__hurd_fail (err), MACH_PORT_NULL) : result; | |
28f540f4 | 417 | } |
2948fc64 | 418 | weak_alias (__file_name_lookup_under, file_name_lookup_under) |