📄 tar.c
字号:
return( FALSE); } } else { actualWriteSz=writeSize; } size -= actualWriteSz; } /* Now we are done writing the file out, so try * and fix up the permissions and whatnot */ if (extractFlag==TRUE && tostdoutFlag==FALSE) { close(outFd); fixUpPermissions(header); } return( TRUE);}static inttarExtractDirectory(TarInfo *header, int extractFlag, int tostdoutFlag){ if (extractFlag==FALSE || tostdoutFlag==TRUE) return( TRUE); if (make_directory(header->name, header->mode, FILEUTILS_RECUR) < 0) return( FALSE); fixUpPermissions(header); return( TRUE);}static inttarExtractHardLink(TarInfo *header, int extractFlag, int tostdoutFlag){ if (extractFlag==FALSE || tostdoutFlag==TRUE) return( TRUE); if (link(header->linkname, header->name) < 0) { perror_msg("%s: Cannot create hard link to '%s'", header->name, header->linkname); return( FALSE); } /* Now set permissions etc. for the new directory */ fixUpPermissions(header); return( TRUE);}static inttarExtractSymLink(TarInfo *header, int extractFlag, int tostdoutFlag){ if (extractFlag==FALSE || tostdoutFlag==TRUE) return( TRUE);#ifdef S_ISLNK if (symlink(header->linkname, header->name) < 0) { perror_msg("%s: Cannot create symlink to '%s'", header->name, header->linkname); return( FALSE); } /* Try to change ownership of the symlink. * If libs doesn't support that, don't bother. * Changing the pointed-to-file is the Wrong Thing(tm). */#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) lchown(header->name, header->uid, header->gid);#endif /* Do not change permissions or date on symlink, * since it changes the pointed to file instead. duh. */#else error_msg("%s: Cannot create symlink to '%s': %s", header->name, header->linkname, "symlinks not supported"); #endif return( TRUE);}static inttarExtractSpecial(TarInfo *header, int extractFlag, int tostdoutFlag){ if (extractFlag==FALSE || tostdoutFlag==TRUE) return( TRUE); if (S_ISCHR(header->mode) || S_ISBLK(header->mode) || S_ISSOCK(header->mode)) { if (mknod(header->name, header->mode, makedev(header->devmajor, header->devminor)) < 0) { perror_msg("%s: Cannot mknod", header->name); return( FALSE); } } else if (S_ISFIFO(header->mode)) { if (mkfifo(header->name, header->mode) < 0) { perror_msg("%s: Cannot mkfifo", header->name); return( FALSE); } } /* Now set permissions etc. for the new directory */ fixUpPermissions(header); return( TRUE);}/* Parse the tar header and fill in the nice struct with the details */static intreadTarHeader(struct TarHeader *rawHeader, struct TarInfo *header){ int i; long chksum, sum=0; unsigned char *s = (unsigned char *)rawHeader; header->name = rawHeader->name; /* Check for and relativify any absolute paths */ if ( *(header->name) == '/' ) { static int alreadyWarned=FALSE; while (*(header->name) == '/') header->name++; if (alreadyWarned == FALSE) { error_msg("Removing leading '/' from member names"); alreadyWarned = TRUE; } } header->mode = strtol(rawHeader->mode, NULL, 8); header->uid = strtol(rawHeader->uid, NULL, 8); header->gid = strtol(rawHeader->gid, NULL, 8); header->size = strtol(rawHeader->size, NULL, 8); header->mtime = strtol(rawHeader->mtime, NULL, 8); chksum = strtol(rawHeader->chksum, NULL, 8); header->type = rawHeader->typeflag; header->linkname = rawHeader->linkname; header->devmajor = strtol(rawHeader->devmajor, NULL, 8); header->devminor = strtol(rawHeader->devminor, NULL, 8); /* Check the checksum */ for (i = sizeof(*rawHeader); i-- != 0;) { sum += *s++; } /* Remove the effects of the checksum field (replace * with blanks for the purposes of the checksum) */ s = rawHeader->chksum; for (i = sizeof(rawHeader->chksum) ; i-- != 0;) { sum -= *s++; } sum += ' ' * sizeof(rawHeader->chksum); if (sum == chksum ) return ( TRUE); return( FALSE);}#if defined BB_FEATURE_TAR_EXCLUDEstatic int exclude_file(char **excluded_files, const char *file){ int i; if (excluded_files == NULL) return 0; for (i = 0; excluded_files[i] != NULL; i++) { if (excluded_files[i][0] == '/') { if (fnmatch(excluded_files[i], file, FNM_PATHNAME | FNM_LEADING_DIR) == 0) return 1; } else { const char *p; for (p = file; p[0] != '\0'; p++) { if ((p == file || p[-1] == '/') && p[0] != '/' && fnmatch(excluded_files[i], p, FNM_PATHNAME | FNM_LEADING_DIR) == 0) return 1; } } } return 0;}#endifstatic int extract_file(char **extract_files, const char *file){ int i; if (extract_files == NULL) return 1; for (i = 0; extract_files[i] != NULL; i++) { if (fnmatch(extract_files[i], file, FNM_LEADING_DIR) == 0) return 1; } return 0;}/* * Read a tar file and extract or list the specified files within it. * If the list is empty than all files are extracted or listed. */static int readTarFile(int tarFd, int extractFlag, int listFlag, int tostdoutFlag, int verboseFlag, char** extractList, char** excludeList){ int status; int errorFlag=FALSE; int skipNextHeaderFlag=FALSE; TarHeader rawHeader; TarInfo header; /* Read the tar file, and iterate over it one file at a time */ while ( (status = full_read(tarFd, (char*)&rawHeader, TAR_BLOCK_SIZE)) == TAR_BLOCK_SIZE ) { /* Try to read the header */ if ( readTarHeader(&rawHeader, &header) == FALSE ) { if ( *(header.name) == '\0' ) { goto endgame; } else { errorFlag=TRUE; error_msg("Bad tar header, skipping"); continue; } } if ( *(header.name) == '\0' ) continue; header.tarFd = tarFd; /* Skip funky extra GNU headers that precede long files */ if ( (header.type == GNULONGNAME) || (header.type == GNULONGLINK) ) { skipNextHeaderFlag=TRUE; if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) errorFlag = TRUE; continue; } if ( skipNextHeaderFlag == TRUE ) { skipNextHeaderFlag=FALSE; error_msg(name_longer_than_foo, NAME_SIZE); if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) errorFlag = TRUE; continue; }#if defined BB_FEATURE_TAR_EXCLUDE if (exclude_file(excludeList, header.name)) { /* There are not the droids you're looking for, move along */ /* If it is a regular file, pretend to extract it with * the extractFlag set to FALSE, so the junk in the tarball * is properly skipped over */ if ( header.type==REGTYPE || header.type==REGTYPE0 ) { if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) errorFlag = TRUE; } continue; }#endif if (!extract_file(extractList, header.name)) { /* There are not the droids you're looking for, move along */ /* If it is a regular file, pretend to extract it with * the extractFlag set to FALSE, so the junk in the tarball * is properly skipped over */ if ( header.type==REGTYPE || header.type==REGTYPE0 ) { if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) errorFlag = TRUE; } continue; } if (listFlag == TRUE) { /* Special treatment if the list (-t) flag is on */ if (verboseFlag == TRUE) { int len, len1; char buf[35]; struct tm *tm = localtime (&(header.mtime)); len=printf("%s ", mode_string(header.mode)); my_getpwuid(buf, header.uid); if (! *buf) len+=printf("%d", header.uid); else len+=printf("%s", buf); my_getgrgid(buf, header.gid); if (! *buf) len+=printf("/%-d ", header.gid); else len+=printf("/%-s ", buf); if (header.type==CHRTYPE || header.type==BLKTYPE) { len1=snprintf(buf, sizeof(buf), "%ld,%-ld ", header.devmajor, header.devminor); } else { len1=snprintf(buf, sizeof(buf), "%lu ", (long)header.size); } /* Jump through some hoops to make the columns match up */ for(;(len+len1)<31;len++) printf(" "); printf(buf); /* Use ISO 8610 time format */ if (tm) { printf ("%04d-%02d-%02d %02d:%02d:%02d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); } } printf("%s", header.name); if (verboseFlag == TRUE) { if (header.type==LNKTYPE) /* If this is a link, say so */ printf(" link to %s", header.linkname); else if (header.type==SYMTYPE) printf(" -> %s", header.linkname); } printf("\n"); } /* List contents if we are supposed to do that */ if (verboseFlag == TRUE && extractFlag == TRUE) { /* Now the normal listing */ FILE *vbFd = stdout; if (tostdoutFlag == TRUE) // If the archive goes to stdout, verbose to stderr vbFd = stderr; fprintf(vbFd, "%s\n", header.name); } /* Remove files if we would overwrite them */ if (extractFlag == TRUE && tostdoutFlag == FALSE) unlink(header.name); /* If we got here, we can be certain we have a legitimate * header to work with. So work with it. */ switch ( header.type ) { case REGTYPE: case REGTYPE0: /* If the name ends in a '/' then assume it is * supposed to be a directory, and fall through */ if (!last_char_is(header.name,'/')) { if (tarExtractRegularFile(&header, extractFlag, tostdoutFlag)==FALSE) errorFlag=TRUE; break; } case DIRTYPE: if (tarExtractDirectory( &header, extractFlag, tostdoutFlag)==FALSE) errorFlag=TRUE; break; case LNKTYPE: if (tarExtractHardLink( &header, extractFlag, tostdoutFlag)==FALSE) errorFlag=TRUE; break; case SYMTYPE: if (tarExtractSymLink( &header, extractFlag, tostdoutFlag)==FALSE) errorFlag=TRUE; break; case CHRTYPE: case BLKTYPE: case FIFOTYPE: if (tarExtractSpecial( &header, extractFlag, tostdoutFlag)==FALSE) errorFlag=TRUE; break;#if 0 /* Handled earlier */ case GNULONGNAME: case GNULONGLINK: skipNextHeaderFlag=TRUE; break;#endif default: error_msg("Unknown file type '%c' in tar file", header.type); close( tarFd); return( FALSE); } } close(tarFd); if (status > 0) { /* Bummer - we read a partial header */ perror_msg("Error reading tar file"); return ( FALSE); } else if (errorFlag==TRUE) { error_msg( "Error exit delayed from previous errors"); return( FALSE); } else return( status); /* Stuff to do when we are done */endgame: close( tarFd); if ( *(header.name) == '\0' ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -