2001-06-18 Roland McGrath <roland@frob.com>
[kopensolaris-gnu/glibc.git] / hurd / hurdlookup.c
1 /* Copyright (C) 1992,93,94,95,96,97,99,2001 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 not,
16    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17    Boston, MA 02111-1307, USA.  */
18
19 #include <hurd.h>
20 #include <hurd/lookup.h>
21 #include <string.h>
22 #include <fcntl.h>
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
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),
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),
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! */
55   int startport;
56
57   error_t lookup_op (mach_port_t startdir)
58     {
59       return lookup_error ((*lookup) (startdir, file_name, flags, mode,
60                                       &doretry, retryname, result));
61     }
62
63   if (! lookup)
64     lookup = __dir_lookup;
65
66   startport = (file_name[0] == '/') ? INIT_PORT_CRDIR : INIT_PORT_CWDIR;
67   while (file_name[0] == '/')
68     file_name++;
69
70   if (flags & O_NOFOLLOW)       /* See comments below about O_NOFOLLOW.  */
71     flags |= O_NOTRANS;
72
73   if (flags & O_DIRECTORY)
74     {
75       /* The caller wants to require that the file we look up is a directory.
76          We can do this without an extra RPC by appending a trailing slash
77          to the file name we look up.  */
78       size_t len = strlen (file_name);
79       if (len == 0)
80         file_name = "/";
81       else if (file_name[len - 1] != '/')
82         {
83           char *n = alloca (len + 2);
84           memcpy (n, file_name, len);
85           n[len] = '/';
86           n[len + 1] = '\0';
87           file_name = n;
88         }
89     }
90
91   err = (*use_init_port) (startport, &lookup_op);
92   if (! err)
93     err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
94                                          lookup, doretry, retryname,
95                                          flags, mode, result);
96
97   return err;
98 }
99 weak_alias (__hurd_file_name_lookup, hurd_file_name_lookup)
100
101 error_t
102 __hurd_file_name_split (error_t (*use_init_port)
103                           (int which, error_t (*operate) (file_t)),
104                         file_t (*get_dtable_port) (int fd),
105                         error_t (*lookup)
106                           (file_t dir, char *name, int flags, mode_t mode,
107                            retry_type *do_retry, string_t retry_name,
108                            mach_port_t *result),
109                         const char *file_name,
110                         file_t *dir, char **name)
111 {
112   error_t addref (file_t crdir)
113     {
114       *dir = crdir;
115       return __mach_port_mod_refs (__mach_task_self (),
116                                    crdir, MACH_PORT_RIGHT_SEND, +1);
117     }
118
119   const char *lastslash = strrchr (file_name, '/');
120
121   if (lastslash != NULL)
122     {
123       if (lastslash == file_name)
124         {
125           /* "/foobar" => crdir + "foobar".  */
126           *name = (char *) file_name + 1;
127           return (*use_init_port) (INIT_PORT_CRDIR, &addref);
128         }
129       else
130         {
131           /* "/dir1/dir2/.../file".  */
132           char dirname[lastslash - file_name + 1];
133           memcpy (dirname, file_name, lastslash - file_name);
134           dirname[lastslash - file_name] = '\0';
135           *name = (char *) lastslash + 1;
136           return
137             __hurd_file_name_lookup (use_init_port, get_dtable_port, lookup,
138                                      dirname, 0, 0, dir);
139         }
140     }
141   else
142     {
143       /* "foobar" => cwdir + "foobar".  */
144       *name = (char *) file_name;
145       return (*use_init_port) (INIT_PORT_CWDIR, &addref);
146     }
147 }
148 weak_alias (__hurd_file_name_split, hurd_file_name_split)
149
150 /* This is the same as hurd_file_name_split, except that it ignores
151    trailing slashes (so *NAME is never "").  */
152 error_t
153 __hurd_directory_name_split (error_t (*use_init_port)
154                              (int which, error_t (*operate) (file_t)),
155                              file_t (*get_dtable_port) (int fd),
156                              error_t (*lookup)
157                              (file_t dir, char *name, int flags, mode_t mode,
158                               retry_type *do_retry, string_t retry_name,
159                               mach_port_t *result),
160                              const char *file_name,
161                              file_t *dir, char **name)
162 {
163   error_t addref (file_t crdir)
164     {
165       *dir = crdir;
166       return __mach_port_mod_refs (__mach_task_self (),
167                                    crdir, MACH_PORT_RIGHT_SEND, +1);
168     }
169
170   const char *lastslash = strrchr (file_name, '/');
171
172   if (lastslash != NULL && lastslash[1] == '\0')
173     {
174       /* Trailing slash doesn't count.  Look back further.  */
175
176       /* Back up over all trailing slashes.  */
177       while (lastslash > file_name && *lastslash == '/')
178         --lastslash;
179
180       /* Find the last one earlier in the string, before the trailing ones.  */
181 #if __GLIBC__ > 2 || __GLIBC_MINOR__ >= 2
182       lastslash = __memrchr (file_name, '/', lastslash - file_name);
183 #else
184       /* Keep backing up, looking for a slash.  */
185       do
186         if (lastslash == file_name)
187           {
188             /* Hit the start with no slash.  */
189             lastslash = NULL;
190             break;
191           }
192       while (*lastslash-- != '/');
193 #endif
194     }
195
196   if (lastslash != NULL)
197     {
198       if (lastslash == file_name)
199         {
200           /* "/foobar" => crdir + "foobar".  */
201           *name = (char *) file_name + 1;
202           return (*use_init_port) (INIT_PORT_CRDIR, &addref);
203         }
204       else
205         {
206           /* "/dir1/dir2/.../file".  */
207           char dirname[lastslash - file_name + 1];
208           memcpy (dirname, file_name, lastslash - file_name);
209           dirname[lastslash - file_name] = '\0';
210           *name = (char *) lastslash + 1;
211           return
212             __hurd_file_name_lookup (use_init_port, get_dtable_port, lookup,
213                                      dirname, 0, 0, dir);
214         }
215     }
216   else
217     {
218       /* "foobar" => cwdir + "foobar".  */
219       *name = (char *) file_name;
220       return (*use_init_port) (INIT_PORT_CWDIR, &addref);
221     }
222 }
223 weak_alias (__hurd_directory_name_split, hurd_directory_name_split)
224
225 \f
226 file_t
227 __file_name_lookup (const char *file_name, int flags, mode_t mode)
228 {
229   error_t err;
230   file_t result;
231
232   err = __hurd_file_name_lookup (&_hurd_ports_use, &__getdport, 0,
233                                  file_name, flags, mode & ~_hurd_umask,
234                                  &result);
235
236   return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
237 }
238 weak_alias (__file_name_lookup, file_name_lookup)
239
240
241 file_t
242 __file_name_split (const char *file_name, char **name)
243 {
244   error_t err;
245   file_t result;
246
247   err = __hurd_file_name_split (&_hurd_ports_use, &__getdport, 0,
248                                 file_name, &result, name);
249
250   return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
251 }
252 weak_alias (__file_name_split, file_name_split)
253
254 file_t
255 __directory_name_split (const char *directory_name, char **name)
256 {
257   error_t err;
258   file_t result;
259
260   err = __hurd_directory_name_split (&_hurd_ports_use, &__getdport, 0,
261                                      directory_name, &result, name);
262
263   return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
264 }
265 weak_alias (__directory_name_split, directory_name_split)
266
267
268 file_t
269 __file_name_lookup_under (file_t startdir,
270                           const char *file_name, int flags, mode_t mode)
271 {
272   error_t err;
273   file_t result;
274
275   error_t use_init_port (int which, error_t (*operate) (mach_port_t))
276     {
277       return (which == INIT_PORT_CWDIR ? (*operate) (startdir) :
278               _hurd_ports_use (which, operate));
279     }
280
281   err = __hurd_file_name_lookup (&use_init_port, &__getdport, 0,
282                                  file_name, flags, mode & ~_hurd_umask,
283                                  &result);
284
285   return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
286 }
287 weak_alias (__file_name_lookup_under, file_name_lookup_under)