gettext: Sync with gettext 0.23.
[gnulib.git] / lib / canonicalize-lgpl.c
blobefd79ceebb890772ac35a4eff225d9ade9fd116f
1 /* Return the canonical absolute name of a given file.
2 Copyright (C) 1996-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
19 #ifndef _LIBC
20 /* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
21 optimizes away the name == NULL test below. */
22 # define _GL_ARG_NONNULL(params)
24 # include <libc-config.h>
25 #endif
27 /* Specification. */
28 #include <stdlib.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <limits.h>
33 #include <string.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
37 #include <eloop-threshold.h>
38 #include <filename.h>
39 #include <idx.h>
40 #include <intprops.h>
41 #include <scratch_buffer.h>
43 #ifdef _LIBC
44 # include <shlib-compat.h>
45 # define GCC_LINT 1
46 # define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__))
47 #else
48 # define __canonicalize_file_name canonicalize_file_name
49 # define __realpath realpath
50 # define __strdup strdup
51 # include "pathmax.h"
52 # define __faccessat faccessat
53 # if defined _WIN32 && !defined __CYGWIN__
54 # define __getcwd _getcwd
55 # elif HAVE_GETCWD
56 # if IN_RELOCWRAPPER
57 /* When building the relocatable program wrapper, use the system's getcwd
58 function, not the gnulib override, otherwise we would get a link error.
60 # undef getcwd
61 # endif
62 # if defined VMS && !defined getcwd
63 /* We want the directory in Unix syntax, not in VMS syntax.
64 The gnulib override of 'getcwd' takes 2 arguments; the original VMS
65 'getcwd' takes 3 arguments. */
66 # define __getcwd(buf, max) getcwd (buf, max, 0)
67 # else
68 # define __getcwd getcwd
69 # endif
70 # else
71 # define __getcwd(buf, max) getwd (buf)
72 # endif
73 # define __mempcpy mempcpy
74 # define __pathconf pathconf
75 # define __rawmemchr rawmemchr
76 # define __readlink readlink
77 # if IN_RELOCWRAPPER
78 /* When building the relocatable program wrapper, use the system's memmove
79 function, not the gnulib override, otherwise we would get a link error.
81 # undef memmove
82 # endif
83 #endif
85 /* Suppress bogus GCC -Wmaybe-uninitialized warnings. */
86 #if defined GCC_LINT || defined lint
87 # define IF_LINT(Code) Code
88 #else
89 # define IF_LINT(Code) /* empty */
90 #endif
92 #ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
93 # define DOUBLE_SLASH_IS_DISTINCT_ROOT false
94 #endif
96 #if defined _LIBC || !FUNC_REALPATH_WORKS
98 /* Return true if FILE's existence can be shown, false (setting errno)
99 otherwise. Follow symbolic links. */
100 static bool
101 file_accessible (char const *file)
103 # if defined _LIBC || HAVE_FACCESSAT
104 return __faccessat (AT_FDCWD, file, F_OK, AT_EACCESS) == 0;
105 # else
106 struct stat st;
107 return stat (file, &st) == 0 || errno == EOVERFLOW;
108 # endif
111 /* True if concatenating END as a suffix to a file name means that the
112 code needs to check that the file name is that of a searchable
113 directory, since the canonicalize_filename_mode_stk code won't
114 check this later anyway when it checks an ordinary file name
115 component within END. END must either be empty, or start with a
116 slash. */
118 static bool _GL_ATTRIBUTE_PURE
119 suffix_requires_dir_check (char const *end)
121 /* If END does not start with a slash, the suffix is OK. */
122 while (ISSLASH (*end))
124 /* Two or more slashes act like a single slash. */
126 end++;
127 while (ISSLASH (*end));
129 switch (*end++)
131 default: return false; /* An ordinary file name component is OK. */
132 case '\0': return true; /* Trailing "/" is trouble. */
133 case '.': break; /* Possibly "." or "..". */
135 /* Trailing "/.", or "/.." even if not trailing, is trouble. */
136 if (!*end || (*end == '.' && (!end[1] || ISSLASH (end[1]))))
137 return true;
140 return false;
143 /* Append this to a file name to test whether it is a searchable directory.
144 On POSIX platforms "/" suffices, but "/./" is sometimes needed on
145 macOS 10.13 <https://bugs.gnu.org/30350>, and should also work on
146 platforms like AIX 7.2 that need at least "/.". */
148 # if defined _LIBC || defined LSTAT_FOLLOWS_SLASHED_SYMLINK
149 static char const dir_suffix[] = "/";
150 # else
151 static char const dir_suffix[] = "/./";
152 # endif
154 /* Return true if DIR is a searchable dir, false (setting errno) otherwise.
155 DIREND points to the NUL byte at the end of the DIR string.
156 Store garbage into DIREND[0 .. strlen (dir_suffix)]. */
158 static bool
159 dir_check (char *dir, char *dirend)
161 strcpy (dirend, dir_suffix);
162 return file_accessible (dir);
165 static idx_t
166 get_path_max (void)
168 # ifdef PATH_MAX
169 long int path_max = PATH_MAX;
170 # else
171 /* The caller invoked realpath with a null RESOLVED, even though
172 PATH_MAX is not defined as a constant. The glibc manual says
173 programs should not do this, and POSIX says the behavior is undefined.
174 Historically, glibc here used the result of pathconf, or 1024 if that
175 failed; stay consistent with this (dubious) historical practice. */
176 int err = errno;
177 long int path_max = __pathconf ("/", _PC_PATH_MAX);
178 __set_errno (err);
179 # endif
180 return path_max < 0 ? 1024 : path_max <= IDX_MAX ? path_max : IDX_MAX;
183 /* Scratch buffers used by realpath_stk and managed by __realpath. */
184 struct realpath_bufs
186 struct scratch_buffer rname;
187 struct scratch_buffer extra;
188 struct scratch_buffer link;
191 static char *
192 realpath_stk (const char *name, char *resolved, struct realpath_bufs *bufs)
194 char *dest;
195 char const *start;
196 char const *end;
197 int num_links = 0;
199 if (name == NULL)
201 /* As per Single Unix Specification V2 we must return an error if
202 either parameter is a null pointer. We extend this to allow
203 the RESOLVED parameter to be NULL in case the we are expected to
204 allocate the room for the return value. */
205 __set_errno (EINVAL);
206 return NULL;
209 if (name[0] == '\0')
211 /* As per Single Unix Specification V2 we must return an error if
212 the name argument points to an empty string. */
213 __set_errno (ENOENT);
214 return NULL;
217 char *rname = bufs->rname.data;
218 bool end_in_extra_buffer = false;
219 bool failed = true;
221 /* This is always zero for Posix hosts, but can be 2 for MS-Windows
222 and MS-DOS X:/foo/bar file names. */
223 idx_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
225 if (!IS_ABSOLUTE_FILE_NAME (name))
227 while (!__getcwd (bufs->rname.data, bufs->rname.length))
229 if (errno != ERANGE)
231 dest = rname;
232 goto error;
234 if (!scratch_buffer_grow (&bufs->rname))
235 return NULL;
236 rname = bufs->rname.data;
238 dest = __rawmemchr (rname, '\0');
239 start = name;
240 prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
242 else
244 dest = __mempcpy (rname, name, prefix_len);
245 *dest++ = '/';
246 if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
248 if (prefix_len == 0 /* implies ISSLASH (name[0]) */
249 && ISSLASH (name[1]) && !ISSLASH (name[2]))
250 *dest++ = '/';
251 *dest = '\0';
253 start = name + prefix_len;
256 for ( ; *start; start = end)
258 /* Skip sequence of multiple file name separators. */
259 while (ISSLASH (*start))
260 ++start;
262 /* Find end of component. */
263 for (end = start; *end && !ISSLASH (*end); ++end)
264 /* Nothing. */;
266 /* Length of this file name component; it can be zero if a file
267 name ends in '/'. */
268 idx_t startlen = end - start;
270 if (startlen == 0)
271 break;
272 else if (startlen == 1 && start[0] == '.')
273 /* nothing */;
274 else if (startlen == 2 && start[0] == '.' && start[1] == '.')
276 /* Back up to previous component, ignore if at root already. */
277 if (dest > rname + prefix_len + 1)
278 for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
279 continue;
280 if (DOUBLE_SLASH_IS_DISTINCT_ROOT
281 && dest == rname + 1 && !prefix_len
282 && ISSLASH (*dest) && !ISSLASH (dest[1]))
283 dest++;
285 else
287 if (!ISSLASH (dest[-1]))
288 *dest++ = '/';
290 while (rname + bufs->rname.length - dest
291 < startlen + sizeof dir_suffix)
293 idx_t dest_offset = dest - rname;
294 if (!scratch_buffer_grow_preserve (&bufs->rname))
295 return NULL;
296 rname = bufs->rname.data;
297 dest = rname + dest_offset;
300 dest = __mempcpy (dest, start, startlen);
301 *dest = '\0';
303 char *buf;
304 ssize_t n;
305 while (true)
307 buf = bufs->link.data;
308 idx_t bufsize = bufs->link.length;
309 n = __readlink (rname, buf, bufsize - 1);
310 if (n < bufsize - 1)
311 break;
312 if (!scratch_buffer_grow (&bufs->link))
313 return NULL;
315 if (0 <= n)
317 if (++num_links > __eloop_threshold ())
319 __set_errno (ELOOP);
320 goto error;
323 buf[n] = '\0';
325 char *extra_buf = bufs->extra.data;
326 idx_t end_idx IF_LINT (= 0);
327 if (end_in_extra_buffer)
328 end_idx = end - extra_buf;
329 size_t len = strlen (end);
330 if (INT_ADD_OVERFLOW (len, n))
332 __set_errno (ENOMEM);
333 return NULL;
335 while (bufs->extra.length <= len + n)
337 if (!scratch_buffer_grow_preserve (&bufs->extra))
338 return NULL;
339 extra_buf = bufs->extra.data;
341 if (end_in_extra_buffer)
342 end = extra_buf + end_idx;
344 /* Careful here, end may be a pointer into extra_buf... */
345 memmove (&extra_buf[n], end, len + 1);
346 name = end = memcpy (extra_buf, buf, n);
347 end_in_extra_buffer = true;
349 if (IS_ABSOLUTE_FILE_NAME (buf))
351 idx_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
353 dest = __mempcpy (rname, buf, pfxlen);
354 *dest++ = '/'; /* It's an absolute symlink */
355 if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
357 if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen)
358 *dest++ = '/';
359 *dest = '\0';
361 /* Install the new prefix to be in effect hereafter. */
362 prefix_len = pfxlen;
364 else
366 /* Back up to previous component, ignore if at root
367 already: */
368 if (dest > rname + prefix_len + 1)
369 for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
370 continue;
371 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
372 && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
373 dest++;
376 else if (! (suffix_requires_dir_check (end)
377 ? dir_check (rname, dest)
378 : errno == EINVAL))
379 goto error;
382 if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1]))
383 --dest;
384 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len
385 && ISSLASH (*dest) && !ISSLASH (dest[1]))
386 dest++;
387 failed = false;
389 error:
390 *dest++ = '\0';
391 if (resolved != NULL)
393 /* Copy the full result on success or partial result if failure was due
394 to the path not existing or not being accessible. */
395 if ((!failed || errno == ENOENT || errno == EACCES)
396 && dest - rname <= get_path_max ())
398 strcpy (resolved, rname);
399 if (failed)
400 return NULL;
401 else
402 return resolved;
404 if (!failed)
405 __set_errno (ENAMETOOLONG);
406 return NULL;
408 else
410 if (failed)
411 return NULL;
412 else
413 return __strdup (bufs->rname.data);
417 /* Return the canonical absolute name of file NAME. A canonical name
418 does not contain any ".", ".." components nor any repeated file name
419 separators ('/') or symlinks. All file name components must exist. If
420 RESOLVED is null, the result is malloc'd; otherwise, if the
421 canonical name is PATH_MAX chars or more, returns null with 'errno'
422 set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
423 returns the name in RESOLVED. If the name cannot be resolved and
424 RESOLVED is non-NULL, it contains the name of the first component
425 that cannot be resolved. If the name can be resolved, RESOLVED
426 holds the same value as the value returned. */
428 char *
429 __realpath (const char *name, char *resolved)
431 struct realpath_bufs bufs;
432 scratch_buffer_init (&bufs.rname);
433 scratch_buffer_init (&bufs.extra);
434 scratch_buffer_init (&bufs.link);
435 char *result = realpath_stk (name, resolved, &bufs);
436 scratch_buffer_free (&bufs.link);
437 scratch_buffer_free (&bufs.extra);
438 scratch_buffer_free (&bufs.rname);
439 return result;
441 libc_hidden_def (__realpath)
442 versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
444 #endif /* defined _LIBC || !FUNC_REALPATH_WORKS */
447 #if SHLIB_COMPAT(libc, GLIBC_2_0, GLIBC_2_3)
448 char *
449 attribute_compat_text_section
450 __old_realpath (const char *name, char *resolved)
452 if (resolved == NULL)
454 __set_errno (EINVAL);
455 return NULL;
458 return __realpath (name, resolved);
460 compat_symbol (libc, __old_realpath, realpath, GLIBC_2_0);
461 #endif
464 char *
465 __canonicalize_file_name (const char *name)
467 return __realpath (name, NULL);
469 weak_alias (__canonicalize_file_name, canonicalize_file_name)