OpenCoverage

pathchk.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/coreutils/src/src/pathchk.c
Source codeSwitch to Preprocessed file
LineSourceCount
1/* pathchk -- check whether file names are valid or portable-
2 Copyright (C) 1991-2018 Free Software Foundation, Inc.-
3-
4 This program is free software: you can redistribute it and/or modify-
5 it under the terms of the GNU General Public License as published by-
6 the Free Software Foundation, either version 3 of the License, or-
7 (at your option) any later version.-
8-
9 This program is distributed in the hope that it will be useful,-
10 but WITHOUT ANY WARRANTY; without even the implied warranty of-
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-
12 GNU General Public License for more details.-
13-
14 You should have received a copy of the GNU General Public License-
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */-
16-
17#include <config.h>-
18#include <stdio.h>-
19#include <getopt.h>-
20#include <sys/types.h>-
21#include <wchar.h>-
22-
23#include "system.h"-
24#include "error.h"-
25#include "quote.h"-
26-
27/* The official name of this program (e.g., no 'g' prefix). */-
28#define PROGRAM_NAME "pathchk"-
29-
30#define AUTHORS \-
31 proper_name ("Paul Eggert"), \-
32 proper_name ("David MacKenzie"), \-
33 proper_name ("Jim Meyering")-
34-
35#ifndef _POSIX_PATH_MAX-
36# define _POSIX_PATH_MAX 256-
37#endif-
38#ifndef _POSIX_NAME_MAX-
39# define _POSIX_NAME_MAX 14-
40#endif-
41-
42#ifdef _XOPEN_NAME_MAX-
43# define NAME_MAX_MINIMUM _XOPEN_NAME_MAX-
44#else-
45# define NAME_MAX_MINIMUM _POSIX_NAME_MAX-
46#endif-
47#ifdef _XOPEN_PATH_MAX-
48# define PATH_MAX_MINIMUM _XOPEN_PATH_MAX-
49#else-
50# define PATH_MAX_MINIMUM _POSIX_PATH_MAX-
51#endif-
52-
53#if ! (HAVE_PATHCONF && defined _PC_NAME_MAX && defined _PC_PATH_MAX)-
54# ifndef _PC_NAME_MAX-
55# define _PC_NAME_MAX 0-
56# define _PC_PATH_MAX 1-
57# endif-
58# ifndef pathconf-
59# define pathconf(file, flag) \-
60 (flag == _PC_NAME_MAX ? NAME_MAX_MINIMUM : PATH_MAX_MINIMUM)-
61# endif-
62#endif-
63-
64static bool validate_file_name (char *, bool, bool);-
65-
66/* For long options that have no equivalent short option, use a-
67 non-character as a pseudo short option, starting with CHAR_MAX + 1. */-
68enum-
69{-
70 PORTABILITY_OPTION = CHAR_MAX + 1-
71};-
72-
73static struct option const longopts[] =-
74{-
75 {"portability", no_argument, NULL, PORTABILITY_OPTION},-
76 {GETOPT_HELP_OPTION_DECL},-
77 {GETOPT_VERSION_OPTION_DECL},-
78 {NULL, 0, NULL, 0}-
79};-
80-
81void-
82usage (int status)-
83{-
84 if (status != EXIT_SUCCESS)
status != 0Description
TRUEevaluated 3 times by 1 test
Evaluated by:
  • pathchk
FALSEevaluated 6 times by 1 test
Evaluated by:
  • pathchk
3-6
85 emit_try_help ();
executed 3 times by 1 test: end of block
Executed by:
  • pathchk
3
86 else-
87 {-
88 printf (_("Usage: %s [OPTION]... NAME...\n"), program_name);-
89 fputs (_("\-
90Diagnose invalid or unportable file names.\n\-
91\n\-
92 -p check for most POSIX systems\n\-
93 -P check for empty names and leading \"-\"\n\-
94 --portability check for all POSIX systems (equivalent to -p -P)\n\-
95"), stdout);-
96 fputs (HELP_OPTION_DESCRIPTION, stdout);-
97 fputs (VERSION_OPTION_DESCRIPTION, stdout);-
98 emit_ancillary_info (PROGRAM_NAME);-
99 }
executed 6 times by 1 test: end of block
Executed by:
  • pathchk
6
100 exit (status);
executed 9 times by 1 test: exit (status);
Executed by:
  • pathchk
9
101}-
102-
103int-
104main (int argc, char **argv)-
105{-
106 bool ok = true;-
107 bool check_basic_portability = false;-
108 bool check_extra_portability = false;-
109 int optc;-
110-
111 initialize_main (&argc, &argv);-
112 set_program_name (argv[0]);-
113 setlocale (LC_ALL, "");-
114 bindtextdomain (PACKAGE, LOCALEDIR);-
115 textdomain (PACKAGE);-
116-
117 atexit (close_stdout);-
118-
119 while ((optc = getopt_long (argc, argv, "+pP", longopts, NULL)) != -1)
(optc = getopt... *)0) )) != -1Description
TRUEevaluated 21 times by 1 test
Evaluated by:
  • pathchk
