aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Kliuchnikov <eustas@google.com>2016-09-21 15:18:35 +0200
committerEugene Kliuchnikov <eustas@google.com>2016-09-21 15:18:35 +0200
commit9223fd4d8d85faf1f3c29a5a63903146d01894d0 (patch)
treee60a75127544243b080a0b21880ce39d0dae1e7c
parentf20b3eeb2f401fc4b87488ca22ca32729a6dec20 (diff)
downloadbrotli-9223fd4d8d85faf1f3c29a5a63903146d01894d0.zip
brotli-9223fd4d8d85faf1f3c29a5a63903146d01894d0.tar.gz
brotli-9223fd4d8d85faf1f3c29a5a63903146d01894d0.tar.bz2
Update bro tool:
* use new decoder API * copy permissions and modification time to output file
-rw-r--r--tools/bro.c82
1 files changed, 62 insertions, 20 deletions
diff --git a/tools/bro.c b/tools/bro.c
index b8fc13f..05f82b1 100644
--- a/tools/bro.c
+++ b/tools/bro.c
@@ -19,9 +19,11 @@
#if !defined(_WIN32)
#include <unistd.h>
+#include <utime.h>
#else
#include <io.h>
#include <share.h>
+#include <sys/utime.h>
#define MAKE_BINARY(FILENO) (_setmode((FILENO), _O_BINARY), (FILENO))
@@ -31,12 +33,18 @@
#define S_IRUSR S_IREAD
#define S_IWUSR S_IWRITE
#endif
+
#define fdopen _fdopen
#define unlink _unlink
+#define utimbuf _utimbuf
+#define utime _utime
#define fopen ms_fopen
#define open ms_open
+#define chmod(F, P)
+#define chown(F, O, G)
+
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#define fseek _fseeki64
#define ftell _ftelli64
@@ -76,7 +84,8 @@ static void ParseArgv(int argc, char **argv,
int *decompress,
int *repeat,
int *verbose,
- int *lgwin) {
+ int *lgwin,
+ int *copy_stat) {
int k;
*force = 0;
*input_path = 0;
@@ -84,6 +93,7 @@ static void ParseArgv(int argc, char **argv,
*repeat = 1;
*verbose = 0;
*lgwin = 22;
+ *copy_stat = 1;
{
size_t argv0_len = strlen(argv[0]);
*decompress =
@@ -109,6 +119,12 @@ static void ParseArgv(int argc, char **argv,
}
*verbose = 1;
continue;
+ } else if (!strcmp("--no-copy-stat", argv[k])) {
+ if (*copy_stat == 0) {
+ goto error;
+ }
+ *copy_stat = 0;
+ continue;
}
if (k < argc - 1) {
if (!strcmp("--input", argv[k]) ||
@@ -150,7 +166,7 @@ static void ParseArgv(int argc, char **argv,
}
++k;
continue;
- } else if (!strcmp("--window", argv[k]) ||
+ } else if (!strcmp("--window", argv[k]) ||
!strcmp("-w", argv[k])) {
if (!ParseQuality(argv[k + 1], lgwin)) {
goto error;
@@ -169,7 +185,8 @@ error:
fprintf(stderr,
"Usage: %s [--force] [--quality n] [--decompress]"
" [--input filename] [--output filename] [--repeat iters]"
- " [--verbose] [--window n] [--custom-dictionary filename]\n",
+ " [--verbose] [--window n] [--custom-dictionary filename]"
+ " [--no-copy-stat]\n",
argv[0]);
exit(1);
}
@@ -225,6 +242,26 @@ static int64_t FileSize(const char *path) {
return retval;
}
+/* Copy file times and permissions.
+ TODO: this is a "best effort" implementation; honest cross-platform
+ fully featured implementation is way too hacky; add more hacks by request. */
+static void CopyStat(const char* input_path, const char* output_path) {
+ struct stat statbuf;
+ struct utimbuf times;
+ if (input_path == 0 || output_path == 0) {
+ return;
+ }
+ if (stat(input_path, &statbuf) != 0) {
+ return;
+ }
+ times.actime = statbuf.st_atime;
+ times.modtime = statbuf.st_mtime;
+ utime(output_path, &times);
+ chmod(output_path, statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
+ chown(output_path, (__uid_t)-1, statbuf.st_gid);
+ chown(output_path, statbuf.st_uid, (__gid_t)-1);
+}
+
/* Result ownersip is passed to caller.
|*dictionary_size| is set to resulting buffer size. */
static uint8_t* ReadDictionary(const char* path, size_t* dictionary_size) {
@@ -273,13 +310,12 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
uint8_t* dictionary = NULL;
uint8_t* input;
uint8_t* output;
- size_t total_out;
size_t available_in;
const uint8_t* next_in;
size_t available_out = kFileBufferSize;
uint8_t* next_out;
- BrotliResult result = BROTLI_RESULT_ERROR;
- BrotliState* s = BrotliCreateState(NULL, NULL, NULL);
+ BrotliDecoderResult result = BROTLI_DECODER_RESULT_ERROR;
+ BrotliDecoderState* s = BrotliDecoderCreateInstance(NULL, NULL, NULL);
if (!s) {
fprintf(stderr, "out of memory\n");
return 0;
@@ -287,7 +323,7 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
if (dictionary_path != NULL) {
size_t dictionary_size = 0;
dictionary = ReadDictionary(dictionary_path, &dictionary_size);
- BrotliSetCustomDictionary(dictionary_size, dictionary, s);
+ BrotliDecoderSetCustomDictionary(s, dictionary_size, dictionary);
}
input = (uint8_t*)malloc(kFileBufferSize);
output = (uint8_t*)malloc(kFileBufferSize);
@@ -296,9 +332,9 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
goto end;
}
next_out = output;
- result = BROTLI_RESULT_NEEDS_MORE_INPUT;
+ result = BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
while (1) {
- if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) {
+ if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
if (feof(fin)) {
break;
}
@@ -307,7 +343,7 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
if (ferror(fin)) {
break;
}
- } else if (result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) {
+ } else if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
fwrite(output, 1, kFileBufferSize, fout);
if (ferror(fout)) {
break;
@@ -317,16 +353,17 @@ static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) {
} else {
break; /* Error or success. */
}
- result = BrotliDecompressStream(&available_in, &next_in,
- &available_out, &next_out, &total_out, s);
+ result = BrotliDecoderDecompressStream(
+ s, &available_in, &next_in, &available_out, &next_out, 0);
}
if (next_out != output) {
fwrite(output, 1, (size_t)(next_out - output), fout);
}
- if ((result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) || ferror(fout)) {
+ if ((result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) || ferror(fout)) {
fprintf(stderr, "failed to write output\n");
- } else if (result != BROTLI_RESULT_SUCCESS) { /* Error or needs more input. */
+ } else if (result != BROTLI_DECODER_RESULT_SUCCESS) {
+ /* Error or needs more input. */
fprintf(stderr, "corrupt input\n");
}
@@ -334,8 +371,8 @@ end:
free(dictionary);
free(input);
free(output);
- BrotliDestroyState(s);
- return (result == BROTLI_RESULT_SUCCESS) ? 1 : 0;
+ BrotliDecoderDestroyInstance(s);
+ return (result == BROTLI_DECODER_RESULT_SUCCESS) ? 1 : 0;
}
static int Compress(int quality, int lgwin, FILE* fin, FILE* fout,
@@ -419,14 +456,15 @@ int main(int argc, char** argv) {
int repeat = 1;
int verbose = 0;
int lgwin = 0;
+ int copy_stat = 1;
clock_t clock_start;
int i;
ParseArgv(argc, argv, &input_path, &output_path, &dictionary_path, &force,
- &quality, &decompress, &repeat, &verbose, &lgwin);
+ &quality, &decompress, &repeat, &verbose, &lgwin, &copy_stat);
clock_start = clock();
for (i = 0; i < repeat; ++i) {
FILE* fin = OpenInputFile(input_path);
- FILE* fout = OpenOutputFile(output_path, force || repeat);
+ FILE* fout = OpenOutputFile(output_path, force || (repeat > 1));
int is_ok = 0;
if (decompress) {
is_ok = Decompress(fin, fout, dictionary_path);
@@ -437,11 +475,15 @@ int main(int argc, char** argv) {
unlink(output_path);
exit(1);
}
- if (fclose(fin) != 0) {
+ if (fclose(fout) != 0) {
perror("fclose");
exit(1);
}
- if (fclose(fout) != 0) {
+ /* TOCTOU violation, but otherwise it is impossible to set file times. */
+ if (copy_stat && (i + 1 == repeat)) {
+ CopyStat(input_path, output_path);
+ }
+ if (fclose(fin) != 0) {
perror("fclose");
exit(1);
}