]>
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. */
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 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 if (allocated_length
== 0)
433 allocated_length
= sizeof (struct name
) + NAME_FIELD_SIZE
;
434 buffer
= (struct name
*) xmalloc (allocated_length
);
435 /* FIXME: This memset is overkill, and ugly... */
436 memset (buffer
, 0, allocated_length
);
438 name
= name_next (0);
441 if (strcmp (name
, "-C") == 0)
443 char *copy
= xstrdup (name_next (0));
445 name
= name_next (0);
447 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
448 buffer
->change_dir
= copy
;
450 buffer
->length
= strlen (name
);
451 if (sizeof (struct name
) + buffer
->length
>= allocated_length
)
453 allocated_length
= sizeof (struct name
) + buffer
->length
;
454 buffer
= (struct name
*) xrealloc (buffer
, allocated_length
);
456 strncpy (buffer
->name
, name
, (size_t) buffer
->length
);
457 buffer
->name
[buffer
->length
] = 0;
461 /* FIXME: Poorly named globals, indeed... */
468 /* Non sorted names -- read them all in. */
470 while (name
= name_next (0), name
)
474 /*-----------------------------.
475 | Add a name to the namelist. |
476 `-----------------------------*/
479 addname (const char *string
)
481 /* FIXME: This is ugly. How is memory managed? */
482 static char *chdir_name
= NULL
;
487 if (strcmp (string
, "-C") == 0)
489 chdir_name
= xstrdup (name_next (0));
490 string
= name_next (0);
492 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
494 if (chdir_name
[0] != '/')
496 char *path
= xmalloc (PATH_MAX
);
498 /* FIXME: Shouldn't we use xgetcwd? */
500 if (!getcwd (path
, PATH_MAX
))
501 FATAL_ERROR ((0, 0, _("Could not get current directory")));
506 FATAL_ERROR ((0, 0, _("Could not get current directory: %s"),
509 chdir_name
= new_name (path
, chdir_name
);
514 length
= string
? strlen (string
) : 0;
515 name
= (struct name
*) xmalloc (sizeof (struct name
) + length
);
516 memset (name
, 0, sizeof (struct name
) + length
);
522 name
->length
= length
;
523 /* FIXME: Possibly truncating a string, here? Tss, tss, tss! */
524 strncpy (name
->name
, string
, length
);
525 name
->name
[length
] = '\0';
531 name
->regexp
= 0; /* assume not a regular expression */
532 name
->firstch
= 1; /* assume first char is literal */
533 name
->change_dir
= chdir_name
;
534 name
->dir_contents
= 0;
536 if (string
&& is_pattern (string
))
539 if (string
[0] == '*' || string
[0] == '[' || string
[0] == '?')
544 namelast
->next
= name
;
550 /*------------------------------------------------------------------------.
551 | Return true if and only if name PATH (from an archive) matches any name |
552 | from the namelist. |
553 `------------------------------------------------------------------------*/
556 name_match (const char *path
)
558 size_t length
= strlen (path
);
562 struct name
*cursor
= namelist
;
565 return 1; /* empty namelist is easy */
569 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
570 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
571 cursor
->change_dir
));
576 for (; cursor
; cursor
= cursor
->next
)
578 /* If first chars don't match, quick skip. */
580 if (cursor
->firstch
&& cursor
->name
[0] != path
[0])
583 /* Regular expressions (shell globbing, actually). */
587 if (fnmatch (cursor
->name
, path
, FNM_LEADING_DIR
) == 0)
589 cursor
->found
= 1; /* remember it matched */
590 if (starting_file_option
)
595 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
596 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
597 cursor
->change_dir
));
599 /* We got a match. */
605 /* Plain Old Strings. */
607 if (cursor
->length
<= length
608 /* archive length >= specified */
609 && (path
[cursor
->length
] == '\0'
610 || path
[cursor
->length
] == '/')
611 /* full match on file/dirname */
612 && strncmp (path
, cursor
->name
, cursor
->length
) == 0)
615 cursor
->found
= 1; /* remember it matched */
616 if (starting_file_option
)
618 free ((void *) namelist
);
621 if (cursor
->change_dir
&& chdir (cursor
->change_dir
))
622 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
623 cursor
->change_dir
));
625 /* We got a match. */
630 /* Filename from archive not found in namelist. If we have the whole
631 namelist here, just return 0. Otherwise, read the next name in and
632 compare it. If this was the last name, namelist->found will remain
633 on. If not, we loop to compare the newly read name. */
635 if (same_order_option
&& namelist
->found
)
637 name_gather (); /* read one more */
646 /*------------------------------------------------------------------.
647 | Print the names of things in the namelist that were not matched. |
648 `------------------------------------------------------------------*/
651 names_notfound (void)
656 for (cursor
= namelist
; cursor
; cursor
= next
)
659 if (!cursor
->found
&& !cursor
->fake
)
660 ERROR ((0, 0, _("%s: Not found in archive"), cursor
->name
));
662 /* We could free the list, but the process is about to die anyway, so
663 save some CPU time. Amigas and other similarly broken software
664 will need to waste the time, though. */
667 if (!same_order_option
)
671 namelist
= (struct name
*) NULL
;
672 namelast
= (struct name
*) NULL
;
674 if (same_order_option
)
678 while (name
= name_next (1), name
)
679 ERROR ((0, 0, _("%s: Not found in archive"), name
));
692 /*-------------------------------------------------------------------------.
693 | This is like name_match, except that it returns a pointer to the name it |
694 | matched, and doesn't set FOUND in structure. The caller will have to do |
695 | that if it wants to. Oh, and if the namelist is empty, it returns NULL, |
696 | unlike name_match, which returns TRUE. |
697 `-------------------------------------------------------------------------*/
700 name_scan (const char *path
)
702 size_t length
= strlen (path
);
706 struct name
*cursor
= namelist
;
709 return NULL
; /* empty namelist is easy */
711 for (; cursor
; cursor
= cursor
->next
)
713 /* If first chars don't match, quick skip. */
715 if (cursor
->firstch
&& cursor
->name
[0] != path
[0])
718 /* Regular expressions. */
722 if (fnmatch (cursor
->name
, path
, FNM_LEADING_DIR
) == 0)
723 return cursor
; /* we got a match */
727 /* Plain Old Strings. */
729 if (cursor
->length
<= length
730 /* archive length >= specified */
731 && (path
[cursor
->length
] == '\0'
732 || path
[cursor
->length
] == '/')
733 /* full match on file/dirname */
734 && strncmp (path
, cursor
->name
, cursor
->length
) == 0)
736 return cursor
; /* we got a match */
739 /* Filename from archive not found in namelist. If we have the whole
740 namelist here, just return 0. Otherwise, read the next name in and
741 compare it. If this was the last name, namelist->found will remain
742 on. If not, we loop to compare the newly read name. */
744 if (same_order_option
&& namelist
->found
)
746 name_gather (); /* read one more */
755 /*-----------------------------------------------------------------------.
756 | This returns a name from the namelist which doesn't have ->found set. |
757 | It sets ->found before returning, so successive calls will find and |
758 | return all the non-found names in the namelist |
759 `-----------------------------------------------------------------------*/
761 struct name
*gnu_list_name
= NULL
;
764 name_from_list (void)
767 gnu_list_name
= namelist
;
768 while (gnu_list_name
&& gnu_list_name
->found
)
769 gnu_list_name
= gnu_list_name
->next
;
772 gnu_list_name
->found
= 1;
773 if (gnu_list_name
->change_dir
)
774 if (chdir (gnu_list_name
->change_dir
) < 0)
775 FATAL_ERROR ((0, errno
, _("Cannot change to directory %s"),
776 gnu_list_name
->change_dir
));
777 return gnu_list_name
->name
;
787 blank_name_list (void)
792 for (name
= namelist
; name
; name
= name
->next
)
801 new_name (const char *path
, const char *name
)
803 char *buffer
= (char *) xmalloc (strlen (path
) + strlen (name
) + 2);
805 sprintf (buffer
, "%s/%s", path
, name
);
This page took 0.069907 seconds and 5 git commands to generate.