libunarchive: clean up dirty hacks. code shrank as a result

function                                             old     new   delta
cpio_main                                            526     539     +13
init_handle                                           57      58      +1
init_archive_deb_ar                                   34      35      +1
get_header_ar                                        408     409      +1
dpkg_main                                           3900    3901      +1
unpack_package                                       516     515      -1
rpm_main                                            1673    1672      -1
tar_main                                             774     767      -7
get_header_cpio                                      990     972     -18
data_extract_all                                     750     727     -23
get_header_tar                                      1631    1576     -55
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/6 up/down: 17/-105)           Total: -88 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2010-01-06 10:53:17 +01:00
parent 86350f8d5f
commit aa4977d8e5
10 changed files with 95 additions and 102 deletions

View File

@ -412,14 +412,14 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
} }
/* see get_header_cpio */ /* see get_header_cpio */
archive_handle->ah_priv[2] = (void*) ~(ptrdiff_t)0; archive_handle->cpio__blocks = (off_t)-1;
while (get_header_cpio(archive_handle) == EXIT_SUCCESS) while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
continue; continue;
if (archive_handle->ah_priv[2] != (void*) ~(ptrdiff_t)0 if (archive_handle->cpio__blocks != (off_t)-1
&& !(opt & CPIO_OPT_QUIET) && !(opt & CPIO_OPT_QUIET)
) )
printf("%lu blocks\n", (unsigned long)(ptrdiff_t)(archive_handle->ah_priv[2])); printf("%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -1446,7 +1446,7 @@ static void init_archive_deb_control(archive_handle_t *ar_handle)
#endif #endif
/* Assign the tar handle as a subarchive of the ar handle */ /* Assign the tar handle as a subarchive of the ar handle */
ar_handle->sub_archive = tar_handle; ar_handle->dpkg__sub_archive = tar_handle;
} }
static void init_archive_deb_data(archive_handle_t *ar_handle) static void init_archive_deb_data(archive_handle_t *ar_handle)
@ -1466,27 +1466,27 @@ static void init_archive_deb_data(archive_handle_t *ar_handle)
#endif #endif
/* Assign the tar handle as a subarchive of the ar handle */ /* Assign the tar handle as a subarchive of the ar handle */
ar_handle->sub_archive = tar_handle; ar_handle->dpkg__sub_archive = tar_handle;
} }
static void FAST_FUNC data_extract_to_buffer(archive_handle_t *archive_handle) static void FAST_FUNC data_extract_to_buffer(archive_handle_t *archive_handle)
{ {
unsigned size = archive_handle->file_header->size; unsigned size = archive_handle->file_header->size;
archive_handle->ah_buffer = xzalloc(size + 1); archive_handle->dpkg__buffer = xzalloc(size + 1);
xread(archive_handle->src_fd, archive_handle->ah_buffer, size); xread(archive_handle->src_fd, archive_handle->dpkg__buffer, size);
} }
static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept) static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept)
{ {
ar_handle->sub_archive->action_data = data_extract_to_buffer; ar_handle->dpkg__sub_archive->action_data = data_extract_to_buffer;
ar_handle->sub_archive->accept = myaccept; ar_handle->dpkg__sub_archive->accept = myaccept;
ar_handle->sub_archive->filter = filter_accept_list; ar_handle->dpkg__sub_archive->filter = filter_accept_list;
unpack_ar_archive(ar_handle); unpack_ar_archive(ar_handle);
close(ar_handle->src_fd); close(ar_handle->src_fd);
return ar_handle->sub_archive->ah_buffer; return ar_handle->dpkg__sub_archive->dpkg__buffer;
} }
static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle) static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle)
@ -1495,7 +1495,7 @@ static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle)
name_ptr += strspn(name_ptr, "./"); name_ptr += strspn(name_ptr, "./");
if (name_ptr[0] != '\0') { if (name_ptr[0] != '\0') {
archive_handle->file_header->name = xasprintf("%s%s", archive_handle->ah_buffer, name_ptr); archive_handle->file_header->name = xasprintf("%s%s", archive_handle->dpkg__buffer, name_ptr);
data_extract_all(archive_handle); data_extract_all(archive_handle);
} }
} }
@ -1535,11 +1535,11 @@ static void unpack_package(deb_file_t *deb_file)
llist_add_to(&accept_list, c); llist_add_to(&accept_list, c);
i++; i++;
} }
archive_handle->sub_archive->accept = accept_list; archive_handle->dpkg__sub_archive->accept = accept_list;
archive_handle->sub_archive->filter = filter_accept_list; archive_handle->dpkg__sub_archive->filter = filter_accept_list;
archive_handle->sub_archive->action_data = data_extract_all_prefix; archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix;
archive_handle->sub_archive->ah_buffer = info_prefix; archive_handle->dpkg__sub_archive->dpkg__buffer = info_prefix;
archive_handle->sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD; archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD;
unpack_ar_archive(archive_handle); unpack_ar_archive(archive_handle);
/* Run the preinst prior to extracting */ /* Run the preinst prior to extracting */
@ -1548,19 +1548,19 @@ static void unpack_package(deb_file_t *deb_file)
/* Extract data.tar.gz to the root directory */ /* Extract data.tar.gz to the root directory */
archive_handle = init_archive_deb_ar(deb_file->filename); archive_handle = init_archive_deb_ar(deb_file->filename);
init_archive_deb_data(archive_handle); init_archive_deb_data(archive_handle);
archive_handle->sub_archive->action_data = data_extract_all_prefix; archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix;
archive_handle->sub_archive->ah_buffer = (char*)"/"; /* huh? */ archive_handle->dpkg__sub_archive->dpkg__buffer = (char*)"/"; /* huh? */
archive_handle->sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD; archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD;
unpack_ar_archive(archive_handle); unpack_ar_archive(archive_handle);
/* Create the list file */ /* Create the list file */
list_filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "list"); list_filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "list");
out_stream = xfopen_for_write(list_filename); out_stream = xfopen_for_write(list_filename);
while (archive_handle->sub_archive->passed) { while (archive_handle->dpkg__sub_archive->passed) {
/* the leading . has been stripped by data_extract_all_prefix already */ /* the leading . has been stripped by data_extract_all_prefix already */
fputs(archive_handle->sub_archive->passed->data, out_stream); fputs(archive_handle->dpkg__sub_archive->passed->data, out_stream);
fputc('\n', out_stream); fputc('\n', out_stream);
archive_handle->sub_archive->passed = archive_handle->sub_archive->passed->link; archive_handle->dpkg__sub_archive->passed = archive_handle->dpkg__sub_archive->passed->link;
} }
fclose(out_stream); fclose(out_stream);

View File

@ -28,7 +28,7 @@ int dpkg_deb_main(int argc, char **argv)
/* Setup an ar archive handle that refers to the gzip sub archive */ /* Setup an ar archive handle that refers to the gzip sub archive */
ar_archive = init_handle(); ar_archive = init_handle();
ar_archive->sub_archive = tar_archive; ar_archive->dpkg__sub_archive = tar_archive;
ar_archive->filter = filter_accept_list_reassign; ar_archive->filter = filter_accept_list_reassign;
#if ENABLE_FEATURE_SEAMLESS_GZ #if ENABLE_FEATURE_SEAMLESS_GZ

View File

@ -127,13 +127,13 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
uid_t uid = file_header->uid; uid_t uid = file_header->uid;
gid_t gid = file_header->gid; gid_t gid = file_header->gid;
if (file_header->uname) { if (file_header->tar__uname) {
//TODO: cache last name/id pair? //TODO: cache last name/id pair?
struct passwd *pwd = getpwnam(file_header->uname); struct passwd *pwd = getpwnam(file_header->tar__uname);
if (pwd) uid = pwd->pw_uid; if (pwd) uid = pwd->pw_uid;
} }
if (file_header->gname) { if (file_header->tar__gname) {
struct group *grp = getgrnam(file_header->gname); struct group *grp = getgrnam(file_header->tar__gname);
if (grp) gid = grp->gr_gid; if (grp) gid = grp->gr_gid;
} }
/* GNU tar 1.15.1 uses chown, not lchown */ /* GNU tar 1.15.1 uses chown, not lchown */

View File

@ -31,19 +31,19 @@ char FAST_FUNC filter_accept_list_reassign(archive_handle_t *archive_handle)
if (ENABLE_FEATURE_SEAMLESS_GZ if (ENABLE_FEATURE_SEAMLESS_GZ
&& strcmp(name_ptr, "gz") == 0 && strcmp(name_ptr, "gz") == 0
) { ) {
archive_handle->action_data_subarchive = get_header_tar_gz; archive_handle->dpkg__action_data_subarchive = get_header_tar_gz;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
if (ENABLE_FEATURE_SEAMLESS_BZ2 if (ENABLE_FEATURE_SEAMLESS_BZ2
&& strcmp(name_ptr, "bz2") == 0 && strcmp(name_ptr, "bz2") == 0
) { ) {
archive_handle->action_data_subarchive = get_header_tar_bz2; archive_handle->dpkg__action_data_subarchive = get_header_tar_bz2;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
if (ENABLE_FEATURE_SEAMLESS_LZMA if (ENABLE_FEATURE_SEAMLESS_LZMA
&& strcmp(name_ptr, "lzma") == 0 && strcmp(name_ptr, "lzma") == 0
) { ) {
archive_handle->action_data_subarchive = get_header_tar_lzma; archive_handle->dpkg__action_data_subarchive = get_header_tar_lzma;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
} }

View File

@ -122,8 +122,8 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle)
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) {
archive_handle->action_header(typed); archive_handle->action_header(typed);
#if ENABLE_DPKG || ENABLE_DPKG_DEB #if ENABLE_DPKG || ENABLE_DPKG_DEB
if (archive_handle->sub_archive) { if (archive_handle->dpkg__sub_archive) {
while (archive_handle->action_data_subarchive(archive_handle->sub_archive) == EXIT_SUCCESS) while (archive_handle->dpkg__action_data_subarchive(archive_handle->dpkg__sub_archive) == EXIT_SUCCESS)
continue; continue;
} else } else
#endif #endif

View File

@ -25,15 +25,6 @@ char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
int major, minor, nlink, mode, inode; int major, minor, nlink, mode, inode;
unsigned size, uid, gid, mtime; unsigned size, uid, gid, mtime;
#define hardlinks_to_create (*(hardlinks_t **)(&archive_handle->ah_priv[0]))
#define created_hardlinks (*(hardlinks_t **)(&archive_handle->ah_priv[1]))
#define block_count (archive_handle->ah_priv[2])
// if (!archive_handle->ah_priv_inited) {
// archive_handle->ah_priv_inited = 1;
// hardlinks_to_create = NULL;
// created_hardlinks = NULL;
// }
/* There can be padding before archive header */ /* There can be padding before archive header */
data_align(archive_handle, 4); data_align(archive_handle, 4);
@ -86,7 +77,7 @@ char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
if (strcmp(file_header->name, "TRAILER!!!") == 0) { if (strcmp(file_header->name, "TRAILER!!!") == 0) {
/* Always round up. ">> 9" divides by 512 */ /* Always round up. ">> 9" divides by 512 */
block_count = (void*)(ptrdiff_t) ((archive_handle->offset + 511) >> 9); archive_handle->cpio__blocks = (uoff_t)(archive_handle->offset + 511) >> 9;
goto create_hardlinks; goto create_hardlinks;
} }
@ -112,13 +103,13 @@ char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
strcpy(new->name, file_header->name); strcpy(new->name, file_header->name);
/* Put file on a linked list for later */ /* Put file on a linked list for later */
if (size == 0) { if (size == 0) {
new->next = hardlinks_to_create; new->next = archive_handle->cpio__hardlinks_to_create;
hardlinks_to_create = new; archive_handle->cpio__hardlinks_to_create = new;
return EXIT_SUCCESS; /* Skip this one */ return EXIT_SUCCESS; /* Skip this one */
/* TODO: this breaks cpio -t (it does not show hardlinks) */ /* TODO: this breaks cpio -t (it does not show hardlinks) */
} }
new->next = created_hardlinks; new->next = archive_handle->cpio__created_hardlinks;
created_hardlinks = new; archive_handle->cpio__created_hardlinks = new;
} }
file_header->device = makedev(major, minor); file_header->device = makedev(major, minor);
@ -142,11 +133,11 @@ char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
free(file_header->link_target); free(file_header->link_target);
free(file_header->name); free(file_header->name);
while (hardlinks_to_create) { while (archive_handle->cpio__hardlinks_to_create) {
hardlinks_t *cur; hardlinks_t *cur;
hardlinks_t *make_me = hardlinks_to_create; hardlinks_t *make_me = archive_handle->cpio__hardlinks_to_create;
hardlinks_to_create = make_me->next; archive_handle->cpio__hardlinks_to_create = make_me->next;
memset(file_header, 0, sizeof(*file_header)); memset(file_header, 0, sizeof(*file_header));
file_header->mtime = make_me->mtime; file_header->mtime = make_me->mtime;
@ -158,7 +149,7 @@ char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
/*file_header->link_target = NULL;*/ /*file_header->link_target = NULL;*/
/* Try to find a file we are hardlinked to */ /* Try to find a file we are hardlinked to */
cur = created_hardlinks; cur = archive_handle->cpio__created_hardlinks;
while (cur) { while (cur) {
/* TODO: must match maj/min too! */ /* TODO: must match maj/min too! */
if (cur->inode == make_me->inode) { if (cur->inode == make_me->inode) {
@ -176,14 +167,14 @@ char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) if (archive_handle->filter(archive_handle) == EXIT_SUCCESS)
archive_handle->action_data(archive_handle); archive_handle->action_data(archive_handle);
/* Move to the list of created hardlinked files */ /* Move to the list of created hardlinked files */
make_me->next = created_hardlinks; make_me->next = archive_handle->cpio__created_hardlinks;
created_hardlinks = make_me; archive_handle->cpio__created_hardlinks = make_me;
next_link: ; next_link: ;
} }
while (created_hardlinks) { while (archive_handle->cpio__created_hardlinks) {
hardlinks_t *p = created_hardlinks; hardlinks_t *p = archive_handle->cpio__created_hardlinks;
created_hardlinks = p->next; archive_handle->cpio__created_hardlinks = p->next;
free(p); free(p);
} }

View File

@ -135,20 +135,13 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
int parse_names; int parse_names;
/* Our "private data" */ /* Our "private data" */
#define p_end (*(smallint *)(&archive_handle->ah_priv[0]))
#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
#define p_longname (*(char* *)(&archive_handle->ah_priv[1])) # define p_longname (archive_handle->tar__longname)
#define p_linkname (*(char* *)(&archive_handle->ah_priv[2])) # define p_linkname (archive_handle->tar__linkname)
#else #else
# define p_longname 0 # define p_longname 0
# define p_linkname 0 # define p_linkname 0
#endif #endif
// if (!archive_handle->ah_priv_inited) {
// archive_handle->ah_priv_inited = 1;
// p_end = 0;
// IF_FEATURE_TAR_GNU_EXTENSIONS(p_longname = NULL;)
// IF_FEATURE_TAR_GNU_EXTENSIONS(p_linkname = NULL;)
// }
if (sizeof(tar) != 512) if (sizeof(tar) != 512)
BUG_tar_header_size(); BUG_tar_header_size();
@ -190,7 +183,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
/* If there is no filename its an empty header */ /* If there is no filename its an empty header */
if (tar.name[0] == 0 && tar.prefix[0] == 0) { if (tar.name[0] == 0 && tar.prefix[0] == 0) {
if (p_end) { if (archive_handle->tar__end) {
/* Second consecutive empty header - end of archive. /* Second consecutive empty header - end of archive.
* Read until the end to empty the pipe from gz or bz2 * Read until the end to empty the pipe from gz or bz2
*/ */
@ -198,10 +191,10 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
continue; continue;
return EXIT_FAILURE; return EXIT_FAILURE;
} }
p_end = 1; archive_handle->tar__end = 1;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
p_end = 0; archive_handle->tar__end = 0;
/* Check header has valid magic, "ustar" is for the proper tar, /* Check header has valid magic, "ustar" is for the proper tar,
* five NULs are for the old tar format */ * five NULs are for the old tar format */
@ -301,8 +294,8 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
/* Will link_target be free()ed? */ /* Will link_target be free()ed? */
} }
#if ENABLE_FEATURE_TAR_UNAME_GNAME #if ENABLE_FEATURE_TAR_UNAME_GNAME
file_header->uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL; file_header->tar__uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL;
file_header->gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL; file_header->tar__gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL;
#endif #endif
/* mtime: rudimentally handle GNU tar's "base256 encoding" /* mtime: rudimentally handle GNU tar's "base256 encoding"
* People report tarballs with NEGATIVE unix times encoded that way */ * People report tarballs with NEGATIVE unix times encoded that way */
@ -449,8 +442,8 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
free(file_header->link_target); free(file_header->link_target);
/* Do not free(file_header->name)! (why?) */ /* Do not free(file_header->name)! (why?) */
#if ENABLE_FEATURE_TAR_UNAME_GNAME #if ENABLE_FEATURE_TAR_UNAME_GNAME
free(file_header->uname); free(file_header->tar__uname);
free(file_header->gname); free(file_header->tar__gname);
#endif #endif
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -16,12 +16,12 @@ void FAST_FUNC header_verbose_list(const file_header_t *file_header)
char *user; char *user;
char *group; char *group;
user = file_header->uname; user = file_header->tar__uname;
if (user == NULL) { if (user == NULL) {
sprintf(uid, "%u", (unsigned)file_header->uid); sprintf(uid, "%u", (unsigned)file_header->uid);
user = uid; user = uid;
} }
group = file_header->gname; group = file_header->tar__gname;
if (group == NULL) { if (group == NULL) {
/*sprintf(gid, "%u", (unsigned)file_header->gid);*/ /*sprintf(gid, "%u", (unsigned)file_header->gid);*/
group = utoa(file_header->gid); group = utoa(file_header->gid);

View File

@ -8,8 +8,8 @@ typedef struct file_header_t {
char *name; char *name;
char *link_target; char *link_target;
#if ENABLE_FEATURE_TAR_UNAME_GNAME #if ENABLE_FEATURE_TAR_UNAME_GNAME
char *uname; char *tar__uname;
char *gname; char *tar__gname;
#endif #endif
off_t size; off_t size;
uid_t uid; uid_t uid;
@ -19,16 +19,25 @@ typedef struct file_header_t {
dev_t device; dev_t device;
} file_header_t; } file_header_t;
struct hardlinks_t;
typedef struct archive_handle_t { typedef struct archive_handle_t {
/* Flags. 1st since it is most used member */
unsigned ah_flags;
/* The raw stream as read from disk or stdin */
int src_fd;
/* Define if the header and data component should be processed */ /* Define if the header and data component should be processed */
char FAST_FUNC (*filter)(struct archive_handle_t *); char FAST_FUNC (*filter)(struct archive_handle_t *);
/* List of files that have been accepted */
llist_t *accept; llist_t *accept;
/* List of files that have been rejected */ /* List of files that have been rejected */
llist_t *reject; llist_t *reject;
/* List of files that have successfully been worked on */ /* List of files that have successfully been worked on */
llist_t *passed; llist_t *passed;
/* Contains the processed header entry */ /* Currently processed file's header */
file_header_t *file_header; file_header_t *file_header;
/* Process the header component, e.g. tar -t */ /* Process the header component, e.g. tar -t */
@ -37,33 +46,33 @@ typedef struct archive_handle_t {
/* Process the data component, e.g. extract to filesystem */ /* Process the data component, e.g. extract to filesystem */
void FAST_FUNC (*action_data)(struct archive_handle_t *); void FAST_FUNC (*action_data)(struct archive_handle_t *);
#if ENABLE_DPKG || ENABLE_DPKG_DEB
/* "subarchive" is used only by dpkg[-deb] applets */
/* How to process any sub archive, e.g. get_header_tar_gz */
char FAST_FUNC (*action_data_subarchive)(struct archive_handle_t *);
/* Contains the handle to a sub archive */
struct archive_handle_t *sub_archive;
#endif
/* The raw stream as read from disk or stdin */
int src_fd;
/* Count the number of bytes processed */
off_t offset;
/* Function that skips data */ /* Function that skips data */
void FAST_FUNC (*seek)(int fd, off_t amount); void FAST_FUNC (*seek)(int fd, off_t amount);
/* Count processed bytes */
off_t offset;
/* Archiver specific. Can make it a union if it ever gets big */
#if ENABLE_TAR
smallint tar__end;
# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
char* tar__longname;
char* tar__linkname;
# endif
#endif
#if ENABLE_CPIO
uoff_t cpio__blocks;
struct hardlinks_t *cpio__hardlinks_to_create;
struct hardlinks_t *cpio__created_hardlinks;
#endif
#if ENABLE_DPKG || ENABLE_DPKG_DEB
/* Temporary storage */ /* Temporary storage */
char *ah_buffer; char *dpkg__buffer;
/* How to process any sub archive, e.g. get_header_tar_gz */
/* Flags and misc. stuff */ char FAST_FUNC (*dpkg__action_data_subarchive)(struct archive_handle_t *);
unsigned ah_flags; /* Contains the handle to a sub archive */
struct archive_handle_t *dpkg__sub_archive;
/* "Private" storage for archivers */ #endif
// unsigned char ah_priv_inited;
void *ah_priv[8];
} archive_handle_t; } archive_handle_t;
/* bits in ah_flags */ /* bits in ah_flags */
#define ARCHIVE_RESTORE_DATE (1 << 0) #define ARCHIVE_RESTORE_DATE (1 << 0)