10

I need to create a tarball of a directory and then compress it with bz2 in C++. Is there any decent tutorial on using libtar and libbz2?

Fred Foo
  • 355,277
  • 75
  • 744
  • 836

2 Answers2

14

Okay, I worked up a quick example for you. No error checking and various arbitrary decisions, but it works. libbzip2 has fairly good web documentation. libtar, not so much, but there are manpages in the package, an example, and a documented header file. The below can be built with g++ C++TarBz2.cpp -ltar -lbz2 -o C++TarBz2.exe:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <libtar.h>
#include <bzlib.h>
#include <unistd.h>

int main()
{
    TAR *pTar;
    char tarFilename[] = "file.tar";
    char srcDir[] = "dirToZip/";
    char extractTo[] = ".";
    
    tar_open(&pTar, tarFilename, NULL, O_WRONLY | O_CREAT, 0644, TAR_GNU);
    tar_append_tree(pTar, srcDir, extractTo);
    
    close(tar_fd(pTar));

    int tarFD = open(tarFilename, O_RDONLY);

    char tbz2Filename[] =  "file.tar.bz2";
    FILE *tbz2File = fopen(tbz2Filename, "wb");
    int bzError;
    const int BLOCK_MULTIPLIER = 7;
    BZFILE *pBz = BZ2_bzWriteOpen(&bzError, tbz2File, BLOCK_MULTIPLIER, 0, 0);
   
    const int BUF_SIZE = 10000;
    char* buf = new char[BUF_SIZE];
    ssize_t bytesRead;
    while((bytesRead = read(tarFD, buf, BUF_SIZE)) > 0) {
        BZ2_bzWrite(&bzError, pBz, buf, bytesRead);
    }        
    BZ2_bzWriteClose(&bzError, pBz, 0, NULL, NULL);
    close(tarFD);
    remove(tarFilename);

    delete[] buf;

}
Gaurang Tandon
  • 6,504
  • 11
  • 47
  • 84
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
1

Assuming this isn't just a "how can I do this" question, then the obvious way is to fork/exec GNU tar to do it for you. The easiest way is with the system(3) library routine:

  system("/path/to/gtar cfj tarballname.tar.bz2 dirname");

According to this, there are example programs in the libtar disty.

Bzip's documentation includes a section on programming with libbz2.

Charlie Martin
  • 110,348
  • 25
  • 193
  • 263
  • 1
    Why is that the obvious way? If he's doing this a lot, the process overhead will become significant. Not to mention that this way he has full control over bzip's options. And of course, best to make sure you escape arguments correctly when calling system. – Matthew Flaschen May 01 '09 at 22:35
  • 1
    because it's simple, it does what's needed, and it's completely insensitive to any little details of the tar format etc. On a UNIX machine, at least, fork/exec is *relatively* cheap. So, "obvious" in the sense of "what's the simplest thing that could work?" – Charlie Martin May 01 '09 at 22:38
  • The request was for libbz2, not calling tar/bzip2 through fork/exec to accomplish the task. – hd1 Dec 07 '11 at 19:49
  • Using system is a terrible idea. Here are more details: http://www.cplusplus.com/forum/articles/11153/ – Tibi Jul 09 '12 at 07:43
  • 1
    Don't teach your grandma to suck eggs, sonny. system(3) is the simplest, most straightforward way to execute a child process. Yes, it forks twice: so what? Fork/exec is cheap. Compared to the processing time of a significant tar, it's nothing. Besides, what do you think, for example `(cd ~; ls)` does? That forks three times and does two execs. The whole "system is evil" thing comes up every so often as yet another generation of amateurs start thinking they're smarter than Ken Thompson. – Charlie Martin Jul 17 '12 at 17:53
  • Does system() work on iPhone? Android? Windows? I'm looking for a way to do this programmatically. Ideally just some function that takes a directory as a parameter, uses libtar and zlib, and produces a compressed folder as a single file. Extra credit if it's encrypted as well. – Fellow Traveler Feb 18 '15 at 11:34
  • The you should have said that, shouldn't you? – Charlie Martin Feb 18 '15 at 15:35