5

Let me explain what I'm trying to realize:

I have a encrypted tar file. I can decrypt it in memory, but obviously I can't write the decrypted data back to hard disk as a real file. The decrypted data is structured as a char* buffer in memory; how can I untar it in memory?

I can't find answer with libtar library. I also tried to untar it with execlp("tar", "tar", "-xvO", (void*)0). But it didn't work as I thought.

Anyone can give me a hint of the best solution? Thanks!

solotim
  • 1,826
  • 4
  • 24
  • 41
  • A easier way would perhaps be to change id to a special user, write a temp file, read it back in, delete it, and then change back to the normal user? – gnud Oct 12 '09 at 10:00
  • Only a simple question: Why to say "C Programming" in the title, because the tag says this to all? – Nathan Campos Oct 12 '09 at 10:45
  • gnud, I think create special user in every target machine is not feasible. Campos, this question is tagged as "c" and "tar", sorry, as I am newbie here, I don't get your point. I'll correct it if I'm wrong. – solotim Oct 13 '09 at 02:39
  • 1
    Note that your 'execlp()' call should end with a '(char *)0' argument marking the end of the list of arguments. Also, you would probably need to specify "-xvf" and "-" as arguments so that tar would read its standard input. Then you'd need to arrange a pipe to connect your application to the input of tar. Then you'd write the buffer full of decrypted tar file to the pipe. – Jonathan Leffler Oct 13 '09 at 04:50
  • Given that the tar file is now decrypted, why can't you afford to write the decrypted file to disk? The contents are about to be extracted onto disk - so the contents of the tar file are not really secret any more. You can give the file you create restrictive permissions. – Jonathan Leffler Oct 13 '09 at 04:51
  • Thanks, I just forgot (void*)0 when I typed. I have tried to use pipes to manage both stdin and stdout of tar command, but failed. See my comment to eyalm below. I can't write it back to disk because user is not allowed to get any information of tarred files. The decrypted and untarred contents will be read by my program only. All stuff are in memory and the end user can never know the contents in the encrypted tar file unless he crack my program. – solotim Oct 13 '09 at 06:01

5 Answers5

8

I suspect that libtar is the answer.

Using libtar, you can specify your own functions for opening/closing, reading and writing. From the manpage:

int tar_open(TAR **t, char *pathname, tartype_t *type, int oflags,
             int mode, int options);

The tar_open() function opens a tar archive file corresponding to the filename named by the pathname argument. The oflags argument must be either O_RDONLY or O_WRONLY.

The type argument specifies the access methods for the given file type. The tartype_t structure has members named openfunc(), closefunc(), readfunc() and writefunc(), which are pointers to the functions for opening, closing, reading, and writing the file, respectively. If type is NULL, the file type defaults to a normal file, and the standard open(), close(), read(), and write() functions are used.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
gnud
  • 77,584
  • 5
  • 64
  • 78
  • as tar_open function read char* pathname: int tar_open(TAR **t, char *pathname, tartype_t *type, int oflags, int mode, int options); the pathname must be some real file, right? – solotim Oct 12 '09 at 09:57
  • 1
    See my edit - you can use your own file-access functions, which could just work on memory. – gnud Oct 12 '09 at 09:59
  • the openfunc must return a fildes, I can't figure out how to get a fildes from a buffer. I have tried to use fileno(fmemopen(...)), but it just return -1. I'm frustrated. – solotim Oct 13 '09 at 06:48
  • @solotim Wouldn't `fildes` be an integer identifier of your choosing? So e.g. it could be an index into an array of virtual files that your program uses to track what it's doing with its reads and writes. – Craig McQueen May 09 '13 at 03:00
  • @CraigMcQueen Thanks. But sorry I don't get it. How can a file descriptor be something I can define? Could you please expand on this? – solotim May 10 '13 at 03:12
  • You define the functions acting on the file (openfunc, closefunc, readfunc, writefunc). They can do whatever you want - you define them, and pass them in to libtar. Since you decide what your functions do with the integer that libtar thinks is a file descriptor, it can actually be anything you want. Only the functions you wrote, and libtar, will ever see it. – gnud May 10 '13 at 07:24
7

I made an example, how to read file contents from an in-memory tar. The is_file_in_tar() function returns the length and the starting position of the named file if it is stored in the tar:

#include <stdio.h> 
#include <fcntl.h> 
#include <string.h> 
#include <sys/mman.h> 

struct tar {
  char name[100];   char _unused[24];
  char size[12];    char _padding[376];
} *tar;

int is_file_in_tar( struct tar *tar, char *name, char **start, int *length ){
  for( ; tar->name[0]; tar+=1+(*length+511)/512 ){
    sscanf( tar->size, "%o", length);
    if( !strcmp(tar->name,name) ){ *start = (char*)(tar+1); return 1; }
  }
  return 0;
}

int main(){
  int fd=open( "libtar-1.2.11.tar", O_RDONLY );
  tar=mmap(NULL, 808960, PROT_READ, MAP_PRIVATE, fd, 0);

  char *start; int length; char name[]="libtar-1.2.11/TODO";
  if( is_file_in_tar(tar,name,&start,&length) ) printf("%.*s",length,start);
}
sambowry
  • 2,436
  • 1
  • 16
  • 13
2

You can execute tar utility redirected to stdout. (tar --to-stdout). You should run it using forkpty() or popen() in order to read the output.

eyalm
  • 3,366
  • 19
  • 21
  • I'v tried to use "tar -xvO", it read from stdin and write to stdout. In my program, I must use two pipes, one: tardata->stdin, two: untarreddata<-stdout. The difficult point is that, when I put tardata to stdin pipe, since there are some '\0' in the raw tardata, the tar command can't recognize a complete tar from stdin. Do you have any idea about this? thanks – solotim Oct 13 '09 at 02:21
2

I've done for that with this code. Try it!

FILE*fp;
if( fp = popen("/bin/tar -xv -C /target/dir", "w") )
{
    fwrite(tar_buffer,1,tar_size,fp);
    pclose(fp);
    printf("Untar End %d Save file\n", tar_size);

}
Sparkup
  • 3,686
  • 2
  • 36
  • 50
Ryan
  • 21
  • 1
0

Just untar to in-memory tmpfs using a normal untar operation.

Test
  • 1,697
  • 1
  • 11
  • 10