FALSEevaluated 6 times by 1 test
Evaluated by:
  • pathchk
6-21
120 {-
121 switch (optc)-
122 {-
123 case PORTABILITY_OPTION:
executed 1 time by 1 test: case PORTABILITY_OPTION:
Executed by:
  • pathchk
1
124 check_basic_portability = true;-
125 check_extra_portability = true;-
126 break;
executed 1 time by 1 test: break;
Executed by:
  • pathchk
1
127-
128 case 'p':
executed 3 times by 1 test: case 'p':
Executed by:
  • pathchk
3
129 check_basic_portability = true;-
130 break;
executed 3 times by 1 test: break;
Executed by:
  • pathchk
3
131-
132 case 'P':
executed 4 times by 1 test: case 'P':
Executed by:
  • pathchk
4
133 check_extra_portability = true;-
134 break;
executed 4 times by 1 test: break;
Executed by:
  • pathchk
4
135-
136 case_GETOPT_HELP_CHAR;
never executed: break;
executed 6 times by 1 test: case GETOPT_HELP_CHAR:
Executed by:
  • pathchk
0-6
137-
138 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
executed 4 times by 1 test: exit ( 0 );
Executed by:
  • pathchk
never executed: break;
executed 4 times by 1 test: case GETOPT_VERSION_CHAR:
Executed by:
  • pathchk
0-4
139-
140 default:
executed 3 times by 1 test: default:
Executed by:
  • pathchk
3
141 usage (EXIT_FAILURE);-
142 }
never executed: end of block
0
143 }-
144-
145 if (optind == argc)
optind == argcDescription
TRUEnever evaluated
FALSEevaluated 6 times by 1 test
Evaluated by:
  • pathchk
0-6
146 {-
147 error (0, 0, _("missing operand"));-
148 usage (EXIT_FAILURE);-
149 }
never executed: end of block
0
150-
151 for (; optind < argc; ++optind)
optind < argcDescription
TRUEevaluated 6 times by 1 test
Evaluated by:
  • pathchk
FALSEevaluated 6 times by 1 test
Evaluated by:
  • pathchk
6
152 ok &= validate_file_name (argv[optind],
executed 6 times by 1 test: ok &= validate_file_name (argv[optind], check_basic_portability, check_extra_portability);
Executed by:
  • pathchk
6
153 check_basic_portability, check_extra_portability);
executed 6 times by 1 test: ok &= validate_file_name (argv[optind], check_basic_portability, check_extra_portability);
Executed by:
  • pathchk
6
154-
155 return ok ? EXIT_SUCCESS : EXIT_FAILURE;
executed 6 times by 1 test: return ok ? 0 : 1 ;
Executed by:
  • pathchk
6
156}-
157-
158/* If FILE contains a component with a leading "-", report an error-
159 and return false; otherwise, return true. */-
160-
161static bool-
162no_leading_hyphen (char const *file)-
163{-
164 char const *p;-
165-
166 for (p = file; (p = strchr (p, '-')); p++)
(p = (__extens... p , '-' ))) )Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • pathchk
FALSEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
__builtin_constant_p ( '-' )Description
TRUEnever evaluated
FALSEnever evaluated
!__builtin_constant_p ( p )Description
TRUEnever evaluated
FALSEnever evaluated
( '-' ) == '\0'Description
TRUEnever evaluated
FALSEnever evaluated
0-2
167 if (p == file || p[-1] == '/')
p == fileDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
FALSEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
p[-1] == '/'Description
TRUEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
FALSEnever evaluated
0-1
168 {-
169 error (0, 0, _("leading '-' in a component of file name %s"),-
170 quoteaf (file));-
171 return false;
executed 2 times by 1 test: return 0 ;
Executed by:
  • pathchk
2
172 }-
173-
174 return true;
executed 1 time by 1 test: return 1 ;
Executed by:
  • pathchk
