aboutsummaryrefslogtreecommitdiffstats
path: root/lib/canonicalize-lgpl.c
diff options
context:
space:
mode:
authorPhilipp Stephani2020-12-24 16:48:40 +0100
committerPhilipp Stephani2020-12-24 16:48:40 +0100
commit29064d02c31b08ae41d41a93fd1439718373b196 (patch)
tree6c976729d7c6f296b36965f235d2a58e8142393e /lib/canonicalize-lgpl.c
parent26b8b30ff42568ff3e3f8599a20328a1efe93d2a (diff)
downloademacs-29064d02c31b08ae41d41a93fd1439718373b196.tar.gz
emacs-29064d02c31b08ae41d41a93fd1439718373b196.zip
Update Gnulib.
All changes in this commit are autogenerated by running admin/merge-gnulib.
Diffstat (limited to 'lib/canonicalize-lgpl.c')
-rw-r--r--lib/canonicalize-lgpl.c381
1 files changed, 168 insertions, 213 deletions
diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c
index 0b89d2a1842..584fce1cfa4 100644
--- a/lib/canonicalize-lgpl.c
+++ b/lib/canonicalize-lgpl.c
@@ -2,18 +2,19 @@
2 Copyright (C) 1996-2020 Free Software Foundation, Inc. 2 Copyright (C) 1996-2020 Free Software Foundation, Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 This program is free software: you can redistribute it and/or modify 5 The GNU C Library is free software; you can redistribute it and/or
6 it under the terms of the GNU General Public License as published by 6 modify it under the terms of the GNU General Public
7 the Free Software Foundation; either version 3 of the License, or 7 License as published by the Free Software Foundation; either
8 (at your option) any later version. 8 version 3 of the License, or (at your option) any later version.
9 9
10 This program is distributed in the hope that it will be useful, 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 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 GNU General Public License for more details. 13 General Public License for more details.
14 14
15 You should have received a copy of the GNU General Public License 15 You should have received a copy of the GNU General Public
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
17 18
18#ifndef _LIBC 19#ifndef _LIBC
19/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc 20/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
@@ -21,36 +22,36 @@
21# define _GL_ARG_NONNULL(params) 22# define _GL_ARG_NONNULL(params)
22 23
23# define _GL_USE_STDLIB_ALLOC 1 24# define _GL_USE_STDLIB_ALLOC 1
24# include <config.h> 25# include <libc-config.h>
25#endif 26#endif
26 27
27#if !HAVE_CANONICALIZE_FILE_NAME || !FUNC_REALPATH_WORKS || defined _LIBC
28
29/* Specification. */ 28/* Specification. */
30#include <stdlib.h> 29#include <stdlib.h>
31 30
32#include <alloca.h>
33#include <string.h>
34#include <unistd.h>
35#include <limits.h>
36#if HAVE_SYS_PARAM_H || defined _LIBC
37# include <sys/param.h>
38#endif
39#include <sys/stat.h>
40#include <errno.h> 31#include <errno.h>
32#include <limits.h>
33#include <stdbool.h>
41#include <stddef.h> 34#include <stddef.h>
35#include <string.h>
36#include <sys/stat.h>
37#include <unistd.h>
38
39#include <scratch_buffer.h>
42 40
43#ifdef _LIBC 41#ifdef _LIBC
42# include <eloop-threshold.h>
44# include <shlib-compat.h> 43# include <shlib-compat.h>
44typedef ptrdiff_t idx_t;
45# define IDX_MAX PTRDIFF_MAX
46# define FILE_SYSTEM_PREFIX_LEN(name) 0
47# define IS_ABSOLUTE_FILE_NAME(name) ISSLASH(*(name))
48# define ISSLASH(c) ((c) == '/')
49# define freea(p) ((void) (p))
45#else 50#else
46# define SHLIB_COMPAT(lib, introduced, obsoleted) 0
47# define versioned_symbol(lib, local, symbol, version) extern int dummy
48# define compat_symbol(lib, local, symbol, version)
49# define weak_alias(local, symbol)
50# define __canonicalize_file_name canonicalize_file_name 51# define __canonicalize_file_name canonicalize_file_name
51# define __realpath realpath 52# define __realpath realpath
53# include "idx.h"
52# include "pathmax.h" 54# include "pathmax.h"
53# include "malloca.h"
54# include "filename.h" 55# include "filename.h"
55# if defined _WIN32 && !defined __CYGWIN__ 56# if defined _WIN32 && !defined __CYGWIN__
56# define __getcwd _getcwd 57# define __getcwd _getcwd
@@ -72,8 +73,10 @@
72# else 73# else
73# define __getcwd(buf, max) getwd (buf) 74# define __getcwd(buf, max) getwd (buf)
74# endif 75# endif
76# define __mempcpy mempcpy
77# define __pathconf pathconf
78# define __rawmemchr rawmemchr
75# define __readlink readlink 79# define __readlink readlink
76# define __set_errno(e) errno = (e)
77# ifndef MAXSYMLINKS 80# ifndef MAXSYMLINKS
78# ifdef SYMLOOP_MAX 81# ifdef SYMLOOP_MAX
79# define MAXSYMLINKS SYMLOOP_MAX 82# define MAXSYMLINKS SYMLOOP_MAX
@@ -81,48 +84,51 @@
81# define MAXSYMLINKS 20 84# define MAXSYMLINKS 20
82# endif 85# endif
83# endif 86# endif
87# define __eloop_threshold() MAXSYMLINKS
84#endif 88#endif
85 89
86#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT 90#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT
87# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 91# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0
88#endif 92#endif
89 93
90/* Define this independently so that stdint.h is not a prerequisite. */
91#ifndef SIZE_MAX
92# define SIZE_MAX ((size_t) -1)
93#endif
94
95#if !FUNC_REALPATH_WORKS || defined _LIBC 94#if !FUNC_REALPATH_WORKS || defined _LIBC
96 95
97static void 96static idx_t
98alloc_failed (void) 97get_path_max (void)
99{ 98{
100#if defined _WIN32 && ! defined __CYGWIN__ 99# ifdef PATH_MAX
101 /* Avoid errno problem without using the malloc or realloc modules; see: 100 long int path_max = PATH_MAX;
102 https://lists.gnu.org/r/bug-gnulib/2016-08/msg00025.html */ 101# else
103 errno = ENOMEM; 102 /* The caller invoked realpath with a null RESOLVED, even though
104#endif 103 PATH_MAX is not defined as a constant. The glibc manual says
104 programs should not do this, and POSIX says the behavior is undefined.
105 Historically, glibc here used the result of pathconf, or 1024 if that
106 failed; stay consistent with this (dubious) historical practice. */
107 int err = errno;
108 long int path_max = __pathconf ("/", _PC_PATH_MAX);
109 __set_errno (err);
110# endif
111 return path_max < 0 ? 1024 : path_max <= IDX_MAX ? path_max : IDX_MAX;
105} 112}
106 113
107/* Return the canonical absolute name of file NAME. A canonical name 114/* Return the canonical absolute name of file NAME. A canonical name
108 does not contain any ".", ".." components nor any repeated path 115 does not contain any ".", ".." components nor any repeated file name
109 separators ('/') or symlinks. All path components must exist. If 116 separators ('/') or symlinks. All file name components must exist. If
110 RESOLVED is null, the result is malloc'd; otherwise, if the 117 RESOLVED is null, the result is malloc'd; otherwise, if the
111 canonical name is PATH_MAX chars or more, returns null with 'errno' 118 canonical name is PATH_MAX chars or more, returns null with 'errno'
112 set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars, 119 set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
113 returns the name in RESOLVED. If the name cannot be resolved and 120 returns the name in RESOLVED. If the name cannot be resolved and
114 RESOLVED is non-NULL, it contains the path of the first component 121 RESOLVED is non-NULL, it contains the name of the first component
115 that cannot be resolved. If the path can be resolved, RESOLVED 122 that cannot be resolved. If the name can be resolved, RESOLVED
116 holds the same value as the value returned. */ 123 holds the same value as the value returned. */
117 124
118char * 125char *
119__realpath (const char *name, char *resolved) 126__realpath (const char *name, char *resolved)
120{ 127{
121 char *rpath, *dest, *extra_buf = NULL; 128 char *dest;
122 const char *start, *end, *rpath_limit; 129 char const *start;
123 long int path_max; 130 char const *end;
124 int num_links = 0; 131 int num_links = 0;
125 size_t prefix_len;
126 132
127 if (name == NULL) 133 if (name == NULL)
128 { 134 {
@@ -142,205 +148,151 @@ __realpath (const char *name, char *resolved)
142 return NULL; 148 return NULL;
143 } 149 }
144 150
145#ifdef PATH_MAX 151 struct scratch_buffer extra_buffer, link_buffer;
146 path_max = PATH_MAX; 152 struct scratch_buffer rname_buffer;
147#else 153 struct scratch_buffer *rname_buf = &rname_buffer;
148 path_max = pathconf (name, _PC_PATH_MAX); 154 scratch_buffer_init (&extra_buffer);
149 if (path_max <= 0) 155 scratch_buffer_init (&link_buffer);
150 path_max = 8192; 156 scratch_buffer_init (rname_buf);
151#endif 157 char *rname_on_stack = rname_buf->data;
152 158 char *rname = rname_on_stack;
153 if (resolved == NULL) 159 bool end_in_extra_buffer = false;
154 { 160 bool failed = true;
155 rpath = malloc (path_max);
156 if (rpath == NULL)
157 {
158 alloc_failed ();
159 return NULL;
160 }
161 }
162 else
163 rpath = resolved;
164 rpath_limit = rpath + path_max;
165 161
166 /* This is always zero for Posix hosts, but can be 2 for MS-Windows 162 /* This is always zero for Posix hosts, but can be 2 for MS-Windows
167 and MS-DOS X:/foo/bar file names. */ 163 and MS-DOS X:/foo/bar file names. */
168 prefix_len = FILE_SYSTEM_PREFIX_LEN (name); 164 idx_t prefix_len = FILE_SYSTEM_PREFIX_LEN (name);
169 165
170 if (!IS_ABSOLUTE_FILE_NAME (name)) 166 if (!IS_ABSOLUTE_FILE_NAME (name))
171 { 167 {
172 if (!__getcwd (rpath, path_max)) 168 while (!__getcwd (rname, rname_buf->length))
173 { 169 {
174 rpath[0] = '\0'; 170 if (errno != ERANGE)
175 goto error; 171 {
172 dest = rname;
173 goto error;
174 }
175 if (!scratch_buffer_grow (rname_buf))
176 goto error_nomem;
177 rname = rname_buf->data;
176 } 178 }
177 dest = strchr (rpath, '\0'); 179 dest = __rawmemchr (rname, '\0');
178 start = name; 180 start = name;
179 prefix_len = FILE_SYSTEM_PREFIX_LEN (rpath); 181 prefix_len = FILE_SYSTEM_PREFIX_LEN (rname);
180 } 182 }
181 else 183 else
182 { 184 {
183 dest = rpath; 185 dest = __mempcpy (rname, name, prefix_len);
184 if (prefix_len)
185 {
186 memcpy (rpath, name, prefix_len);
187 dest += prefix_len;
188 }
189 *dest++ = '/'; 186 *dest++ = '/';
190 if (DOUBLE_SLASH_IS_DISTINCT_ROOT) 187 if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
191 { 188 {
192 if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len) 189 if (prefix_len == 0 /* implies ISSLASH (name[0]) */
190 && ISSLASH (name[1]) && !ISSLASH (name[2]))
193 *dest++ = '/'; 191 *dest++ = '/';
194 *dest = '\0'; 192 *dest = '\0';
195 } 193 }
196 start = name + prefix_len; 194 start = name + prefix_len;
197 } 195 }
198 196
199 for (end = start; *start; start = end) 197 for ( ; *start; start = end)
200 { 198 {
201#ifdef _LIBC 199 /* Skip sequence of multiple file name separators. */
202 struct stat64 st;
203#else
204 struct stat st;
205#endif
206
207 /* Skip sequence of multiple path-separators. */
208 while (ISSLASH (*start)) 200 while (ISSLASH (*start))
209 ++start; 201 ++start;
210 202
211 /* Find end of path component. */ 203 /* Find end of component. */
212 for (end = start; *end && !ISSLASH (*end); ++end) 204 for (end = start; *end && !ISSLASH (*end); ++end)
213 /* Nothing. */; 205 /* Nothing. */;
214 206
215 if (end - start == 0) 207 /* Length of this file name component; it can be zero if a file
216 break; 208 name ends in '/'. */
217 else if (end - start == 1 && start[0] == '.') 209 idx_t startlen = end - start;
210
211 if (startlen == 1 && start[0] == '.')
218 /* nothing */; 212 /* nothing */;
219 else if (end - start == 2 && start[0] == '.' && start[1] == '.') 213 else if (startlen == 2 && start[0] == '.' && start[1] == '.')
220 { 214 {
221 /* Back up to previous component, ignore if at root already. */ 215 /* Back up to previous component, ignore if at root already. */
222 if (dest > rpath + prefix_len + 1) 216 if (dest > rname + prefix_len + 1)
223 for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest) 217 for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
224 continue; 218 continue;
225 if (DOUBLE_SLASH_IS_DISTINCT_ROOT 219 if (DOUBLE_SLASH_IS_DISTINCT_ROOT
226 && dest == rpath + 1 && !prefix_len 220 && dest == rname + 1 && !prefix_len
227 && ISSLASH (*dest) && !ISSLASH (dest[1])) 221 && ISSLASH (*dest) && !ISSLASH (dest[1]))
228 dest++; 222 dest++;
229 } 223 }
230 else 224 else
231 { 225 {
232 size_t new_size;
233
234 if (!ISSLASH (dest[-1])) 226 if (!ISSLASH (dest[-1]))
235 *dest++ = '/'; 227 *dest++ = '/';
236 228
237 if (dest + (end - start) >= rpath_limit) 229 while (rname + rname_buf->length - dest <= startlen)
238 { 230 {
239 ptrdiff_t dest_offset = dest - rpath; 231 idx_t dest_offset = dest - rname;
240 char *new_rpath; 232 if (!scratch_buffer_grow_preserve (rname_buf))
241 233 goto error_nomem;
242 if (resolved) 234 rname = rname_buf->data;
243 { 235 dest = rname + dest_offset;
244 __set_errno (ENAMETOOLONG);
245 if (dest > rpath + prefix_len + 1)
246 dest--;
247 *dest = '\0';
248 goto error;
249 }
250 new_size = rpath_limit - rpath;
251 if (end - start + 1 > path_max)
252 new_size += end - start + 1;
253 else
254 new_size += path_max;
255 new_rpath = (char *) realloc (rpath, new_size);
256 if (new_rpath == NULL)
257 {
258 alloc_failed ();
259 goto error;
260 }
261 rpath = new_rpath;
262 rpath_limit = rpath + new_size;
263
264 dest = rpath + dest_offset;
265 } 236 }
266 237
267#ifdef _LIBC 238 dest = __mempcpy (dest, start, startlen);
268 dest = __mempcpy (dest, start, end - start);
269#else
270 memcpy (dest, start, end - start);
271 dest += end - start;
272#endif
273 *dest = '\0'; 239 *dest = '\0';
274 240
275 /* FIXME: if lstat fails with errno == EOVERFLOW, 241 /* If STARTLEN == 0, RNAME ends in '/'; use stat rather than
276 the entry exists. */ 242 readlink, because readlink might fail with EINVAL without
277#ifdef _LIBC 243 checking whether RNAME sans '/' is valid. */
278 if (__lxstat64 (_STAT_VER, rpath, &st) < 0) 244 struct stat st;
279#else 245 char *buf = NULL;
280 if (lstat (rpath, &st) < 0) 246 ssize_t n;
281#endif 247 if (startlen != 0)
282 goto error;
283
284 if (S_ISLNK (st.st_mode))
285 { 248 {
286 char *buf; 249 while (true)
287 size_t len;
288 ssize_t n;
289
290 if (++num_links > MAXSYMLINKS)
291 {
292 __set_errno (ELOOP);
293 goto error;
294 }
295
296 buf = malloca (path_max);
297 if (!buf)
298 { 250 {
299 __set_errno (ENOMEM); 251 buf = link_buffer.data;
300 goto error; 252 idx_t bufsize = link_buffer.length;
253 n = __readlink (rname, buf, bufsize - 1);
254 if (n < bufsize - 1)
255 break;
256 if (!scratch_buffer_grow (&link_buffer))
257 goto error_nomem;
301 } 258 }
302
303 n = __readlink (rpath, buf, path_max - 1);
304 if (n < 0) 259 if (n < 0)
260 buf = NULL;
261 }
262 if (buf)
263 {
264 if (++num_links > __eloop_threshold ())
305 { 265 {
306 int saved_errno = errno; 266 __set_errno (ELOOP);
307 freea (buf);
308 __set_errno (saved_errno);
309 goto error; 267 goto error;
310 } 268 }
311 buf[n] = '\0';
312 269
313 if (!extra_buf) 270 buf[n] = '\0';
314 {
315 extra_buf = malloca (path_max);
316 if (!extra_buf)
317 {
318 freea (buf);
319 __set_errno (ENOMEM);
320 goto error;
321 }
322 }
323 271
324 len = strlen (end); 272 char *extra_buf = extra_buffer.data;
325 /* Check that n + len + 1 doesn't overflow and is <= path_max. */ 273 idx_t end_idx;
326 if (n >= SIZE_MAX - len || n + len >= path_max) 274 if (end_in_extra_buffer)
275 end_idx = end - extra_buf;
276 idx_t len = strlen (end);
277 while (extra_buffer.length <= len + n)
327 { 278 {
328 freea (buf); 279 if (!scratch_buffer_grow_preserve (&extra_buffer))
329 __set_errno (ENAMETOOLONG); 280 goto error_nomem;
330 goto error; 281 extra_buf = extra_buffer.data;
331 } 282 }
283 if (end_in_extra_buffer)
284 end = extra_buf + end_idx;
332 285
333 /* Careful here, end may be a pointer into extra_buf... */ 286 /* Careful here, end may be a pointer into extra_buf... */
334 memmove (&extra_buf[n], end, len + 1); 287 memmove (&extra_buf[n], end, len + 1);
335 name = end = memcpy (extra_buf, buf, n); 288 name = end = memcpy (extra_buf, buf, n);
289 end_in_extra_buffer = true;
336 290
337 if (IS_ABSOLUTE_FILE_NAME (buf)) 291 if (IS_ABSOLUTE_FILE_NAME (buf))
338 { 292 {
339 size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf); 293 idx_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf);
340 294
341 if (pfxlen) 295 dest = __mempcpy (rname, buf, pfxlen);
342 memcpy (rpath, buf, pfxlen);
343 dest = rpath + pfxlen;
344 *dest++ = '/'; /* It's an absolute symlink */ 296 *dest++ = '/'; /* It's an absolute symlink */
345 if (DOUBLE_SLASH_IS_DISTINCT_ROOT) 297 if (DOUBLE_SLASH_IS_DISTINCT_ROOT)
346 { 298 {
@@ -355,44 +307,55 @@ __realpath (const char *name, char *resolved)
355 { 307 {
356 /* Back up to previous component, ignore if at root 308 /* Back up to previous component, ignore if at root
357 already: */ 309 already: */
358 if (dest > rpath + prefix_len + 1) 310 if (dest > rname + prefix_len + 1)
359 for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest) 311 for (--dest; dest > rname && !ISSLASH (dest[-1]); --dest)
360 continue; 312 continue;
361 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 313 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1
362 && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len) 314 && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len)
363 dest++; 315 dest++;
364 } 316 }
365 } 317 }
366 else if (!S_ISDIR (st.st_mode) && *end != '\0') 318 else if (! (startlen == 0
367 { 319 ? stat (rname, &st) == 0 || errno == EOVERFLOW
368 __set_errno (ENOTDIR); 320 : errno == EINVAL))
369 goto error; 321 goto error;
370 }
371 } 322 }
372 } 323 }
373 if (dest > rpath + prefix_len + 1 && ISSLASH (dest[-1])) 324 if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1]))
374 --dest; 325 --dest;
375 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && !prefix_len 326 if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len
376 && ISSLASH (*dest) && !ISSLASH (dest[1])) 327 && ISSLASH (*dest) && !ISSLASH (dest[1]))
377 dest++; 328 dest++;
378 *dest = '\0'; 329 failed = false;
379
380 if (extra_buf)
381 freea (extra_buf);
382
383 return rpath;
384 330
385error: 331error:
386 { 332 *dest++ = '\0';
387 int saved_errno = errno; 333 if (resolved != NULL && dest - rname <= get_path_max ())
388 if (extra_buf) 334 rname = strcpy (resolved, rname);
389 freea (extra_buf); 335
390 if (resolved == NULL) 336error_nomem:
391 free (rpath); 337 scratch_buffer_free (&extra_buffer);
392 __set_errno (saved_errno); 338 scratch_buffer_free (&link_buffer);
393 } 339 if (failed || rname == resolved)
394 return NULL; 340 scratch_buffer_free (rname_buf);
341
342 if (failed)
343 return NULL;
344
345 if (rname == resolved)
346 return rname;
347 idx_t rname_size = dest - rname;
348 if (rname == rname_on_stack)
349 {
350 rname = malloc (rname_size);
351 if (rname == NULL)
352 return NULL;
353 return memcpy (rname, rname_on_stack, rname_size);
354 }
355 char *result = realloc (rname, rname_size);
356 return result != NULL ? result : rname;
395} 357}
358libc_hidden_def (__realpath)
396versioned_symbol (libc, __realpath, realpath, GLIBC_2_3); 359versioned_symbol (libc, __realpath, realpath, GLIBC_2_3);
397#endif /* !FUNC_REALPATH_WORKS || defined _LIBC */ 360#endif /* !FUNC_REALPATH_WORKS || defined _LIBC */
398 361
@@ -420,11 +383,3 @@ __canonicalize_file_name (const char *name)
420 return __realpath (name, NULL); 383 return __realpath (name, NULL);
421} 384}
422weak_alias (__canonicalize_file_name, canonicalize_file_name) 385weak_alias (__canonicalize_file_name, canonicalize_file_name)
423
424#else
425
426/* This declaration is solely to ensure that after preprocessing
427 this file is never empty. */
428typedef int dummy;
429
430#endif