/* Verify the tar checksum. */ static int verify_checksum(const char *p) { int n, u = 0; for (n = 0; n < 512; ++n) { if (n < 148 || n > 155) /* Standard tar checksum adds unsigned bytes. */ u += ((unsigned char *)p)[n]; else u += 0x20; } return (u == parseoct(p + 148, 8)); }
/* Extract a tar archive. */ static void untar(FILE *a, const char *path) { char buff[512]; FILE *f = NULL; size_t bytes_read; int filesize; char *fullPath = NULL; printf("Extracting from %s\n", path); for (;;) { bytes_read = fread(buff, 1, 512, a); if (bytes_read < 512) { fprintf(stderr, "Short read on %s: expected 512, got %d\n", path, (int)bytes_read); return; } if (is_end_of_archive(buff)) { printf("End of %s\n", path); return; } if (!verify_checksum(buff)) { fprintf(stderr, "Checksum failure\n"); return; } filesize = parseoct(buff + 124, 12); switch (buff[156]) { case '1': printf(" Ignoring hardlink %s\n", buff); break; case '2': printf(" Ignoring symlink %s\n", buff); break; case '3': printf(" Ignoring character device %s\n", buff); break; case '4': printf(" Ignoring block device %s\n", buff); break; case '5': printf(" Extracting dir %s\n", buff); fullPath = string_concat(3, basePath, "/", buff); create_dir(fullPath, parseoct(buff + 100, 8)); free(fullPath); filesize = 0; break; case '6': printf(" Ignoring FIFO %s\n", buff); break; default: printf(" Extracting file %s\n", buff); fullPath = string_concat(3, basePath, "/", buff); f = create_file(fullPath, parseoct(buff + 100, 8)); free(fullPath); break; } while (filesize > 0) { bytes_read = fread(buff, 1, 512, a); if (bytes_read < 512) { fprintf(stderr, "Short read on %s: Expected 512, got %d\n", path, (int)bytes_read); return; } if (filesize < 512) bytes_read = filesize; if (f != NULL) { if (fwrite(buff, 1, bytes_read, f) != bytes_read) { fprintf(stderr, "Failed write\n"); fclose(f); f = NULL; } } filesize -= bytes_read; } if (f != NULL) { fclose(f); f = NULL; } } }
/* Extract a tar archive. */ void untar(FILE *a, const char *path) { #ifdef ASSET_VERBOSE printf("==== storm untar v1.1.2 ====\n"); clock_t start = clock() / (CLOCKS_PER_SEC / 1000); printf("unpacking archive..\n"); #endif char buff[512]; FILE *f = NULL; size_t bytes_read; int filesize; for (;;) { bytes_read = fread(buff, 1, 512, a); if (bytes_read < 512) { #ifdef ASSET_VERBOSE fprintf(stderr, "Short read: expected 512, got %d\n", (int)bytes_read); #endif return; } if (is_end_of_archive(buff)) { #ifdef ASSET_VERBOSE printf("===== completed in %lums ======\n", (clock() / (CLOCKS_PER_SEC / 1000)) - start); #endif return; } if (!verify_checksum(buff)) { #ifdef ASSET_VERBOSE fprintf(stderr, "Checksum failure\n"); #endif return; } filesize = parseoct(buff + 124, 12); char *filepath = malloc(sizeof(buff) + sizeof(path) + sizeof("/")); if (filepath) { strcpy(filepath, path); strcat(filepath, "/"); strcat(filepath, buff); } switch (buff[156]) { case '1': // printf("> Ignoring hardlink %s\n", buff); break; case '2': // printf("> Ignoring symlink %s\n", buff); break; case '3': // printf("> Ignoring character device %s\n", buff); break; case '4': // printf("> Ignoring block device %s\n", buff); break; case '5': create_dir(filepath, parseoct(buff + 100, 8)); filesize = 0; break; case '6': // printf("> Ignoring FIFO %s\n", buff); break; default: #ifdef ASSET_VERBOSE printf("> %s\n", buff); #endif f = create_file(filepath, parseoct(buff + 100, 8)); break; } while (filesize > 0) { bytes_read = fread(buff, 1, 512, a); if (bytes_read < 512) { #ifdef ASSET_VERBOSE fprintf(stderr, "Short read on %s: Expected 512, got %d\n", path, (int)bytes_read); #endif if (filepath != NULL) free(filepath); // Clear up any memory left for the file path return; } if (filesize < 512) bytes_read = filesize; if (f != NULL) { if (fwrite(buff, 1, bytes_read, f) != bytes_read) { #ifdef ASSET_VERBOSE fprintf(stderr, "Failed write\n"); fclose(f); f = NULL; #endif } } filesize -= bytes_read; } if (f != NULL) { fclose(f); f = NULL; } free(filepath); } }