(__hurd_path_lookup_retry): Don't handle FS_RETRY_NONE (it's gone).
[kopensolaris-gnu/glibc.git] / hurd / hurdlookup.c
1 /* Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
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>
20 #include <string.h>
21 #include <limits.h>
22 #include <fcntl.h>
23 #include "stdio/_itoa.h"
24 #include <hurd/term.h>
25
26
27 /* Translate the error from dir_pathtrans into the error the user sees.  */
28 static inline error_t
29 pathtrans_error (error_t error)
30 {
31   switch (error)
32     {
33     case EOPNOTSUPP:
34     case MIG_BAD_ID:
35       /* These indicate that the server does not understand dir_pathtrans
36          at all.  If it were a directory, it would, by definition.  */
37       return ENOTDIR;
38     default:
39       return error;
40     }
41 }
42
43 error_t
44 __hurd_path_lookup (file_t crdir, file_t cwdir,
45                     const char *path, int flags, mode_t mode,
46                     file_t *result)
47 {
48   error_t err;
49   enum retry_type doretry;
50   char retryname[1024];         /* XXX string_t LOSES! */
51   file_t startdir;
52
53   startdir = path[0] == '/' ? crdir : cwdir;
54
55   while (path[0] == '/')
56     path++;
57
58   if (err = __dir_pathtrans (startdir, path, flags, mode,
59                              &doretry, retryname, result))
60     return pathtrans_error (err);
61
62   return __hurd_path_lookup_retry (crdir, doretry, retryname, flags, mode,
63                                    result);
64 }
65
66 error_t
67 __hurd_path_lookup_retry (file_t crdir,
68                           enum retry_type doretry,
69                           char retryname[1024],
70                           int flags, mode_t mode,
71                           file_t *result)
72 {
73   error_t err;
74   file_t startdir;
75   file_t newpt;
76   char *path;
77   int dealloc_dir;
78   int nloops;
79
80   dealloc_dir = 0;
81   nloops = 0;
82   err = 0;
83   
84   while (1)
85     {
86       if (dealloc_dir)
87         __mach_port_deallocate (__mach_task_self (), startdir);
88       if (err)
89         return pathtrans_error (err);
90
91       switch (doretry)
92         {
93         case FS_RETRY_REAUTH:
94           {
95             mach_port_t ref = __mach_reply_port ();
96             err = __io_reauthenticate (*result,
97                                        ref, MACH_MSG_TYPE_MAKE_SEND_ONCE);
98             if (! err)
99               err = __USEPORT
100                 (AUTH, __auth_user_authenticate (port, *result,
101                                                  ref,
102                                                  MACH_MSG_TYPE_MAKE_SEND_ONCE,
103                                                  &newpt));
104             __mach_port_destroy (__mach_task_self (), ref);
105           }
106           __mach_port_deallocate (__mach_task_self (), *result);
107           if (err)
108             return err;
109           *result = newpt;
110           /* Fall through.  */
111
112         case FS_RETRY_NORMAL:
113 #ifdef SYMLOOP_MAX
114           if (nloops++ >= SYMLOOP_MAX)
115             return ELOOP;
116 #endif
117
118           /* An empty RETRYNAME indicates we have the final port.  */
119           if (retryname[0] == '\0')
120             {
121               /* We got a successful translation.  Now apply any open-time
122                  action flags we were passed.  */
123               if (flags & O_EXLOCK)
124                 ;               /* XXX */
125               if (!err && (flags & O_SHLOCK))
126                 ;               /* XXX */
127               if (!err && (flags & O_TRUNC))
128                 err = __file_truncate (*result, 0);
129
130               if (err)
131                 __mach_port_deallocate (__mach_task_self (), *result);
132               return err;
133             }
134
135           startdir = *result;
136           dealloc_dir = 1;
137           path = retryname;
138           break;
139
140         case FS_RETRY_MAGICAL:
141           switch (retryname[0])
142             {
143             case '/':
144               startdir = crdir;
145               dealloc_dir = 0;
146               if (*result != MACH_PORT_NULL)
147                 __mach_port_deallocate (__mach_task_self (), *result);
148               path = &retryname[1];
149               break;
150
151             case 'f':
152               if (retryname[1] == 'd' && retryname[2] == '/')
153                 {
154                   int fd;
155                   char *end;
156                   int save = errno;
157                   errno = 0;
158                   fd = (int) strtol (retryname, &end, 10);
159                   if (end == NULL || errno || /* Malformed number.  */
160                       /* Check for excess text after the number.  A slash
161                          is valid; it ends the component.  Anything else
162                          does not name a numeric file descriptor.  */
163                       (*end != '/' && *end != '\0'))
164                     {
165                       errno = save;
166                       return ENOENT;
167                     }
168                   *result = __getdport (fd);
169                   if (*result == MACH_PORT_NULL)
170                     {
171                       /* If the name was a proper number, but the file
172                          descriptor does not exist, we return EBADF instead
173                          of ENOENT.  */
174                       error_t err = errno;
175                       errno = save;
176                       return err;
177                     }
178                   errno = save;
179                   if (*end == '\0')
180                     return 0;
181                   else
182                     {
183                       /* Do a normal retry on the remaining components.  */
184                       startdir = *result;
185                       dealloc_dir = 1;
186                       path = end + 1; /* Skip the slash.  */
187                       break;
188                     }
189                 }
190               else
191                 goto bad_magic;
192               break;
193
194             case 'm':
195               if (retryname[1] == 'a' && retryname[2] == 'c' &&
196                   retryname[3] == 'h' && retryname[4] == 't' &&
197                   retryname[5] == 'y' && retryname[6] == 'p' &&
198                   retryname[7] == 'e')
199                 {
200                   error_t err;
201                   struct host_basic_info hostinfo;
202                   unsigned int hostinfocnt = HOST_BASIC_INFO_COUNT;
203                   char *p;
204                   if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO,
205                                          (int *) &hostinfo, &hostinfocnt))
206                     return err;
207                   if (hostinfocnt != HOST_BASIC_INFO_COUNT)
208                     return EGRATUITOUS;
209                   p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0);
210                   *--p = '/';
211                   p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0);
212                   if (p < retryname)
213                     abort ();   /* XXX write this right if this ever happens */
214                   if (p > retryname)
215                     strcpy (retryname, p);
216                   startdir = *result;
217                   dealloc_dir = 1;
218                 }
219               else
220                 goto bad_magic;
221               break;
222
223             case 't':
224               if (retryname[1] == 't' && retryname[2] == 'y')
225                 switch (retryname[3])
226                   {
227                     error_t opentty (file_t *result)
228                       {
229                         error_t err;
230                         file_t unauth;
231                         err = __USEPORT (CTTYID,
232                                          __termctty_open_terminal (port,
233                                                                    flags,
234                                                                    &unauth));
235                         if (! err)
236                           {
237                             mach_port_t ref = __mach_reply_port ();
238                             err = __io_reauthenticate
239                               (unauth,
240                                ref,
241                                MACH_MSG_TYPE_MAKE_SEND_ONCE);
242                             if (! err)
243                               err = __USEPORT
244                                 (AUTH, __auth_user_authenticate
245                                  (port,
246                                   unauth,
247                                   ref, MACH_MSG_TYPE_MAKE_SEND_ONCE,
248                                   result));
249                             __mach_port_deallocate (__mach_task_self (),
250                                                     unauth);
251                             __mach_port_destroy (__mach_task_self (), ref);
252                           }
253                         return err;
254                       }
255
256                   case '\0':
257                     return opentty (result);
258                   case '/':
259                     if (err = opentty (&startdir))
260                       return err;
261                     dealloc_dir = 1;
262                     strcpy (retryname, &retryname[4]);
263                     break;
264                   default:
265                     goto bad_magic;
266                   }
267               else
268                 goto bad_magic;
269               break;
270
271             default:
272             bad_magic:
273               return EGRATUITOUS;
274             }
275
276         default:
277           return EGRATUITOUS;
278         }
279
280       err = __dir_pathtrans (startdir, path, flags, mode,
281                              &doretry, retryname, result);
282     }
283 }
284
285 error_t
286 __hurd_path_split (file_t crdir, file_t cwdir,
287                    const char *path,
288                    file_t *dir, char **name)
289 {
290   const char *lastslash;
291   error_t err;
292   
293   /* Skip leading slashes in the pathname.  */
294   if (*path == '/')
295     {
296       while (*path == '/')
297         ++path;
298       --path;                   /* Leave on one slash.  */
299     }
300   
301   lastslash = strrchr (path, '/');
302   
303   if (lastslash != NULL)
304     {
305       if (lastslash == path)
306         {
307           /* "/foobar" => crdir + "foobar".  */
308           *name = (char *) path + 1;
309           if (err = __mach_port_mod_refs (__mach_task_self (), 
310                                           crdir, MACH_PORT_RIGHT_SEND, +1))
311             return err;
312           *dir = crdir;
313           return 0;
314         }
315       else
316         {
317           /* "/dir1/dir2/.../file".  */
318           char dirname[lastslash - path + 1];
319           memcpy (dirname, path, lastslash - path);
320           dirname[lastslash - path] = '\0';
321           *name = (char *) lastslash + 1;
322           return __hurd_path_lookup (crdir, cwdir, dirname, 0, 0, dir);
323         }
324     }
325   else
326     {
327       /* "foobar" => cwdir + "foobar".  */
328       *name = (char *) path;
329       if (err = __mach_port_mod_refs (__mach_task_self (),
330                                       cwdir, MACH_PORT_RIGHT_SEND, +1))
331         return err;
332       *dir = cwdir;
333       return 0;
334     }
335 }
336 \f
337 file_t
338 __path_lookup (const char *path, int flags, mode_t mode)
339 {
340   error_t err;
341   file_t result, crdir, cwdir;
342   struct hurd_userlink crdir_ulink, cwdir_ulink;
343
344   crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink);
345   cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink);
346
347   err = __hurd_path_lookup (crdir, cwdir, path, flags, mode, &result);
348
349   _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir);
350   _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir);
351
352   if (err)
353     {
354       errno = err;
355       return MACH_PORT_NULL;
356     }
357   else
358     return result;
359 }
360
361 file_t
362 __path_split (const char *path, char **name)
363 {
364   error_t err;
365   file_t dir, crdir, cwdir;
366   struct hurd_userlink crdir_ulink, cwdir_ulink;
367
368   crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink);
369   cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink);
370
371   err = __hurd_path_split (crdir, cwdir, path, &dir, name);
372
373   _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir);
374   _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir);
375
376   if (err)
377     {
378       errno = err;
379       return MACH_PORT_NULL;
380     }
381   else
382     return dir;
383 }