Home | History | Annotate | Line # | Download | only in recovery
      1  1.1  christos /*
      2  1.1  christos  * Copyright (c) Meta Platforms, Inc. and affiliates.
      3  1.1  christos  * All rights reserved.
      4  1.1  christos  *
      5  1.1  christos  * This source code is licensed under both the BSD-style license (found in the
      6  1.1  christos  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
      7  1.1  christos  * in the COPYING file in the root directory of this source tree).
      8  1.1  christos  * You may select, at your option, one of the above-listed licenses.
      9  1.1  christos  */
     10  1.1  christos 
     11  1.1  christos #include <string.h>
     12  1.1  christos #include <stdio.h>
     13  1.1  christos #include <stdlib.h>
     14  1.1  christos 
     15  1.1  christos #define ZSTD_STATIC_LINKING_ONLY
     16  1.1  christos #include "util.h"
     17  1.1  christos #include "zstd.h"
     18  1.1  christos 
     19  1.1  christos #define CHECK(cond, ...)                                                       \
     20  1.1  christos   do {                                                                         \
     21  1.1  christos     if (!(cond)) {                                                             \
     22  1.1  christos       fprintf(stderr, "%s:%d CHECK(%s) failed: ", __FILE__, __LINE__, #cond);  \
     23  1.1  christos       fprintf(stderr, "" __VA_ARGS__);                                         \
     24  1.1  christos       fprintf(stderr, "\n");                                                   \
     25  1.1  christos       exit(1);                                                                 \
     26  1.1  christos     }                                                                          \
     27  1.1  christos   } while (0)
     28  1.1  christos 
     29  1.1  christos static void usage(char const *program) {
     30  1.1  christos   fprintf(stderr, "USAGE: %s FILE.zst PREFIX\n", program);
     31  1.1  christos   fprintf(stderr, "FILE.zst: A zstd compressed file with multiple frames\n");
     32  1.1  christos   fprintf(stderr, "PREFIX:   The output prefix. Uncompressed files will be "
     33  1.1  christos                   "created named ${PREFIX}0 ${PREFIX}1...\n\n");
     34  1.1  christos   fprintf(stderr, "This program takes concatenated zstd frames and "
     35  1.1  christos                   "decompresses them into individual files.\n");
     36  1.1  christos   fprintf(stderr, "E.g. files created with a command like: zstd -r directory "
     37  1.1  christos                   "-o file.zst\n");
     38  1.1  christos }
     39  1.1  christos 
     40  1.1  christos typedef struct {
     41  1.1  christos   char *data;
     42  1.1  christos   size_t size;
     43  1.1  christos   size_t frames;
     44  1.1  christos   size_t maxFrameSize;
     45  1.1  christos } ZstdFrames;
     46  1.1  christos 
     47  1.1  christos static ZstdFrames readFile(char const *fileName) {
     48  1.1  christos   U64 const fileSize = UTIL_getFileSize(fileName);
     49  1.1  christos   CHECK(fileSize != UTIL_FILESIZE_UNKNOWN, "Unknown file size!");
     50  1.1  christos 
     51  1.1  christos   char *const data = (char *)malloc(fileSize);
     52  1.1  christos   CHECK(data != NULL, "Allocation failed");
     53  1.1  christos 
     54  1.1  christos   FILE *file = fopen(fileName, "rb");
     55  1.1  christos   CHECK(file != NULL, "fopen failed");
     56  1.1  christos 
     57  1.1  christos   size_t const readSize = fread(data, 1, fileSize, file);
     58  1.1  christos   CHECK(readSize == fileSize, "fread failed");
     59  1.1  christos 
     60  1.1  christos   fclose(file);
     61  1.1  christos   ZstdFrames frames;
     62  1.1  christos   frames.data = (char *)data;
     63  1.1  christos   frames.size = fileSize;
     64  1.1  christos   frames.frames = 0;
     65  1.1  christos 
     66  1.1  christos   size_t index;
     67  1.1  christos   size_t maxFrameSize = 0;
     68  1.1  christos   for (index = 0; index < fileSize;) {
     69  1.1  christos     size_t const frameSize =
     70  1.1  christos         ZSTD_findFrameCompressedSize(data + index, fileSize - index);
     71  1.1  christos     CHECK(!ZSTD_isError(frameSize), "Bad zstd frame: %s",
     72  1.1  christos           ZSTD_getErrorName(frameSize));
     73  1.1  christos     if (frameSize > maxFrameSize)
     74  1.1  christos       maxFrameSize = frameSize;
     75  1.1  christos     frames.frames += 1;
     76  1.1  christos     index += frameSize;
     77  1.1  christos   }
     78  1.1  christos   CHECK(index == fileSize, "Zstd file corrupt!");
     79  1.1  christos   frames.maxFrameSize = maxFrameSize;
     80  1.1  christos 
     81  1.1  christos   return frames;
     82  1.1  christos }
     83  1.1  christos 
     84  1.1  christos static int computePadding(size_t numFrames) {
     85  1.1  christos   return snprintf(NULL, 0, "%u", (unsigned)numFrames);
     86  1.1  christos }
     87  1.1  christos 
     88  1.1  christos int main(int argc, char **argv) {
     89  1.1  christos   if (argc != 3) {
     90  1.1  christos     usage(argv[0]);
     91  1.1  christos     exit(1);
     92  1.1  christos   }
     93  1.1  christos   char const *const zstdFile = argv[1];
     94  1.1  christos   char const *const prefix = argv[2];
     95  1.1  christos 
     96  1.1  christos   ZstdFrames frames = readFile(zstdFile);
     97  1.1  christos 
     98  1.1  christos   if (frames.frames <= 1) {
     99  1.1  christos     fprintf(
    100  1.1  christos         stderr,
    101  1.1  christos         "%s only has %u zstd frame. Simply use `zstd -d` to decompress it.\n",
    102  1.1  christos         zstdFile, (unsigned)frames.frames);
    103  1.1  christos     exit(1);
    104  1.1  christos   }
    105  1.1  christos 
    106  1.1  christos   int const padding = computePadding(frames.frames - 1);
    107  1.1  christos 
    108  1.1  christos   size_t const outFileNameSize = strlen(prefix) + padding + 1;
    109  1.1  christos   char* outFileName = malloc(outFileNameSize);
    110  1.1  christos   CHECK(outFileName != NULL, "Allocation failure");
    111  1.1  christos 
    112  1.1  christos   size_t const bufferSize = 128 * 1024;
    113  1.1  christos   void *buffer = malloc(bufferSize);
    114  1.1  christos   CHECK(buffer != NULL, "Allocation failure");
    115  1.1  christos 
    116  1.1  christos   ZSTD_DCtx* dctx = ZSTD_createDCtx();
    117  1.1  christos   CHECK(dctx != NULL, "Allocation failure");
    118  1.1  christos 
    119  1.1  christos   fprintf(stderr, "Recovering %u files...\n", (unsigned)frames.frames);
    120  1.1  christos 
    121  1.1  christos   size_t index;
    122  1.1  christos   size_t frame = 0;
    123  1.1  christos   for (index = 0; index < frames.size; ++frame) {
    124  1.1  christos     size_t const frameSize =
    125  1.1  christos         ZSTD_findFrameCompressedSize(frames.data + index, frames.size - index);
    126  1.1  christos 
    127  1.1  christos     int const ret = snprintf(outFileName, outFileNameSize, "%s%0*u", prefix, padding, (unsigned)frame);
    128  1.1  christos     CHECK(ret >= 0 && (size_t)ret <= outFileNameSize, "snprintf failed!");
    129  1.1  christos 
    130  1.1  christos     FILE* outFile = fopen(outFileName, "wb");
    131  1.1  christos     CHECK(outFile != NULL, "fopen failed");
    132  1.1  christos 
    133  1.1  christos     ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only);
    134  1.1  christos     ZSTD_inBuffer in = {frames.data + index, frameSize, 0};
    135  1.1  christos     while (in.pos < in.size) {
    136  1.1  christos         ZSTD_outBuffer out = {buffer, bufferSize, 0};
    137  1.1  christos         CHECK(!ZSTD_isError(ZSTD_decompressStream(dctx, &out, &in)), "decompression failed");
    138  1.1  christos         size_t const writeSize = fwrite(out.dst, 1, out.pos, outFile);
    139  1.1  christos         CHECK(writeSize == out.pos, "fwrite failed");
    140  1.1  christos     }
    141  1.1  christos     fclose(outFile);
    142  1.1  christos     fprintf(stderr, "Recovered %s\n", outFileName);
    143  1.1  christos     index += frameSize;
    144  1.1  christos   }
    145  1.1  christos   fprintf(stderr, "Complete\n");
    146  1.1  christos 
    147  1.1  christos   free(outFileName);
    148  1.1  christos   ZSTD_freeDCtx(dctx);
    149  1.1  christos   free(buffer);
    150  1.1  christos   free(frames.data);
    151  1.1  christos   return 0;
    152  1.1  christos }
    153