1
175}-
176-
177/* If FILE (of length FILELEN) contains only portable characters,-
178 return true, else report an error and return false. */-
179-
180static bool-
181portable_chars_only (char const *file, size_t filelen)-
182{-
183 size_t validlen = strspn (file,-
184 ("/"-
185 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"-
186 "abcdefghijklmnopqrstuvwxyz"-
187 "0123456789._-"));-
188 char const *invalid = file + validlen;-
189-
190 if (*invalid)
*invalidDescription
TRUEnever evaluated
FALSEnever evaluated
0
191 {-
192 mbstate_t mbstate = { 0, };-
193 size_t charlen = mbrlen (invalid, filelen - validlen, &mbstate);-
194 error (0, 0,-
195 _("nonportable character %s in file name %s"),-
196 quotearg_n_style_mem (1, locale_quoting_style, invalid,-
197 (charlen <= MB_LEN_MAX ? charlen : 1)),-
198 quoteaf_n (0, file));-
199 return false;
never executed: return 0 ;
0
200 }-
201-
202 return true;
never executed: return 1 ;
0
203}-
204-
205/* Return the address of the start of the next file name component in F. */-
206-
207static char * _GL_ATTRIBUTE_PURE-
208component_start (char *f)-
209{-
210 while (*f == '/')
*f == '/'Description
TRUEnever evaluated
FALSEnever evaluated
0
211 f++;
never executed: f++;
0
212 return f;
never executed: return f;
0
213}-
214-
215/* Return the size of the file name component F. F must be nonempty. */-
216-
217static size_t _GL_ATTRIBUTE_PURE-
218component_len (char const *f)-
219{-
220 size_t len;-
221 for (len = 1; f[len] != '/' && f[len]; len++)
f[len] != '/'Description
TRUEnever evaluated
FALSEnever evaluated
f[len]Description
TRUEnever evaluated
FALSEnever evaluated
0
222 continue;
never executed: continue;
0
223 return len;
never executed: return len;
0
224}-
225-
226/* Make sure that-
227 strlen (FILE) <= PATH_MAX-
228 && strlen (each-existing-directory-in-FILE) <= NAME_MAX-
229-
230 If CHECK_BASIC_PORTABILITY is true, compare against _POSIX_PATH_MAX and-
231 _POSIX_NAME_MAX instead, and make sure that FILE contains no-
232 characters not in the POSIX portable filename character set, which-
233 consists of A-Z, a-z, 0-9, ., _, - (plus / for separators).-
234-
235 If CHECK_BASIC_PORTABILITY is false, make sure that all leading directories-
236 along FILE that exist are searchable.-
237-
238 If CHECK_EXTRA_PORTABILITY is true, check that file name components do not-
239 begin with "-".-
240-
241 If either CHECK_BASIC_PORTABILITY or CHECK_EXTRA_PORTABILITY is true,-
242 check that the file name is not empty.-
243-
244 Return true if all of these tests are successful, false if any fail. */-
245-
246static bool-
247validate_file_name (char *file, bool check_basic_portability,-
248 bool check_extra_portability)-
249{-
250 size_t filelen = strlen (file);-
251-
252 /* Start of file name component being checked. */-
253 char *start;-
254-
255 /* True if component lengths need to be checked. */-
256 bool check_component_lengths;-
257-
258 /* True if the file is known to exist. */-
259 bool file_exists = false;-
260-
261 if (check_extra_portability && ! no_leading_hyphen (file))
check_extra_portabilityDescription
TRUEevaluated 3 times by 1 test
Evaluated by:
  • pathchk
FALSEevaluated 3 times by 1 test
Evaluated by:
  • pathchk
! no_leading_hyphen (file)Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • pathchk
FALSEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
1-3
262 return false;
executed 2 times by 1 test: return 0 ;
Executed by:
  • pathchk
2
263-
264 if ((check_basic_portability || check_extra_portability)
check_basic_portabilityDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
FALSEevaluated 3 times by 1 test
Evaluated by:
  • pathchk
check_extra_portabilityDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
FALSEevaluated 2 times by 1 test
Evaluated by:
  • pathchk
1-3
265 && filelen == 0)
filelen == 0Description
TRUEevaluated 2 times by 1 test
Evaluated by:
  • pathchk
FALSEnever evaluated
0-2
266 {-
267 /* Fail, since empty names are not portable. As of-
268 2005-01-06 POSIX does not address whether "pathchk -p ''"-
269 should (or is allowed to) fail, so this is not a-
270 conformance violation. */-
271 error (0, 0, _("empty file name"));-
272 return false;
executed 2 times by 1 test: return 0 ;
Executed by:
  • pathchk
2
273 }-
274-
275 if (check_basic_portability)
check_basic_portabilityDescription
TRUEnever evaluated
FALSEevaluated 2 times by 1 test
Evaluated by:
  • pathchk
0-2
276 {-
277 if (! portable_chars_only (file, filelen))
! portable_cha...file, filelen)Description
TRUEnever evaluated
FALSEnever evaluated
0
278 return false;
never executed: return 0 ;
0
279 }
never executed: end of block
0
280 else-
281 {-
282 /* Check whether a file name component is in a directory that-
283 is not searchable, or has some other serious problem.-
284 POSIX does not allow "" as a file name, but some non-POSIX-
285 hosts do (as an alias for "."), so allow "" if lstat does. */-
286-
287 struct stat st;-
288 if (lstat (file, &st) == 0)
lstat (file, &st) == 0Description
TRUEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
FALSEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
1
289 file_exists = true;
executed 1 time by 1 test: file_exists = 1 ;
Executed by:
  • pathchk
1
290 else if (errno != ENOENT || filelen == 0)
(*__errno_location ()) != 2Description
TRUEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
FALSEnever evaluated
filelen == 0Description
TRUEnever evaluated
FALSEnever evaluated
0-1
291 {-
292 error (0, errno, "%s", quotef (file));-
293 return false;
executed 1 time by 1 test: return 0 ;
Executed by:
  • pathchk
1
294 }-
295 }
executed 1 time by 1 test: end of block
Executed by:
  • pathchk
