]>
Dogcows Code - chaz/tar/blob - src/names.c
1 /* Various processing of names.
2 Copyright (C) 1988, 92, 94, 96, 97, 98, 1999 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2, or (at your option) any later
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Enable GNU extensions in fnmatch.h. */
20 # define _GNU_SOURCE 1
31 /* User and group names. */
33 extern struct group
*getgrnam ();
34 extern struct passwd
*getpwnam ();
36 extern struct passwd
*getpwuid ();
39 extern struct group
*getgrgid ();
42 /* Make sure you link with the proper libraries if you are running the
43 Yellow Peril (thanks for the good laugh, Ian J.!), or, euh... NIS.
44 This code should also be modified for non-UNIX systems to do something
47 static char cached_uname
[UNAME_FIELD_SIZE
] = "";
48 static char cached_gname
[GNAME_FIELD_SIZE
] = "";
50 static uid_t cached_uid
; /* valid only if cached_uname is not empty */
51 static gid_t cached_gid
; /* valid only if cached_gname is not empty */
53 /* These variables are valid only if nonempty. */
54 static char cached_no_such_uname
[UNAME_FIELD_SIZE
] = "";
55 static char cached_no_such_gname
[GNAME_FIELD_SIZE
] = "";
57 /* These variables are valid only if nonzero. It's not worth optimizing
58 the case for weird systems where 0 is not a valid uid or gid. */
59 static uid_t cached_no_such_uid
= 0;
60 static gid_t cached_no_such_gid
= 0;
62 /*------------------------------------------.
63 | Given UID, find the corresponding UNAME. |
64 `------------------------------------------*/
67 uid_to_uname (uid_t uid
, char uname
[UNAME_FIELD_SIZE
])
69 struct passwd
*passwd
;
71 if (uid
!= 0 && uid
== cached_no_such_uid
)
77 if (!cached_uname
[0] || uid
!= cached_uid
)
79 passwd
= getpwuid (uid
);
83 strncpy (cached_uname
, passwd
->pw_name
, UNAME_FIELD_SIZE
);
87 cached_no_such_uid
= uid
;
92 strncpy (uname
, cached_uname
, UNAME_FIELD_SIZE
);
95 /*------------------------------------------.
96 | Given GID, find the corresponding GNAME. |
97 `------------------------------------------*/
100 gid_to_gname (gid_t gid
, char gname
[GNAME_FIELD_SIZE
])
104 if (gid
!= 0 && gid
== cached_no_such_gid
)
110 if (!cached_gname
[0] || gid
!= cached_gid
)
112 setgrent (); /* FIXME: why?! */
113 group
= getgrgid (gid
);
117 strncpy (cached_gname
, group
->gr_name
, GNAME_FIELD_SIZE
);
121 cached_no_such_gid
= gid
;
126 strncpy (gname
, cached_gname
, GNAME_FIELD_SIZE
);
129 /*-------------------------------------------------------------------------.
130 | Given UNAME, set the corresponding UID and return 1, or else, return 0. |
131 `-------------------------------------------------------------------------*/
134 uname_to_uid (char uname
[UNAME_FIELD_SIZE
], uid_t
*uidp
)
136 struct passwd
*passwd
;
138 if (cached_no_such_uname
[0]
139 && strncmp (uname
, cached_no_such_uname
, UNAME_FIELD_SIZE
) == 0)
143 || uname
[0] != cached_uname
[0]
144 || strncmp (uname
, cached_uname
, UNAME_FIELD_SIZE
) != 0)
146 passwd
= getpwnam (uname
);
149 cached_uid
= passwd
->pw_uid
;
150 strncpy (cached_uname
, uname
, UNAME_FIELD_SIZE
);
154 strncpy (cached_no_such_uname
, uname
, UNAME_FIELD_SIZE
);
162 /*-------------------------------------------------------------------------.
163 | Given GNAME, set the corresponding GID and return 1, or else, return 0. |
164 `-------------------------------------------------------------------------*/
167 gname_to_gid (char gname
[GNAME_FIELD_SIZE
], gid_t
*gidp
)
171 if (cached_no_such_gname
[0]
172 && strncmp (gname
, cached_no_such_gname
, GNAME_FIELD_SIZE
) == 0)
176 || gname
[0] != cached_gname
[0]
177 || strncmp (gname
, cached_gname
, GNAME_FIELD_SIZE
) != 0)
179 group
= getgrnam (gname
);
182 cached_gid
= group
->gr_gid
;
183 strncpy (cached_gname
, gname
, GNAME_FIELD_SIZE
);
187 strncpy (cached_no_such_gname
, gname
, GNAME_FIELD_SIZE
);
195 /* Names from the command call. */
197 static const char **name_array
; /* store an array of names */
198 static int allocated_names
; /* how big is the array? */
199 static int names
; /* how many entries does it have? */
200 static int name_index
= 0; /* how many of the entries have we scanned? */
202 /*------------------------.
203 | Initialize structures. |
204 `------------------------*/
209 allocated_names
= 10;
210 name_array
= (const char **)
211 xmalloc (sizeof (const char *) * allocated_names
);
215 /*--------------------------------------------------------------.
216 | Add NAME at end of name_array, reallocating it as necessary. |
217 `--------------------------------------------------------------*/
220 name_add (const char *name
)
222 if (names
== allocated_names
)
224 allocated_names
*= 2;
225 name_array
= (const char **)
226 xrealloc (name_array
, sizeof (const char *) * allocated_names
);
228 name_array
[names
++] = name
;
231 /* Names from external name file. */
233 static FILE *name_file
; /* file to read names from */
234 static char *name_buffer
; /* buffer to hold the current file name */
235 static size_t name_buffer_length
; /* allocated length of name_buffer */
241 /* FIXME: I should better check more closely. It seems at first glance that
242 is_pattern is only used when reading a file, and ignored for all
243 command line arguments. */
246 is_pattern (const char *string
)
248 return strchr (string
, '*') || strchr (string
, '[') || strchr (string
, '?');
251 /*-----------------------------------------------------------------------.
252 | Set up to gather file names for tar. They can either come from a file |
253 | or were saved from decoding arguments. |
254 `-----------------------------------------------------------------------*/
257 name_init (int argc
, char *const *argv
)
259 name_buffer
= xmalloc (NAME_FIELD_SIZE
+ 2);
260 name_buffer_length
= NAME_FIELD_SIZE
;
262 if (files_from_option
)
264 if (!strcmp (files_from_option
, "-"))
266 request_stdin ("-T");
269 else if (name_file
= fopen (files_from_option
, "r"), !name_file
)
270 FATAL_ERROR ((0, errno
, _("Cannot open file %s"), files_from_option
));
285 /*---------------------------------------------------------------------.
286 | Read the next filename from name_file and null-terminate it. Put it |
287 | into name_buffer, reallocating and adjusting name_buffer_length if |
288 | necessary. Return 0 at end of file, 1 otherwise. |
289 `---------------------------------------------------------------------*/
292 read_name_from_file (void)
297 /* FIXME: getc may be called even if character was EOF the last time here. */
299 /* FIXME: This + 2 allocation might serve no purpose. */
301 while (character
= getc (name_file
),
302 character
!= EOF
&& character
!= filename_terminator
)
304 if (counter
== name_buffer_length
)
306 name_buffer_length
+= NAME_FIELD_SIZE
;
307 name_buffer
= xrealloc (name_buffer
, name_buffer_length
+ 2);
309 name_buffer
[counter
++] = character
;
312 if (counter
== 0 && character
== EOF
)
315 if (counter
== name_buffer_length
)
317 name_buffer_length
+= NAME_FIELD_SIZE
;
318 name_buffer
= xrealloc (name_buffer
, name_buffer_length
+ 2);
320 name_buffer
[counter
] = '\0';
325 /*------------------------------------------------------------------------.
326 | Get the next name from ARGV or the file of names. Result is in static |
327 | storage and can't be relied upon across two calls. |
329 | If CHANGE_DIRS is true, treat a filename of the form "-C" as meaning |
330 | that the next filename is the name of a directory to change to. If |
331 | `filename_terminator' is NUL, CHANGE_DIRS is effectively always false. |
332 `------------------------------------------------------------------------*/
335 name_next (int change_dirs
)
341 if (filename_terminator
== '\0')
346 /* Get a name, either from file or from saved arguments. */
350 if (!read_name_from_file ())
355 if (name_index
== names
)
358 source
= name_array
[name_index
++];
359 if (strlen (source
) > name_buffer_length
)
362 name_buffer_length
= strlen (source
);
363 name_buffer
= xmalloc (name_buffer_length
+ 2);
365 strcpy (name_buffer
, source
);
368 /* Zap trailing slashes. */
370 cursor
= name_buffer
+ strlen (name_buffer
) - 1;
371 while (cursor
> name_buffer
&& *cursor
== '/')
376 chdir_from_initial_wd (name_buffer
);
379 else if (change_dirs
&& strcmp (name_buffer
, "-C") == 0)
383 unquote_string (name_buffer
);
388 /* No more names in file. */
390 if (name_file
&& chdir_flag
)
391 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
396 /*------------------------------.
397 | Close the name file, if any. |
398 `------------------------------*/
403 if (name_file
!= NULL
&& name_file
!= stdin
)
404 if (fclose (name_file
) == EOF
)
405 ERROR ((0, errno
, "%s", name_buffer
));
408 /*-------------------------------------------------------------------------.
409 | Gather names in a list for scanning. Could hash them later if we really |
412 | If the names are already sorted to match the archive, we just read them |
413 | one by one. name_gather reads the first one, and it is called by |
414 | name_match as appropriate to read the next ones. At EOF, the last name |
415 | read is just left in the buffer. This option lets users of small |
416 | machines extract an arbitrary number of files by doing "tar t" and |
417 | editing down the list of files. |
418 `-------------------------------------------------------------------------*/
423 /* Buffer able to hold a single name. */
424 static struct name
*buffer
;
425 static size_t allocated_length
= 0;
429 if (same_order_option
)
431 char *change_dir
= NULL
;
433 if (allocated_length
== 0)
435 allocated_length
= sizeof (struct name
) + NAME_FIELD_SIZE
;
436 buffer
= (struct name
*) xmalloc (allocated_length
);
437 /* FIXME: This memset is overkill, and ugly... */
438 memset (buffer
, 0, allocated_length
);
441 while ((name
= name_next (0)) && strcmp (name
, "-C") == 0)
443 char const *dir
= name_next (0);
445 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
448 change_dir
= xstrdup (dir
);
453 buffer
->length
= strlen (name
);
454 if (sizeof (struct name
) + buffer
->length
>= allocated_length
)
456 allocated_length
= sizeof (struct name
) + buffer
->length
;
457 buffer
= (struct name
*) xrealloc (buffer
, allocated_length
);
459 buffer
->change_dir
= change_dir
;
460 strncpy (buffer
->name
, name
, (size_t) buffer
->length
);
461 buffer
->name
[buffer
->length
] = 0;
465 /* FIXME: Poorly named globals, indeed... */
475 /* Non sorted names -- read them all in. */
479 char *change_dir
= NULL
;
480 while ((name
= name_next (0)) && strcmp (name
, "-C") == 0)
482 char const *dir
= name_next (0);
484 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
487 change_dir
= xstrdup (dir
);
490 addname (name
, change_dir
);
500 /*-----------------------------.
501 | Add a name to the namelist. |
502 `-----------------------------*/
505 addname (char const *string
, char const *change_dir
)
510 length
= string
? strlen (string
) : 0;
511 name
= (struct name
*) xmalloc (sizeof (struct name
) + length
);
512 memset (name
, 0, sizeof (struct name
) + length
);
518 name
->length
= length
;
519 /* FIXME: Possibly truncating a string, here? Tss, tss, tss! */
520 strncpy (name
->name
, string
, length
);
521 name
->name
[length
] = '\0';
527 name
->regexp
= 0; /* assume not a regular expression */
528 name
->firstch
= 1; /* assume first char is literal */
529 name
->change_dir
= change_dir
;
530 name
->dir_contents
= 0;
532 if (string
&& is_pattern (string
))
535 if (string
[0] == '*' || string
[0] == '[' || string
[0] == '?')
540 namelast
->next
= name
;
546 /*------------------------------------------------------------------------.
547 | Return true if and only if name PATH (from an archive) matches any name |
548 | from the namelist. |
549 `------------------------------------------------------------------------*/
552 name_match (const char *path
)
554 size_t length
= strlen (path
);
558 struct name
*cursor
= namelist
;
561 return 1; /* empty namelist is easy */
565 chdir_from_initial_wd (cursor
->change_dir
);
570 for (; cursor
; cursor
= cursor
->next
)
572 /* If first chars don't match, quick skip. */
574 if (cursor
->firstch
&& cursor
->name
[0] != path
[0])
577 /* Regular expressions (shell globbing, actually). */
581 if (fnmatch (cursor
->name
, path
, FNM_LEADING_DIR
) == 0)
583 cursor
->found
= 1; /* remember it matched */
584 if (starting_file_option
)
589 chdir_from_initial_wd (cursor
->change_dir
);
591 /* We got a match. */
597 /* Plain Old Strings. */
599 if (cursor
->length
<= length
600 /* archive length >= specified */
601 && (path
[cursor
->length
] == '\0'
602 || path
[cursor
->length
] == '/')
603 /* full match on file/dirname */
604 && strncmp (path
, cursor
->name
, cursor
->length
) == 0)
607 cursor
->found
= 1; /* remember it matched */
608 if (starting_file_option
)
610 free ((void *) namelist
);
613 chdir_from_initial_wd (cursor
->change_dir
);
615 /* We got a match. */
620 /* Filename from archive not found in namelist. If we have the whole
621 namelist here, just return 0. Otherwise, read the next name in and
622 compare it. If this was the last name, namelist->found will remain
623 on. If not, we loop to compare the newly read name. */
625 if (same_order_option
&& namelist
->found
)
627 name_gather (); /* read one more */
636 /*------------------------------------------------------------------.
637 | Print the names of things in the namelist that were not matched. |
638 `------------------------------------------------------------------*/
641 names_notfound (void)
646 for (cursor
= namelist
; cursor
; cursor
= next
)
649 if (!cursor
->found
&& !cursor
->fake
)
650 ERROR ((0, 0, _("%s: Not found in archive"), cursor
->name
));
652 /* We could free the list, but the process is about to die anyway, so
653 save some CPU time. Amigas and other similarly broken software
654 will need to waste the time, though. */
657 if (!same_order_option
)
661 namelist
= (struct name
*) NULL
;
662 namelast
= (struct name
*) NULL
;
664 if (same_order_option
)
668 while (name
= name_next (1), name
)
669 ERROR ((0, 0, _("%s: Not found in archive"), name
));
682 /*-------------------------------------------------------------------------.
683 | This is like name_match, except that it returns a pointer to the name it |
684 | matched, and doesn't set FOUND in structure. The caller will have to do |
685 | that if it wants to. Oh, and if the namelist is empty, it returns NULL, |
686 | unlike name_match, which returns TRUE. |
687 `-------------------------------------------------------------------------*/
690 name_scan (const char *path
)
692 size_t length
= strlen (path
);
696 struct name
*cursor
= namelist
;
699 return NULL
; /* empty namelist is easy */
701 for (; cursor
; cursor
= cursor
->next
)
703 /* If first chars don't match, quick skip. */
705 if (cursor
->firstch
&& cursor
->name
[0] != path
[0])
708 /* Regular expressions. */
712 if (fnmatch (cursor
->name
, path
, FNM_LEADING_DIR
) == 0)
713 return cursor
; /* we got a match */
717 /* Plain Old Strings. */
719 if (cursor
->length
<= length
720 /* archive length >= specified */
721 && (path
[cursor
->length
] == '\0'
722 || path
[cursor
->length
] == '/')
723 /* full match on file/dirname */
724 && strncmp (path
, cursor
->name
, cursor
->length
) == 0)
726 return cursor
; /* we got a match */
729 /* Filename from archive not found in namelist. If we have the whole
730 namelist here, just return 0. Otherwise, read the next name in and
731 compare it. If this was the last name, namelist->found will remain
732 on. If not, we loop to compare the newly read name. */
734 if (same_order_option
&& namelist
->found
)
736 name_gather (); /* read one more */
745 /*-----------------------------------------------------------------------.
746 | This returns a name from the namelist which doesn't have ->found set. |
747 | It sets ->found before returning, so successive calls will find and |
748 | return all the non-found names in the namelist |
749 `-----------------------------------------------------------------------*/
751 struct name
*gnu_list_name
= NULL
;
754 name_from_list (void)
757 gnu_list_name
= namelist
;
758 while (gnu_list_name
&& gnu_list_name
->found
)
759 gnu_list_name
= gnu_list_name
->next
;
762 gnu_list_name
->found
= 1;
763 chdir_from_initial_wd (gnu_list_name
->change_dir
);
764 return gnu_list_name
->name
;
774 blank_name_list (void)
779 for (name
= namelist
; name
; name
= name
->next
)
788 new_name (const char *path
, const char *name
)
790 char *buffer
= (char *) xmalloc (strlen (path
) + strlen (name
) + 2);
792 sprintf (buffer
, "%s/%s", path
, name
);
796 /* Return nonzero if file NAME is excluded. Exclude a name if its
797 prefix matches a pattern that contains slashes, or if one of its
798 components matches a pattern that contains no slashes. */
800 excluded_name (char const *name
)
803 name
+= FILESYSTEM_PREFIX_LEN (name
);
805 if (excluded_filename (excluded_with_slash
, name
,
806 FNM_FILE_NAME
| FNM_LEADING_DIR
))
809 for (p
= name
; *p
; p
++)
810 if ((p
== name
|| (ISSLASH (p
[-1]) && !ISSLASH (p
[0])))
811 && excluded_filename (excluded_without_slash
, p
,
812 FNM_FILE_NAME
| FNM_LEADING_DIR
))
This page took 0.071066 seconds and 5 git commands to generate.