entered into RCS
[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
25 error_t
26 __hurd_path_lookup (file_t crdir, file_t cwdir,
27                     const char *path, int flags, mode_t mode,
28                     file_t *result)
29 {
30   error_t err;
31   enum retry_type doretry;
32   char retryname[1024];         /* XXX string_t LOSES! */
33   file_t startdir;
34
35   startdir = path[0] == '/' ? crdir : cwdir;
36
37   if (err = __dir_pathtrans (startdir, path, flags, mode,
38                              &doretry, retryname, result))
39     return err;
40
41   return __hurd_path_lookup_retry (crdir, doretry, retryname, flags, mode,
42                                    result);
43 }
44
45 error_t
46 __hurd_path_lookup_retry (file_t crdir,
47                           enum retry_type doretry,
48                           char retryname[1024],
49                           int flags, mode_t mode,
50                           file_t *result)
51 {
52   error_t err;
53   file_t startdir;
54   file_t newpt;
55   char *path;
56   int dealloc_dir;
57   int nloops;
58
59   dealloc_dir = 0;
60   nloops = 0;
61   
62   while (1)
63     {
64       if (dealloc_dir)
65         __mach_port_deallocate (__mach_task_self (), startdir);
66       if (err)
67         return err;
68
69       switch (doretry)
70         {
71         case FS_RETRY_NONE:
72           /* We got a successful translation.  Now apply any
73              open-time action flags we were passed.  */
74           if (flags & O_EXLOCK)
75             ;                   /* XXX */
76           if (!err && (flags & O_SHLOCK))
77             ;                   /* XXX */
78           if (!err && (flags & O_TRUNC))
79             err = __file_truncate (*result, 0);
80
81           if (err)
82             __mach_port_deallocate (__mach_task_self (), *result);
83           return err;
84           
85         case FS_RETRY_REAUTH:
86           err = __io_reauthenticate (*result, _hurd_pid);
87           if (! err)
88             err = __USEPORT (AUTH, __auth_user_authenticate (port, *result,
89                                                              _hurd_pid,
90                                                              &newpt));
91           __mach_port_deallocate (__mach_task_self (), *result);
92           if (err)
93             return err;
94           *result = newpt;
95           /* Fall through.  */
96
97         case FS_RETRY_NORMAL:
98 #ifdef SYMLOOP_MAX
99           if (nloops++ >= SYMLOOP_MAX)
100             return ELOOP;
101 #endif
102
103           startdir = *result;
104           dealloc_dir = 1;
105           path = retryname;
106           break;
107
108         case FS_RETRY_MAGICAL:
109           switch (retryname[0])
110             {
111             case '/':
112               startdir = crdir;
113               dealloc_dir = 0;
114               if (*result != MACH_PORT_NULL)
115                 __mach_port_deallocate (__mach_task_self (), *result);
116               path = &retryname[1];
117               break;
118
119             case 'f':
120               if (retryname[1] == 'd' && retryname[2] == '/')
121                 {
122                   int fd;
123                   char *end;
124                   int save = errno;
125                   errno = 0;
126                   fd = (int) strtol (retryname, &end, 10);
127                   if (end == NULL || errno)
128                     {
129                       errno = save;
130                       goto bad_magic;
131                     }
132                   *result = __getdport (fd);
133                   if (*result == MACH_PORT_NULL)
134                     {
135                       error_t err = errno;
136                       errno = save;
137                       return err;
138                     }
139                   errno = save;
140                   return 0;
141                 }
142               else
143                 goto bad_magic;
144               break;
145
146             case 'm':
147               if (retryname[1] == 'a' && retryname[2] == 'c' &&
148                   retryname[3] == 'h' && retryname[4] == 't' &&
149                   retryname[5] == 'y' && retryname[6] == 'p' &&
150                   retryname[7] == 'e')
151                 {
152                   error_t err;
153                   struct host_basic_info hostinfo;
154                   unsigned int hostinfocnt = HOST_BASIC_INFO_COUNT;
155                   char *p;
156                   if (err = __host_info (__mach_host_self (), HOST_BASIC_INFO,
157                                          (int *) &hostinfo, &hostinfocnt))
158                     return err;
159                   if (hostinfocnt != HOST_BASIC_INFO_COUNT)
160                     return EGRATUITOUS;
161                   p = _itoa (hostinfo.cpu_subtype, &retryname[8], 10, 0);
162                   *--p = '/';
163                   p = _itoa (hostinfo.cpu_type, &retryname[8], 10, 0);
164                   if (p < retryname)
165                     abort ();   /* XXX write this right if this ever happens */
166                   if (p > retryname)
167                     strcpy (retryname, p);
168                   startdir = *result;
169                   dealloc_dir = 1;
170                 }
171               else
172                 goto bad_magic;
173               break;
174
175             default:
176             bad_magic:
177               return EGRATUITOUS;
178             }
179
180         default:
181           return EGRATUITOUS;
182         }
183
184       err = __dir_pathtrans (startdir, path, flags, mode,
185                              &doretry, retryname, result);
186     }
187 }
188
189 error_t
190 __hurd_path_split (file_t crdir, file_t cwdir,
191                    const char *path,
192                    file_t *dir, char **name)
193 {
194   const char *lastslash;
195   error_t err;
196   
197   /* Skip leading slashes in the pathname.  */
198   if (*path == '/')
199     {
200       while (*path == '/')
201         ++path;
202       --path;                   /* Leave on one slash.  */
203     }
204   
205   lastslash = strrchr (path, '/');
206   
207   if (lastslash != NULL)
208     {
209       if (lastslash == path)
210         {
211           /* "/foobar" => crdir + "foobar".  */
212           *name = (char *) path + 1;
213           if (err = __mach_port_mod_refs (__mach_task_self (), 
214                                           crdir, MACH_PORT_RIGHT_SEND, +1))
215             return err;
216           *dir = crdir;
217           return 0;
218         }
219       else
220         {
221           /* "/dir1/dir2/.../file".  */
222           char dirname[lastslash - path + 1];
223           memcpy (dirname, path, lastslash - path);
224           dirname[lastslash - path] = '\0';
225           *name = (char *) lastslash + 1;
226           return __hurd_path_lookup (crdir, cwdir, dirname, 0, 0, dir);
227         }
228     }
229   else
230     {
231       /* "foobar" => cwdir + "foobar".  */
232       *name = (char *) path;
233       if (err = __mach_port_mod_refs (__mach_task_self (),
234                                       cwdir, MACH_PORT_RIGHT_SEND, +1))
235         return err;
236       *dir = cwdir;
237       return 0;
238     }
239 }
240 \f
241 file_t
242 __path_lookup (const char *path, int flags, mode_t mode)
243 {
244   error_t err;
245   file_t result, crdir, cwdir;
246   struct hurd_userlink crdir_ulink, cwdir_ulink;
247
248   crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink);
249   cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink);
250
251   err = __hurd_path_lookup (crdir, cwdir, path, flags, mode, &result);
252
253   _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir);
254   _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir);
255
256   if (err)
257     {
258       errno = err;
259       return MACH_PORT_NULL;
260     }
261   else
262     return result;
263 }
264
265 file_t
266 __path_split (const char *path, char **name)
267 {
268   error_t err;
269   file_t dir, crdir, cwdir;
270   struct hurd_userlink crdir_ulink, cwdir_ulink;
271
272   crdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink);
273   cwdir = _hurd_port_get (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink);
274
275   err = __hurd_path_split (crdir, cwdir, path, &dir, name);
276
277   _hurd_port_free (&_hurd_ports[INIT_PORT_CRDIR], &crdir_ulink, crdir);
278   _hurd_port_free (&_hurd_ports[INIT_PORT_CWDIR], &cwdir_ulink, cwdir);
279
280   if (err)
281     {
282       errno = err;
283       return MACH_PORT_NULL;
284     }
285   else
286     return dir;
287 }