- int f; /* file descriptor */
- size_t bufsize;
- ssize_t count;
- off_t sizeleft;
- union block *start;
- int header_moved;
- char isextended = 0;
- int sparses = 0;
-
- header_moved = 0;
-
- if (sparse_option)
- {
- /* Check the size of the file against the number of blocks
- allocated for it, counting both data and indirect blocks.
- If there is a smaller number of blocks than would be
- necessary to accommodate a file of this size, this is safe
- to say that we have a sparse file: at least one of those
- blocks in the file is just a useless hole. For sparse
- files not having more hole blocks than indirect blocks, the
- sparseness will go undetected. */
-
- /* Bruno Haible sent me these statistics for Linux. It seems
- that some filesystems count indirect blocks in st_blocks,
- while others do not seem to:
-
- minix-fs tar: size=7205, st_blocks=18 and ST_NBLOCKS=18
- extfs tar: size=7205, st_blocks=18 and ST_NBLOCKS=18
- ext2fs tar: size=7205, st_blocks=16 and ST_NBLOCKS=16
- msdos-fs tar: size=7205, st_blocks=16 and ST_NBLOCKS=16
-
- Dick Streefland reports the previous numbers as misleading,
- because ext2fs use 12 direct blocks, while minix-fs uses only
- 6 direct blocks. Dick gets:
-
- ext2 size=20480 ls listed blocks=21
- minix size=20480 ls listed blocks=21
- msdos size=20480 ls listed blocks=20
-
- It seems that indirect blocks *are* included in st_blocks.
- The minix filesystem does not account for phantom blocks in
- st_blocks, so `du' and `ls -s' give wrong results. So, the
- --sparse option would not work on a minix filesystem. */
-
- if (ST_NBLOCKS (current_stat_info.stat)
- < (current_stat_info.stat.st_size / ST_NBLOCKSIZE
- + (current_stat_info.stat.st_size % ST_NBLOCKSIZE != 0)))
- {
- int counter;
-
- block_ordinal = current_block_ordinal ();
- header = start_header (p, ¤t_stat_info);
- header->header.typeflag = GNUTYPE_SPARSE;
- header_moved = 1;
-
- /* Call the routine that figures out the layout of the
- sparse file in question. SPARSES is the index of the
- first unused element of the "sparsearray," i.e.,
- the number of elements it needed to describe the file. */
-
- sparses = deal_with_sparse (p, header);
-
- /* See if we'll need an extended header later. */
-
- if (SPARSES_IN_OLDGNU_HEADER < sparses)
- header->oldgnu_header.isextended = 1;
-
- /* We store the "real" file size so we can show that in
- case someone wants to list the archive, i.e., tar tvf
- <file>. It might be kind of disconcerting if the
- shrunken file size was the one that showed up. */
-
- OFF_TO_CHARS (current_stat_info.stat.st_size,
- header->oldgnu_header.realsize);
-
- /* This will be the new "size" of the file, i.e., the size
- of the file minus the blocks of holes that we're
- skipping over. */
-
- current_stat_info.stat.st_size = find_new_file_size (sparses);
- OFF_TO_CHARS (current_stat_info.stat.st_size, header->header.size);
-
- for (counter = 0;
- counter < sparses && counter < SPARSES_IN_OLDGNU_HEADER;
- counter++)
- {
- OFF_TO_CHARS (sparsearray[counter].offset,
- header->oldgnu_header.sp[counter].offset);
- SIZE_TO_CHARS (sparsearray[counter].numbytes,
- header->oldgnu_header.sp[counter].numbytes);
- }
- }
- }
-
- sizeleft = current_stat_info.stat.st_size;
-
- /* Don't bother opening empty, world readable files. Also do not open
- files when archive is meant for /dev/null. */
-
- if (dev_null_output
- || (sizeleft == 0
- && MODE_R == (MODE_R & current_stat_info.stat.st_mode)))
- f = -1;
- else
- {
- f = open (p, O_RDONLY | O_BINARY);
- if (f < 0)
- {
- if (! top_level && errno == ENOENT)
- WARN ((0, 0, _("%s: File removed before we read it"),
- quotearg_colon (p)));
- else
- (ignore_failed_read_option ? open_warn : open_error) (p);
- return;
- }
- }
-
- /* If the file is sparse, we've already taken care of this. */