Skip to content

Instantly share code, notes, and snippets.

@orlp
Created December 19, 2010 18:27
Show Gist options
  • Save orlp/747565 to your computer and use it in GitHub Desktop.
Save orlp/747565 to your computer and use it in GitHub Desktop.
unpacks a tar archive
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "zlib.h"
struct tarheader { // for parsing the tar headers
char name[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char typeflag;
char linkname[100];
char magic[8];
char uname[32];
char gname[32];
char devmajor[8];
char devminor[8];
char prefix[155];
char padding[12];
};
static void _mkdir(const char *dir, __mode_t mode) { // mkdir with parent tree
char tmp[256];
char *p = NULL;
size_t len;
snprintf(tmp, sizeof(tmp), "%s", dir);
len = strlen(tmp);
if (tmp[len - 1] == '/') tmp[len - 1] = 0;
for (p = tmp + 1; *p; p++)
if(*p == '/') {
*p = 0;
mkdir(tmp, mode);
*p = '/';
}
mkdir(tmp, mode);
}
int unpack_tar(const char* tarname, const char* prefix) {
struct tarheader header;
char buf[512];
long size;
int r;
FILE* tar = fopen(tarname, "rb");
FILE* output; // reuse same pointer for every file
while (fread(&header, 1, 512, tar)!=0) {
size = strtol(header.size, NULL, 8); // octal numbers, who doesn't love them?
if (header.typeflag == '0') {
char filename[FILENAME_MAX];
strcpy(filename, prefix);
strcat(filename, "/");
strcat(filename, header.name);
output = fopen(filename, "wb");
printf("%s\n", filename);
while (size > 512) {
r = fread(&buf, 1, 512, tar);
fwrite(&buf, 1, 512, output);
size -= 512;
}
r = fread(&buf, 1, 512, tar);
fwrite(&buf, 1, size, output);
fclose(output);
} else if (header.typeflag == '5') {
char foldername[FILENAME_MAX];
strcpy(foldername, prefix);
strcat(foldername, "/");
strcat(foldername, header.name);
_mkdir(foldername, (__mode_t) strtol(header.mode, NULL, 8));
fseek(tar, size + (512 - size & 0x1ff), SEEK_CUR);
} else {
fseek(tar, size + (512 - size & 0x1ff), SEEK_CUR);
}
}
}
int decompressgz(const char* in, const char* out) {
gzFile infile = gzopen(in, "rb");
FILE *outfile = fopen(out, "wb");
if (!infile || !outfile) return -1;
char buffer[128];
int num_read = 0;
while ((num_read = gzread(infile, buffer, sizeof(buffer))) > 0) {
fwrite(buffer, 1, num_read, outfile);
}
gzclose(infile);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment