Skip to content

Instantly share code, notes, and snippets.

@lighth7015
Created February 16, 2020 20:18
Show Gist options
  • Save lighth7015/ba63c9a99c906c182a57d10fcb1c5f56 to your computer and use it in GitHub Desktop.
Save lighth7015/ba63c9a99c906c182a57d10fcb1c5f56 to your computer and use it in GitHub Desktop.
tar.c
#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