@@ -494,7 +494,10 @@ int tracecmd_compress_proto_register(const char *name, const char *version, int
char *out, unsigned int *out_bytes),
unsigned int (*comress_size)(unsigned int bytes),
bool (*is_supported)(const char *name, const char *version));
-
+int tracecmd_compress_copy_from(struct tracecmd_compression *handle, int fd, int chunk_size,
+ unsigned long long *read_size, unsigned long long *write_size);
+int tracecmd_uncompress_copy_to(struct tracecmd_compression *handle, int fd,
+ unsigned long long *read_size, unsigned long long *write_size);
/* --- Plugin handling --- */
extern struct tep_plugin_option trace_ftrace_options[];
@@ -595,3 +595,203 @@ error:
free(v);
return -1;
}
+
+/**
+ * tracecmd_compress_copy_from - Copy and compress data from a file
+ * @handle: compression handler
+ * @fd: file descriptor to uncompressed data to copy from
+ * @chunk_size: size of one compression chunk
+ * @read_size: in - max bytes to read from @fd, 0 to read till the EOF
+ * out - size of the uncompressed data read from @fd
+ * @write_size: return, size of the compressed data written into @handle
+ *
+ * This function reads uncompressed data from given @fd, compresses the data using the @handle
+ * compression context and writes the compressed data into the fd associated with the @handle.
+ * The data is compressed on chunks with given @chunk_size size.
+ * The compressed data is written in the format:
+ * - 4 bytes, chunks count
+ * - for each chunk:
+ * - 4 bytes, size of compressed data in this chunk
+ * - 4 bytes, uncompressed size of the data in this chunk
+ * - data, bytes of <size of compressed data in this chunk>
+ *
+ * On success 0 is returned, @read_size and @write_size are updated with the size of
+ * read and written data.
+ */
+int tracecmd_compress_copy_from(struct tracecmd_compression *handle, int fd, int chunk_size,
+ unsigned long long *read_size, unsigned long long *write_size)
+{
+ unsigned int rchunk = 0;
+ unsigned int chunks = 0;
+ unsigned int wsize = 0;
+ unsigned int rsize = 0;
+ unsigned int rmax = 0;
+ unsigned int csize;
+ unsigned int size;
+ unsigned int r;
+ off64_t offset;
+ char *buf_from;
+ char *buf_to;
+ int endian4;
+ int ret;
+
+ if (!handle || !handle->proto ||
+ !handle->proto->compress_block || !handle->proto->compress_size)
+ return 0;
+ if (read_size)
+ rmax = *read_size;
+ csize = handle->proto->compress_size(chunk_size);
+ buf_from = malloc(chunk_size);
+ if (!buf_from)
+ return -1;
+ buf_to = malloc(csize);
+ if (!buf_to)
+ return -1;
+ /* save the initial offset and write 0 chunks */
+ offset = lseek64(handle->fd, 0, SEEK_CUR);
+ write_fd(handle->fd, &chunks, 4);
+
+ do {
+ if (rmax > 0 && (rmax - rsize) < chunk_size)
+ rchunk = (rmax - rsize);
+ else
+ rchunk = chunk_size;
+
+ r = read(fd, buf_from, rchunk);
+ if (r < 0 || (rmax > 0 && rsize >= rmax))
+ break;
+ rsize += r;
+ size = csize;
+ if (r > 0) {
+ ret = handle->proto->compress_block(buf_from, r, buf_to, &size);
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ break;
+ }
+ /* Write compressed data size */
+ endian4 = tep_read_number(handle->tep, &size, 4);
+ ret = write_fd(handle->fd, &endian4, 4);
+ if (ret != 4)
+ break;
+ /* Write uncompressed data size */
+ endian4 = tep_read_number(handle->tep, &r, 4);
+ ret = write_fd(handle->fd, &endian4, 4);
+ if (ret != 4)
+ break;
+ /* Write the compressed data */
+ ret = write_fd(handle->fd, buf_to, size);
+ if (ret != size)
+ break;
+ /* data + compress header */
+ wsize += (size + 8);
+ chunks++;
+ }
+ } while (r > 0);
+ free(buf_from);
+ free(buf_to);
+ if (r)
+ return -1;
+ if (lseek64(handle->fd, offset, SEEK_SET) == (off_t)-1)
+ return -1;
+ endian4 = tep_read_number(handle->tep, &chunks, 4);
+ /* write chunks count*/
+ write_fd(handle->fd, &chunks, 4);
+ lseek64(handle->fd, offset, SEEK_SET);
+ if (lseek64(handle->fd, 0, SEEK_END) == (off_t)-1)
+ return -1;
+ if (read_size)
+ *read_size = rsize;
+ if (write_size)
+ *write_size = wsize;
+ return 0;
+}
+
+/**
+ * tracecmd_uncompress_copy_to - Uncompress data and copy to a file
+ * @handle: compression handler
+ * @fd: file descriptor to uncompressed data to copy into
+ * @read_size: return, size of the compressed data read from @handle
+ * @write_size: return, size of the uncompressed data written into @fd
+ *
+ * This function reads compressed data from the fd, associated with @handle, uncompresses it
+ * using the @handle compression context and writes the uncompressed data into the fd.
+ * The compressed data must be in the format:
+ * - 4 bytes, chunks count
+ * - for each chunk:
+ * - 4 bytes, size of compressed data in this chunk
+ * - 4 bytes, uncompressed size of the data in this chunk
+ * - data, bytes of <size of compressed data in this chunk>
+ *
+ * On success 0 is returned, @read_size and @write_size are updated with the size of
+ * read and written data.
+ */
+int tracecmd_uncompress_copy_to(struct tracecmd_compression *handle, int fd,
+ unsigned long long *read_size, unsigned long long *write_size)
+{
+ unsigned int s_uncompressed;
+ unsigned int s_compressed;
+ unsigned int rsize = 0;
+ unsigned int wsize = 0;
+ char *bytes_out = NULL;
+ char *bytes_in = NULL;
+ int size_out;
+ int size_in;
+ int chunks;
+ char buf[4];
+ char *tmp;
+ int ret;
+
+ if (!handle || !handle->proto || !handle->proto->uncompress_block)
+ return -1;
+
+ if (read(handle->fd, buf, 4) != 4)
+ return -1;
+ chunks = tep_read_number(handle->tep, buf, 4);
+ rsize += 4;
+ while (chunks) {
+ if (read(handle->fd, buf, 4) != 4)
+ break;
+ s_compressed = tep_read_number(handle->tep, buf, 4);
+ rsize += 4;
+ if (read(handle->fd, buf, 4) != 4)
+ break;
+ s_uncompressed = tep_read_number(handle->tep, buf, 4);
+ rsize += 4;
+ if (!bytes_in || size_in < s_compressed) {
+ tmp = realloc(bytes_in, s_compressed);
+ if (!tmp)
+ break;
+ bytes_in = tmp;
+ size_in = s_compressed;
+ }
+
+ if (!bytes_out || size_out < s_uncompressed) {
+ tmp = realloc(bytes_out, s_uncompressed);
+ if (!tmp)
+ break;
+ bytes_out = tmp;
+ size_out = s_uncompressed;
+ }
+
+ if (read_fd(handle->fd, bytes_in, s_compressed) < 0)
+ break;
+ rsize += s_compressed;
+ ret = handle->proto->uncompress_block(bytes_in, s_compressed,
+ bytes_out, &s_uncompressed);
+ if (ret)
+ break;
+ write_fd(fd, bytes_out, s_uncompressed);
+ wsize += s_uncompressed;
+ chunks--;
+ }
+ free(bytes_in);
+ free(bytes_out);
+ if (chunks)
+ return -1;
+ if (read_size)
+ *read_size = rsize;
+ if (write_size)
+ *write_size = wsize;
+ return 0;
+}
New compression APIs are added for writing and reading compressed data from / to files in chunks: tracecmd_compress_copy_from() tracecmd_uncompress_copy_to() Format of the compressed data, used by these APIs, is: - 4 bytes, chunks count - for each chunk: - 4 bytes, size of compressed data in this chunk - 4 bytes, uncompressed size of the data in this chunk - data, bytes of <size of compressed data in this chunk> Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com> --- .../include/private/trace-cmd-private.h | 5 +- lib/trace-cmd/trace-compress.c | 200 ++++++++++++++++++ 2 files changed, 204 insertions(+), 1 deletion(-)