1 /* Various processing of names.
2 Copyright (C) 1988, 1992, 1994, 1996, 1997 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 /*------------------------------------------.
52 | Given UID, find the corresponding UNAME. |
53 `------------------------------------------*/
56 uid_to_uname (uid_t uid
, char uname
[UNAME_FIELD_SIZE
])
58 struct passwd
*passwd
;
60 if (!cached_uname
[0] || uid
!= cached_uid
)
62 passwd
= getpwuid (uid
);
66 strncpy (cached_uname
, passwd
->pw_name
, UNAME_FIELD_SIZE
);
71 strncpy (uname
, cached_uname
, UNAME_FIELD_SIZE
);
74 /*------------------------------------------.
75 | Given GID, find the corresponding GNAME. |
76 `------------------------------------------*/
79 gid_to_gname (gid_t gid
, char gname
[GNAME_FIELD_SIZE
])
83 if (!cached_gname
[0] || gid
!= cached_gid
)
85 setgrent (); /* FIXME: why?! */
86 group
= getgrgid (gid
);
90 strncpy (cached_gname
, group
->gr_name
, GNAME_FIELD_SIZE
);
95 strncpy (gname
, cached_gname
, GNAME_FIELD_SIZE
);
98 /*-------------------------------------------------------------------------.
99 | Given UNAME, set the corresponding UID and return 1, or else, return 0. |
100 `-------------------------------------------------------------------------*/
103 uname_to_uid (char uname
[UNAME_FIELD_SIZE
], uid_t
*uidp
)
105 struct passwd
*passwd
;
108 || uname
[0] != cached_uname
[0]
109 || strncmp (uname
, cached_uname
, UNAME_FIELD_SIZE
) != 0)
111 passwd
= getpwnam (uname
);
114 cached_uid
= passwd
->pw_uid
;
115 strncpy (cached_uname
, uname
, UNAME_FIELD_SIZE
);
124 /*-------------------------------------------------------------------------.
125 | Given GNAME, set the corresponding GID and return 1, or else, return 0. |
126 `-------------------------------------------------------------------------*/
129 gname_to_gid (char gname
[GNAME_FIELD_SIZE
], gid_t
*gidp
)
134 || gname
[0] != cached_gname
[0]
135 || strncmp (gname
, cached_gname
, GNAME_FIELD_SIZE
) != 0)
137 group
= getgrnam (gname
);
140 cached_gid
= group
->gr_gid
;
141 strncpy (cached_gname
, gname
, GNAME_FIELD_SIZE
);
150 /* Names from the command call. */
152 static const char **name_array
; /* store an array of names */
153 static int allocated_names
; /* how big is the array? */
154 static int names
; /* how many entries does it have? */
155 static int name_index
= 0; /* how many of the entries have we scanned? */
157 /*------------------------.
158 | Initialize structures. |
159 `------------------------*/
164 allocated_names
= 10;
165 name_array
= (const char **)
166 xmalloc (sizeof (const char *) * allocated_names
);
170 /*--------------------------------------------------------------.
171 | Add NAME at end of name_array, reallocating it as necessary. |
172 `--------------------------------------------------------------*/
175 name_add (const char *name
)
177 if (names
== allocated_names
)
179 allocated_names
*= 2;
180 name_array
= (const char **)
181 xrealloc (name_array
, sizeof (const char *) * allocated_names
);
183 name_array
[names
++] = name
;
186 /* Names from external name file. */
188 static FILE *name_file
; /* file to read names from */
189 static char *name_buffer
; /* buffer to hold the current file name */
190 static size_t name_buffer_length
; /* allocated length of name_buffer */
196 /* FIXME: I should better check more closely. It seems at first glance that
197 is_pattern is only used when reading a file, and ignored for all
198 command line arguments. */
201 is_pattern (const char *string
)
203 return strchr (string
, '*') || strchr (string
, '[') || strchr (string
, '?');
206 /*-----------------------------------------------------------------------.
207 | Set up to gather file names for tar. They can either come from a file |
208 | or were saved from decoding arguments. |
209 `-----------------------------------------------------------------------*/
212 name_init (int argc
, char *const *argv
)
214 name_buffer
= xmalloc (NAME_FIELD_SIZE
+ 2);
215 name_buffer_length
= NAME_FIELD_SIZE
;
217 if (files_from_option
)
219 if (!strcmp (files_from_option
, "-"))
221 request_stdin ("-T");
224 else if (name_file
= fopen (files_from_option
, "r"), !name_file
)
225 FATAL_ERROR ((0, errno
, _("Cannot open file %s"), files_from_option
));
240 /*---------------------------------------------------------------------.
241 | Read the next filename from name_file and null-terminate it. Put it |
242 | into name_buffer, reallocating and adjusting name_buffer_length if |
243 | necessary. Return 0 at end of file, 1 otherwise. |
244 `---------------------------------------------------------------------*/
247 read_name_from_file (void)
252 /* FIXME: getc may be called even if character was EOF the last time here. */
254 /* FIXME: This + 2 allocation might serve no purpose. */
256 while (character
= getc (name_file
),
257 character
!= EOF
&& character
!= filename_terminator
)
259 if (counter
== name_buffer_length
)
261 name_buffer_length
+= NAME_FIELD_SIZE
;
262 name_buffer
= xrealloc (name_buffer
, name_buffer_length
+ 2);
264 name_buffer
[counter
++] = character
;
267 if (counter
== 0 && character
== EOF
)
270 if (counter
== name_buffer_length
)
272 name_buffer_length
+= NAME_FIELD_SIZE
;
273 name_buffer
= xrealloc (name_buffer
, name_buffer_length
+ 2);
275 name_buffer
[counter
] = '\0';
280 /*------------------------------------------------------------------------.
281 | Get the next name from ARGV or the file of names. Result is in static |
282 | storage and can't be relied upon across two calls. |
284 | If CHANGE_DIRS is true, treat a filename of the form "-C" as meaning |
285 | that the next filename is the name of a directory to change to. If |
286 | `filename_terminator' is NUL, CHANGE_DIRS is effectively always false. |
287 `------------------------------------------------------------------------*/
290 name_next (int change_dirs
)
296 if (filename_terminator
== '\0')
301 /* Get a name, either from file or from saved arguments. */
305 if (!read_name_from_file ())
310 if (name_index
== names
)
313 source
= name_array
[name_index
++];
314 if (strlen (source
) > name_buffer_length
)
317 name_buffer_length
= strlen (source
);
318 name_buffer
= xmalloc (name_buffer_length
+ 2);
320 strcpy (name_buffer
, source
);
323 /* Zap trailing slashes. */
325 cursor
= name_buffer
+ strlen (name_buffer
) - 1;
326 while (cursor
> name_buffer
&& *cursor
== '/')
331 if (chdir (name_buffer
) < 0)
332 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
336 else if (change_dirs
&& strcmp (name_buffer
, "-C") == 0)
340 if (!exclude_option
|| !check_exclude (name_buffer
))
343 unquote_string (name_buffer
);
348 /* No more names in file. */
350 if (name_file
&& chdir_flag
)
351 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
356 /*------------------------------.
357 | Close the name file, if any. |
358 `------------------------------*/
363 if (name_file
!= NULL
&& name_file
!= stdin
)
364 if (fclose (name_file
) == EOF
)
365 ERROR ((0, errno
, "%s", name_buffer
));
368 /*-------------------------------------------------------------------------.
369 | Gather names in a list for scanning. Could hash them later if we really |
372 | If the names are already sorted to match the archive, we just read them |
373 | one by one. name_gather reads the first one, and it is called by |
374 | name_match as appropriate to read the next ones. At EOF, the last name |
375 | read is just left in the buffer. This option lets users of small |
376 | machines extract an arbitrary number of files by doing "tar t" and |
377 | editing down the list of files. |
378 `-------------------------------------------------------------------------*/
383 /* Buffer able to hold a single name. */
384 static struct name
*buffer
;
385 static size_t allocated_length
= 0;
389 if (same_order_option
)
391 if (allocated_length
== 0)
393 allocated_length
= sizeof (struct name
) + NAME_FIELD_SIZE
;
394 buffer
= (struct name
*) xmalloc (allocated_length
);
395 /* FIXME: This memset is overkill, and ugly... */
396 memset (buffer
, 0, allocated_length
);
398 name
= name_next (0);
401 if (strcmp (name
, "-C") == 0)
403 char *copy
= xstrdup (name_next (0));
405 name
= name_next (0);
407 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
408 buffer
->change_dir
= copy
;
410 buffer
->length
= strlen (name
);
411 if (sizeof (struct name
) + buffer
->length
>= allocated_length
)
413 allocated_length
= sizeof (struct name
) + buffer
->length
;
414 buffer
= (struct name
*) xrealloc (buffer
, allocated_length
);
416 strncpy (buffer
->name
, name
, (size_t) buffer
->length
);
417 buffer
->name
[buffer
->length
] = 0;
421 /* FIXME: Poorly named globals, indeed... */
428 /* Non sorted names -- read them all in. */
430 while (name
= name_next (0), name
)
434 /*-----------------------------.
435 | Add a name to the namelist. |
436 `-----------------------------*/
439 addname (const char *string
)
441 /* FIXME: This is ugly. How is memory managed? */
442 static char *chdir_name
= NULL
;
447 if (strcmp (string
, "-C") == 0)
449 chdir_name
= xstrdup (name_next (0));
450 string
= name_next (0);
452 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
454 if (chdir_name
[0] != '/')
456 char *path
= xmalloc (PATH_MAX
);
458 /* FIXME: Shouldn't we use xgetcwd? */
460 if (!getcwd (path
, PATH_MAX
))
461 FATAL_ERROR ((0, 0, _("Could not get current directory")));
466 FATAL_ERROR ((0, 0, _("Could not get current directory: %s"),
469 chdir_name
= new_name (path
, chdir_name
);
474 length
= string
? strlen (string
) : 0;
475 name
= (struct name
*) xmalloc (sizeof (struct name
) + length
);
476 memset (name
, 0, sizeof (struct name
) + length
);
482 name
->length
= length
;
483 /* FIXME: Possibly truncating a string, here? Tss, tss, tss! */
484 strncpy (name
->name
, string
, length
);
485 name
->name
[length
] = '\0';
491 name
->regexp
= 0; /* assume not a regular expression */
492 name
->firstch
= 1; /* assume first char is literal */
493 name
->change_dir
= chdir_name
;
494 name
->dir_contents
= 0;
496 if (string
&& is_pattern (string
))
499 if (string
[0] == '*' || string
[0] == '[' || string
[0] == '?')
504 namelast
->next
= name
;
510 /*------------------------------------------------------------------------.
511 | Return true if and only if name PATH (from an archive) matches any name |
512 | from the namelist. |
513 `------------------------------------------------------------------------*/
516 name_match (const char *path
)
518 size_t length
= strlen (path
);
522 struct name
*cursor
= namelist
;
525 return 1; /* empty namelist is easy */
529 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
530 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
531 cursor
->change_dir
));
536 for (; cursor
; cursor
= cursor
->next
)
538 /* If first chars don't match, quick skip. */
540 if (cursor
->firstch
&& cursor
->name
[0] != path
[0])
543 /* Regular expressions (shell globbing, actually). */
547 if (fnmatch (cursor
->name
, path
, FNM_LEADING_DIR
) == 0)
549 cursor
->found
= 1; /* remember it matched */
550 if (starting_file_option
)
555 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
556 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
557 cursor
->change_dir
));
559 /* We got a match. */
565 /* Plain Old Strings. */
567 if (cursor
->length
<= length
568 /* archive length >= specified */
569 && (path
[cursor
->length
] == '\0'
570 || path
[cursor
->length
] == '/')
571 /* full match on file/dirname */
572 && strncmp (path
, cursor
->name
, cursor
->length
) == 0)
575 cursor
->found
= 1; /* remember it matched */
576 if (starting_file_option
)
578 free ((void *) namelist
);
581 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
582 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
583 cursor
->change_dir
));
585 /* We got a match. */
590 /* Filename from archive not found in namelist. If we have the whole
591 namelist here, just return 0. Otherwise, read the next name in and
592 compare it. If this was the last name, namelist->found will remain
593 on. If not, we loop to compare the newly read name. */
595 if (same_order_option
&& namelist
->found
)
597 name_gather (); /* read one more */
606 /*------------------------------------------------------------------.
607 | Print the names of things in the namelist that were not matched. |
608 `------------------------------------------------------------------*/
611 names_notfound (void)
616 for (cursor
= namelist
; cursor
; cursor
= next
)
619 if (!cursor
->found
&& !cursor
->fake
)
620 ERROR ((0, 0, _("%s: Not found in archive"), cursor
->name
));
622 /* We could free the list, but the process is about to die anyway, so
623 save some CPU time. Amigas and other similarly broken software
624 will need to waste the time, though. */
627 if (!same_order_option
)
631 namelist
= (struct name
*) NULL
;
632 namelast
= (struct name
*) NULL
;
634 if (same_order_option
)
638 while (name
= name_next (1), name
)
639 ERROR ((0, 0, _("%s: Not found in archive"), name
));
652 /*-------------------------------------------------------------------------.
653 | This is like name_match, except that it returns a pointer to the name it |
654 | matched, and doesn't set FOUND in structure. The caller will have to do |
655 | that if it wants to. Oh, and if the namelist is empty, it returns NULL, |
656 | unlike name_match, which returns TRUE. |
657 `-------------------------------------------------------------------------*/
660 name_scan (const char *path
)
662 size_t length
= strlen (path
);
666 struct name
*cursor
= namelist
;
669 return NULL
; /* empty namelist is easy */
671 for (; cursor
; cursor
= cursor
->next
)
673 /* If first chars don't match, quick skip. */
675 if (cursor
->firstch
&& cursor
->name
[0] != path
[0])
678 /* Regular expressions. */
682 if (fnmatch (cursor
->name
, path
, FNM_LEADING_DIR
) == 0)
683 return cursor
; /* we got a match */
687 /* Plain Old Strings. */
689 if (cursor
->length
<= length
690 /* archive length >= specified */
691 && (path
[cursor
->length
] == '\0'
692 || path
[cursor
->length
] == '/')
693 /* full match on file/dirname */
694 && strncmp (path
, cursor
->name
, cursor
->length
) == 0)
696 return cursor
; /* we got a match */
699 /* Filename from archive not found in namelist. If we have the whole
700 namelist here, just return 0. Otherwise, read the next name in and
701 compare it. If this was the last name, namelist->found will remain
702 on. If not, we loop to compare the newly read name. */
704 if (same_order_option
&& namelist
->found
)
706 name_gather (); /* read one more */
715 /*-----------------------------------------------------------------------.
716 | This returns a name from the namelist which doesn't have ->found set. |
717 | It sets ->found before returning, so successive calls will find and |
718 | return all the non-found names in the namelist |
719 `-----------------------------------------------------------------------*/
721 struct name
*gnu_list_name
= NULL
;
724 name_from_list (void)
727 gnu_list_name
= namelist
;
728 while (gnu_list_name
&& gnu_list_name
->found
)
729 gnu_list_name
= gnu_list_name
->next
;
732 gnu_list_name
->found
= 1;
733 if (gnu_list_name
->change_dir
)
734 if (chdir (gnu_list_name
->change_dir
) < 0)
735 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
736 gnu_list_name
->change_dir
));
737 return gnu_list_name
->name
;
747 blank_name_list (void)
752 for (name
= namelist
; name
; name
= name
->next
)
761 new_name (const char *path
, const char *name
)
763 char *buffer
= (char *) xmalloc (strlen (path
) + strlen (name
) + 2);
765 sprintf (buffer
, "%s/%s", path
, name
);
769 /* Excludes names. */
771 static char *exclude_pool
= NULL
;
772 static size_t exclude_pool_size
= 0;
773 static size_t allocated_exclude_pool_size
= 0;
775 static char **simple_exclude_array
= NULL
;
776 static int simple_excludes
= 0;
777 static int allocated_simple_excludes
= 0;
779 static char **pattern_exclude_array
= NULL
;
780 static int pattern_excludes
= 0;
781 static int allocated_pattern_excludes
= 0;
788 add_exclude (char *name
)
792 unquote_string (name
); /* FIXME: unquote in all cases? If ever? */
793 name_size
= strlen (name
) + 1;
795 if (exclude_pool_size
+ name_size
> allocated_exclude_pool_size
)
797 char *previous_exclude_pool
= exclude_pool
;
800 allocated_exclude_pool_size
= exclude_pool_size
+ name_size
+ 1024;
801 exclude_pool
= (char *)
802 xrealloc (exclude_pool
, allocated_exclude_pool_size
);
804 for (cursor
= simple_exclude_array
;
805 cursor
< simple_exclude_array
+ simple_excludes
;
807 *cursor
= exclude_pool
+ (*cursor
- previous_exclude_pool
);
808 for (cursor
= pattern_exclude_array
;
809 cursor
< pattern_exclude_array
+ pattern_excludes
;
811 *cursor
= exclude_pool
+ (*cursor
- previous_exclude_pool
);
814 if (is_pattern (name
))
816 if (pattern_excludes
== allocated_pattern_excludes
)
818 allocated_pattern_excludes
+= 32;
819 pattern_exclude_array
= (char **)
820 xrealloc (pattern_exclude_array
,
821 allocated_pattern_excludes
* sizeof (char *));
823 pattern_exclude_array
[pattern_excludes
++]
824 = exclude_pool
+ exclude_pool_size
;
828 if (simple_excludes
== allocated_simple_excludes
)
830 allocated_simple_excludes
+= 32;
831 simple_exclude_array
= (char **)
832 xrealloc (simple_exclude_array
,
833 allocated_simple_excludes
* sizeof (char *));
835 simple_exclude_array
[simple_excludes
++]
836 = exclude_pool
+ exclude_pool_size
;
839 strcpy (exclude_pool
+ exclude_pool_size
, name
);
840 exclude_pool_size
+= name_size
;
848 add_exclude_file (const char *name
)
853 if (strcmp (name
, "-"))
854 file
= fopen (name
, "r");
857 request_stdin ("-X");
861 FATAL_ERROR ((0, errno
, _("Cannot open %s"), name
));
863 while (fgets (buffer
, 1024, file
))
865 char *end_of_line
= strrchr (buffer
, '\n');
869 add_exclude (buffer
);
871 if (fclose (file
) == EOF
)
872 ERROR ((0, errno
, "%s", name
));
875 /*------------------------------------------------------------------.
876 | Returns true if the file NAME should not be added nor extracted. |
877 `------------------------------------------------------------------*/
880 check_exclude (const char *name
)
884 for (counter
= 0; counter
< pattern_excludes
; counter
++)
885 if (fnmatch (pattern_exclude_array
[counter
], name
, FNM_LEADING_DIR
) == 0)
888 for (counter
= 0; counter
< simple_excludes
; counter
++)
890 /* Accept the output from strstr only if it is the last part of the
891 string. FIXME: Find a faster way to do this. */
893 char *string
= strstr (name
, simple_exclude_array
[counter
]);
896 && (string
== name
|| string
[-1] == '/')
897 && string
[strlen (simple_exclude_array
[counter
])] == '\0')