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 Place - Suite 330, Boston, MA 02111-1307, USA. */
23 #ifndef FNM_LEADING_DIR
29 /* User and group names. */
31 extern struct group
*getgrnam ();
32 extern struct passwd
*getpwnam ();
34 extern struct passwd
*getpwuid ();
37 extern struct group
*getgrgid ();
40 /* Make sure you link with the proper libraries if you are running the
41 Yellow Peril (thanks for the good laugh, Ian J.!), or, euh... NIS.
42 This code should also be modified for non-UNIX systems to do something
45 static char cached_uname
[UNAME_FIELD_SIZE
] = "";
46 static char cached_gname
[GNAME_FIELD_SIZE
] = "";
48 static uid_t cached_uid
; /* valid only if cached_uname is not empty */
49 static gid_t cached_gid
; /* valid only if cached_gname is not empty */
51 /* These variables are valid only if nonempty. */
52 static char cached_no_such_uname
[UNAME_FIELD_SIZE
] = "";
53 static char cached_no_such_gname
[GNAME_FIELD_SIZE
] = "";
55 /* These variables are valid only if nonzero. It's not worth optimizing
56 the case for weird systems where 0 is not a valid uid or gid. */
57 static uid_t cached_no_such_uid
= 0;
58 static gid_t cached_no_such_gid
= 0;
60 /*------------------------------------------.
61 | Given UID, find the corresponding UNAME. |
62 `------------------------------------------*/
65 uid_to_uname (uid_t uid
, char uname
[UNAME_FIELD_SIZE
])
67 struct passwd
*passwd
;
69 if (uid
!= 0 && uid
== cached_no_such_uid
)
75 if (!cached_uname
[0] || uid
!= cached_uid
)
77 passwd
= getpwuid (uid
);
81 strncpy (cached_uname
, passwd
->pw_name
, UNAME_FIELD_SIZE
);
85 cached_no_such_uid
= uid
;
90 strncpy (uname
, cached_uname
, UNAME_FIELD_SIZE
);
93 /*------------------------------------------.
94 | Given GID, find the corresponding GNAME. |
95 `------------------------------------------*/
98 gid_to_gname (gid_t gid
, char gname
[GNAME_FIELD_SIZE
])
102 if (gid
!= 0 && gid
== cached_no_such_gid
)
108 if (!cached_gname
[0] || gid
!= cached_gid
)
110 setgrent (); /* FIXME: why?! */
111 group
= getgrgid (gid
);
115 strncpy (cached_gname
, group
->gr_name
, GNAME_FIELD_SIZE
);
119 cached_no_such_gid
= gid
;
124 strncpy (gname
, cached_gname
, GNAME_FIELD_SIZE
);
127 /*-------------------------------------------------------------------------.
128 | Given UNAME, set the corresponding UID and return 1, or else, return 0. |
129 `-------------------------------------------------------------------------*/
132 uname_to_uid (char uname
[UNAME_FIELD_SIZE
], uid_t
*uidp
)
134 struct passwd
*passwd
;
136 if (cached_no_such_uname
[0]
137 && strncmp (uname
, cached_no_such_uname
, UNAME_FIELD_SIZE
) == 0)
141 || uname
[0] != cached_uname
[0]
142 || strncmp (uname
, cached_uname
, UNAME_FIELD_SIZE
) != 0)
144 passwd
= getpwnam (uname
);
147 cached_uid
= passwd
->pw_uid
;
148 strncpy (cached_uname
, uname
, UNAME_FIELD_SIZE
);
152 strncpy (cached_no_such_uname
, uname
, UNAME_FIELD_SIZE
);
160 /*-------------------------------------------------------------------------.
161 | Given GNAME, set the corresponding GID and return 1, or else, return 0. |
162 `-------------------------------------------------------------------------*/
165 gname_to_gid (char gname
[GNAME_FIELD_SIZE
], gid_t
*gidp
)
169 if (cached_no_such_gname
[0]
170 && strncmp (gname
, cached_no_such_gname
, GNAME_FIELD_SIZE
) == 0)
174 || gname
[0] != cached_gname
[0]
175 || strncmp (gname
, cached_gname
, GNAME_FIELD_SIZE
) != 0)
177 group
= getgrnam (gname
);
180 cached_gid
= group
->gr_gid
;
181 strncpy (cached_gname
, gname
, GNAME_FIELD_SIZE
);
185 strncpy (cached_no_such_gname
, gname
, GNAME_FIELD_SIZE
);
193 /* Names from the command call. */
195 static const char **name_array
; /* store an array of names */
196 static int allocated_names
; /* how big is the array? */
197 static int names
; /* how many entries does it have? */
198 static int name_index
= 0; /* how many of the entries have we scanned? */
200 /*------------------------.
201 | Initialize structures. |
202 `------------------------*/
207 allocated_names
= 10;
208 name_array
= (const char **)
209 xmalloc (sizeof (const char *) * allocated_names
);
213 /*--------------------------------------------------------------.
214 | Add NAME at end of name_array, reallocating it as necessary. |
215 `--------------------------------------------------------------*/
218 name_add (const char *name
)
220 if (names
== allocated_names
)
222 allocated_names
*= 2;
223 name_array
= (const char **)
224 xrealloc (name_array
, sizeof (const char *) * allocated_names
);
226 name_array
[names
++] = name
;
229 /* Names from external name file. */
231 static FILE *name_file
; /* file to read names from */
232 static char *name_buffer
; /* buffer to hold the current file name */
233 static size_t name_buffer_length
; /* allocated length of name_buffer */
239 /* FIXME: I should better check more closely. It seems at first glance that
240 is_pattern is only used when reading a file, and ignored for all
241 command line arguments. */
244 is_pattern (const char *string
)
246 return strchr (string
, '*') || strchr (string
, '[') || strchr (string
, '?');
249 /*-----------------------------------------------------------------------.
250 | Set up to gather file names for tar. They can either come from a file |
251 | or were saved from decoding arguments. |
252 `-----------------------------------------------------------------------*/
255 name_init (int argc
, char *const *argv
)
257 name_buffer
= xmalloc (NAME_FIELD_SIZE
+ 2);
258 name_buffer_length
= NAME_FIELD_SIZE
;
260 if (files_from_option
)
262 if (!strcmp (files_from_option
, "-"))
264 request_stdin ("-T");
267 else if (name_file
= fopen (files_from_option
, "r"), !name_file
)
268 FATAL_ERROR ((0, errno
, _("Cannot open file %s"), files_from_option
));
283 /*---------------------------------------------------------------------.
284 | Read the next filename from name_file and null-terminate it. Put it |
285 | into name_buffer, reallocating and adjusting name_buffer_length if |
286 | necessary. Return 0 at end of file, 1 otherwise. |
287 `---------------------------------------------------------------------*/
290 read_name_from_file (void)
295 /* FIXME: getc may be called even if character was EOF the last time here. */
297 /* FIXME: This + 2 allocation might serve no purpose. */
299 while (character
= getc (name_file
),
300 character
!= EOF
&& character
!= filename_terminator
)
302 if (counter
== name_buffer_length
)
304 name_buffer_length
+= NAME_FIELD_SIZE
;
305 name_buffer
= xrealloc (name_buffer
, name_buffer_length
+ 2);
307 name_buffer
[counter
++] = character
;
310 if (counter
== 0 && character
== EOF
)
313 if (counter
== name_buffer_length
)
315 name_buffer_length
+= NAME_FIELD_SIZE
;
316 name_buffer
= xrealloc (name_buffer
, name_buffer_length
+ 2);
318 name_buffer
[counter
] = '\0';
323 /*------------------------------------------------------------------------.
324 | Get the next name from ARGV or the file of names. Result is in static |
325 | storage and can't be relied upon across two calls. |
327 | If CHANGE_DIRS is true, treat a filename of the form "-C" as meaning |
328 | that the next filename is the name of a directory to change to. If |
329 | `filename_terminator' is NUL, CHANGE_DIRS is effectively always false. |
330 `------------------------------------------------------------------------*/
333 name_next (int change_dirs
)
339 if (filename_terminator
== '\0')
344 /* Get a name, either from file or from saved arguments. */
348 if (!read_name_from_file ())
353 if (name_index
== names
)
356 source
= name_array
[name_index
++];
357 if (strlen (source
) > name_buffer_length
)
360 name_buffer_length
= strlen (source
);
361 name_buffer
= xmalloc (name_buffer_length
+ 2);
363 strcpy (name_buffer
, source
);
366 /* Zap trailing slashes. */
368 cursor
= name_buffer
+ strlen (name_buffer
) - 1;
369 while (cursor
> name_buffer
&& *cursor
== '/')
374 if (chdir (name_buffer
) < 0)
375 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
379 else if (change_dirs
&& strcmp (name_buffer
, "-C") == 0)
383 if (!exclude_option
|| !check_exclude (name_buffer
))
386 unquote_string (name_buffer
);
391 /* No more names in file. */
393 if (name_file
&& chdir_flag
)
394 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
399 /*------------------------------.
400 | Close the name file, if any. |
401 `------------------------------*/
406 if (name_file
!= NULL
&& name_file
!= stdin
)
407 if (fclose (name_file
) == EOF
)
408 ERROR ((0, errno
, "%s", name_buffer
));
411 /*-------------------------------------------------------------------------.
412 | Gather names in a list for scanning. Could hash them later if we really |
415 | If the names are already sorted to match the archive, we just read them |
416 | one by one. name_gather reads the first one, and it is called by |
417 | name_match as appropriate to read the next ones. At EOF, the last name |
418 | read is just left in the buffer. This option lets users of small |
419 | machines extract an arbitrary number of files by doing "tar t" and |
420 | editing down the list of files. |
421 `-------------------------------------------------------------------------*/
426 /* Buffer able to hold a single name. */
427 static struct name
*buffer
;
428 static size_t allocated_length
= 0;
432 if (same_order_option
)
434 if (allocated_length
== 0)
436 allocated_length
= sizeof (struct name
) + NAME_FIELD_SIZE
;
437 buffer
= (struct name
*) xmalloc (allocated_length
);
438 /* FIXME: This memset is overkill, and ugly... */
439 memset (buffer
, 0, allocated_length
);
441 name
= name_next (0);
444 if (strcmp (name
, "-C") == 0)
446 char *copy
= xstrdup (name_next (0));
448 name
= name_next (0);
450 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
451 buffer
->change_dir
= copy
;
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 strncpy (buffer
->name
, name
, (size_t) buffer
->length
);
460 buffer
->name
[buffer
->length
] = 0;
464 /* FIXME: Poorly named globals, indeed... */
471 /* Non sorted names -- read them all in. */
473 while (name
= name_next (0), name
)
477 /*-----------------------------.
478 | Add a name to the namelist. |
479 `-----------------------------*/
482 addname (const char *string
)
484 /* FIXME: This is ugly. How is memory managed? */
485 static char *chdir_name
= NULL
;
490 if (strcmp (string
, "-C") == 0)
492 chdir_name
= xstrdup (name_next (0));
493 string
= name_next (0);
495 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
497 if (chdir_name
[0] != '/')
499 char *path
= xmalloc (PATH_MAX
);
501 /* FIXME: Shouldn't we use xgetcwd? */
503 if (!getcwd (path
, PATH_MAX
))
504 FATAL_ERROR ((0, 0, _("Could not get current directory")));
509 FATAL_ERROR ((0, 0, _("Could not get current directory: %s"),
512 chdir_name
= new_name (path
, chdir_name
);
517 length
= string
? strlen (string
) : 0;
518 name
= (struct name
*) xmalloc (sizeof (struct name
) + length
);
519 memset (name
, 0, sizeof (struct name
) + length
);
525 name
->length
= length
;
526 /* FIXME: Possibly truncating a string, here? Tss, tss, tss! */
527 strncpy (name
->name
, string
, length
);
528 name
->name
[length
] = '\0';
534 name
->regexp
= 0; /* assume not a regular expression */
535 name
->firstch
= 1; /* assume first char is literal */
536 name
->change_dir
= chdir_name
;
537 name
->dir_contents
= 0;
539 if (string
&& is_pattern (string
))
542 if (string
[0] == '*' || string
[0] == '[' || string
[0] == '?')
547 namelast
->next
= name
;
553 /*------------------------------------------------------------------------.
554 | Return true if and only if name PATH (from an archive) matches any name |
555 | from the namelist. |
556 `------------------------------------------------------------------------*/
559 name_match (const char *path
)
561 size_t length
= strlen (path
);
565 struct name
*cursor
= namelist
;
568 return 1; /* empty namelist is easy */
572 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
573 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
574 cursor
->change_dir
));
579 for (; cursor
; cursor
= cursor
->next
)
581 /* If first chars don't match, quick skip. */
583 if (cursor
->firstch
&& cursor
->name
[0] != path
[0])
586 /* Regular expressions (shell globbing, actually). */
590 if (fnmatch (cursor
->name
, path
, FNM_LEADING_DIR
) == 0)
592 cursor
->found
= 1; /* remember it matched */
593 if (starting_file_option
)
598 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
599 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
600 cursor
->change_dir
));
602 /* We got a match. */
608 /* Plain Old Strings. */
610 if (cursor
->length
<= length
611 /* archive length >= specified */
612 && (path
[cursor
->length
] == '\0'
613 || path
[cursor
->length
] == '/')
614 /* full match on file/dirname */
615 && strncmp (path
, cursor
->name
, cursor
->length
) == 0)
618 cursor
->found
= 1; /* remember it matched */
619 if (starting_file_option
)
621 free ((void *) namelist
);
624 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
625 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
626 cursor
->change_dir
));
628 /* We got a match. */
633 /* Filename from archive not found in namelist. If we have the whole
634 namelist here, just return 0. Otherwise, read the next name in and
635 compare it. If this was the last name, namelist->found will remain
636 on. If not, we loop to compare the newly read name. */
638 if (same_order_option
&& namelist
->found
)
640 name_gather (); /* read one more */
649 /*------------------------------------------------------------------.
650 | Print the names of things in the namelist that were not matched. |
651 `------------------------------------------------------------------*/
654 names_notfound (void)
659 for (cursor
= namelist
; cursor
; cursor
= next
)
662 if (!cursor
->found
&& !cursor
->fake
)
663 ERROR ((0, 0, _("%s: Not found in archive"), cursor
->name
));
665 /* We could free the list, but the process is about to die anyway, so
666 save some CPU time. Amigas and other similarly broken software
667 will need to waste the time, though. */
670 if (!same_order_option
)
674 namelist
= (struct name
*) NULL
;
675 namelast
= (struct name
*) NULL
;
677 if (same_order_option
)
681 while (name
= name_next (1), name
)
682 ERROR ((0, 0, _("%s: Not found in archive"), name
));
695 /*-------------------------------------------------------------------------.
696 | This is like name_match, except that it returns a pointer to the name it |
697 | matched, and doesn't set FOUND in structure. The caller will have to do |
698 | that if it wants to. Oh, and if the namelist is empty, it returns NULL, |
699 | unlike name_match, which returns TRUE. |
700 `-------------------------------------------------------------------------*/
703 name_scan (const char *path
)
705 size_t length
= strlen (path
);
709 struct name
*cursor
= namelist
;
712 return NULL
; /* empty namelist is easy */
714 for (; cursor
; cursor
= cursor
->next
)
716 /* If first chars don't match, quick skip. */
718 if (cursor
->firstch
&& cursor
->name
[0] != path
[0])
721 /* Regular expressions. */
725 if (fnmatch (cursor
->name
, path
, FNM_LEADING_DIR
) == 0)
726 return cursor
; /* we got a match */
730 /* Plain Old Strings. */
732 if (cursor
->length
<= length
733 /* archive length >= specified */
734 && (path
[cursor
->length
] == '\0'
735 || path
[cursor
->length
] == '/')
736 /* full match on file/dirname */
737 && strncmp (path
, cursor
->name
, cursor
->length
) == 0)
739 return cursor
; /* we got a match */
742 /* Filename from archive not found in namelist. If we have the whole
743 namelist here, just return 0. Otherwise, read the next name in and
744 compare it. If this was the last name, namelist->found will remain
745 on. If not, we loop to compare the newly read name. */
747 if (same_order_option
&& namelist
->found
)
749 name_gather (); /* read one more */
758 /*-----------------------------------------------------------------------.
759 | This returns a name from the namelist which doesn't have ->found set. |
760 | It sets ->found before returning, so successive calls will find and |
761 | return all the non-found names in the namelist |
762 `-----------------------------------------------------------------------*/
764 struct name
*gnu_list_name
= NULL
;
767 name_from_list (void)
770 gnu_list_name
= namelist
;
771 while (gnu_list_name
&& gnu_list_name
->found
)
772 gnu_list_name
= gnu_list_name
->next
;
775 gnu_list_name
->found
= 1;
776 if (gnu_list_name
->change_dir
)
777 if (chdir (gnu_list_name
->change_dir
) < 0)
778 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
779 gnu_list_name
->change_dir
));
780 return gnu_list_name
->name
;
790 blank_name_list (void)
795 for (name
= namelist
; name
; name
= name
->next
)
804 new_name (const char *path
, const char *name
)
806 char *buffer
= (char *) xmalloc (strlen (path
) + strlen (name
) + 2);
808 sprintf (buffer
, "%s/%s", path
, name
);
812 /* Excludes names. */
814 static char *exclude_pool
= NULL
;
815 static size_t exclude_pool_size
= 0;
816 static size_t allocated_exclude_pool_size
= 0;
818 static char **simple_exclude_array
= NULL
;
819 static int simple_excludes
= 0;
820 static int allocated_simple_excludes
= 0;
822 static char **pattern_exclude_array
= NULL
;
823 static int pattern_excludes
= 0;
824 static int allocated_pattern_excludes
= 0;
831 add_exclude (char *name
)
835 unquote_string (name
); /* FIXME: unquote in all cases? If ever? */
836 name_size
= strlen (name
) + 1;
838 if (exclude_pool_size
+ name_size
> allocated_exclude_pool_size
)
840 char *previous_exclude_pool
= exclude_pool
;
843 allocated_exclude_pool_size
= exclude_pool_size
+ name_size
+ 1024;
844 exclude_pool
= (char *)
845 xrealloc (exclude_pool
, allocated_exclude_pool_size
);
847 for (cursor
= simple_exclude_array
;
848 cursor
< simple_exclude_array
+ simple_excludes
;
850 *cursor
= exclude_pool
+ (*cursor
- previous_exclude_pool
);
851 for (cursor
= pattern_exclude_array
;
852 cursor
< pattern_exclude_array
+ pattern_excludes
;
854 *cursor
= exclude_pool
+ (*cursor
- previous_exclude_pool
);
857 if (is_pattern (name
))
859 if (pattern_excludes
== allocated_pattern_excludes
)
861 allocated_pattern_excludes
+= 32;
862 pattern_exclude_array
= (char **)
863 xrealloc (pattern_exclude_array
,
864 allocated_pattern_excludes
* sizeof (char *));
866 pattern_exclude_array
[pattern_excludes
++]
867 = exclude_pool
+ exclude_pool_size
;
871 if (simple_excludes
== allocated_simple_excludes
)
873 allocated_simple_excludes
+= 32;
874 simple_exclude_array
= (char **)
875 xrealloc (simple_exclude_array
,
876 allocated_simple_excludes
* sizeof (char *));
878 simple_exclude_array
[simple_excludes
++]
879 = exclude_pool
+ exclude_pool_size
;
882 strcpy (exclude_pool
+ exclude_pool_size
, name
);
883 exclude_pool_size
+= name_size
;
891 add_exclude_file (const char *name
)
896 if (strcmp (name
, "-"))
897 file
= fopen (name
, "r");
900 request_stdin ("-X");
904 FATAL_ERROR ((0, errno
, _("Cannot open %s"), name
));
906 while (fgets (buffer
, 1024, file
))
908 char *end_of_line
= strrchr (buffer
, '\n');
912 add_exclude (buffer
);
914 if (fclose (file
) == EOF
)
915 ERROR ((0, errno
, "%s", name
));
918 /*------------------------------------------------------------------.
919 | Returns true if the file NAME should not be added nor extracted. |
920 `------------------------------------------------------------------*/
923 check_exclude (const char *name
)
927 for (counter
= 0; counter
< pattern_excludes
; counter
++)
928 if (fnmatch (pattern_exclude_array
[counter
], name
, FNM_LEADING_DIR
) == 0)
931 for (counter
= 0; counter
< simple_excludes
; counter
++)
933 /* Accept the output from strstr only if it is the last part of the
934 string. FIXME: Find a faster way to do this. */
936 char *string
= strstr (name
, simple_exclude_array
[counter
]);
939 && (string
== name
|| string
[-1] == '/')
940 && string
[strlen (simple_exclude_array
[counter
])] == '\0')