+ long chksum=0;
+ struct TarHeader header;
+#if defined BB_FEATURE_TAR_EXCLUDE
+ char** tmpList;
+#endif
+ const unsigned char *cp = (const unsigned char *) &header;
+ ssize_t size = sizeof(struct TarHeader);
+
+ memset( &header, 0, size);
+
+ if (*fileName=='/') {
+ static int alreadyWarned=FALSE;
+ if (alreadyWarned==FALSE) {
+ errorMsg("tar: Removing leading '/' from member names\n");
+ alreadyWarned=TRUE;
+ }
+ strncpy(header.name, fileName+1, sizeof(header.name));
+ }
+ else {
+ strncpy(header.name, fileName, sizeof(header.name));
+ }
+
+#if defined BB_FEATURE_TAR_EXCLUDE
+ /* Check for excluded files.... */
+ for (tmpList=tbInfo->excludeList; tmpList && *tmpList; tmpList++) {
+ /* Do some extra hoop jumping for when directory names
+ * end in '/' but the entry in tmpList doesn't */
+ if (strncmp( *tmpList, header.name, strlen(*tmpList))==0 || (
+ header.name[strlen(header.name)-1]=='/'
+ && strncmp( *tmpList, header.name,
+ MIN(strlen(header.name)-1, strlen(*tmpList)))==0)) {
+ /* Set the mode to something that is not a regular file, thereby
+ * faking out writeTarFile into thinking that nothing further need
+ * be done for this file. Yes, I know this is ugly, but it works. */
+ statbuf->st_mode = 0;
+ return( TRUE);
+ }
+ }
+#endif
+
+ putOctal(header.mode, sizeof(header.mode), statbuf->st_mode);
+ putOctal(header.uid, sizeof(header.uid), statbuf->st_uid);
+ putOctal(header.gid, sizeof(header.gid), statbuf->st_gid);
+ putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */
+ putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime);
+ strncpy(header.magic, TAR_MAGIC TAR_VERSION,
+ TAR_MAGIC_LEN + TAR_VERSION_LEN );
+
+ /* Enter the user and group names (default to root if it fails) */
+ my_getpwuid(header.uname, statbuf->st_uid);
+ if (! *header.uname)
+ strcpy(header.uname, "root");
+ my_getgrgid(header.gname, statbuf->st_gid);
+ if (! *header.uname)
+ strcpy(header.uname, "root");
+
+ /* WARNING/NOTICE: I break Hard Links */
+ if (S_ISLNK(statbuf->st_mode)) {
+ char buffer[BUFSIZ];
+ header.typeflag = SYMTYPE;
+ if ( readlink(fileName, buffer, sizeof(buffer) - 1) < 0) {
+ errorMsg("Error reading symlink '%s': %s\n", header.name, strerror(errno));
+ return ( FALSE);
+ }
+ strncpy(header.linkname, buffer, sizeof(header.linkname));
+ } else if (S_ISDIR(statbuf->st_mode)) {
+ header.typeflag = DIRTYPE;
+ strncat(header.name, "/", sizeof(header.name));
+ } else if (S_ISCHR(statbuf->st_mode)) {
+ header.typeflag = CHRTYPE;
+ putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
+ putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
+ } else if (S_ISBLK(statbuf->st_mode)) {
+ header.typeflag = BLKTYPE;
+ putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev));
+ putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev));
+ } else if (S_ISFIFO(statbuf->st_mode)) {
+ header.typeflag = FIFOTYPE;
+ } else if (S_ISREG(statbuf->st_mode)) {
+ header.typeflag = REGTYPE;
+ putOctal(header.size, sizeof(header.size), statbuf->st_size);
+ } else {
+ errorMsg("tar: %s: Unknown file type\n", fileName);
+ return ( FALSE);
+ }
+
+ /* Calculate and store the checksum (i.e. the sum of all of the bytes of
+ * the header). The checksum field must be filled with blanks for the
+ * calculation. The checksum field is formatted differently from the
+ * other fields: it has [6] digits, a null, then a space -- rather than
+ * digits, followed by a null like the other fields... */
+ memset(header.chksum, ' ', sizeof(header.chksum));
+ cp = (const unsigned char *) &header;
+ while (size-- > 0)
+ chksum += *cp++;
+ putOctal(header.chksum, 7, chksum);
+
+ /* Now write the header out to disk */
+ if ((size=fullWrite(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) {
+ errorMsg(io_error, fileName, strerror(errno));
+ return ( FALSE);
+ }
+ /* Pad the header up to the tar block size */
+ for (; size<TAR_BLOCK_SIZE; size++) {
+ write(tbInfo->tarFd, "\0", 1);
+ }
+ /* Now do the verbose thing (or not) */
+ if (tbInfo->verboseFlag==TRUE)
+ fprintf(stdout, "%s\n", header.name);
+
+ return ( TRUE);