void bufferAccessOutOfBounds(int fd) { char a[5]; read(fd,a,5); // cppcheck-suppress bufferAccessOutOfBounds read(fd,a,6); write(fd,a,5); // cppcheck-suppress bufferAccessOutOfBounds write(fd,a,6); recv(fd,a,5,0); // cppcheck-suppress bufferAccessOutOfBounds recv(fd,a,6,0); recvfrom(fd,a,5,0,0x0,0x0); // cppcheck-suppress bufferAccessOutOfBounds recvfrom(fd,a,6,0,0x0,0x0); send(fd,a,5,0); // cppcheck-suppress bufferAccessOutOfBounds send(fd,a,6,0); sendto(fd,a,5,0,0x0,0x0); // cppcheck-suppress bufferAccessOutOfBounds sendto(fd,a,6,0,0x0,0x0); // cppcheck-suppress constStatement 0; readlink("path", a, 5); // cppcheck-suppress bufferAccessOutOfBounds readlink("path", a, 6); readlinkat(1, "path", a, 5); // cppcheck-suppress bufferAccessOutOfBounds readlinkat(1, "path", a, 6); // This is valid gethostname(a, 5); // cppcheck-suppress bufferAccessOutOfBounds gethostname(a, 6); }
int main (void) { char buf[80]; int result; /* Remove any leftovers from a previous partial run. */ ignore_value (system ("rm -rf " BASE "*")); /* Perform same checks as counterpart functions. */ result = test_readlink (do_readlink, false); ASSERT (test_symlink (do_symlink, false) == result); dfd = openat (AT_FDCWD, ".", O_RDONLY); ASSERT (0 <= dfd); ASSERT (test_readlink (do_readlink, false) == result); ASSERT (test_symlink (do_symlink, false) == result); /* Now perform some cross-directory checks. Skip everything else on mingw. */ if (HAVE_SYMLINK) { const char *contents = "don't matter!"; ssize_t exp = strlen (contents); /* Create link while cwd is '.', then read it in '..'. */ ASSERT (symlinkat (contents, AT_FDCWD, BASE "link") == 0); errno = 0; ASSERT (symlinkat (contents, dfd, BASE "link") == -1); ASSERT (errno == EEXIST); ASSERT (chdir ("..") == 0); errno = 0; ASSERT (readlinkat (AT_FDCWD, BASE "link", buf, sizeof buf) == -1); ASSERT (errno == ENOENT); ASSERT (readlinkat (dfd, BASE "link", buf, sizeof buf) == exp); ASSERT (strncmp (contents, buf, exp) == 0); ASSERT (unlinkat (dfd, BASE "link", 0) == 0); /* Create link while cwd is '..', then read it in '.'. */ ASSERT (symlinkat (contents, dfd, BASE "link") == 0); ASSERT (fchdir (dfd) == 0); errno = 0; ASSERT (symlinkat (contents, AT_FDCWD, BASE "link") == -1); ASSERT (errno == EEXIST); buf[0] = '\0'; ASSERT (readlinkat (AT_FDCWD, BASE "link", buf, sizeof buf) == exp); ASSERT (strncmp (contents, buf, exp) == 0); buf[0] = '\0'; ASSERT (readlinkat (dfd, BASE "link", buf, sizeof buf) == exp); ASSERT (strncmp (contents, buf, exp) == 0); ASSERT (unlink (BASE "link") == 0); } ASSERT (close (dfd) == 0); if (result == 77) fputs ("skipping test: symlinks not supported on this file system\n", stderr); return result; }
void sc_reassociate_with_pid1_mount_ns(void) { int init_mnt_fd SC_CLEANUP(sc_cleanup_close) = -1; int self_mnt_fd SC_CLEANUP(sc_cleanup_close) = -1; debug("checking if the current process shares mount namespace" " with the init process"); init_mnt_fd = open("/proc/1/ns/mnt", O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_PATH); if (init_mnt_fd < 0) { die("cannot open mount namespace of the init process (O_PATH)"); } self_mnt_fd = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_PATH); if (self_mnt_fd < 0) { die("cannot open mount namespace of the current process (O_PATH)"); } char init_buf[128] = { 0 }; char self_buf[128] = { 0 }; memset(init_buf, 0, sizeof init_buf); if (readlinkat(init_mnt_fd, "", init_buf, sizeof init_buf) < 0) { if (errno == ENOENT) { // According to namespaces(7) on a pre 3.8 kernel the namespace // files are hardlinks, not sylinks. If that happens readlinkat // fails with ENOENT. As a quick workaround for this special-case // functionality, just bail out and do nothing without raising an // error. return; } die("cannot perform readlinkat() on the mount namespace file " "descriptor of the init process"); } memset(self_buf, 0, sizeof self_buf); if (readlinkat(self_mnt_fd, "", self_buf, sizeof self_buf) < 0) { die("cannot perform readlinkat() on the mount namespace file " "descriptor of the current process"); } if (memcmp(init_buf, self_buf, sizeof init_buf) != 0) { debug("the current process does not share mount namespace with " "the init process, re-association required"); // NOTE: we cannot use O_NOFOLLOW here because that file will always be a // symbolic link. We actually want to open it this way. int init_mnt_fd_real SC_CLEANUP(sc_cleanup_close) = -1; init_mnt_fd_real = open("/proc/1/ns/mnt", O_RDONLY | O_CLOEXEC); if (init_mnt_fd_real < 0) { die("cannot open mount namespace of the init process"); } if (setns(init_mnt_fd_real, CLONE_NEWNS) < 0) { die("cannot re-associate the mount namespace with the init process"); } } else { debug("re-associating is not required"); } }
char *readlinkat_malloc (int dirfd, const char *filename) { int size = 100; int nchars; char *buffer = NULL; char *tmp; while (1) { tmp = (char *) realloc (buffer, size); if (tmp == NULL) { free(buffer); /* if failed, dealloc is not performed */ return NULL; } buffer = tmp; nchars = readlinkat (dirfd, filename, buffer, size); if (nchars < 0) { free (buffer); return NULL; } if (nchars < size) { buffer[nchars] = '\0'; return buffer; } size *= 2; } }
/* * For debugging: show open file descriptors */ void list_fd(const pid_t pid) { struct dirent *dr; char *fds; DIR *dir; int ret; ret = asprintf(&fds, "/proc/%lu/fd", (unsigned long)pid); if (ret < 0) error("can not allocate string for /proc/%lu/fd", (unsigned long)pid); dir = opendir(fds); if (!dir) { warn("can not open %s", fds); return; } free(fds); while ((dr = readdir(dir))) { char tmp[LINE_MAX+1]; ssize_t len; if (dr->d_name[0] == '.') continue; len = readlinkat(dirfd(dir), dr->d_name, &tmp[0], LINE_MAX); tmp[len] = '\0'; fprintf(stderr, "/proc/%d/fd/%s %s\n", (int)pid, dr->d_name, tmp); } closedir(dir); }
/* * record_open_files -- make a list of open files (used at START() time) */ static void record_open_files() { int dirfd; DIR *dirp = NULL; struct dirent *dp; if ((dirfd = open("/proc/self/fd", O_RDONLY)) < 0 || (dirp = fdopendir(dirfd)) == NULL) FATAL("!/proc/self/fd"); while ((dp = readdir(dirp)) != NULL) { int fdnum; char fdfile[PATH_MAX]; ssize_t cc; if (*dp->d_name == '.') continue; if ((cc = readlinkat(dirfd, dp->d_name, fdfile, PATH_MAX)) < 0) FATAL("!readlinkat: /proc/self/fd/%s", dp->d_name); fdfile[cc] = '\0'; fdnum = atoi(dp->d_name); if (dirfd == fdnum) continue; Fd_lut = open_file_add(Fd_lut, fdnum, fdfile); } closedir(dirp); }
// Parse a symlink in /proc/pid/fd/$x and return the inode number of the // socket. // inode_out: (output) set to the inode number on success // path: e.g. /proc/1234/fd/5 (must be a UNIX domain socket descriptor) static bool ProcPathGetInodeAt(ino_t* inode_out, int base_dir_fd, const char* path) { // We also check that the path is relative. if (!inode_out || !path || *path == '/') return false; char buf[256]; const ssize_t n = readlinkat(base_dir_fd, path, buf, sizeof(buf) - 1); if (n < 0) return false; buf[n] = 0; if (memcmp(kSocketLinkPrefix, buf, sizeof(kSocketLinkPrefix) - 1)) return false; char* endptr = NULL; errno = 0; const unsigned long long int inode_ull = strtoull(buf + sizeof(kSocketLinkPrefix) - 1, &endptr, 10); if (inode_ull == ULLONG_MAX || !endptr || *endptr != ']' || errno != 0) return false; *inode_out = inode_ull; return true; }
/* * check_open_files -- verify open files match recorded open files */ static void check_open_files() { int dirfd; DIR *dirp = NULL; struct dirent *dp; if ((dirfd = open("/proc/self/fd", O_RDONLY)) < 0 || (dirp = fdopendir(dirfd)) == NULL) FATAL("!/proc/self/fd"); while ((dp = readdir(dirp)) != NULL) { int fdnum; char fdfile[PATH_MAX]; ssize_t cc; if (*dp->d_name == '.') continue; if ((cc = readlinkat(dirfd, dp->d_name, fdfile, PATH_MAX)) < 0) FATAL("!readlinkat: /proc/self/fd/%s", dp->d_name); fdfile[cc] = '\0'; fdnum = atoi(dp->d_name); if (dirfd == fdnum) continue; open_file_remove(Fd_lut, fdnum, fdfile); } closedir(dirp); open_file_walk(Fd_lut); if (Fd_errcount) FATAL("open file list changed between START() and DONE()"); open_file_free(Fd_lut); }
ssize_t readlink(const char *path, char *buf, size_t bufsize) { int fd = -1; if (path[0] != VFS_SEPARATOR_CHAR) { fd = AT_FDCWD; } return readlinkat(fd, path, buf, bufsize); }
/** * -i?lname test. */ bool eval_lname(const struct expr *expr, struct eval_state *state) { struct BFTW *ftwbuf = state->ftwbuf; if (ftwbuf->typeflag != BFTW_LNK) { return false; } const struct stat *statbuf = fill_statbuf(state); if (!statbuf) { return false; } size_t size = statbuf->st_size + 1; char *name = malloc(size); if (!name) { eval_error(state); return false; } ssize_t ret = readlinkat(ftwbuf->at_fd, ftwbuf->at_path, name, size); if (ret < 0) { eval_error(state); return false; } else if (ret >= size) { return false; } name[ret] = '\0'; bool match = fnmatch(expr->sdata, name, expr->idata) == 0; free(name); return match; }
gboolean ot_readlinkat_gfile_info (int dfd, const char *path, GFileInfo *target_info, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; char targetbuf[PATH_MAX+1]; ssize_t len; do len = readlinkat (dfd, path, targetbuf, sizeof (targetbuf) - 1); while (G_UNLIKELY (len == -1 && errno == EINTR)); if (len == -1) { glnx_set_error_from_errno (error); goto out; } targetbuf[len] = '\0'; g_file_info_set_symlink_target (target_info, targetbuf); ret = TRUE; out: return ret; }
ATF_TC_BODY(readlinkat_failure, tc) { memset(buff, 0, sizeof(buff)); FILE *pipefd = setup(fds, "fr"); /* Failure reason: symbolic link does not exist */ ATF_REQUIRE_EQ(-1, readlinkat(AT_FDCWD, path, buff, sizeof(buff)-1)); check_audit(fds, failurereg, pipefd); }
ATF_TC_BODY(readlinkat_success, tc) { memset(buff, 0, sizeof(buff)); ATF_REQUIRE_EQ(0, symlink("symlink", path)); FILE *pipefd = setup(fds, "fr"); ATF_REQUIRE(readlinkat(AT_FDCWD, path, buff, sizeof(buff)-1) != -1); check_audit(fds, successreg, pipefd); }
/* move any old watches directory out of the way, and then restore * the watches */ void udev_watch_restore(struct udev *udev) { char filename[UTIL_PATH_SIZE], oldname[UTIL_PATH_SIZE]; if (inotify_fd < 0) return; util_strscpyl(oldname, sizeof(oldname), udev_get_dev_path(udev), "/.udev/watch.old", NULL); util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/watch", NULL); if (rename(filename, oldname) == 0) { DIR *dir; struct dirent *ent; dir = opendir(oldname); if (dir == NULL) { err(udev, "unable to open old watches dir '%s', old watches will not be restored: %m", oldname); return; } for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) { char device[UTIL_PATH_SIZE]; char *s; size_t l; ssize_t len; struct udev_device *dev; int maj, min; char type; if (ent->d_name[0] == '.') continue; s = device; l = util_strpcpy(&s, sizeof(device), udev_get_sys_path(udev)); len = readlinkat(dirfd(dir), ent->d_name, s, l); if (len <= 0 || len == (ssize_t)l) goto unlink; s[len] = '\0'; if (sscanf(s, "%c%i:%i", &type, &maj, &min) != 3) goto unlink; dev = udev_device_new_from_devnum(udev, type, makedev(maj, min)); if (dev == NULL) goto unlink; info(udev, "restoring old watch on '%s'\n", udev_device_get_devnode(dev)); udev_watch_begin(udev, dev); udev_device_unref(dev); unlink: unlinkat(dirfd(dir), ent->d_name, 0); } closedir(dir); rmdir(oldname); } else if (errno != ENOENT) { err(udev, "unable to move watches dir '%s', old watches will not be restored: %m", filename); } }
ssize_t __readlinkat_chk (int fd, const char *path, void *buf, size_t len, size_t buflen) { if (len > buflen) __chk_fail (); return readlinkat (fd, path, buf, len); }
ATF_TC_BODY(readlinkat_fderr1, tc) { int dfd; ATF_REQUIRE(mkdir(DIR, 0755) == 0); ATF_REQUIRE((dfd = open(DIR, O_RDONLY, 0)) != -1); ATF_REQUIRE(readlinkat(dfd, FILEERR, F_OK, 0) == -1); ATF_REQUIRE(close(dfd) == 0); }
int main(int argc, char *argv[]) { char linkname[NCHAR + 1] = { 0 }; ssize_t r; r = (argc < 2) ? -1 : readlinkat(1, argv[1], linkname, NCHAR); return (r > 0) ? EXIT_SUCCESS : EXIT_FAILURE; }
char * areadlinkat_with_size (int fd, char const *file, size_t size) { /* Some buggy file systems report garbage in st_size. Defend against them by ignoring outlandish st_size values in the initial memory allocation. */ size_t symlink_max = SYMLINK_MAX; size_t INITIAL_LIMIT_BOUND = 8 * 1024; size_t initial_limit = (symlink_max < INITIAL_LIMIT_BOUND ? symlink_max + 1 : INITIAL_LIMIT_BOUND); /* The initial buffer size for the link value. */ size_t buf_size = size < initial_limit ? size + 1 : initial_limit; while (1) { ssize_t r; size_t link_length; char *buffer = malloc (buf_size); if (buffer == NULL) return NULL; r = readlinkat (fd, file, buffer, buf_size); link_length = r; /* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1 with errno == ERANGE if the buffer is too small. */ if (r < 0 && errno != ERANGE) { int saved_errno = errno; free (buffer); errno = saved_errno; return NULL; } if (link_length < buf_size) { buffer[link_length] = 0; return buffer; } free (buffer); if (buf_size <= MAXSIZE / 2) buf_size *= 2; else if (buf_size < MAXSIZE) buf_size = MAXSIZE; else { errno = ENOMEM; return NULL; } } }
ssize_t ast_readlinkat(int cwd, const char* path, char* buf, size_t size) { ssize_t r = -1; PATHIFY(cwd, path, 1, 1); RESTART(r, readlinkat(cwd, path, buf, size)); PATHEND(); return r; }
ATF_TC_BODY(readlinkat_fderr2, tc) { int fd; char buf[MAXPATHLEN]; ATF_REQUIRE(mkdir(DIR, 0755) == 0); ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1); ATF_REQUIRE(close(fd) == 0); ATF_REQUIRE(symlink(FILE, LINK) == 0); ATF_REQUIRE(readlinkat(-1, LINK, buf, sizeof(buf)) == -1); }
static int copyat(int olddirfd, const char* oldpath, int newdirfd, const char* newpath) { int err; int oldfd = openat(olddirfd, oldpath, O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NOATIME); if (oldfd == -1 && errno == EPERM) { oldfd = openat(olddirfd, oldpath, O_RDONLY | O_CLOEXEC | O_NOFOLLOW); } if (oldfd == -1 && errno == ELOOP) { char oldtarget[PATH_MAX]; ssize_t oldlen = readlinkat(olddirfd, oldpath, oldtarget, sizeof(oldtarget)); if (oldlen == -1) { return -1; } oldtarget[oldlen] = '\0'; return symlinkat(oldtarget, newdirfd, newpath); } if (oldfd == -1) { return -1; } struct stat oldstat; if (fstat(oldfd, &oldstat) == -1) { err = errno; close(oldfd); errno = err; return -1; } int newfd = openat(newdirfd, newpath, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC | O_NOATIME, oldstat.st_mode); if (newfd == -1 && errno == EPERM) { newfd = openat(newdirfd, newpath, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC, oldstat.st_mode); } if (newfd == -1) { err = errno; close(oldfd); errno = err; return -1; } if (fchown(newfd, oldstat.st_uid, oldstat.st_gid) == -1) { // ignore error } if (copyfile_sparse(oldfd, newfd) == -1) { err = errno; close(newfd); close(oldfd); errno = err; return -1; } close(newfd); close(oldfd); struct timespec times[2]; times[0] = oldstat.st_atim; times[1] = oldstat.st_mtim; utimensat(newdirfd, newpath, times, 0); // ignore error return 0; }
CAMLprim value netsys_readlinkat(value dirfd, value path) { #ifdef HAVE_AT char buffer[PATH_MAX]; int len; len = readlinkat(Int_val(dirfd), String_val(path), buffer, sizeof(buffer)-1); if (len == -1) uerror("readlinkat", path); buffer[len] = '\0'; return copy_string(buffer); #else invalid_argument("Netsys_posix.readlinkat not available"); #endif }
int main() { struct stat st; struct stat st2; openat(AT_FDCWD, PWD "openat.txt", O_CREAT | O_WRONLY, 0644); assert(stat("openat.txt", &st) == 0); // relative path assert(faccessat(AT_FDCWD, PWD "openat.txt", F_OK, 0) == 0); assert(fstatat(AT_FDCWD, PWD "openat.txt", &st2, 0) == 0); assert(fchmodat(AT_FDCWD, PWD "openat.txt", 0777, 0) == 0); struct timeval my_times[2]; my_times[0].tv_sec = 0; my_times[0].tv_usec = 0; my_times[1].tv_sec = 0; my_times[1].tv_usec = 0; assert(futimesat(AT_FDCWD, PWD "openat.txt", my_times, 0) == 0); // see /etc/passwd, user 'pgbovine' is 508:100 assert(fchownat(AT_FDCWD, PWD "openat.txt", 508, 100, 0) == 0); assert(linkat(AT_FDCWD, PWD "openat.txt", AT_FDCWD, PWD "openat_hardlink.txt", 0) == 0); assert(stat("openat_hardlink.txt", &st) == 0); // relative path assert(symlinkat(PWD "openat.txt", AT_FDCWD, PWD "openat_symlink.txt") == 0); assert(lstat("openat_symlink.txt", &st) == 0); // relative path char res[300]; assert(readlinkat(AT_FDCWD, PWD "openat_symlink.txt", res, sizeof(res)) > 0); assert(renameat(AT_FDCWD, PWD "openat.txt", AT_FDCWD, PWD "openat_newname.txt", 0) == 0); assert(stat("openat.txt", &st) != 0); // should not exist anymore assert(stat("openat_newname.txt", &st) == 0); // relative path unlinkat(AT_FDCWD, PWD "openat_newname.txt", 0); unlinkat(AT_FDCWD, PWD "openat_hardlink.txt", 0); unlinkat(AT_FDCWD, PWD "openat_symlink.txt", 0); mknodat(AT_FDCWD, PWD "mknodat.fifo", S_IFIFO); assert(stat("mknodat.fifo", &st) == 0); // relative path unlinkat(AT_FDCWD, PWD "mknodat.fifo", 0); mkdirat(AT_FDCWD, PWD "mkdirat_dir", 0); assert(stat("mkdirat_dir", &st) == 0); // relative path unlinkat(AT_FDCWD, PWD "mkdirat_dir", AT_REMOVEDIR); // like 'rmdir' return 0; }
int pkg_symlink_cksumat(int fd, const char *path, const char *root, char *cksum) { char linkbuf[MAXPATHLEN]; int linklen; if ((linklen = readlinkat(fd, path, linkbuf, sizeof(linkbuf) - 1)) == -1) { pkg_emit_errno("pkg_symlink_cksum", "readlink failed"); return (EPKG_FATAL); } linkbuf[linklen] = '\0'; return (pkg_symlink_cksum_readlink(linkbuf, linklen, root, cksum)); }
static int callback_readlink (const char *path, char *buf, size_t size) { int r; path = ENSURE_RELPATH (path); /* Note FUSE wants the string to be always nul-terminated, even if * truncated. */ r = readlinkat (basefd, path, buf, size - 1); if (r == -1) return -errno; buf[r] = '\0'; return 0; }
static void lo_readlink(fuse_req_t req, fuse_ino_t ino) { char buf[PATH_MAX + 1]; int res; res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf)); if (res == -1) return (void) fuse_reply_err(req, errno); if (res == sizeof(buf)) return (void) fuse_reply_err(req, ENAMETOOLONG); buf[res] = '\0'; fuse_reply_readlink(req, buf); }
/* move any old watches directory out of the way, and then restore * the watches */ void udev_watch_restore(struct udev *udev) { if (inotify_fd < 0) return; if (rename("/run/udev/watch", "/run/udev/watch.old") == 0) { DIR *dir; struct dirent *ent; dir = opendir("/run/udev/watch.old"); if (dir == NULL) { log_error("unable to open old watches dir /run/udev/watch.old; old watches will not be restored: %m"); return; } for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) { char device[UTIL_PATH_SIZE]; ssize_t len; struct udev_device *dev; if (ent->d_name[0] == '.') continue; len = readlinkat(dirfd(dir), ent->d_name, device, sizeof(device)); if (len <= 0 || len == (ssize_t)sizeof(device)) goto unlink; device[len] = '\0'; dev = udev_device_new_from_device_id(udev, device); if (dev == NULL) goto unlink; log_debug("restoring old watch on '%s'", udev_device_get_devnode(dev)); udev_watch_begin(udev, dev); udev_device_unref(dev); unlink: unlinkat(dirfd(dir), ent->d_name, 0); } closedir(dir); rmdir("/run/udev/watch.old"); } else if (errno != ENOENT) { log_error("unable to move watches dir /run/udev/watch; old watches will not be restored: %m"); } }
ATF_TC_BODY(readlinkat_fdcwd, tc) { int fd; ssize_t len; char buf[MAXPATHLEN]; ATF_REQUIRE(mkdir(DIR, 0755) == 0); ATF_REQUIRE((fd = open(FILE, O_CREAT|O_RDWR, 0644)) != -1); ATF_REQUIRE(close(fd) == 0); ATF_REQUIRE(symlink(FILE, LINK) == 0); len = readlinkat(AT_FDCWD, LINK, buf, sizeof(buf)-1); ATF_REQUIRE(len != -1); buf[len] = 0; ATF_REQUIRE(strcmp(buf, FILE) == 0); }
void test_create_symlink_at() { char *symlink_filename = alloc_filename("symlink"); int dir_fd = get_dir_fd("."); const char *dest_path = "dest_path"; t_check_zero(symlinkat(dest_path, dir_fd, symlink_filename)); char buf[100]; int got; got = readlinkat(dir_fd, symlink_filename, buf, sizeof(buf)); t_check(got >= 0); assert(got == strlen(dest_path)); buf[got] = 0; assert(strcmp(buf, dest_path) == 0); t_check_zero(unlinkat(dir_fd, symlink_filename, 0)); close(dir_fd); free(symlink_filename); }
struct dirtree *dirtree_add_node(struct dirtree *parent, char *name, int symfollow) { struct dirtree *dt = NULL; struct stat st; char buf[4096]; int len = 0, linklen = 0; if (name) { // open code this because haven't got node to call dirtree_parentfd() on yet int fd = parent ? parent->data : AT_FDCWD; if (fstatat(fd, name, &st, symfollow ? 0 : AT_SYMLINK_NOFOLLOW)) goto error; if (S_ISLNK(st.st_mode)) { if (0>(linklen = readlinkat(fd, name, buf, 4095))) goto error; buf[linklen++]=0; } len = strlen(name); } dt = xzalloc((len = sizeof(struct dirtree)+len+1)+linklen); dt->parent = parent; if (name) { memcpy(&(dt->st), &st, sizeof(struct stat)); strcpy(dt->name, name); if (linklen) { dt->symlink = memcpy(len+(char *)dt, buf, linklen); dt->data = --linklen; } } return dt; error: if (notdotdot(name)) { char *path = parent ? dirtree_path(parent, 0) : ""; perror_msg("%s%s%s",path, parent ? "/" : "", name); } if (parent) parent->symlink = (char *)1; free(dt); return 0; }