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