Fix readdir regressions on sparc 32-bit.
[platform/upstream/glibc.git] / hurd / path-lookup.c
1 /* Filename lookup using a search path
2    Copyright (C) 1995-2013 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Written by Miles Bader <miles@gnu.ai.mit.edu>
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <http://www.gnu.org/licenses/>.  */
19
20 #include <string.h>
21 #include <hurd.h>
22 #include <hurd/lookup.h>
23
24 /* If FILE_NAME contains a '/', or PATH is NULL, call FUN with FILE_NAME, and
25    return the result (if PREFIXED_NAME is non-NULL, setting *PREFIXED_NAME to
26    NULL).  Otherwise, call FUN repeatedly with FILE_NAME prefixed with each
27    successive `:' separated element of PATH, returning whenever FUN returns
28    0 (if PREFIXED_NAME is non-NULL, setting *PREFIXED_NAME to the resulting
29    prefixed path).  If FUN never returns 0, return the first non-ENOENT
30    return value, or ENOENT if there is none.  */
31 error_t
32 file_name_path_scan (const char *file_name, const char *path,
33                      error_t (*fun)(const char *name),
34                      char **prefixed_name)
35 {
36   if (path == NULL || index (file_name, '/'))
37     {
38       if (prefixed_name)
39         *prefixed_name = 0;
40       return (*fun)(file_name);
41     }
42   else
43     {
44       error_t real_err = 0;
45       size_t file_name_len = strlen (file_name);
46
47       for (;;)
48         {
49           error_t err;
50           const char *next = index (path, ':') ?: path + strlen (path);
51           size_t pfx_len = next - path;
52           char pfxed_name[pfx_len + 2 + file_name_len + 1];
53
54           if (pfx_len == 0)
55             pfxed_name[pfx_len++] = '.';
56           else
57             memcpy (pfxed_name, path, pfx_len);
58           if (pfxed_name[pfx_len - 1] != '/')
59             pfxed_name[pfx_len++] = '/';
60           memcpy (pfxed_name + pfx_len, file_name, file_name_len + 1);
61
62           err = (*fun)(pfxed_name);
63           if (err == 0)
64             {
65               if (prefixed_name)
66                 *prefixed_name = strdup (pfxed_name);
67               return 0;
68             }
69           if (!real_err && err != ENOENT)
70             real_err = err;
71
72           if (*next == '\0')
73             return real_err ?: ENOENT;
74           else
75             path = next + 1;
76         }
77     }
78 }
79
80 /* Lookup FILE_NAME and return the node opened with FLAGS & MODE in result
81    (see hurd_file_name_lookup for details), but a simple filename (without
82    any directory prefixes) will be consecutively prefixed with the pathnames
83    in the `:' separated list PATH until one succeeds in a successful lookup.
84    If none succeed, then the first error that wasn't ENOENT is returned, or
85    ENOENT if no other errors were returned.  If PREFIXED_NAME is non-NULL,
86    then if RESULT is looked up directly, *PREFIXED_NAME is set to NULL, and
87    if it is looked up using a prefix from PATH, *PREFIXED_NAME is set to
88    malloced storage containing the prefixed name.  */
89 error_t
90 hurd_file_name_path_lookup (error_t (*use_init_port)
91                               (int which, error_t (*operate) (mach_port_t)),
92                             file_t (*get_dtable_port) (int fd),
93                             error_t (*lookup)
94                               (file_t dir, char *name, int flags, mode_t mode,
95                                retry_type *do_retry, string_t retry_name,
96                                mach_port_t *result),
97                             const char *file_name, const char *path,
98                             int flags, mode_t mode,
99                             file_t *result, char **prefixed_name)
100 {
101   error_t scan_lookup (const char *name)
102     {
103       return
104         __hurd_file_name_lookup (use_init_port, get_dtable_port, lookup,
105                                  name, flags, mode, result);
106     }
107   return file_name_path_scan (file_name, path, scan_lookup, prefixed_name);
108 }
109
110 file_t
111 file_name_path_lookup (const char *file_name, const char *path,
112                        int flags, mode_t mode, char **prefixed_name)
113 {
114   error_t err;
115   file_t result;
116
117   err = hurd_file_name_path_lookup (&_hurd_ports_use, &__getdport, 0,
118                                     file_name, path, flags, mode,
119                                     &result, prefixed_name);
120
121   return err ? (__hurd_fail (err), MACH_PORT_NULL) : result;
122 }