uint8_t buffer[BUFFER_SIZE];
};
+static void zstd_free(struct zstd_cookie* cookie) {
+ if (cookie->cstream)
+ ZSTD_freeCStream(cookie->cstream);
+ if (cookie->dstream)
+ ZSTD_freeDStream(cookie->dstream);
+ free(cookie);
+}
+
static ssize_t zstd_read(void* data, char* buffer, size_t size) {
- struct zstd_cookie* cookie = (struct zstd_cookie*)data;
+ struct zstd_cookie* cookie = data;
+ int r;
+
if (!cookie)
return -1;
if (cookie->done)
return 0;
- size_t r = 0;
-
// Configure output buffer
- cookie->out.dst = buffer;
- cookie->out.pos = 0;
+ cookie->out.dst = buffer;
cookie->out.size = size;
+ cookie->out.pos = 0;
- while (1) {
- if (!feof(cookie->f) && (cookie->in.pos == cookie->in.size)) {
- cookie->in.pos = 0;
+ while (cookie->out.pos < cookie->out.size) {
+ if (cookie->in.pos >= cookie->in.size) {
cookie->in.size = fread(cookie->buffer, 1, sizeof(cookie->buffer), cookie->f);
- }
- if (r || cookie->in.size)
- r = ZSTD_decompressStream(cookie->dstream, &cookie->out, &cookie->in);
+ // EOF?
+ if (!cookie->in.size)
+ return 0;
- if (r == 0 && feof(cookie->f)) {
- cookie->done = 1;
- return cookie->out.pos;
+ cookie->in.pos = 0;
}
+ r = ZSTD_decompressStream(cookie->dstream, &cookie->out, &cookie->in);
if (ZSTD_isError(r))
return -1;
-
- // Buffer full
- if (cookie->out.pos == size)
- return size;
}
+
+ return cookie->out.pos;
}
static ssize_t zstd_write(void* data, const char* buffer, size_t size) {
- struct zstd_cookie* cookie = (struct zstd_cookie*)data;
+ struct zstd_cookie* cookie = data;
+ int r;
+
if (!cookie)
return -1;
if (cookie->mode == 'r')
return -1;
- // Return nothing when there is no input
- if (size == 0)
- return 0;
-
// Configure input buffer
- cookie->in.src = buffer;
- cookie->in.pos = 0;
+ cookie->in.src = buffer;
cookie->in.size = size;
+ cookie->in.pos = 0;
- while (1) {
- cookie->out.pos = 0;
+ while (cookie->in.pos < cookie->in.size) {
+ cookie->out.dst = cookie->buffer;
+ cookie->out.size = sizeof(cookie->buffer);
+ cookie->out.pos = 0;
- size_t r = ZSTD_compressStream(cookie->cstream, &cookie->out, &cookie->in);
+ r = ZSTD_compressStream(cookie->cstream, &cookie->out, &cookie->in);
if (ZSTD_isError(r))
return -1;
- if (cookie->out.pos > 0) {
- size_t bytes_written = fwrite(cookie->buffer, 1, cookie->out.pos, cookie->f);
-
- if (bytes_written != cookie->out.pos)
- return -1;
- }
-
- // Return when all input has been written
- if (cookie->in.pos == size)
- return size;
+ r = fwrite(cookie->buffer, 1, cookie->out.pos, cookie->f);
+ if (r < (ssize_t)cookie->out.pos)
+ return -1;
}
+
+ return size;
}
-static int zstd_close(void* data) {
- struct zstd_cookie* cookie = (struct zstd_cookie*)data;
+static int zstd_flush(void* data) {
+ struct zstd_cookie* cookie = data;
+ int r;
+
+ // Fail if were given no cookie
if (!cookie)
- return -1;
+ return -EINVAL;
+ // Reset the input buffer
+ cookie->in.src = NULL;
+ cookie->in.size = 0;
+ cookie->in.pos = 0;
+
+ // In write mode, we will have to flush all buffers
if (cookie->mode == 'w') {
- while (1) {
+ for (;;) {
// Reset output buffer
+ cookie->out.dst = cookie->buffer;
+ cookie->out.size = sizeof(cookie->buffer);
cookie->out.pos = 0;
- size_t r = ZSTD_endStream(cookie->cstream, &cookie->out);
+ r = ZSTD_endStream(cookie->cstream, &cookie->out);
if (ZSTD_isError(r))
return -1;
- if (cookie->out.pos > 0) {
- size_t bytes_written = fwrite(cookie->buffer, 1, cookie->out.pos, cookie->f);
-
- if (bytes_written != cookie->out.pos)
- return -1;
- }
-
+ // If the buffer is empty we are done
if (r == 0)
break;
+
+ // Otherwise we write the buffer to the file
+ r = fwrite(cookie->buffer, 1, cookie->out.pos, cookie->f);
+ if (r < (ssize_t)cookie->out.pos)
+ return -1;
}
}
- int r = fclose(cookie->f);
+ return 0;
+}
+
+static int zstd_close(void* data) {
+ struct zstd_cookie* cookie = data;
+ int r;
+
+ // Fail if were given no cookie
+ if (!cookie)
+ return -EINVAL;
+
+ // In write mode, we will have to flush all buffers
+ if (cookie->mode == 'w')
+ zstd_flush(cookie);
+
+ // Close the underlying file handle
+ r = fclose(cookie->f);
// Free everything
- if (cookie->cstream)
- ZSTD_freeCStream(cookie->cstream);
- if (cookie->dstream)
- ZSTD_freeDStream(cookie->dstream);
- free(cookie);
+ zstd_free(cookie);
return r;
}
};
FILE* pakfire_zstdfopen(FILE* f, const char* mode) {
+ struct zstd_cookie* cookie = NULL;
+ int r;
+
+ // Check for a valid file handle
if (!f) {
errno = EBADFD;
return NULL;
}
+ // Check for some mode
if (!mode) {
errno = EINVAL;
return NULL;
}
- struct zstd_cookie* cookie = calloc(1, sizeof(*cookie));
+ // Allocate a new cookie
+ cookie = calloc(1, sizeof(*cookie));
if (!cookie)
- return NULL;
+ goto ERROR;
+ // Store the file handle
cookie->f = f;
+
+ // Store the mode
cookie->mode = *mode;
- size_t r;
switch (cookie->mode) {
case 'r':
// Allocate stream
return fopencookie(cookie, mode, zstd_functions);
ERROR:
- if (cookie->cstream)
- ZSTD_freeCStream(cookie->cstream);
- if (cookie->dstream)
- ZSTD_freeDStream(cookie->dstream);
- free(cookie);
+ if (cookie)
+ zstd_free(cookie);
return NULL;
}