#ifdef HAVE_LINUX_MAGIC_H
#include <linux/magic.h>
#endif
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#endif
+/*
+ * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
+ * As the include guards don't agree, the order of include is important.
+ */
+#ifdef HAVE_LINUX_EXT2_FS_H
+#include <linux/ext2_fs.h> /* for Linux file flags */
+#endif
+#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
+#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */
+#endif
#ifdef HAVE_DIRECT_H
#include <direct.h>
#endif
#endif
}
+int
+archive_read_disk_honor_nodump(struct archive *_a)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");
+ a->honor_nodump = 1;
+ return (ARCHIVE_OK);
+}
+
/*
* Trivial implementations of gname/uname lookup functions.
* These are normally overridden by the client, but these stub
goto next_entry;
}
}
+
+#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
+ if (a->honor_nodump) {
+ if (st->st_flags & UF_NODUMP) {
+ archive_entry_unset_atime(entry);
+ archive_entry_unset_birthtime(entry);
+ archive_entry_unset_ctime(entry);
+ archive_entry_unset_mtime(entry);
+ goto next_entry;
+ }
+ }
+#endif
+
archive_entry_copy_sourcepath(entry, tree_current_access_path(t));
/* Save the times to be restored. */
if (fd >= 0)
close(fd);
+#if defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+ /* Linux uses ioctl to read flags. */
+ if (r == ARCHIVE_OK && a->honor_nodump) {
+ unsigned long flags, clear;
+ archive_entry_fflags(entry, &flags, &clear);
+ if (flags & EXT2_NODUMP_FL) {
+ archive_entry_unset_atime(entry);
+ archive_entry_unset_birthtime(entry);
+ archive_entry_unset_ctime(entry);
+ archive_entry_unset_mtime(entry);
+ goto next_entry;
+ }
+ }
+#endif
+
/* Return to the initial directory. */
tree_enter_initial_dir(t);
archive_entry_copy_sourcepath(entry, tree_current_path(t));
#include "test.h"
__FBSDID("$FreeBSD$");
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
#include <limits.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
# if !defined(__BORLANDC__)
# define getcwd _getcwd
archive_entry_free(ae);
}
+#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
+static int
+canNodump()
+{
+ const char *path = "cannodumptest";
+ struct stat sb;
+
+ assertMakeFile(path, 0644, NULL);
+ if (chflags(path, UF_NODUMP) < 0)
+ return (0);
+ if (stat(path, &sb) < 0)
+ return (0);
+ if (sb.st_flags & UF_NODUMP)
+ return (1);
+ return (0);
+}
+
+static int
+assertNodump(const char *path)
+{
+ return (assertEqualInt(0, chflags(path, UF_NODUMP)));
+}
+
+#else
+
+static int
+canNodump()
+{
+ return (0);
+}
+
+static int
+assertNodump(const char *path)
+{
+ (void)path; /* UNUSED */
+ return (0);
+}
+
+#endif
+
+static void
+test_nodump(void)
+{
+ struct archive *a;
+ struct archive_entry *ae;
+ const void *p;
+ size_t size;
+ int64_t offset;
+ int file_count;
+
+ if (!canNodump()) {
+ skipping("Can't test nodump on this filesystem");
+ return;
+ }
+
+ assertMakeDir("nd", 0755);
+ assertMakeFile("nd/f1", 0644, "0123456789");
+ assertMakeFile("nd/f2", 0644, "hello world");
+ assertMakeFile("nd/fe", 0644, NULL);
+ assertNodump("nd/f2");
+ assertUtimes("nd/f1", 886600, 0, 886600, 0);
+ assertUtimes("nd/f2", 886611, 0, 886611, 0);
+ assertUtimes("nd/fe", 886611, 0, 886611, 0);
+ assertUtimes("nd", 886622, 0, 886622, 0);
+
+ assert((ae = archive_entry_new()) != NULL);
+ assert((a = archive_read_disk_new()) != NULL);
+
+ /*
+ * Test1: Traversals without archive_read_disk_honor_nodump().
+ */
+ failure("Directory traversals should work as well");
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "nd"));
+
+ file_count = 4;
+ while (file_count--) {
+ archive_entry_clear(ae);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
+ if (strcmp(archive_entry_pathname(ae), "nd") == 0) {
+ assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
+ } else if (strcmp(archive_entry_pathname(ae), "nd/f1") == 0) {
+ assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
+ assertEqualInt(archive_entry_size(ae), 10);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 10);
+ assertEqualInt((int)offset, 0);
+ assertEqualMem(p, "0123456789", 10);
+ assertEqualInt(ARCHIVE_EOF,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 0);
+ assertEqualInt((int)offset, 10);
+ } else if (strcmp(archive_entry_pathname(ae), "nd/f2") == 0) {
+ assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
+ assertEqualInt(archive_entry_size(ae), 11);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 11);
+ assertEqualInt((int)offset, 0);
+ assertEqualMem(p, "hello world", 11);
+ assertEqualInt(ARCHIVE_EOF,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 0);
+ assertEqualInt((int)offset, 11);
+ } else if (strcmp(archive_entry_pathname(ae), "nd/fe") == 0) {
+ assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
+ assertEqualInt(archive_entry_size(ae), 0);
+ }
+ if (archive_read_disk_can_descend(a)) {
+ /* Descend into the current object */
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_disk_descend(a));
+ }
+ }
+ /* There is no entry. */
+ failure("There should be no entry");
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
+
+ /* Close the disk object. */
+ assertEqualInt(ARCHIVE_OK, archive_read_close(a));
+
+ /*
+ * Test2: Traversals with archive_read_disk_honor_nodump().
+ */
+ assertUtimes("nd/f1", 886600, 0, 886600, 0);
+ assertUtimes("nd/f2", 886611, 0, 886611, 0);
+ assertUtimes("nd/fe", 886611, 0, 886611, 0);
+ assertUtimes("nd", 886622, 0, 886622, 0);
+
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_honor_nodump(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_atime_restored(a));
+ failure("Directory traversals should work as well");
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "nd"));
+
+ file_count = 3;
+ while (file_count--) {
+ archive_entry_clear(ae);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
+ failure("File 'nd/f2' should be exclueded");
+ assert(strcmp(archive_entry_pathname(ae), "nd/f2") != 0);
+ if (strcmp(archive_entry_pathname(ae), "nd") == 0) {
+ assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
+ } else if (strcmp(archive_entry_pathname(ae), "nd/f1") == 0) {
+ assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
+ assertEqualInt(archive_entry_size(ae), 10);
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 10);
+ assertEqualInt((int)offset, 0);
+ assertEqualMem(p, "0123456789", 10);
+ assertEqualInt(ARCHIVE_EOF,
+ archive_read_data_block(a, &p, &size, &offset));
+ assertEqualInt((int)size, 0);
+ assertEqualInt((int)offset, 10);
+ } else if (strcmp(archive_entry_pathname(ae), "nd/fe") == 0) {
+ assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
+ assertEqualInt(archive_entry_size(ae), 0);
+ }
+ if (archive_read_disk_can_descend(a)) {
+ /* Descend into the current object */
+ assertEqualIntA(a, ARCHIVE_OK,
+ archive_read_disk_descend(a));
+ }
+ }
+ /* There is no entry. */
+ failure("There should be no entry");
+ assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
+
+ failure("Atime should be restored");
+ assertFileAtime("nd/f2", 886611, 0);
+
+ /* Destroy the disk object. */
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+ archive_entry_free(ae);
+}
DEFINE_TEST(test_read_disk_directory_traversals)
{
test_restore_atime();
/* Test callbacks. */
test_callbacks();
+ /* Test nodump. */
+ test_nodump();
}