1
296-
297 if (check_basic_portability
check_basic_portabilityDescription
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
0-1
298 || (! file_exists && PATH_MAX_MINIMUM <= filelen))
! file_existsDescription
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
256 <= filelenDescription
TRUEnever evaluated
FALSEnever evaluated
0-1
299 {-
300 size_t maxsize;-
301-
302 if (check_basic_portability)
check_basic_portabilityDescription
TRUEnever evaluated
FALSEnever evaluated
0
303 maxsize = _POSIX_PATH_MAX;
never executed: maxsize = 256 ;
0
304 else-
305 {-
306 long int size;-
307 char const *dir = (*file == '/' ? "/" : ".");
*file == '/'Description
TRUEnever evaluated
FALSEnever evaluated
0
308 errno = 0;-
309 size = pathconf (dir, _PC_PATH_MAX);-
310 if (size < 0 && errno != 0)
size < 0Description
TRUEnever evaluated
FALSEnever evaluated
(*__errno_location ()) != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
311 {-
312 error (0, errno,-
313 _("%s: unable to determine maximum file name length"),-
314 dir);-
315 return false;
never executed: return 0 ;
0
316 }-
317 maxsize = MIN (size, SSIZE_MAX);
(( size )<(0x7...fffffffffffL))Description
TRUEnever evaluated
FALSEnever evaluated
0
318 }
never executed: end of block
0
319-
320 if (maxsize <= filelen)
maxsize <= filelenDescription
TRUEnever evaluated
FALSEnever evaluated
0
321 {-
322 unsigned long int len = filelen;-
323 unsigned long int maxlen = maxsize - 1;-
324 error (0, 0, _("limit %lu exceeded by length %lu of file name %s"),-
325 maxlen, len, quoteaf (file));-
326 return false;
never executed: return 0 ;
0
327 }-
328 }
never executed: end of block
0
329-
330 /* Check whether pathconf (..., _PC_NAME_MAX) can be avoided, i.e.,-
331 whether all file name components are so short that they are valid-
332 in any file system on this platform. If CHECK_BASIC_PORTABILITY, though,-
333 it's more convenient to check component lengths below. */-
334-
335 check_component_lengths = check_basic_portability;-
336 if (! check_component_lengths && ! file_exists)
! check_component_lengthsDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
FALSEnever evaluated
! file_existsDescription
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
0-1
337 {-
338 for (start = file; *(start = component_start (start)); )
*(start = comp...start (start))Description
TRUEnever evaluated
FALSEnever evaluated
0
339 {-
340 size_t length = component_len (start);-
341-
342 if (NAME_MAX_MINIMUM < length)
14 < lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
343 {-
344 check_component_lengths = true;-
345 break;
never executed: break;
0
346 }-
347-
348 start += length;-
349 }
never executed: end of block
0
350 }
never executed: end of block
0
351-
352 if (check_component_lengths)
check_component_lengthsDescription
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • pathchk
0-1
353 {-
354 /* The limit on file name components for the current component.-
355 This defaults to NAME_MAX_MINIMUM, for the sake of non-POSIX-
356 systems (NFS, say?) where pathconf fails on "." or "/" with-
357 errno == ENOENT. */-
358 size_t name_max = NAME_MAX_MINIMUM;-
359-
360 /* If nonzero, the known limit on file name components. */-
361 size_t known_name_max = (check_basic_portability ? _POSIX_NAME_MAX : 0);
check_basic_portabilityDescription
TRUEnever evaluated
FALSEnever evaluated
0
362-
363 for (start = file; *(start = component_start (start)); )
*(start = comp...start (start))Description
TRUEnever evaluated
FALSEnever evaluated
0
364 {-
365 size_t length;-
366-
367 if (known_name_max)
known_name_maxDescription
TRUEnever evaluated
FALSEnever evaluated
0
368 name_max = known_name_max;
never executed: name_max = known_name_max;
0
369 else-
370 {-
371 long int len;-
372 char const *dir = (start == file ? "." : file);
start == fileDescription
TRUEnever evaluated
FALSEnever evaluated
0
373 char c = *start;-
374 errno = 0;-
375 *start = '\0';-
376 len = pathconf (dir, _PC_NAME_MAX);-
377 *start = c;-
378 if (0 <= len)
0 <= lenDescription
TRUEnever evaluated
FALSEnever evaluated
0
379 name_max = MIN (len, SSIZE_MAX);
never executed: name_max = ((( len )<(0x7fffffffffffffffL))?( len ):(0x7fffffffffffffffL)) ;
(( len )<(0x7f...fffffffffffL))Description
TRUEnever evaluated
FALSEnever evaluated
0
380 else-
381 switch (errno)-
382 {-
383 case 0:
never executed: case 0:
0
384 /* There is no limit. */-
385 name_max = SIZE_MAX;-
386 break;
never executed: break;
0
387-
388 case ENOENT:
never executed: case 2 :
0
389 /* DIR does not exist; use its parent's maximum. */-
390 known_name_max = name_max;-
391 break;
never executed: break;
0
392-
393 default:
never executed: default:
0
394 *start = '\0';-
395 error (0, errno, "%s", quotef (dir));-
396 *start = c;-
397 return false;
never executed: return 0 ;
0
398 }-
399 }-
400-
401 length = component_len (start);-
402-
403 if (name_max < length)
name_max < lengthDescription
TRUEnever evaluated
FALSEnever evaluated
0
404 {-
405 unsigned long int len = length;-
406 unsigned long int maxlen = name_max;-
407 char c = start[len];-
408 start[len] = '\0';-
409 error (0, 0,-
410 _("limit %lu exceeded by length %lu "-
411 "of file name component %s"),-
412 maxlen, len, quote (start));-
413 start[len] = c;-
414 return false;
never executed: return 0 ;
0
415 }-
416-
417 start += length;-
418 }
never executed: end of block
0
419 }
never executed: end of block
0
420-
421 return true;
executed 1 time by 1 test: return 1 ;
Executed by:
  • pathchk
1
422}-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.1.2