1 /* Various processing of names.
2 Copyright (C) 1988, 92, 94, 96, 97, 1998 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
);
74 strncpy (uname
, cached_uname
, UNAME_FIELD_SIZE
);
77 /*------------------------------------------.
78 | Given GID, find the corresponding GNAME. |
79 `------------------------------------------*/
82 gid_to_gname (gid_t gid
, char gname
[GNAME_FIELD_SIZE
])
86 if (!cached_gname
[0] || gid
!= cached_gid
)
88 setgrent (); /* FIXME: why?! */
89 group
= getgrgid (gid
);
93 strncpy (cached_gname
, group
->gr_name
, GNAME_FIELD_SIZE
);
101 strncpy (gname
, cached_gname
, GNAME_FIELD_SIZE
);
104 /*-------------------------------------------------------------------------.
105 | Given UNAME, set the corresponding UID and return 1, or else, return 0. |
106 `-------------------------------------------------------------------------*/
109 uname_to_uid (char uname
[UNAME_FIELD_SIZE
], uid_t
*uidp
)
111 struct passwd
*passwd
;
114 || uname
[0] != cached_uname
[0]
115 || strncmp (uname
, cached_uname
, UNAME_FIELD_SIZE
) != 0)
117 passwd
= getpwnam (uname
);
120 cached_uid
= passwd
->pw_uid
;
121 strncpy (cached_uname
, uname
, UNAME_FIELD_SIZE
);
130 /*-------------------------------------------------------------------------.
131 | Given GNAME, set the corresponding GID and return 1, or else, return 0. |
132 `-------------------------------------------------------------------------*/
135 gname_to_gid (char gname
[GNAME_FIELD_SIZE
], gid_t
*gidp
)
140 || gname
[0] != cached_gname
[0]
141 || strncmp (gname
, cached_gname
, GNAME_FIELD_SIZE
) != 0)
143 group
= getgrnam (gname
);
146 cached_gid
= group
->gr_gid
;
147 strncpy (cached_gname
, gname
, GNAME_FIELD_SIZE
);
156 /* Names from the command call. */
158 static const char **name_array
; /* store an array of names */
159 static int allocated_names
; /* how big is the array? */
160 static int names
; /* how many entries does it have? */
161 static int name_index
= 0; /* how many of the entries have we scanned? */
163 /*------------------------.
164 | Initialize structures. |
165 `------------------------*/
170 allocated_names
= 10;
171 name_array
= (const char **)
172 xmalloc (sizeof (const char *) * allocated_names
);
176 /*--------------------------------------------------------------.
177 | Add NAME at end of name_array, reallocating it as necessary. |
178 `--------------------------------------------------------------*/
181 name_add (const char *name
)
183 if (names
== allocated_names
)
185 allocated_names
*= 2;
186 name_array
= (const char **)
187 xrealloc (name_array
, sizeof (const char *) * allocated_names
);
189 name_array
[names
++] = name
;
192 /* Names from external name file. */
194 static FILE *name_file
; /* file to read names from */
195 static char *name_buffer
; /* buffer to hold the current file name */
196 static size_t name_buffer_length
; /* allocated length of name_buffer */
202 /* FIXME: I should better check more closely. It seems at first glance that
203 is_pattern is only used when reading a file, and ignored for all
204 command line arguments. */
207 is_pattern (const char *string
)
209 return strchr (string
, '*') || strchr (string
, '[') || strchr (string
, '?');
212 /*-----------------------------------------------------------------------.
213 | Set up to gather file names for tar. They can either come from a file |
214 | or were saved from decoding arguments. |
215 `-----------------------------------------------------------------------*/
218 name_init (int argc
, char *const *argv
)
220 name_buffer
= xmalloc (NAME_FIELD_SIZE
+ 2);
221 name_buffer_length
= NAME_FIELD_SIZE
;
223 if (files_from_option
)
225 if (!strcmp (files_from_option
, "-"))
227 request_stdin ("-T");
230 else if (name_file
= fopen (files_from_option
, "r"), !name_file
)
231 FATAL_ERROR ((0, errno
, _("Cannot open file %s"), files_from_option
));
246 /*---------------------------------------------------------------------.
247 | Read the next filename from name_file and null-terminate it. Put it |
248 | into name_buffer, reallocating and adjusting name_buffer_length if |
249 | necessary. Return 0 at end of file, 1 otherwise. |
250 `---------------------------------------------------------------------*/
253 read_name_from_file (void)
258 /* FIXME: getc may be called even if character was EOF the last time here. */
260 /* FIXME: This + 2 allocation might serve no purpose. */
262 while (character
= getc (name_file
),
263 character
!= EOF
&& character
!= filename_terminator
)
265 if (counter
== name_buffer_length
)
267 name_buffer_length
+= NAME_FIELD_SIZE
;
268 name_buffer
= xrealloc (name_buffer
, name_buffer_length
+ 2);
270 name_buffer
[counter
++] = character
;
273 if (counter
== 0 && character
== EOF
)
276 if (counter
== name_buffer_length
)
278 name_buffer_length
+= NAME_FIELD_SIZE
;
279 name_buffer
= xrealloc (name_buffer
, name_buffer_length
+ 2);
281 name_buffer
[counter
] = '\0';
286 /*------------------------------------------------------------------------.
287 | Get the next name from ARGV or the file of names. Result is in static |
288 | storage and can't be relied upon across two calls. |
290 | If CHANGE_DIRS is true, treat a filename of the form "-C" as meaning |
291 | that the next filename is the name of a directory to change to. If |
292 | `filename_terminator' is NUL, CHANGE_DIRS is effectively always false. |
293 `------------------------------------------------------------------------*/
296 name_next (int change_dirs
)
302 if (filename_terminator
== '\0')
307 /* Get a name, either from file or from saved arguments. */
311 if (!read_name_from_file ())
316 if (name_index
== names
)
319 source
= name_array
[name_index
++];
320 if (strlen (source
) > name_buffer_length
)
323 name_buffer_length
= strlen (source
);
324 name_buffer
= xmalloc (name_buffer_length
+ 2);
326 strcpy (name_buffer
, source
);
329 /* Zap trailing slashes. */
331 cursor
= name_buffer
+ strlen (name_buffer
) - 1;
332 while (cursor
> name_buffer
&& *cursor
== '/')
337 if (chdir (name_buffer
) < 0)
338 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
342 else if (change_dirs
&& strcmp (name_buffer
, "-C") == 0)
346 if (!exclude_option
|| !check_exclude (name_buffer
))
349 unquote_string (name_buffer
);
354 /* No more names in file. */
356 if (name_file
&& chdir_flag
)
357 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
362 /*------------------------------.
363 | Close the name file, if any. |
364 `------------------------------*/
369 if (name_file
!= NULL
&& name_file
!= stdin
)
370 if (fclose (name_file
) == EOF
)
371 ERROR ((0, errno
, "%s", name_buffer
));
374 /*-------------------------------------------------------------------------.
375 | Gather names in a list for scanning. Could hash them later if we really |
378 | If the names are already sorted to match the archive, we just read them |
379 | one by one. name_gather reads the first one, and it is called by |
380 | name_match as appropriate to read the next ones. At EOF, the last name |
381 | read is just left in the buffer. This option lets users of small |
382 | machines extract an arbitrary number of files by doing "tar t" and |
383 | editing down the list of files. |
384 `-------------------------------------------------------------------------*/
389 /* Buffer able to hold a single name. */
390 static struct name
*buffer
;
391 static size_t allocated_length
= 0;
395 if (same_order_option
)
397 if (allocated_length
== 0)
399 allocated_length
= sizeof (struct name
) + NAME_FIELD_SIZE
;
400 buffer
= (struct name
*) xmalloc (allocated_length
);
401 /* FIXME: This memset is overkill, and ugly... */
402 memset (buffer
, 0, allocated_length
);
404 name
= name_next (0);
407 if (strcmp (name
, "-C") == 0)
409 char *copy
= xstrdup (name_next (0));
411 name
= name_next (0);
413 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
414 buffer
->change_dir
= copy
;
416 buffer
->length
= strlen (name
);
417 if (sizeof (struct name
) + buffer
->length
>= allocated_length
)
419 allocated_length
= sizeof (struct name
) + buffer
->length
;
420 buffer
= (struct name
*) xrealloc (buffer
, allocated_length
);
422 strncpy (buffer
->name
, name
, (size_t) buffer
->length
);
423 buffer
->name
[buffer
->length
] = 0;
427 /* FIXME: Poorly named globals, indeed... */
434 /* Non sorted names -- read them all in. */
436 while (name
= name_next (0), name
)
440 /*-----------------------------.
441 | Add a name to the namelist. |
442 `-----------------------------*/
445 addname (const char *string
)
447 /* FIXME: This is ugly. How is memory managed? */
448 static char *chdir_name
= NULL
;
453 if (strcmp (string
, "-C") == 0)
455 chdir_name
= xstrdup (name_next (0));
456 string
= name_next (0);
458 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
460 if (chdir_name
[0] != '/')
462 char *path
= xmalloc (PATH_MAX
);
464 /* FIXME: Shouldn't we use xgetcwd? */
466 if (!getcwd (path
, PATH_MAX
))
467 FATAL_ERROR ((0, 0, _("Could not get current directory")));
472 FATAL_ERROR ((0, 0, _("Could not get current directory: %s"),
475 chdir_name
= new_name (path
, chdir_name
);
480 length
= string
? strlen (string
) : 0;
481 name
= (struct name
*) xmalloc (sizeof (struct name
) + length
);
482 memset (name
, 0, sizeof (struct name
) + length
);
488 name
->length
= length
;
489 /* FIXME: Possibly truncating a string, here? Tss, tss, tss! */
490 strncpy (name
->name
, string
, length
);
491 name
->name
[length
] = '\0';
497 name
->regexp
= 0; /* assume not a regular expression */
498 name
->firstch
= 1; /* assume first char is literal */
499 name
->change_dir
= chdir_name
;
500 name
->dir_contents
= 0;
502 if (string
&& is_pattern (string
))
505 if (string
[0] == '*' || string
[0] == '[' || string
[0] == '?')
510 namelast
->next
= name
;
516 /*------------------------------------------------------------------------.
517 | Return true if and only if name PATH (from an archive) matches any name |
518 | from the namelist. |
519 `------------------------------------------------------------------------*/
522 name_match (const char *path
)
524 size_t length
= strlen (path
);
528 struct name
*cursor
= namelist
;
531 return 1; /* empty namelist is easy */
535 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
536 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
537 cursor
->change_dir
));
542 for (; cursor
; cursor
= cursor
->next
)
544 /* If first chars don't match, quick skip. */
546 if (cursor
->firstch
&& cursor
->name
[0] != path
[0])
549 /* Regular expressions (shell globbing, actually). */
553 if (fnmatch (cursor
->name
, path
, FNM_LEADING_DIR
) == 0)
555 cursor
->found
= 1; /* remember it matched */
556 if (starting_file_option
)
561 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
562 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
563 cursor
->change_dir
));
565 /* We got a match. */
571 /* Plain Old Strings. */
573 if (cursor
->length
<= length
574 /* archive length >= specified */
575 && (path
[cursor
->length
] == '\0'
576 || path
[cursor
->length
] == '/')
577 /* full match on file/dirname */
578 && strncmp (path
, cursor
->name
, cursor
->length
) == 0)
581 cursor
->found
= 1; /* remember it matched */
582 if (starting_file_option
)
584 free ((void *) namelist
);
587 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
588 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
589 cursor
->change_dir
));
591 /* We got a match. */
596 /* Filename from archive not found in namelist. If we have the whole
597 namelist here, just return 0. Otherwise, read the next name in and
598 compare it. If this was the last name, namelist->found will remain
599 on. If not, we loop to compare the newly read name. */
601 if (same_order_option
&& namelist
->found
)
603 name_gather (); /* read one more */
612 /*------------------------------------------------------------------.
613 | Print the names of things in the namelist that were not matched. |
614 `------------------------------------------------------------------*/
617 names_notfound (void)
622 for (cursor
= namelist
; cursor
; cursor
= next
)
625 if (!cursor
->found
&& !cursor
->fake
)
626 ERROR ((0, 0, _("%s: Not found in archive"), cursor
->name
));
628 /* We could free the list, but the process is about to die anyway, so
629 save some CPU time. Amigas and other similarly broken software
630 will need to waste the time, though. */
633 if (!same_order_option
)
637 namelist
= (struct name
*) NULL
;
638 namelast
= (struct name
*) NULL
;
640 if (same_order_option
)
644 while (name
= name_next (1), name
)
645 ERROR ((0, 0, _("%s: Not found in archive"), name
));
658 /*-------------------------------------------------------------------------.
659 | This is like name_match, except that it returns a pointer to the name it |
660 | matched, and doesn't set FOUND in structure. The caller will have to do |
661 | that if it wants to. Oh, and if the namelist is empty, it returns NULL, |
662 | unlike name_match, which returns TRUE. |
663 `-------------------------------------------------------------------------*/
666 name_scan (const char *path
)
668 size_t length
= strlen (path
);
672 struct name
*cursor
= namelist
;
675 return NULL
; /* empty namelist is easy */
677 for (; cursor
; cursor
= cursor
->next
)
679 /* If first chars don't match, quick skip. */
681 if (cursor
->firstch
&& cursor
->name
[0] != path
[0])
684 /* Regular expressions. */
688 if (fnmatch (cursor
->name
, path
, FNM_LEADING_DIR
) == 0)
689 return cursor
; /* we got a match */
693 /* Plain Old Strings. */
695 if (cursor
->length
<= length
696 /* archive length >= specified */
697 && (path
[cursor
->length
] == '\0'
698 || path
[cursor
->length
] == '/')
699 /* full match on file/dirname */
700 && strncmp (path
, cursor
->name
, cursor
->length
) == 0)
702 return cursor
; /* we got a match */
705 /* Filename from archive not found in namelist. If we have the whole
706 namelist here, just return 0. Otherwise, read the next name in and
707 compare it. If this was the last name, namelist->found will remain
708 on. If not, we loop to compare the newly read name. */
710 if (same_order_option
&& namelist
->found
)
712 name_gather (); /* read one more */
721 /*-----------------------------------------------------------------------.
722 | This returns a name from the namelist which doesn't have ->found set. |
723 | It sets ->found before returning, so successive calls will find and |
724 | return all the non-found names in the namelist |
725 `-----------------------------------------------------------------------*/
727 struct name
*gnu_list_name
= NULL
;
730 name_from_list (void)
733 gnu_list_name
= namelist
;
734 while (gnu_list_name
&& gnu_list_name
->found
)
735 gnu_list_name
= gnu_list_name
->next
;
738 gnu_list_name
->found
= 1;
739 if (gnu_list_name
->change_dir
)
740 if (chdir (gnu_list_name
->change_dir
) < 0)
741 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
742 gnu_list_name
->change_dir
));
743 return gnu_list_name
->name
;
753 blank_name_list (void)
758 for (name
= namelist
; name
; name
= name
->next
)
767 new_name (const char *path
, const char *name
)
769 char *buffer
= (char *) xmalloc (strlen (path
) + strlen (name
) + 2);
771 sprintf (buffer
, "%s/%s", path
, name
);
775 /* Excludes names. */
777 static char *exclude_pool
= NULL
;
778 static size_t exclude_pool_size
= 0;
779 static size_t allocated_exclude_pool_size
= 0;
781 static char **simple_exclude_array
= NULL
;
782 static int simple_excludes
= 0;
783 static int allocated_simple_excludes
= 0;
785 static char **pattern_exclude_array
= NULL
;
786 static int pattern_excludes
= 0;
787 static int allocated_pattern_excludes
= 0;
794 add_exclude (char *name
)
798 unquote_string (name
); /* FIXME: unquote in all cases? If ever? */
799 name_size
= strlen (name
) + 1;
801 if (exclude_pool_size
+ name_size
> allocated_exclude_pool_size
)
803 char *previous_exclude_pool
= exclude_pool
;
806 allocated_exclude_pool_size
= exclude_pool_size
+ name_size
+ 1024;
807 exclude_pool
= (char *)
808 xrealloc (exclude_pool
, allocated_exclude_pool_size
);
810 for (cursor
= simple_exclude_array
;
811 cursor
< simple_exclude_array
+ simple_excludes
;
813 *cursor
= exclude_pool
+ (*cursor
- previous_exclude_pool
);
814 for (cursor
= pattern_exclude_array
;
815 cursor
< pattern_exclude_array
+ pattern_excludes
;
817 *cursor
= exclude_pool
+ (*cursor
- previous_exclude_pool
);
820 if (is_pattern (name
))
822 if (pattern_excludes
== allocated_pattern_excludes
)
824 allocated_pattern_excludes
+= 32;
825 pattern_exclude_array
= (char **)
826 xrealloc (pattern_exclude_array
,
827 allocated_pattern_excludes
* sizeof (char *));
829 pattern_exclude_array
[pattern_excludes
++]
830 = exclude_pool
+ exclude_pool_size
;
834 if (simple_excludes
== allocated_simple_excludes
)
836 allocated_simple_excludes
+= 32;
837 simple_exclude_array
= (char **)
838 xrealloc (simple_exclude_array
,
839 allocated_simple_excludes
* sizeof (char *));
841 simple_exclude_array
[simple_excludes
++]
842 = exclude_pool
+ exclude_pool_size
;
845 strcpy (exclude_pool
+ exclude_pool_size
, name
);
846 exclude_pool_size
+= name_size
;
854 add_exclude_file (const char *name
)
859 if (strcmp (name
, "-"))
860 file
= fopen (name
, "r");
863 request_stdin ("-X");
867 FATAL_ERROR ((0, errno
, _("Cannot open %s"), name
));
869 while (fgets (buffer
, 1024, file
))
871 char *end_of_line
= strrchr (buffer
, '\n');
875 add_exclude (buffer
);
877 if (fclose (file
) == EOF
)
878 ERROR ((0, errno
, "%s", name
));
881 /*------------------------------------------------------------------.
882 | Returns true if the file NAME should not be added nor extracted. |
883 `------------------------------------------------------------------*/
886 check_exclude (const char *name
)
890 for (counter
= 0; counter
< pattern_excludes
; counter
++)
891 if (fnmatch (pattern_exclude_array
[counter
], name
, FNM_LEADING_DIR
) == 0)
894 for (counter
= 0; counter
< simple_excludes
; counter
++)
896 /* Accept the output from strstr only if it is the last part of the
897 string. FIXME: Find a faster way to do this. */
899 char *string
= strstr (name
, simple_exclude_array
[counter
]);
902 && (string
== name
|| string
[-1] == '/')
903 && string
[strlen (simple_exclude_array
[counter
])] == '\0')