Back to index

glibc  2.9
hurdlookup.c
Go to the documentation of this file.
00001 /* Copyright (C) 1992,1993,1994,1995,1996,1997,1999,2001,2004,2006
00002        Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <hurd.h>
00021 #include <hurd/lookup.h>
00022 #include <string.h>
00023 #include <fcntl.h>
00024 
00025 
00026 /* Translate the error from dir_lookup into the error the user sees.  */
00027 static inline error_t
00028 lookup_error (error_t error)
00029 {
00030   switch (error)
00031     {
00032     case EOPNOTSUPP:
00033     case MIG_BAD_ID:
00034       /* These indicate that the server does not understand dir_lookup
00035         at all.  If it were a directory, it would, by definition.  */
00036       return ENOTDIR;
00037     default:
00038       return error;
00039     }
00040 }
00041 
00042 error_t
00043 __hurd_file_name_lookup (error_t (*use_init_port)
00044                         (int which, error_t (*operate) (file_t)),
00045                       file_t (*get_dtable_port) (int fd),
00046                       error_t (*lookup)
00047                         (file_t dir, char *name, int flags, mode_t mode,
00048                          retry_type *do_retry, string_t retry_name,
00049                          mach_port_t *result),
00050                       const char *file_name, int flags, mode_t mode,
00051                       file_t *result)
00052 {
00053   error_t err;
00054   enum retry_type doretry;
00055   char retryname[1024];            /* XXX string_t LOSES! */
00056   int startport;
00057 
00058   error_t lookup_op (mach_port_t startdir)
00059     {
00060       return lookup_error ((*lookup) (startdir, file_name, flags, mode,
00061                                   &doretry, retryname, result));
00062     }
00063 
00064   if (! lookup)
00065     lookup = __dir_lookup;
00066 
00067   if (file_name[0] == '\0')
00068     return ENOENT;
00069 
00070   startport = (file_name[0] == '/') ? INIT_PORT_CRDIR : INIT_PORT_CWDIR;
00071   while (file_name[0] == '/')
00072     file_name++;
00073 
00074   if (flags & O_NOFOLLOW)   /* See lookup-retry.c about O_NOFOLLOW.  */
00075     flags |= O_NOTRANS;
00076 
00077   if (flags & O_DIRECTORY)
00078     {
00079       /* The caller wants to require that the file we look up is a directory.
00080         We can do this without an extra RPC by appending a trailing slash
00081         to the file name we look up.  */
00082       size_t len = strlen (file_name);
00083       if (len == 0)
00084        file_name = "/";
00085       else if (file_name[len - 1] != '/')
00086        {
00087          char *n = alloca (len + 2);
00088          memcpy (n, file_name, len);
00089          n[len] = '/';
00090          n[len + 1] = '\0';
00091          file_name = n;
00092        }
00093     }
00094 
00095   err = (*use_init_port) (startport, &lookup_op);
00096   if (! err)
00097     err = __hurd_file_name_lookup_retry (use_init_port, get_dtable_port,
00098                                     lookup, doretry, retryname,
00099                                     flags, mode, result);
00100 
00101   return err;
00102 }
00103 weak_alias (__hurd_file_name_lookup, hurd_file_name_lookup)
00104 
00105 error_t
00106 __hurd_file_name_split (error_t (*use_init_port)
00107                        (int which, error_t (*operate) (file_t)),
00108                      file_t (*get_dtable_port) (int fd),
00109                      error_t (*lookup)
00110                        (file_t dir, char *name, int flags, mode_t mode,
00111                         retry_type *do_retry, string_t retry_name,
00112                         mach_port_t *result),
00113                      const char *file_name,
00114                      file_t *dir, char **name)
00115 {
00116   error_t addref (file_t crdir)
00117     {
00118       *dir = crdir;
00119       return __mach_port_mod_refs (__mach_task_self (),
00120                                crdir, MACH_PORT_RIGHT_SEND, +1);
00121     }
00122 
00123   const char *lastslash = strrchr (file_name, '/');
00124 
00125   if (lastslash != NULL)
00126     {
00127       if (lastslash == file_name)
00128        {
00129          /* "/foobar" => crdir + "foobar".  */
00130          *name = (char *) file_name + 1;
00131          return (*use_init_port) (INIT_PORT_CRDIR, &addref);
00132        }
00133       else
00134        {
00135          /* "/dir1/dir2/.../file".  */
00136          char dirname[lastslash - file_name + 1];
00137          memcpy (dirname, file_name, lastslash - file_name);
00138          dirname[lastslash - file_name] = '\0';
00139          *name = (char *) lastslash + 1;
00140          return
00141            __hurd_file_name_lookup (use_init_port, get_dtable_port, lookup,
00142                                  dirname, 0, 0, dir);
00143        }
00144     }
00145   else if (file_name[0] == '\0')
00146     return ENOENT;
00147   else
00148     {
00149       /* "foobar" => cwdir + "foobar".  */
00150       *name = (char *) file_name;
00151       return (*use_init_port) (INIT_PORT_CWDIR, &addref);
00152     }
00153 }
00154 weak_alias (__hurd_file_name_split, hurd_file_name_split)
00155 
00156 /* This is the same as hurd_file_name_split, except that it ignores
00157    trailing slashes (so *NAME is never "").  */
00158 error_t
00159 __hurd_directory_name_split (error_t (*use_init_port)
00160                           (int which, error_t (*operate) (file_t)),
00161                           file_t (*get_dtable_port) (int fd),
00162                           error_t (*lookup)
00163                           (file_t dir, char *name, int flags, mode_t mode,
00164                            retry_type *do_retry, string_t retry_name,
00165                            mach_port_t *result),
00166                           const char *file_name,
00167                           file_t *dir, char **name)
00168 {
00169   error_t addref (file_t crdir)
00170     {
00171       *dir = crdir;
00172       return __mach_port_mod_refs (__mach_task_self (),
00173                                crdir, MACH_PORT_RIGHT_SEND, +1);
00174     }
00175 
00176   const char *lastslash = strrchr (file_name, '/');
00177 
00178   if (lastslash != NULL && lastslash[1] == '\0')
00179     {
00180       /* Trailing slash doesn't count.  Look back further.  */
00181 
00182       /* Back up over all trailing slashes.  */
00183       while (lastslash > file_name && *lastslash == '/')
00184        --lastslash;
00185 
00186       /* Find the last one earlier in the string, before the trailing ones.  */
00187       lastslash = __memrchr (file_name, '/', lastslash - file_name);
00188     }
00189 
00190   if (lastslash != NULL)
00191     {
00192       if (lastslash == file_name)
00193        {
00194          /* "/foobar" => crdir + "foobar".  */
00195          *name = (char *) file_name + 1;
00196          return (*use_init_port) (INIT_PORT_CRDIR, &addref);
00197        }
00198       else
00199        {
00200          /* "/dir1/dir2/.../file".  */
00201          char dirname[lastslash - file_name + 1];
00202          memcpy (dirname, file_name, lastslash - file_name);
00203          dirname[lastslash - file_name] = '\0';
00204          *name = (char *) lastslash + 1;
00205          return
00206            __hurd_file_name_lookup (use_init_port, get_dtable_port, lookup,
00207                                  dirname, 0, 0, dir);
00208        }
00209     }
00210   else if (file_name[0] == '\0')
00211     return ENOENT;
00212   else
00213     {
00214       /* "foobar" => cwdir + "foobar".  */
00215       *name = (char *) file_name;
00216       return (*use_init_port) (INIT_PORT_CWDIR, &addref);
00217     }
00218 }
00219 weak_alias (__hurd_directory_name_split, hurd_directory_name_split)
00220 
00221 
00222 file_t
00223 __file_name_lookup (const char *file_name, int flags, mode_t mode)
00224 {
00225   error_t err;
00226   file_t result;
00227 
00228   err = __hurd_file_name_lookup (&_hurd_ports_use, &__getdport, 0,
00229                              file_name, flags, mode & ~_hurd_umask,
00230                              &result);
00231 
00232   return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
00233 }
00234 weak_alias (__file_name_lookup, file_name_lookup)
00235 
00236 
00237 file_t
00238 __file_name_split (const char *file_name, char **name)
00239 {
00240   error_t err;
00241   file_t result;
00242 
00243   err = __hurd_file_name_split (&_hurd_ports_use, &__getdport, 0,
00244                             file_name, &result, name);
00245 
00246   return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
00247 }
00248 weak_alias (__file_name_split, file_name_split)
00249 
00250 file_t
00251 __directory_name_split (const char *directory_name, char **name)
00252 {
00253   error_t err;
00254   file_t result;
00255 
00256   err = __hurd_directory_name_split (&_hurd_ports_use, &__getdport, 0,
00257                                  directory_name, &result, name);
00258 
00259   return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
00260 }
00261 weak_alias (__directory_name_split, directory_name_split)
00262 
00263 
00264 file_t
00265 __file_name_lookup_under (file_t startdir,
00266                        const char *file_name, int flags, mode_t mode)
00267 {
00268   error_t err;
00269   file_t result;
00270 
00271   error_t use_init_port (int which, error_t (*operate) (mach_port_t))
00272     {
00273       return (which == INIT_PORT_CWDIR ? (*operate) (startdir) :
00274              _hurd_ports_use (which, operate));
00275     }
00276 
00277   err = __hurd_file_name_lookup (&use_init_port, &__getdport, 0,
00278                              file_name, flags, mode & ~_hurd_umask,
00279                              &result);
00280 
00281   return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
00282 }
00283 weak_alias (__file_name_lookup_under, file_name_lookup_under)