-   Programming (
-   -   libtar: what is the right way to use libtar with buffers instead of files? (

eantoranz 08-01-2012 09:52 AM

libtar: what is the right way to use libtar with buffers instead of files?

I want to handle tgz files that are in memory. At the time I'm working with a tar file that I have read into memory. I create a FILE * with fmemopen, I can read the file content with fgetc successfully on the FILE * created by fmemopen. Now, when I try to use this file with libtar, I get a Bad file descriptor message on th_read() (though tar_fdopen was successful).


FILE* memoryFile = fmemopen(fileContent, fileSize + 1, "rb");
TAR *t;
if(tar_fdopen(&t, fileno(memoryFile), NULL, O_RDONLY, 0, TAR_VERBOSE, TAR_GNU) == 0) {
        fprintf(stderr, "File successfully opened by tar\n");
} else {
        fprintf(stderr, "Couldn't open tgz file\n");
        fprintf(stderr, "tar_open(): %s\n", strerror(errno));
        return 1;

while ((i = th_read(t)) == 0) {

        if (TH_ISREG(t) && tar_skip_regfile(t) != 0) {
                fprintf(stderr, "tar_skip_regfile(): %s\n",
                return -1;

if (i == 1) {
        fprintf(stderr, "Reached EOF\n");
} else if (i == -1) {
        fprintf(stderr, "th_read(): %s\n", strerror(errno));
        return -1;

Is there a problem with fileno() or it's just not possible to use libtar from buffers at all?

eantoranz 08-01-2012 10:05 AM

Oh, I get it. The problem is that fileno returns -1 which means it's a bad file descriptor.... also from fmemopen's man page:


There is no file descriptor associated with the file stream returned by these functions (i.e., fileno(3) will return an error if called on the returned stream).
And that ends my adventure into using fmemopen and then tar_fdopen. What's the right way to do it then? Thanks in advance.

eantoranz 08-01-2012 10:41 AM

Got it. Have to set a custom tartype_t when calling tar_fdopen that calls your own handlers for opening/reading/writing/closing.

eantoranz 08-01-2012 05:02 PM

I'm having a lot of fun over here.

I can correctly use my custom function to read the tar file except when I try to get the content of the files with tar_block_read. When I only use th_read/tar_skip_regfile it works like a charm. I can get the filename, the file size of all files, print them to stderr, beautyful!.

Now, when I try to run tar_block_read, I get to read the content of the first file (this as a matter of fact is a proxy call to my custom reader) and then libtar goes nuts and can't seem to see the other files. From libtar.h:


#define tar_block_read(t, buf) (*((t)->type->readfunc))((t)->fd, (char *)(buf), T_BLOCKSIZE)
The only thing is that T_BLOCKSIZE is some value that is not related to the size of the file I want to read (and in my custom reader I don't have any check for file (as in files in the tar) boundaries.... you ask me to read 512 bytes? I'll read 512 bytes). This sounds a little weird because seems like libtar is asking to read the same mount of bytes per secula seculorum. I'd expect to get a call controlled by libtar adjusting to what's left of the file I want to expand.

So, what I did is replace the call for tar_block_read for a call to t->type->readfunc (in other words, an indirect call to my custom reader) with the actual size of the file I want to extract. That works and I get the contents of the file, however, I think that given that I moved the position of the pointer in the tar file, now calls to th_read fail (it's like something else has to be called after tar_block_read so that libtar gets the pointer at the right location or something like that). Can anybody give me a hand over here?

Thanks in advance.

eantoranz 08-01-2012 05:19 PM

This is a utterly simple (and un-elegant) hack but it works.

Given that libtar is calling my own writer to get the file content, I created another writer (not related to libtar) that can read from memory _without_ moving the memory pointer for libtar... in other words, libtar leaves the pointer where I need it with th_read and then I read memory (behind libtar's back) to get file content and then I can call tar_skip_regfile() to get to the next file's position. How about that?

But there has to be a clean way to do it, don't you think? What's that?

All times are GMT -5. The time now is 11:37 AM.