/*-
* Copyright (c) 2003-2009 Tim Kientzle
- * Copyright (c) 2010 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#endif
static int setup_acls_posix1e(struct archive_read_disk *,
- struct archive_entry *, int fd);
+ struct archive_entry *, int *fd);
static int setup_mac_metadata(struct archive_read_disk *,
- struct archive_entry *, int fd);
+ struct archive_entry *, int *fd);
static int setup_xattrs(struct archive_read_disk *,
- struct archive_entry *, int fd);
+ struct archive_entry *, int *fd);
static int setup_sparse(struct archive_read_disk *,
- struct archive_entry *, int fd);
+ struct archive_entry *, int *fd);
int
archive_read_disk_entry_from_file(struct archive *_a,
* this is an extra step, it has a nice side-effect: We get an
* open file descriptor which we can use in the subsequent lookups. */
if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
- if (fd < 0)
- fd = open(path, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ if (a->tree != NULL)
+ fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK);
+ else
+ fd = open(path, O_RDONLY | O_NONBLOCK);
+ }
if (fd >= 0) {
unsigned long stflags;
r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
"Couldn't read link data");
return (ARCHIVE_FAILED);
}
+ if (a->tree != NULL) {
#ifdef HAVE_READLINKAT
- if (a->entry_wd_fd >= 0)
- lnklen = readlinkat(a->entry_wd_fd, path,
- linkbuffer, linkbuffer_len);
- else
+ lnklen = readlinkat(a->tree_current_dir_fd(a->tree),
+ path, linkbuffer, linkbuffer_len);
+#else
+ if (a->tree_enter_working_dir(a->tree) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't read link data");
+ free(linkbuffer);
+ return (ARCHIVE_FAILED);
+ }
+ lnklen = readlink(path, linkbuffer, linkbuffer_len);
#endif /* HAVE_READLINKAT */
- lnklen = readlink(path, linkbuffer, linkbuffer_len);
+ } else
+ lnklen = readlink(path, linkbuffer, linkbuffer_len);
if (lnklen < 0) {
archive_set_error(&a->archive, errno,
"Couldn't read link data");
}
#endif /* HAVE_READLINK || HAVE_READLINKAT */
- r = setup_acls_posix1e(a, entry, fd);
- r1 = setup_xattrs(a, entry, fd);
+ r = setup_acls_posix1e(a, entry, &fd);
+ r1 = setup_xattrs(a, entry, &fd);
if (r1 < r)
r = r1;
if (a->enable_copyfile) {
- r1 = setup_mac_metadata(a, entry, fd);
+ r1 = setup_mac_metadata(a, entry, &fd);
if (r1 < r)
r = r1;
}
- r1 = setup_sparse(a, entry, fd);
+ r1 = setup_sparse(a, entry, &fd);
if (r1 < r)
r = r1;
*/
static int
setup_mac_metadata(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
int tempfd = -1;
int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
int have_attrs;
const char *name, *tempdir, *tempfile = NULL;
+ (void)fd; /* UNUSED */
name = archive_entry_sourcepath(entry);
if (name == NULL)
name = archive_entry_pathname(entry);
return (ARCHIVE_WARN);
}
+ if (a->tree != NULL) {
+ if (a->tree_enter_working_dir(a->tree) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't change dir");
+ return (ARCHIVE_FAILED);
+ }
+ }
+
/* Short-circuit if there's nothing to do. */
have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
if (have_attrs == -1) {
*/
static int
setup_mac_metadata(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
static int
setup_acls_posix1e(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
const char *accpath;
acl_t acl;
archive_entry_acl_clear(entry);
+ if (*fd < 0 && a->tree != NULL &&
+ (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)){
+ *fd = a->open_on_current_dir(a->tree, accpath,
+ O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't access %s", accpath);
+ return (ARCHIVE_FAILED);
+ }
+ }
+
/* Retrieve access ACL from file. */
- if (fd >= 0)
- acl = acl_get_fd(fd);
+ if (*fd >= 0)
+ acl = acl_get_fd(*fd);
#if HAVE_ACL_GET_LINK_NP
else if (!a->follow_symlinks)
acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
#else
static int
setup_acls_posix1e(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
static int
setup_xattrs(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
char *list, *p;
const char *path;
if (path == NULL)
path = archive_entry_pathname(entry);
+ if (*fd < 0 && a->tree != NULL) {
+ if (a->follow_symlinks ||
+ archive_entry_filetype(entry) != AE_IFLNK)
+ *fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
+ if (a->tree_enter_working_dir(a->tree) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't access %s", path);
+ return (ARCHIVE_FAILED);
+ }
+ }
+ }
+
#if HAVE_FLISTXATTR
- if (fd >= 0)
- list_size = flistxattr(fd, NULL, 0);
+ if (*fd >= 0)
+ list_size = flistxattr(*fd, NULL, 0);
else if (!a->follow_symlinks)
list_size = llistxattr(path, NULL, 0);
else
list_size = listxattr(path, NULL, 0);
#elif HAVE_FLISTEA
- if (fd >= 0)
- list_size = flistea(fd, NULL, 0);
+ if (*fd >= 0)
+ list_size = flistea(*fd, NULL, 0);
else if (!a->follow_symlinks)
list_size = llistea(path, NULL, 0);
else
}
#if HAVE_FLISTXATTR
- if (fd >= 0)
- list_size = flistxattr(fd, list, list_size);
+ if (*fd >= 0)
+ list_size = flistxattr(*fd, list, list_size);
else if (!a->follow_symlinks)
list_size = llistxattr(path, list, list_size);
else
list_size = listxattr(path, list, list_size);
#elif HAVE_FLISTEA
- if (fd >= 0)
- list_size = flistea(fd, list, list_size);
+ if (*fd >= 0)
+ list_size = flistea(*fd, list, list_size);
else if (!a->follow_symlinks)
list_size = llistea(path, list, list_size);
else
if (strncmp(p, "system.", 7) == 0 ||
strncmp(p, "xfsroot.", 8) == 0)
continue;
- setup_xattr(a, entry, p, fd);
+ setup_xattr(a, entry, p, *fd);
}
free(list);
static int
setup_xattrs(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
char buff[512];
char *list, *p;
if (path == NULL)
path = archive_entry_pathname(entry);
- if (fd >= 0)
- list_size = extattr_list_fd(fd, namespace, NULL, 0);
+ if (*fd < 0 && a->tree != NULL) {
+ if (a->follow_symlinks ||
+ archive_entry_filetype(entry) != AE_IFLNK)
+ *fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
+ if (a->tree_enter_working_dir(a->tree) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't access %s", path);
+ return (ARCHIVE_FAILED);
+ }
+ }
+ }
+
+ if (*fd >= 0)
+ list_size = extattr_list_fd(*fd, namespace, NULL, 0);
else if (!a->follow_symlinks)
list_size = extattr_list_link(path, namespace, NULL, 0);
else
return (ARCHIVE_FATAL);
}
- if (fd >= 0)
- list_size = extattr_list_fd(fd, namespace, list, list_size);
+ if (*fd >= 0)
+ list_size = extattr_list_fd(*fd, namespace, list, list_size);
else if (!a->follow_symlinks)
list_size = extattr_list_link(path, namespace, list, list_size);
else
name = buff + strlen(buff);
memcpy(name, p + 1, len);
name[len] = '\0';
- setup_xattr(a, entry, namespace, name, buff, fd);
+ setup_xattr(a, entry, namespace, name, buff, *fd);
p += 1 + len;
}
*/
static int
setup_xattrs(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
static int
setup_sparse(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
char buff[4096];
struct fiemap *fm;
struct fiemap_extent *fe;
int64_t size;
int count, do_fiemap;
- int initial_fd = fd;
int exit_sts = ARCHIVE_OK;
if (archive_entry_filetype(entry) != AE_IFREG
|| archive_entry_hardlink(entry) != NULL)
return (ARCHIVE_OK);
- if (fd < 0) {
+ if (*fd < 0) {
const char *path;
path = archive_entry_sourcepath(entry);
if (path == NULL)
path = archive_entry_pathname(entry);
- fd = open(path, O_RDONLY | O_NONBLOCK);
- if (fd < 0) {
+ if (a->tree != NULL) {
+ *fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK);
+ else
+ *fd = open(path, O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
archive_set_error(&a->archive, errno,
"Can't open `%s'", path);
return (ARCHIVE_FAILED);
for (;;) {
int i, r;
- r = ioctl(fd, FS_IOC_FIEMAP, fm);
+ r = ioctl(*fd, FS_IOC_FIEMAP, fm);
if (r < 0) {
/* When something error happens, it is better we
* should return ARCHIVE_OK because an earlier
break;
}
exit_setup_sparse:
- if (initial_fd != fd)
- close(fd);
return (exit_sts);
}
static int
setup_sparse(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
int64_t size;
- int initial_fd = fd;
off_t initial_off; /* FreeBSD/Solaris only, so off_t okay here */
off_t off_s, off_e; /* FreeBSD/Solaris only, so off_t okay here */
int exit_sts = ARCHIVE_OK;
return (ARCHIVE_OK);
/* Does filesystem support the reporting of hole ? */
- if (fd >= 0) {
- if (fpathconf(fd, _PC_MIN_HOLE_SIZE) <= 0)
+ if (*fd < 0 && a->tree != NULL) {
+ const char *path;
+
+ path = archive_entry_sourcepath(entry);
+ if (path == NULL)
+ path = archive_entry_pathname(entry);
+ *fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
+ archive_set_error(&a->archive, errno,
+ "Can't open `%s'", path);
+ return (ARCHIVE_FAILED);
+ }
+ }
+
+ if (*fd >= 0) {
+ if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)
return (ARCHIVE_OK);
- initial_off = lseek(fd, 0, SEEK_CUR);
+ initial_off = lseek(*fd, 0, SEEK_CUR);
if (initial_off != 0)
- lseek(fd, 0, SEEK_SET);
+ lseek(*fd, 0, SEEK_SET);
} else {
const char *path;
+ if (a->tree != NULL) {
+ if (a->tree_enter_working_dir(a->tree) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't change dir");
+ return (ARCHIVE_FAILED);
+ }
+ }
path = archive_entry_sourcepath(entry);
if (path == NULL)
path = archive_entry_pathname(entry);
+
if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
return (ARCHIVE_OK);
- fd = open(path, O_RDONLY | O_NONBLOCK);
- if (fd < 0) {
+ *fd = open(path, O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
archive_set_error(&a->archive, errno,
"Can't open `%s'", path);
return (ARCHIVE_FAILED);
off_s = 0;
size = archive_entry_size(entry);
while (off_s < size) {
- off_s = lseek(fd, off_s, SEEK_DATA);
+ off_s = lseek(*fd, off_s, SEEK_DATA);
if (off_s == (off_t)-1) {
if (errno == ENXIO)
break;/* no more hole */
exit_sts = ARCHIVE_FAILED;
goto exit_setup_sparse;
}
- off_e = lseek(fd, off_s, SEEK_HOLE);
+ off_e = lseek(*fd, off_s, SEEK_HOLE);
if (off_s == (off_t)-1) {
if (errno == ENXIO) {
- off_e = lseek(fd, 0, SEEK_END);
+ off_e = lseek(*fd, 0, SEEK_END);
if (off_e != (off_t)-1)
break;/* no more data */
}
off_s = off_e;
}
exit_setup_sparse:
- if (initial_fd != fd)
- close(fd);
- else
- lseek(fd, initial_off, SEEK_SET);
+ lseek(*fd, initial_off, SEEK_SET);
return (exit_sts);
}
*/
static int
setup_sparse(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
#define onWorkingDir 64 /* We are on the working dir where we are
* reading directory entry at this time. */
#define needsRestoreTimes 128
+#define onInitialDir 256 /* We are on the initial dir. */
static int
tree_dir_next_posix(struct tree *t);
static int setup_sparse(struct archive_read_disk *, struct archive_entry *);
static int close_and_restore_time(int fd, struct tree *,
struct restore_time *);
+static int open_on_current_dir(struct tree *, const char *, int);
static struct archive_vtable *
a->lookup_gname = trivial_lookup_gname;
a->enable_copyfile = 1;
a->traverse_mount_points = 1;
- a->entry_wd_fd = -1;
+ a->open_on_current_dir = open_on_current_dir;
+ a->tree_current_dir_fd = tree_current_dir_fd;
+ a->tree_enter_working_dir = tree_enter_working_dir;
return (&a->archive);
}
flags |= O_NOATIME;
do {
#endif
-#ifdef HAVE_OPENAT
- t->entry_fd = openat(tree_current_dir_fd(t),
+ t->entry_fd = open_on_current_dir(t,
tree_current_access_path(t), flags);
-#else
- tree_enter_working_dir(t);
- t->entry_fd = open(tree_current_access_path(t), flags);
-#endif
#if defined(O_NOATIME)
/*
* When we did open the file with O_NOATIME flag,
close_and_restore_time(t->entry_fd, t, &t->restore_time);
t->entry_fd = -1;
}
-#if !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR))
- /* Restore working directory. */
- tree_enter_working_dir(t);
-#endif
next_entry:
st = NULL;
if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) {
unsigned long stflags;
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
- fd = openat(tree_current_dir_fd(t),
+ fd = open_on_current_dir(t,
tree_current_access_path(t), O_RDONLY | O_NONBLOCK);
-#else
- tree_enter_working_dir(t);
- fd = open(tree_current_access_path(t),
- O_RDONLY | O_NONBLOCK);
-
-#endif
if (fd >= 0) {
r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0) {
}
}
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
- /*
- * Open the current file to freely gather its metadata anywhere in
- * working directory.
- * Note: A symbolic link file cannot be opened with O_NOFOLLOW.
- */
- if (fd < 0 && archive_entry_filetype(entry) != AE_IFLNK)
- fd = openat(tree_current_dir_fd(t), tree_current_access_path(t),
- O_RDONLY | O_NONBLOCK);
- /* Restore working directory if openat() operation failed or
- * the file is a symbolic link. */
- if (fd < 0)
- tree_enter_working_dir(t);
-
- /* The current direcotry fd is needed at
- * archive_read_disk_entry_from_file() function to read link data
- * with readlinkat(). */
- a->entry_wd_fd = tree_current_dir_fd(t);
-#endif
-
/*
* Populate the archive_entry with metadata from the disk.
*/
t->current_filesystem->synthetic = -1;
t->current_filesystem->remote = -1;
if (tree_current_is_symblic_link_target(t)) {
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+#if defined(HAVE_OPENAT)
/*
* Get file system statistics on any directory
* where current is.
xr = get_xfer_size(t, fd, NULL);
close(fd);
#else
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
r = statfs(tree_current_access_path(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, -1, tree_current_access_path(t));
int r, vr = 0, xr = 0;
if (tree_current_is_symblic_link_target(t)) {
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+#if defined(HAVE_OPENAT)
/*
* Get file system statistics on any directory
* where current is.
xr = get_xfer_size(t, fd, NULL);
close(fd);
#else
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
vr = statvfs(tree_current_access_path(t), &svfs);
r = statfs(tree_current_access_path(t), &sfs);
if (r == 0)
r = fstatfs(tree_current_dir_fd(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
-#elif defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
-#error "Unexpected case. Please tell us about this error."
#else
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
vr = statvfs(".", &svfs);
r = statfs(".", &sfs);
if (r == 0)
t->current_filesystem->synthetic = -1;/* Not supported */
t->current_filesystem->remote = -1;/* Not supported */
if (tree_current_is_symblic_link_target(t)) {
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+#if defined(HAVE_OPENAT)
/*
* Get file system statistics on any directory
* where current is.
xr = get_xfer_size(t, fd, NULL);
close(fd);
#else
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
r = statvfs(tree_current_access_path(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, -1, tree_current_access_path(t));
r = fstatvfs(tree_current_dir_fd(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
-#elif defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
-#error "Unexpected case. Please tell us about this error."
#else
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
r = statvfs(".", &sfs);
if (r == 0)
xr = get_xfer_size(t, -1, ".");
return (0);
}
+static int
+open_on_current_dir(struct tree *t, const char *path, int flags)
+{
+#ifdef HAVE_OPENAT
+ return (openat(tree_current_dir_fd(t), path, flags));
+#else
+ if (tree_enter_working_dir(t) != 0)
+ return (-1);
+ return (open(path, flags));
+#endif
+}
+
/*
* Add a directory path to the current stack.
*/
tree_reopen(struct tree *t, const char *path, int restore_time)
{
t->flags = (restore_time)?needsRestoreTimes:0;
+ t->flags |= onInitialDir;
t->visit_type = 0;
t->tree_errno = 0;
t->dirname_length = 0;
#if defined(O_DIRECTORY)
flag |= O_DIRECTORY;
#endif
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
- new_fd = openat(t->working_dir_fd, t->stack->name.s, flag);
-#else
- new_fd = open(t->stack->name.s, flag);
- if (new_fd >= 0) {
- if (fchdir(new_fd) != 0) {
- close(new_fd);
- new_fd = -1;
- }
- }
-#endif
+ new_fd = open_on_current_dir(t, t->stack->name.s, flag);
if (new_fd < 0) {
t->tree_errno = errno;
r = TREE_ERROR_DIR;
t->maxOpenCount = t->openCount;
} else
close(t->working_dir_fd);
+ /* Renew the current working directory. */
t->working_dir_fd = new_fd;
+ t->flags &= ~onWorkingDir;
}
return (r);
}
te = t->stack;
prev_dir_fd = t->working_dir_fd;
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
if (te->flags & isDirLink)
new_fd = te->symlink_parent_fd;
else
- new_fd = openat(t->working_dir_fd, "..", O_RDONLY);
-#else
- if (te->flags & isDirLink)
- new_fd = te->symlink_parent_fd;
- else
- new_fd = open("..", O_RDONLY);
- if (new_fd >= 0) {
- if (fchdir(new_fd) != 0) {
- if ((te->flags & isDirLink) == 0)
- close(new_fd);
- new_fd = -1;
- }
- }
-#endif
+ new_fd = open_on_current_dir(t, "..", O_RDONLY);
if (new_fd < 0) {
t->tree_errno = errno;
r = TREE_ERROR_FATAL;
} else {
+ /* Renew the current working directory. */
t->working_dir_fd = new_fd;
+ t->flags &= ~onWorkingDir;
/* Current directory has been changed, we should
* close an fd of previous working directory. */
close_and_restore_time(prev_dir_fd, t, &te->restore_time);
{
int r = 0;
- if (t->flags & onWorkingDir) {
+ if ((t->flags & onInitialDir) == 0) {
r = fchdir(t->initial_dir_fd);
- if (r == 0)
+ if (r == 0) {
t->flags &= ~onWorkingDir;
+ t->flags |= onInitialDir;
+ }
}
return (r);
}
*/
if (t->depth > 0 && (t->flags & onWorkingDir) == 0) {
r = fchdir(t->working_dir_fd);
- if (r == 0)
+ if (r == 0) {
+ t->flags &= ~onInitialDir;
t->flags |= onWorkingDir;
+ }
}
return (r);
}
#if defined(HAVE_FDOPENDIR)
if ((t->d = fdopendir(dup(t->working_dir_fd))) == NULL) {
#else
- if ((t->d = opendir(".")) == NULL) {
+ if (tree_enter_working_dir(t) != 0 ||
+ (t->d = opendir(".")) == NULL) {
#endif
r = tree_ascend(t); /* Undo "chdir" */
tree_pop(t);
if (fstatat(tree_current_dir_fd(t),
tree_current_access_path(t), &t->st, 0) != 0)
#else
+ if (tree_enter_working_dir(t) != 0)
+ return NULL;
if (stat(tree_current_access_path(t), &t->st) != 0)
#endif
return NULL;
tree_current_access_path(t), &t->lst,
AT_SYMLINK_NOFOLLOW) != 0)
#else
+ if (tree_enter_working_dir(t) != 0)
+ return NULL;
if (lstat(tree_current_access_path(t), &t->lst) != 0)
#endif
return NULL;
*/
if (t->flags & hasLstat) {
/* If lstat() says it's a dir, it must be a dir. */
- if (S_ISDIR(tree_current_lstat(t)->st_mode))
+ st = tree_current_lstat(t);
+ if (st == NULL)
+ return 0;
+ if (S_ISDIR(st->st_mode))
return 1;
/* Not a dir; might be a link to a dir. */
/* If it's not a link, then it's not a link to a dir. */
* If stat() says it isn't a dir, then it's not a dir.
* If stat() data is cached, this check is free, so do it first.
*/
- if ((t->flags & hasStat)
- && (!S_ISDIR(tree_current_stat(t)->st_mode)))
- return 0;
+ if (t->flags & hasStat) {
+ st = tree_current_stat(t);
+ if (st == NULL)
+ return (0);
+ if (!S_ISDIR(st->st_mode))
+ return (0);
+ }
/*
* Either stat() said it was a dir (in which case, we have
lst = tree_current_lstat(t);
st = tree_current_stat(t);
- return (st != NULL &&
+ return (st != NULL && lst != NULL &&
(int64_t)st->st_dev == t->current_filesystem->dev &&
st->st_dev != lst->st_dev);
}