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