Created
February 16, 2020 20:18
-
-
Save lighth7015/ba63c9a99c906c182a57d10fcb1c5f56 to your computer and use it in GitHub Desktop.
tar.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <fcntl.h> | |
#include <errno.h> | |
#include <unistd.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <stdbool.h> | |
#include <sys/stat.h> | |
#include <sys/mman.h> | |
typedef const char* string_t; | |
bool VfsReadFile( string_t buffer, struct stat file, | |
string_t fileName, string_t* contents, size_t* readLength) | |
{ | |
const uint32_t magicOffs = 257, nameOffs = 0, | |
sizeOffs = 124, szBlock = 512, | |
szLength = 12; | |
bool successful = false; | |
const char magic[] = "ustar"; | |
*contents = NULL; | |
*readLength = 0; | |
for ( size_t size, szContents = 0, p = 0, newOffset = 0 | |
; !successful && (p + newOffset + szBlock <= file.st_size) | |
; size = 0 | |
, p += newOffset) | |
{ | |
string_t entryName = buffer + nameOffs + p + newOffset, | |
offset = buffer + sizeOffs + p + newOffset; | |
for(uint32_t i = 0; i< 5; i++) { | |
// Check for supported TAR version | |
if( buffer[i + magicOffs + p] != magic[i] ) { | |
goto finished; | |
} | |
} | |
for (uint32_t i = szLength-2, szWord = 1; i + 1 > 0; szWord*=8, i--) { | |
if (( offset[i] >= '1' ) && (offset[i] <= '9')) { | |
size += (offset[i]-'0') * szWord; | |
} | |
} | |
// Offset size in bytes. Depends on file size and TAR block size; trim by block | |
if (( size % szBlock )>= 0 ) { | |
newOffset += (1 + size/szBlock) * szBlock; | |
} | |
if(strncmp(fileName, entryName, strlen(fileName)) == 0 ) { | |
*readLength = size; | |
*contents = (string_t) buffer + p + szBlock; | |
successful = true; | |
} | |
} | |
finished: | |
return successful; | |
} | |
int main(int args, char* arg[]) { | |
int fd; | |
if (args - 1 == 2 ) { | |
switch (fd = open( arg[1], O_RDWR)) { | |
case -1: | |
switch (errno) { | |
case ENOENT: | |
printf( "Error opening the file %s: No such file or directory.\n", arg[1] ); | |
break; | |
default: | |
break; | |
} | |
break; | |
default: { | |
struct stat file; | |
fstat( fd, &file ); | |
size_t length; | |
string_t contents; | |
if (file.st_size > 0 ) { | |
char* buffer = mmap(NULL, file.st_size, PROT_READ, MAP_PRIVATE, fd, 0); | |
bool result = 0; | |
if (( result = VfsReadFile( buffer, file, arg[2], &contents, &length ))) { | |
printf( "%s: File is %zx bytes in length:\n%s\n", arg[2], length, contents ); | |
} | |
else { | |
printf( "%s: No such file in archive. (%d)\n", arg[2], result ); | |
} | |
munmap(buffer, file.st_size); | |
} | |
else { | |
printf( "%s: File is empty.\n", arg[1] ); | |
} | |
} break; | |
} | |
close(fd); | |
} | |
else { | |
puts( "Please specify an archive name and filename to open on the commandline." ); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment