GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |
GeezerVison is showing github.com — Examples Examples
Tim Kientzle edited this page
Short code examples illustrating usage of the library. This page collects several short examples illustrating usage of libarchive. The intent here is to provide basic templates that can be copied and used to bootstrap your own development. All of the code on this page is in the public domain. You may use it for any purpose whatsoever. (Please note that libarchive itself is not in the public domain; please read the license information in the source distribution for details.) If there is an example you'd like to see added to this page, please ask. Libarchive is based around two types of "objects": archive objects (pointers to `struct archive`) and entry objects (pointers to `struct archive_entry`). These are opaque references: you cannot directly access the structure fields, you can only invoke libarchive functions that create, manipulate, and destroy these objects for you. The basic lifecycle of an archive object is very simple:
Here's a very basic example that simply opens a file and lists the contents of the archive: struct archive *a; struct archive_entry *entry; int r; a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_all(a); r = archive_read_open_filename(a, "archive.tar", 10240); // Note 1 if (r != ARCHIVE_OK) exit(1); while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { printf("%s\n",archive_entry_pathname(entry)); archive_read_data_skip(a); // Note 2 } r = archive_read_free(a); // Note 3 if (r != ARCHIVE_OK) exit(1); Note 1: Beginning with libarchive 3.0, the `archive_read_open_filename()` function inspects the file before deciding how to handle the blocksize. If the filename provided refers to a tape device, for example, it will use exactly the blocksize you specify. For other devices, it may adjust the requested blocksize in order to obtain better performance. Note 2: The call to `archive_read_data_skip()` here is not actually necessary, since libarchive will invoke it automatically if you request the next header without reading the data for the last entry. Note 3: This function was called `archive_read_finish()` in earlier versions of libarchive. That name will remain available for at least a few years. There are several variants of the "open" functions. The "filename" variant used above is intended to be simple to use in the common case, but you may find the "memory" variant more useful sometimes: struct archive *a = archive_read_new(); archive_read_support_compression_gzip(a); archive_read_support_format_tar(a); r = archive_read_open_memory(a, buff, sizeof(buff)); Note that the "filename" variant accepts a block size indicating how large each read from disk will be. In the memory case, all that's needed is the total size of the archive stored in memory. There are also variants to read from an already-opened file descriptor (which is useful if you need to skip the first part of a file before using libarchive to extract the rest) or `FILE *` pointer. Sometimes, none of the packaged "open" functions will work for you. In that case, you can use the lower-level `archive_read_open` function. This accepts three callbacks and a pointer to your data:
All of the callbacks use certain common libarchive conventions:
void list_archive(const char *name) { struct mydata *mydata; struct archive *a; struct archive_entry *entry; mydata = malloc(sizeof(struct mydata)); a = archive_read_new(); mydata->name = name; mydata->fd = open(mydata->name, O_RDONLY); // Include O_BINARY on Windows archive_read_support_filter_all(a); archive_read_support_format_all(a); archive_read_open(a, mydata, NULL, myread, myclose); while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { printf("%s\n",archive_entry_pathname(entry)); } archive_read_finish(a); free(mydata); } ssize_t myread(struct archive *a, void *client_data, const void **buff) { struct mydata *mydata = client_data; *buff = mydata->buff; return (read(mydata->fd, mydata->buff, 10240)); } int myclose(struct archive *a, void *client_data) { struct mydata *mydata = client_data; if (mydata->fd > 0) close(mydata->fd); free(mydata); return (ARCHIVE_OK); } LibarchiveIO has more details about designing and implementing effective I/O callback functions. The `archive_read_open2` function is like `archive_read_open` but it accepts an additional "skip" callback function. The skip callback is never required. However, if it is available, libarchive can optimize certain reads. In particular, none of the examples above read the body of an archive entry. For some archive formats, libarchive can invoke the "skip" callback to quickly seek over the entire body entry. The skip callback must satisfy the following:
Libarchive 3.0 can now support a _seek_ callback. The seek callback is used to read archive formats that are not amenable to streaming, such as 7-Zip and some Zip variants. Be careful: If you provide a seek callback function, you are guaranteeing that it will work. In particular, the system `lseek()` or `fseek()` generally does not work with tape files, some raw disk devices, pipes, or network sockets. If you provide a seek callback that just invokes the system function on such a file, libarchive will likely get very confused. Starting with libarchive 2.8, there is a "raw" format handler that treats arbitrary binary input as a single-element archive. This is basically a cheat to allow you to get the output of a libarchive filter chain, including files with multiple encodings such as `gz.uu` files: int r; ssize_t size; struct archive *a = archive_read_new(); archive_read_support_filter_all(a); archive_read_support_format_raw(a); r = archive_read_open_filename(a, filename, 16384); if (r != ARCHIVE_OK) { /* ERROR */ } r = archive_read_next_header(a, &ae); if (r != ARCHIVE_OK) { /* ERROR */ } for (;;) { size = archive_read_data(a, buff, buffsize); if (size < 0) { /* ERROR */ } if (size == 0) break; write(1, buff, size); } archive_read_free(a)); Note that the "raw" format is not enabled by `archive_read_support_format_all()`. Also please note that the raw format handler does not recognize or accept empty files. If you specifically want to be able to read empty files, you'll need to also invoke `archive_read_support_format_empty()`. The following is a very simple example of using libarchive to write a group of files into a gzipped tar archive. This is a little more complex than the read examples above because the write example actually does something with the file bodies. void write_archive(const char *outname, const char **filename) { struct archive *a; struct archive_entry *entry; struct stat st; char buff[8192]; int len; int fd; a = archive_write_new(); archive_write_add_filter_gzip(a); archive_write_set_format_pax_restricted(a); // Note 1 archive_write_open_filename(a, outname); while (*filename) { stat(*filename, &st); entry = archive_entry_new(); // Note 2 archive_entry_set_pathname(entry, *filename); archive_entry_set_size(entry, st.st_size); // Note 3 archive_entry_set_filetype(entry, AE_IFREG); archive_entry_set_perm(entry, 0644); archive_write_header(a, entry); fd = open(*filename, O_RDONLY); len = read(fd, buff, sizeof(buff)); while ( len > 0 ) { archive_write_data(a, buff, len); len = read(fd, buff, sizeof(buff)); } close(fd); archive_entry_free(entry); filename++; } archive_write_close(a); // Note 4 archive_write_free(a); // Note 5 } int main(int argc, const char **argv) { const char *outname; argv++; outname = *argv++; write_archive(outname, argv); return 0; } Note 1: Libarchive's "pax restricted" format is a tar format that uses pax extensions only when absolutely necessary. Most of the time, it will write plain ustar entries. This is the recommended tar format for most uses. You should explicitly use ustar format only when you have to create archives that will be readable on older systems; you should explicitly request pax format only when you need to preserve as many attributes as possible. Note 2: This example creates a fresh archive_entry object for each file. For better performance, you can reuse the same archive_entry object by using `archive_entry_clear()` to erase it after each use. Note 3: Size, file type, and pathname are all required attributes here. You can also use `archive_entry_copy_stat()` to copy all information from the `struct stat` to the archive entry, including file type. To get even more complete information, look at the `archive_read_disk` API, which provides an easy way to get more extensive file metadata---including ACLs and extended attributes on some systems---than using the system `stat()` system call. It also works on platforms such as Windows where `stat()` either doesn't exist or is broken. Note 4: The free/finish call will implicitly call `archive_write_close()` if necessary. However, the close call returns an error code and the free/finish call does not, so if you rely on the implicit close, you won't be able to detect any errors that happen with the final writes. Note 5: Beginning with libarchive 3.0, this function is called `archive_write_free()`. The previous name was `archive_write_finish()`. If you want to write software compatible with libarchive 2.x and libarchive 3.x, you should use the old name, but be aware that it will be removed when libarchive 4.x is released. Libarchive includes an `archive_write_disk` facility that works very much like `archive_write`, except that it constructs objects on disk instead of adding entries to an archive. The `archive_write_disk` facility knows how to construct directories, regular files, symlinks, hard links, and other types of disk objects. Here is a very simple example showing how you could use it to create a regular file on disk: struct archive *a; struct archive_entry *entry; a = archive_write_disk_new(); archive_write_disk_set_options(a, ARCHIVE_EXTRACT_TIME); entry = archive_entry_new(); archive_entry_set_pathname(entry, "my_file.txt"); archive_entry_set_filetype(entry, AE_IFREG); // Note 1 archive_entry_set_size(ae, 5); // Note 2 archive_entry_set_mtime(ae, 123456789, 0); archive_write_header(a, entry); archive_write_data(a, "abcde", 5); // Note 3 archive_write_finish_entry(a); archive_write_free(a); archive_entry_free(entry); Note 1: The `archive_entry.h` header defines a set of `AE_XXXXX` constants for various file types. These are the same as the `IF_XXXXX` constants that are defined on many systems, except that not all systems have a complete set of `IF_XXXXX` definitions in the standard headers. Note 2: If you set a size in the entry, the `archive_write_disk` object will enforce that size. Note 3: If you try to write more than the size set in the entry, your writes will be truncated; if you write fewer bytes than you promised, the file will be extended with zero bytes. The pattern above can also be used to reconstruct directories, device nodes, and FIFOs. The same idea also works for restoring symlinks and hardlinks, but you do have to initialize the entry a little differently:
Using the facilities described above, you can extract most archives to disk by simply copying entries from an `archive_read` object to an `archive_write_disk` object. The following code is slightly simplified from the `examples/untar.c` code included in the libarchive distribution: static void extract(const char *filename) { struct archive *a; struct archive *ext; struct archive_entry *entry; int flags; int r; /* Select which attributes we want to restore. */ flags = ARCHIVE_EXTRACT_TIME; flags |= ARCHIVE_EXTRACT_PERM; flags |= ARCHIVE_EXTRACT_ACL; flags |= ARCHIVE_EXTRACT_FFLAGS; a = archive_read_new(); archive_read_support_format_all(a); archive_read_support_filter_all(a); ext = archive_write_disk_new(); archive_write_disk_set_options(ext, flags); archive_write_disk_set_standard_lookup(ext); if ((r = archive_read_open_filename(a, filename, 10240))) exit(1); for (;;) { r = archive_read_next_header(a, &entry); if (r == ARCHIVE_EOF) break; if (r < ARCHIVE_OK) fprintf(stderr, "%s\n", archive_error_string(a)); if (r < ARCHIVE_WARN) exit(1); r = archive_write_header(ext, entry); if (r < ARCHIVE_OK) fprintf(stderr, "%s\n", archive_error_string(ext)); else if (archive_entry_size(entry) > 0) { r = copy_data(a, ext); if (r < ARCHIVE_OK) fprintf(stderr, "%s\n", archive_error_string(ext)); if (r < ARCHIVE_WARN) exit(1); } r = archive_write_finish_entry(ext); if (r < ARCHIVE_OK) fprintf(stderr, "%s\n", archive_error_string(ext)); if (r < ARCHIVE_WARN) exit(1); } archive_read_close(a); archive_read_free(a); archive_write_close(ext); archive_write_free(ext); exit(0); } The function above just reads headers from the input archive and writes them to disk. The key missing piece in the above is the `copy_data()` function to actually pull data from a read archive and write it to a write handle: static int copy_data(struct archive *ar, struct archive *aw) { int r; const void *buff; size_t size; la_int64_t offset; for (;;) { r = archive_read_data_block(ar, &buff, &size, &offset); if (r == ARCHIVE_EOF) return (ARCHIVE_OK); if (r < ARCHIVE_OK) return (r); r = archive_write_data_block(aw, buff, size, offset); if (r < ARCHIVE_OK) { fprintf(stderr, "%s\n", archive_error_string(aw)); return (r); } } } For simplicity, the examples above do not all demonstrate proper error handling. Most libarchive functions return a status code that should be acted on. The most important values are:
Complete example programs can be found in the `examples` directory within the distribution. | |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |