static int metadata_filter(struct archive *a, void *_data, struct archive_entry *entry) { struct bsdtar *bsdtar = (struct bsdtar *)_data; /* XXX TODO: check whether this filesystem is * synthetic and/or local. Add a new * --local-only option to skip non-local * filesystems. Skip synthetic filesystems * regardless. * * The results should be cached, since * tree.c doesn't usually visit a directory * and the directory contents together. A simple * move-to-front list should perform quite well. * * Use archive_read_disk_current_filesystem_is_remote(). */ /* * If the user vetoes this file/directory, skip it. * We want this to be fairly late; if some other * check would veto this file, we shouldn't bother * the user with it. */ if (bsdtar->option_interactive && !yes("add '%s'", archive_entry_pathname(entry))) return (0); /* Note: if user vetoes, we won't descend. */ if (!bsdtar->option_no_subdirs && archive_read_disk_can_descend(a)) archive_read_disk_descend(a); return (1); }
static int metadata_filter(archive *a, void *data, archive_entry *entry) { (void) data; (void) entry; if (archive_read_disk_can_descend(a)) { archive_read_disk_descend(a); } return 1; }
static void excluded_callback(struct archive *a, void *_data, struct archive_entry *entry) { struct bsdtar *bsdtar = (struct bsdtar *)_data; if (bsdtar->option_no_subdirs) return; if (!archive_read_disk_can_descend(a)) return; if (bsdtar->option_interactive && !yes("add '%s'", archive_entry_pathname(entry))) return; archive_read_disk_descend(a); }
compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n) #endif { int *marker; int matched; int i; #if HAVE_SUN_ACL int e; aclent_t *acl_entry; #else int entry_id = ACL_FIRST_ENTRY; acl_entry_t acl_entry; #endif /* Count ACL entries in myacls array and allocate an indirect array. */ marker = malloc(sizeof(marker[0]) * n); if (marker == NULL) return; for (i = 0; i < n; i++) marker[i] = i; /* * Iterate over acls in system acl object, try to match each * one with an item in the myacls array. */ #if HAVE_SUN_ACL for(e = 0; e < acl->acl_cnt; e++) { acl_entry = &((aclent_t *)acl->acl_aclp)[e]; #else while (1 == acl_get_entry(acl, entry_id, &acl_entry)) { /* After the first time... */ entry_id = ACL_NEXT_ENTRY; #endif /* Search for a matching entry (tag and qualifier) */ for (i = 0, matched = 0; i < n && !matched; i++) { if (acl_match(acl_entry, &myacls[marker[i]])) { /* We found a match; remove it. */ marker[i] = marker[n - 1]; n--; matched = 1; } } /* TODO: Print out more details in this case. */ failure("ACL entry on file that shouldn't be there"); assert(matched == 1); } /* Dump entries in the myacls array that weren't in the system acl. */ for (i = 0; i < n; ++i) { failure(" ACL entry missing from file: " "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n", myacls[marker[i]].type, myacls[marker[i]].permset, myacls[marker[i]].tag, myacls[marker[i]].qual, myacls[marker[i]].name); assert(0); /* Record this as a failure. */ } free(marker); } #endif /* * Verify ACL restore-to-disk. This test is Platform-specific. */ DEFINE_TEST(test_acl_platform_posix1e_restore) { #if !HAVE_SUN_ACL && !HAVE_POSIX_ACL skipping("POSIX.1e ACLs are not supported on this platform"); #else /* HAVE_SUN_ACL || HAVE_POSIX_ACL */ struct stat st; struct archive *a; struct archive_entry *ae; int n, fd; char *func; #if HAVE_SUN_ACL acl_t *acl, *acl2; #else acl_t acl; #endif /* * First, do a quick manual set/read of ACL data to * verify that the local filesystem does support ACLs. * If it doesn't, we'll simply skip the remaining tests. */ #if HAVE_SUN_ACL n = acl_fromtext("user::rwx,user:1:rw-,group::rwx,group:15:r-x,other:rwx,mask:rwx", &acl); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl = acl_from_text("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx"); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl != NULL); #endif /* Create a test file and try ACL on it. */ fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { acl_free(acl); return; } #if HAVE_SUN_ACL n = facl_get(fd, 0, &acl2); if (n != 0) { close(fd); acl_free(acl); } if (errno == ENOSYS) { skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } failure("facl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); if (acl2->acl_type != ACLENT_T) { acl_free(acl2); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } acl_free(acl2); func = "facl_set()"; n = facl_set(fd, acl); #else func = "acl_set_fd()"; n = acl_set_fd(fd, acl); #endif acl_free(acl); if (n != 0) { #if HAVE_SUN_ACL if (errno == ENOSYS) #else if (errno == EOPNOTSUPP || errno == EINVAL) #endif { close(fd); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } } failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); #if HAVE_SUN_ACL #endif close(fd); /* Create a write-to-disk object. */ assert(NULL != (a = archive_write_disk_new())); archive_write_disk_set_options(a, ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL); /* Populate an archive entry with some metadata, including ACL info */ ae = archive_entry_new(); assert(ae != NULL); archive_entry_set_pathname(ae, "test0"); archive_entry_set_mtime(ae, 123456, 7890); archive_entry_set_size(ae, 0); assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); archive_entry_free(ae); /* Close the archive. */ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); assertEqualInt(ARCHIVE_OK, archive_write_free(a)); /* Verify the data on disk. */ assertEqualInt(0, stat("test0", &st)); assertEqualInt(st.st_mtime, 123456); #if HAVE_SUN_ACL n = acl_get("test0", 0, &acl); failure("acl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl = acl_get_file("test0", ACL_TYPE_ACCESS); failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno)); assert(acl != (acl_t)NULL); #endif compare_acls(acl, acls2, sizeof(acls2)/sizeof(acls2[0])); acl_free(acl); #endif /* HAVE_SUN_ACL || HAVE_POSIX_ACL */ } /* * Verify ACL read-from-disk. This test is Platform-specific. */ DEFINE_TEST(test_acl_platform_posix1e_read) { #if !HAVE_SUN_ACL && !HAVE_POSIX_ACL skipping("POSIX.1e ACLs are not supported on this platform"); #else struct archive *a; struct archive_entry *ae; int n, fd, flags, dflags; char *func, *acl_text; const char *acl1_text, *acl2_text, *acl3_text; #if HAVE_SUN_ACL acl_t *acl, *acl1, *acl2, *acl3; #else acl_t acl1, acl2, acl3; #endif /* * Manually construct a directory and two files with * different ACLs. This also serves to verify that ACLs * are supported on the local filesystem. */ /* Create a test file f1 with acl1 */ #if HAVE_SUN_ACL acl1_text = "user::rwx," "group::rwx," "other:rwx," "user:1:rw-," "group:15:r-x," "mask:rwx"; n = acl_fromtext(acl1_text, &acl1); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl1_text = "user::rwx\n" "group::rwx\n" "other::rwx\n" "user:1:rw-\n" "group:15:r-x\n" "mask::rwx"; acl1 = acl_from_text(acl1_text); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl1 != NULL); #endif fd = open("f1", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { acl_free(acl1); return; } #if HAVE_SUN_ACL /* Check if Solaris filesystem supports POSIX.1e ACLs */ n = facl_get(fd, 0, &acl); if (n != 0) close(fd); if (n != 0 && errno == ENOSYS) { acl_free(acl1); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } failure("facl_get(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); if (acl->acl_type != ACLENT_T) { acl_free(acl); acl_free(acl1); close(fd); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } func = "facl_set()"; n = facl_set(fd, acl1); #else func = "acl_set_fd()"; n = acl_set_fd(fd, acl1); #endif acl_free(acl1); if (n != 0) { #if HAVE_SUN_ACL if (errno == ENOSYS) #else if (errno == EOPNOTSUPP || errno == EINVAL) #endif { close(fd); skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } } failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); close(fd); assertMakeDir("d", 0700); /* * Create file d/f1 with acl2 * * This differs from acl1 in the u:1: and g:15: permissions. * * This file deliberately has the same name but a different ACL. * Github Issue #777 explains how libarchive's directory traversal * did not always correctly enter directories before attempting * to read ACLs, resulting in reading the ACL from a like-named * file in the wrong directory. */ #if HAVE_SUN_ACL acl2_text = "user::rwx," "group::rwx," "other:---," "user:1:r--," "group:15:r--," "mask:rwx"; n = acl_fromtext(acl2_text, &acl2); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl2_text = "user::rwx\n" "group::rwx\n" "other::---\n" "user:1:r--\n" "group:15:r--\n" "mask::rwx"; acl2 = acl_from_text(acl2_text); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl2 != NULL); #endif fd = open("d/f1", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { acl_free(acl2); return; } #if HAVE_SUN_ACL func = "facl_set()"; n = facl_set(fd, acl2); #else func = "acl_set_fd()"; n = acl_set_fd(fd, acl2); #endif acl_free(acl2); if (n != 0) close(fd); failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); close(fd); /* Create nested directory d2 with default ACLs */ assertMakeDir("d/d2", 0755); #if HAVE_SUN_ACL acl3_text = "user::rwx," "group::r-x," "other:r-x," "user:2:r--," "group:16:-w-," "mask:rwx," "default:user::rwx," "default:user:1:r--," "default:group::r-x," "default:group:15:r--," "default:mask:rwx," "default:other:r-x"; n = acl_fromtext(acl3_text, &acl3); failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); assertEqualInt(0, n); #else acl3_text = "user::rwx\n" "user:1:r--\n" "group::r-x\n" "group:15:r--\n" "mask::rwx\n" "other::r-x"; acl3 = acl_from_text(acl3_text); failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl3 != NULL); #endif #if HAVE_SUN_ACL func = "acl_set()"; n = acl_set("d/d2", acl3); #else func = "acl_set_file()"; n = acl_set_file("d/d2", ACL_TYPE_DEFAULT, acl3); #endif acl_free(acl3); failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); /* Create a read-from-disk object. */ assert(NULL != (a = archive_read_disk_new())); assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, ".")); assert(NULL != (ae = archive_entry_new())); #if HAVE_SUN_ACL flags = ARCHIVE_ENTRY_ACL_TYPE_POSIX1E | ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA | ARCHIVE_ENTRY_ACL_STYLE_SOLARIS; dflags = flags; #else flags = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; dflags = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; #endif /* Walk the dir until we see both of the files */ while (ARCHIVE_OK == archive_read_next_header2(a, ae)) { archive_read_disk_descend(a); if (strcmp(archive_entry_pathname(ae), "./f1") == 0) { acl_text = archive_entry_acl_to_text(ae, NULL, flags); assertEqualString(acl_text, acl1_text); free(acl_text); } else if (strcmp(archive_entry_pathname(ae), "./d/f1") == 0) { acl_text = archive_entry_acl_to_text(ae, NULL, flags); assertEqualString(acl_text, acl2_text); free(acl_text); } else if (strcmp(archive_entry_pathname(ae), "./d/d2") == 0) { acl_text = archive_entry_acl_to_text(ae, NULL, dflags); assertEqualString(acl_text, acl3_text); free(acl_text); } } archive_entry_free(ae); assertEqualInt(ARCHIVE_OK, archive_free(a)); #endif }
static void create(const char *filename, int compress, const char **argv) { struct archive *a; struct archive *disk; struct archive_entry *entry; ssize_t len; int fd; a = archive_write_new(); switch (compress) { #ifndef NO_BZIP2_CREATE case 'j': case 'y': archive_write_add_filter_bzip2(a); break; #endif #ifndef NO_COMPRESS_CREATE case 'Z': archive_write_add_filter_compress(a); break; #endif #ifndef NO_GZIP_CREATE case 'z': archive_write_add_filter_gzip(a); break; #endif default: archive_write_add_filter_none(a); break; } archive_write_set_format_ustar(a); if (filename != NULL && strcmp(filename, "-") == 0) filename = NULL; archive_write_open_filename(a, filename); disk = archive_read_disk_new(); #ifndef NO_LOOKUP archive_read_disk_set_standard_lookup(disk); #endif while (*argv != NULL) { struct archive *disk = archive_read_disk_new(); int r; r = archive_read_disk_open(disk, *argv); if (r != ARCHIVE_OK) { errmsg(archive_error_string(disk)); errmsg("\n"); exit(1); } for (;;) { int needcr = 0; entry = archive_entry_new(); r = archive_read_next_header2(disk, entry); if (r == ARCHIVE_EOF) break; if (r != ARCHIVE_OK) { errmsg(archive_error_string(disk)); errmsg("\n"); exit(1); } archive_read_disk_descend(disk); if (verbose) { msg("a "); msg(archive_entry_pathname(entry)); needcr = 1; } r = archive_write_header(a, entry); if (r < ARCHIVE_OK) { errmsg(": "); errmsg(archive_error_string(a)); needcr = 1; } if (r == ARCHIVE_FATAL) exit(1); if (r > ARCHIVE_FAILED) { #if 0 /* Ideally, we would be able to use * the same code to copy a body from * an archive_read_disk to an * archive_write that we use for * copying data from an archive_read * to an archive_write_disk. * Unfortunately, this doesn't quite * work yet. */ copy_data(disk, a); #else /* For now, we use a simpler loop to copy data * into the target archive. */ fd = open(archive_entry_sourcepath(entry), 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); #endif } archive_entry_free(entry); if (needcr) msg("\n"); } archive_read_close(disk); archive_read_free(disk); argv++; } archive_write_close(a); archive_write_free(a); }
int archive_create2( char *arch_file, int compress, int format, char **files ) { int fd, len, ret; struct archive *arch_w = NULL, *arch_r; struct archive_entry *arch_entry = NULL; char buf[8192]; if( !arch_file || !files ) return -1; arch_w = archive_write_new(); switch( compress ) { case 'j': //bz2 //archive_write_add_filter_bzip2( arch_w ); archive_write_set_compression_bzip2( arch_w ); break; case 'J': //xz //archive_write_add_filter_xz( arch_w ); archive_write_set_compression_xz( arch_w ); break; case 'z': //gzip //archive_write_add_filter_gzip( arch_w ); archive_write_set_compression_gzip( arch_w ); break; } switch( format ) { case 'c': //cpio archive_write_set_format_cpio( arch_w ); break; case 't': //tar archive_write_set_format_ustar( arch_w ); break; default: //tar archive_write_set_format_ustar( arch_w ); break; } ret = archive_write_open_filename( arch_w, arch_file ); if( ret != ARCHIVE_OK ) { archive_write_finish( arch_w ); return -1; } while( *files ) { arch_r = archive_read_disk_new(); ret = archive_read_disk_open( arch_r, *files ); if( ret != ARCHIVE_OK ) { #ifdef DEBUG printf( "%s\n", archive_error_string( arch_r ) ); #endif archive_write_finish( arch_w ); return -1; } for( ; ; ) { arch_entry = archive_entry_new(); ret = archive_read_next_header2( arch_r, arch_entry ); if( ret == ARCHIVE_EOF ) break; if( ret != ARCHIVE_OK ) { #ifdef DEBUG printf( "%s\n", archive_error_string( arch_r ) ); #endif archive_entry_free( arch_entry ); archive_write_finish( arch_r ); archive_write_finish( arch_w ); return -1; } archive_read_disk_descend( arch_r ); ret = archive_write_header( arch_w, arch_entry ); if( ret < ARCHIVE_OK ) { #ifdef DEBUG printf( "%s\n", archive_error_string( arch_w ) ); #endif archive_entry_free( arch_entry ); archive_write_finish( arch_r ); archive_write_finish( arch_w ); return -1; } if( ( fd = open( archive_entry_sourcepath( arch_entry ), O_RDONLY ) ) != -1 ) { len = read( fd, buf, 8192 ); while( len > 0 ) { archive_write_data( arch_w, buf, len ); len = read( fd, buf, 8192 ); } close( fd ); } archive_entry_free( arch_entry ); } /* libarchive 3 archive_read_close( arch_r ); archive_read_free( arch_r ); */ archive_read_finish( arch_r ); } if( arch_w ) archive_write_finish( arch_w ); return 0; }
int archive_create( char *arch_file, int compress, int format, char *src_dir, char **exclude ) { int fd, len, ret, skip; char *pwd, **files; DIR *dir; struct dirent *dir_entry; struct archive *arch_w = NULL, *arch_r = NULL; struct archive_entry *arch_entry = NULL; char buf[8192]; if( !arch_file || !src_dir ) return -1; dir = opendir( src_dir ); if( !dir ) return -1; arch_w = archive_write_new(); switch( compress ) { case 'j': //bz2 //archive_write_add_filter_bzip2( arch_w ); //libarchive 3 archive_write_set_compression_bzip2( arch_w ); break; case 'J': //xz //archive_write_add_filter_xz( arch_w ); archive_write_set_compression_xz( arch_w ); break; case 'z': //gzip //archive_write_add_filter_gzip( arch_w ); archive_write_set_compression_gzip( arch_w ); break; } switch( format ) { case 'c': //cpio archive_write_set_format_cpio( arch_w ); break; case 't': //tar archive_write_set_format_ustar( arch_w ); break; default: //tar archive_write_set_format_ustar( arch_w ); break; } ret = archive_write_open_filename( arch_w, arch_file ); if( ret != ARCHIVE_OK ) { archive_write_finish( arch_w ); return -1; } pwd = getcwd( NULL, 0 ); chdir( src_dir ); while( (dir_entry = readdir( dir )) ) { if( !strcmp( dir_entry->d_name, "." ) || !strcmp( dir_entry->d_name, ".." ) ) { continue; } if( exclude ) { files = exclude; skip = 0; while( *files ) { if( !strcmp( *files, dir_entry->d_name ) ) { skip = 1; break; } files++; } if( skip ) continue; } arch_r = archive_read_disk_new(); ret = archive_read_disk_open( arch_r, dir_entry->d_name ); if( ret != ARCHIVE_OK ) { #ifdef DEBUG printf( "%s\n", archive_error_string( arch_r ) ); #endif archive_write_finish( arch_w ); return -1; } for( ; ; ) { arch_entry = archive_entry_new(); ret = archive_read_next_header2( arch_r, arch_entry ); if( ret == ARCHIVE_EOF ) break; if( ret != ARCHIVE_OK ) { #ifdef DEBUG printf( "%s\n", archive_error_string( arch_r ) ); #endif archive_entry_free( arch_entry ); archive_write_finish( arch_r ); archive_write_finish( arch_w ); return -1; } #ifdef DEBUG printf( "%s\n", archive_entry_pathname( arch_entry ) ); #endif archive_read_disk_descend( arch_r ); ret = archive_write_header( arch_w, arch_entry ); if( ret < ARCHIVE_OK ) { #ifdef DEBUG printf( "%s\n", archive_error_string( arch_w ) ); #endif archive_entry_free( arch_entry ); archive_write_finish( arch_r ); archive_write_finish( arch_w ); return -1; } if( ( fd = open( archive_entry_sourcepath( arch_entry ), O_RDONLY ) ) != -1 ) { len = read( fd, buf, 8192 ); while( len > 0 ) { archive_write_data( arch_w, buf, len ); len = read( fd, buf, 8192 ); } close( fd ); } archive_entry_free( arch_entry ); } /* libarchive 3 archive_read_close( arch_r ); archive_read_free( arch_r ); */ archive_read_finish( arch_r ); } if( arch_w ) { /* libarchive 3 archive_write_close( arch_r ); archive_write_free( arch_r ); */ archive_write_finish( arch_w ); } if( pwd ) { chdir( pwd ); free( pwd ); } return 0; }