- msg ("%s: Unknown file type; file ignored.", p);
-}
-
-int
-finish_sparse_file (fd, sizeleft, fullsize, name)
- int fd;
- long *sizeleft, fullsize;
- char *name;
-{
- union record *start;
- char tempbuf[RECORDSIZE];
- int bufsize, sparse_ind = 0, count;
- long pos;
- long nwritten = 0;
-
-
- while (*sizeleft > 0)
- {
- start = findrec ();
- bzero (start->charptr, RECORDSIZE);
- bufsize = sparsearray[sparse_ind].numbytes;
- if (!bufsize)
- { /* we blew it, maybe */
- msg ("Wrote %ld of %ld bytes to file %s",
- fullsize - *sizeleft, fullsize, name);
- break;
- }
- pos = lseek (fd, sparsearray[sparse_ind++].offset, 0);
- /*
- * If the number of bytes to be written here exceeds
- * the size of the temporary buffer, do it in steps.
- */
- while (bufsize > RECORDSIZE)
- {
- /* if (amt_read) {
- count = read(fd, start->charptr+amt_read, RECORDSIZE-amt_read);
- bufsize -= RECORDSIZE - amt_read;
- amt_read = 0;
- userec(start);
- start = findrec();
- bzero(start->charptr, RECORDSIZE);
- }*/
- /* store the data */
- count = read (fd, start->charptr, RECORDSIZE);
- if (count < 0)
- {
- msg_perror ("read error at byte %ld, reading %d bytes, in file %s",
- fullsize - *sizeleft, bufsize, name);
- return 1;
- }
- bufsize -= count;
- *sizeleft -= count;
- userec (start);
- nwritten += RECORDSIZE; /* XXX */
- start = findrec ();
- bzero (start->charptr, RECORDSIZE);
- }
-
-
- clear_buffer (tempbuf);
- count = read (fd, tempbuf, bufsize);
- bcopy (tempbuf, start->charptr, RECORDSIZE);
- if (count < 0)
- {
- msg_perror ("read error at byte %ld, reading %d bytes, in file %s",
- fullsize - *sizeleft, bufsize, name);
- return 1;
- }
- /* if (amt_read >= RECORDSIZE) {
- amt_read = 0;
- userec(start+(count-1)/RECORDSIZE);
- if (count != bufsize) {
- msg("file %s shrunk by %d bytes, padding with zeros.", name, sizeleft);
- return 1;
- }
- start = findrec();
- } else
- amt_read += bufsize;*/
- nwritten += count; /* XXX */
- *sizeleft -= count;
- userec (start);
-
- }
- free (sparsearray);
- /* printf ("Amount actually written is (I hope) %d.\n", nwritten); */
- /* userec(start+(count-1)/RECORDSIZE);*/
- return 0;
-
-}
-
-void
-init_sparsearray ()
-{
- register int i;
-
- sp_array_size = 10;
- /*
- * Make room for our scratch space -- initially is 10 elts long
- */
- sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array));
- for (i = 0; i < sp_array_size; i++)
- {
- sparsearray[i].offset = 0;
- sparsearray[i].numbytes = 0;
- }
-}
-
-
-
-/*
- * Okay, we've got a sparse file on our hands -- now, what we need to do is
- * make a pass through the file and carefully note where any data is, i.e.,
- * we want to find how far into the file each instance of data is, and how
- * many bytes are there. We store this information in the sparsearray,
- * which will later be translated into header information. For now, we use
- * the sparsearray as convenient storage.
- *
- * As a side note, this routine is a mess. If I could have found a cleaner
- * way to do it, I would have. If anyone wants to find a nicer way to do
- * this, feel free.
- */
-
-/* There is little point in trimming small amounts of null data at the */
-/* head and tail of blocks -- it's ok if we only avoid dumping blocks */
-/* of complete null data */
-int
-deal_with_sparse (name, header, nulls_at_end)
- char *name;
- union record *header;
- int nulls_at_end;
-{
- long numbytes = 0;
- long offset = 0;
- /* long save_offset;*/
- int fd;
- /* int current_size = hstat.st_size;*/
- int sparse_ind = 0, cc;
- char buf[RECORDSIZE];
-#if 0
- int read_last_data = 0; /* did we just read the last record? */
-#endif
- int amidst_data = 0;
-
- header->header.isextended = 0;
- /*
- * Can't open the file -- this problem will be caught later on,
- * so just return.
- */
- if ((fd = open (name, O_RDONLY)) < 0)
- return 0;
-
- init_sparsearray ();
- clear_buffer (buf);
-
- while ((cc = read (fd, buf, sizeof buf)) != 0)
- {
-
- if (sparse_ind > sp_array_size - 1)
- {
-
- /*
- * realloc the scratch area, since we've run out of room --
- */
- sparsearray = (struct sp_array *)
- ck_realloc (sparsearray,
- 2 * sp_array_size * (sizeof (struct sp_array)));
- sp_array_size *= 2;
- }
- if (cc == sizeof buf)
- {
- if (zero_record (buf))
- {
- if (amidst_data)
- {
- sparsearray[sparse_ind++].numbytes
- = numbytes;
- amidst_data = 0;
- }
- }
- else
- { /* !zero_record(buf) */
- if (amidst_data)
- numbytes += cc;
- else
- {
- amidst_data = 1;
- numbytes = cc;
- sparsearray[sparse_ind].offset
- = offset;
- }
- }
- }
- else if (cc < sizeof buf)
- {
- /* This has to be the last bit of the file, so this */
- /* is somewhat shorter than the above. */
- if (!zero_record (buf))
- {
- if (!amidst_data)
- {
- amidst_data = 1;
- numbytes = cc;
- sparsearray[sparse_ind].offset
- = offset;
- }
- else
- numbytes += cc;
- }
- }
- offset += cc;
- clear_buffer (buf);
- }
- if (amidst_data)
- sparsearray[sparse_ind++].numbytes = numbytes;
- else
- {
- sparsearray[sparse_ind].offset = offset-1;
- sparsearray[sparse_ind++].numbytes = 1;
- }
- close (fd);
-
- return sparse_ind - 1;
-}
-
-/*
- * Just zeroes out the buffer so we don't confuse ourselves with leftover
- * data.
- */
-void
-clear_buffer (buf)
- char *buf;
-{
- register int i;
-
- for (i = 0; i < RECORDSIZE; i++)
- buf[i] = '\0';
-}
-
-#if 0 /* I'm leaving this as a monument to Joy Kendall, who wrote it -mib */
-/*
- * JK -
- * This routine takes a character array, and tells where within that array
- * the data can be found. It skips over any zeros, and sets the first
- * non-zero point in the array to be the "start", and continues until it
- * finds non-data again, which is marked as the "end." This routine is
- * mainly for 1) seeing how far into a file we must lseek to data, given
- * that we have a sparse file, and 2) determining the "real size" of the
- * file, i.e., the number of bytes in the sparse file that are data, as
- * opposed to the zeros we are trying to skip.
- */
-where_is_data (from, to, buffer)
- int *from, *to;
- char *buffer;
-{
- register int i = 0;
- register int save_to = *to;
- int amidst_data = 0;
-
-
- while (!buffer[i])
- i++;
- *from = i;
-
- if (*from < 16) /* don't bother */
- *from = 0;
- /* keep going to make sure there isn't more real
- data in this record */
- while (i < RECORDSIZE)
- {
- if (!buffer[i])
- {
- if (amidst_data)
- {
- save_to = i;
- amidst_data = 0;
- }
- i++;
- }
- else if (buffer[i])
- {
- if (!amidst_data)
- amidst_data = 1;
- i++;
- }
- }
- if (i == RECORDSIZE)
- *to = i;
- else
- *to = save_to;
-
-}
-
-#endif
-
-/* Note that this routine is only called if zero_record returned true */
-#if 0 /* But we actually don't need it at all. */
-where_is_data (from, to, buffer)
- int *from, *to;
- char *buffer;
-{
- char *fp, *tp;
-
- for (fp = buffer; !*fp; fp++)
- ;
- for (tp = buffer + RECORDSIZE - 1; !*tp; tp--)
- ;
- *from = fp - buffer;
- *to = tp - buffer + 1;
-}
-
-#endif
-
-
-
-/*
- * Takes a recordful of data and basically cruises through it to see if
- * it's made *entirely* of zeros, returning a 0 the instant it finds
- * something that is a non-zero, i.e., useful data.
- */
-int
-zero_record (buffer)
- char *buffer;
-{
- register int i;
-
- for (i = 0; i < RECORDSIZE; i++)
- if (buffer[i] != '\000')
- return 0;
- return 1;
-}
-
-void
-find_new_file_size (filesize, highest_index)
- int *filesize;
- int highest_index;
-{
- register int i;
-
- *filesize = 0;
- for (i = 0; sparsearray[i].numbytes && i <= highest_index; i++)
- *filesize += sparsearray[i].numbytes;
-}
-
-/*
- * Make a header block for the file name whose stat info is st .
- * Return header pointer for success, NULL if the name is too long.
- */
-union record *
-start_header (name, st)
- char *name;
- register struct stat *st;
-{
- register union record *header;
-
- if (strlen (name) >= NAMSIZ)
- write_long (name, LF_LONGNAME);
-
- header = (union record *) findrec ();
- bzero (header->charptr, sizeof (*header)); /* XXX speed up */
-
- /*
- * Check the file name and put it in the record.
- */
- if (!f_absolute_paths)
- {
- static int warned_once = 0;
-#ifdef __MSDOS__
- if (name[1] == ':')
- {
- name += 2;
- if (!warned_once++)
- msg ("Removing drive spec from names in the archive");
- }
-#endif
- while ('/' == *name)
- {
- name++; /* Force relative path */
- if (!warned_once++)
- msg ("Removing leading / from absolute path names in the archive.");
- }
- }
- current_file_name = name;
- strncpy (header->header.arch_name, name, NAMSIZ);
- header->header.arch_name[NAMSIZ - 1] = '\0';
-
- to_oct ((long) (f_oldarch ? (st->st_mode & 07777) : st->st_mode),
- 8, header->header.mode);
- to_oct ((long) st->st_uid, 8, header->header.uid);
- to_oct ((long) st->st_gid, 8, header->header.gid);
- to_oct ((long) st->st_size, 1 + 12, header->header.size);
- to_oct ((long) st->st_mtime, 1 + 12, header->header.mtime);
- /* header->header.linkflag is left as null */
- if (f_gnudump)
- {
- to_oct ((long) st->st_atime, 1 + 12, header->header.atime);
- to_oct ((long) st->st_ctime, 1 + 12, header->header.ctime);
- }
-
-#ifndef NONAMES
- /* Fill in new Unix Standard fields if desired. */
- if (f_standard)
- {
- header->header.linkflag = LF_NORMAL; /* New default */
- strcpy (header->header.magic, TMAGIC); /* Mark as Unix Std */
- finduname (header->header.uname, st->st_uid);
- findgname (header->header.gname, st->st_gid);
- }
-#endif
- return header;
-}
-
-/*
- * Finish off a filled-in header block and write it out.
- * We also print the file name and/or full info if verbose is on.
- */
-void
-finish_header (header)
- register union record *header;
-{
- register int i, sum;
- register char *p;
-
- bcopy (CHKBLANKS, header->header.chksum, sizeof (header->header.chksum));
-
- sum = 0;
- p = header->charptr;
- for (i = sizeof (*header); --i >= 0;)
- {
- /*
- * We can't use unsigned char here because of old compilers,
- * e.g. V7.
- */
- sum += 0xFF & *p++;
- }
-
- /*
- * Fill in the checksum field. It's formatted differently
- * from the other fields: it has [6] digits, a null, then a
- * space -- rather than digits, a space, then a null.
- * We use to_oct then write the null in over to_oct's space.
- * The final space is already there, from checksumming, and
- * to_oct doesn't modify it.
- *
- * This is a fast way to do:
- * (void) sprintf(header->header.chksum, "%6o", sum);
- */
- to_oct ((long) sum, 8, header->header.chksum);
- header->header.chksum[6] = '\0'; /* Zap the space */
-
- userec (header);
-
- if (f_verbose)
- {
- extern union record *head;/* Points to current tape header */
- extern int head_standard; /* Tape header is in ANSI format */
-
- /* These globals are parameters to print_header, sigh */
- head = header;
- /* hstat is already set up */
- head_standard = f_standard;
- print_header ();
- }
-
- return;
-}
-
-
-/*
- * Quick and dirty octal conversion.
- * Converts long "value" into a "digs"-digit field at "where",
- * including a trailing space and room for a null. "digs"==3 means
- * 1 digit, a space, and room for a null.
- *
- * We assume the trailing null is already there and don't fill it in.
- * This fact is used by start_header and finish_header, so don't change it!
- *
- * This should be equivalent to:
- * (void) sprintf(where, "%*lo ", digs-2, value);
- * except that sprintf fills in the trailing null and we don't.
- */
-void
-to_oct (value, digs, where)
- register long value;
- register int digs;
- register char *where;
-{
-
- --digs; /* Trailing null slot is left alone */
- where[--digs] = ' '; /* Put in the space, though */
-
- /* Produce the digits -- at least one */
- do
- {
- where[--digs] = '0' + (char) (value & 7); /* one octal digit */
- value >>= 3;
- }
- while (digs > 0 && value != 0);
-
- /* Leading spaces, if necessary */
- while (digs > 0)
- where[--digs] = ' ';
-
-}
-
-
-/*
- * Write the EOT record(s).
- * We actually zero at least one record, through the end of the block.
- * Old tar writes garbage after two zeroed records -- and PDtar used to.
- */
-void
-write_eot ()
-{
- union record *p;
- int bufsize;
-
- p = findrec ();
- if (p)
- {
- bufsize = endofrecs ()->charptr - p->charptr;
- bzero (p->charptr, bufsize);
- userec (p);
- }
-}
-
-/* Write a LF_LONGLINK or LF_LONGNAME record. */
-void
-write_long (p, type)
- char *p;
- char type;
-{
- int size = strlen (p) + 1;
- int bufsize;
- union record *header;
- struct stat foo;
-
-
- bzero (&foo, sizeof foo);
- foo.st_size = size;
-
- header = start_header ("././@LongLink", &foo);
- header->header.linkflag = type;
- finish_header (header);
-
- header = findrec ();
-
- bufsize = endofrecs ()->charptr - header->charptr;
-
- while (bufsize < size)
- {
- bcopy (p, header->charptr, bufsize);
- p += bufsize;
- size -= bufsize;
- userec (header + (bufsize - 1) / RECORDSIZE);
- header = findrec ();
- bufsize = endofrecs ()->charptr - header->charptr;
- }
- bcopy (p, header->charptr, size);
- bzero (header->charptr + size, bufsize - size);
- userec (header + (size - 1) / RECORDSIZE);