-
- else if (S_ISDIR (current_stat.st_mode))
- {
- DIR *directory;
- struct dirent *entry;
- char *namebuf;
- size_t buflen;
- size_t len;
- dev_t our_device = current_stat.st_dev;
-
- /* If this tar program is installed suid root, like for Amanda, the
- access might look like denied, while it is not really.
-
- FIXME: I have the feeling this test is done too early. Couldn't it
- just be bundled in later actions? I guess that the proper support
- of --ignore-failed-read is the key of the current writing. */
-
- if (access (p, R_OK) == -1 && geteuid () != 0)
- {
- WARN ((0, errno, _("Cannot add directory %s"), p));
- if (!ignore_failed_read_option)
- exit_status = TAREXIT_FAILURE;
- return;
- }
-
- /* Build new prototype name. Ensure exactly one trailing slash. */
-
- len = strlen (p);
- buflen = len + NAME_FIELD_SIZE;
- namebuf = xmalloc (buflen + 1);
- strncpy (namebuf, p, buflen);
- while (len >= 1 && namebuf[len - 1] == '/')
- len--;
- namebuf[len++] = '/';
- namebuf[len] = '\0';
-
- if (1)
- {
- /* The "1" above used to be "archive_format != V7_FORMAT", GNU tar
- was just not writing directory blocks at all. Daniel Trinkle
- writes: ``All old versions of tar I have ever seen have
- correctly archived an empty directory. The really old ones I
- checked included HP-UX 7 and Mt. Xinu More/BSD. There may be
- some subtle reason for the exclusion that I don't know, but the
- current behavior is broken.'' I do not know those subtle
- reasons either, so until these are reported (anew?), just allow
- directory blocks to be written even with old archives. */
-
- current_stat.st_size = 0; /* force 0 size on dir */
-
- /* FIXME: If people could really read standard archives, this
- should be:
-
- header
- = start_header (standard_option ? p : namebuf, ¤t_stat);
-
- but since they'd interpret DIRTYPE blocks as regular
- files, we'd better put the / on the name. */
-
- header = start_header (namebuf, ¤t_stat);
- if (header == NULL)
- {
- exit_status = TAREXIT_FAILURE;
- return; /* eg name too long */
- }
-
- if (incremental_option)
- header->header.typeflag = GNUTYPE_DUMPDIR;
- else /* if (standard_option) */
- header->header.typeflag = DIRTYPE;
-
- /* If we're gnudumping, we aren't done yet so don't close it. */
-
- if (!incremental_option)
- finish_header (header); /* done with directory header */
- }
-
- if (incremental_option && gnu_list_name->dir_contents)
- {
- off_t sizeleft;
- off_t totsize;
- size_t bufsize;
- union block *start;
- ssize_t count;
- const char *buffer, *p_buffer;
-
- buffer = gnu_list_name->dir_contents; /* FOO */
- totsize = 0;
- for (p_buffer = buffer; p_buffer && *p_buffer;)
- {
- size_t tmp;
-
- tmp = strlen (p_buffer) + 1;
- totsize += tmp;
- p_buffer += tmp;
- }
- totsize++;
- OFF_TO_CHARS (totsize, header->header.size);
- finish_header (header);
- p_buffer = buffer;
- sizeleft = totsize;
- while (sizeleft > 0)
- {
- if (multi_volume_option)
- {
- assign_string (&save_name, p);
- save_sizeleft = sizeleft;
- save_totsize = totsize;
- }
- start = find_next_block ();
- bufsize = available_space_after (start);
- if (sizeleft < bufsize)
- {
- bufsize = sizeleft;
- count = bufsize % BLOCKSIZE;
- if (count)
- memset (start->buffer + sizeleft, 0,
- (size_t) (BLOCKSIZE - count));
- }
- memcpy (start->buffer, p_buffer, bufsize);
- sizeleft -= bufsize;
- p_buffer += bufsize;
- set_next_block_after (start + (bufsize - 1) / BLOCKSIZE);
- }
- if (multi_volume_option)
- assign_string (&save_name, NULL);
- if (atime_preserve_option)
- utime (p, &restore_times);
- return;
- }
-
- /* See if we are about to recurse into a directory, and avoid doing
- so if the user wants that we do not descend into directories. */
-
- if (no_recurse_option)
- return;
-
- /* See if we are crossing from one file system to another, and
- avoid doing so if the user only wants to dump one file system. */
-
- if (one_file_system_option && !top_level
- && parent_device != current_stat.st_dev)
- {
- if (verbose_option)
- WARN ((0, 0, _("%s: On a different filesystem; not dumped"), p));
- return;
- }
-
- /* Now output all the files in the directory. */
-
- errno = 0; /* FIXME: errno should be read-only */
-
- directory = opendir (p);
- if (!directory)
- {
- ERROR ((0, errno, _("Cannot open directory %s"), p));
- return;
- }
-
- /* FIXME: Should speed this up by cd-ing into the dir. */
-
- while (entry = readdir (directory), entry)
- {
- /* Skip `.', `..', and excluded file names. */
-
- if (is_dot_or_dotdot (entry->d_name))
- continue;
-
- if ((int) NAMLEN (entry) + len >= buflen)
- {
- buflen = len + NAMLEN (entry);
- namebuf = (char *) xrealloc (namebuf, buflen + 1);
-#if 0
- namebuf[len] = '\0';
- ERROR ((0, 0, _("File name %s%s too long"),
- namebuf, entry->d_name));
- continue;
-#endif
- }
- strcpy (namebuf + len, entry->d_name);
- if (!excluded_name (namebuf))
- dump_file (namebuf, our_device, 0);
- }
-
- closedir (directory);
- free (namebuf);
- if (atime_preserve_option)
- utime (p, &restore_times);
- return;
- }
-
- else if (S_ISCHR (current_stat.st_mode))