X-Git-Url: https://git.saurik.com/apple/libc.git/blobdiff_plain/70ad1dc8a19d6edd9b97aa81f32cfd65758ae97d..aa54d2fad3d9038b43475aa93c76795c5141a993:/gen/FreeBSD/getcwd.c diff --git a/gen/FreeBSD/getcwd.c b/gen/FreeBSD/getcwd.c index 4a19890..3951c7b 100644 --- a/gen/FreeBSD/getcwd.c +++ b/gen/FreeBSD/getcwd.c @@ -49,10 +49,48 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/getcwd.c,v 1.29 2007/01/09 00:27:53 imp Exp #include #include "un-namespace.h" +#if TARGET_OS_OSX && !TARGET_OS_SIMULATOR +#include /* for FSOPT_NOFOLLOW */ +#include +#endif + #define ISDOT(dp) \ (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) +/* + * Check if the given directory is a firmlink. + * Return 1 if it is firmlink otherwise return 0. + */ +static inline int +__check_for_firmlink(char *dir_path) +{ +#if TARGET_OS_OSX && !TARGET_OS_SIMULATOR + apfs_firmlink_control_t afc; + int is_firmlink; + int err; + + afc.cmd = FIRMLINK_GET; + afc.val = 0; + + err = fsctl(dir_path, APFSIOC_FIRMLINK_CTL, (void *)&afc, FSOPT_NOFOLLOW); + if (err == 0) { + is_firmlink = afc.val ? 1 : 0; + } else { + /* + * On error, we assume it is a firmlink. This could be a false positive + * and we will end up incurring a lstat() cost but it will give us some + * chance to build the path successfully. + */ + is_firmlink = 1; + } + + return is_firmlink; +#else + return 0; +#endif +} + /* * If __getcwd() ever becomes a syscall, we can remove this workaround. * The problem here is that fcntl() assumes a buffer of size MAXPATHLEN, @@ -253,8 +291,29 @@ __private_getcwd(pt, size, usegetpath) for (;;) { if (!(dp = readdir(dir))) goto notfound; - if (dp->d_fileno == ino) + if (dp->d_fileno == ino) { break; + } else if (!ISDOT(dp) && dp->d_type == DT_DIR) { + /* + * The 'd_fileno' for firmlink directory would be different + * than the 'st_ino' returned by stat(). We have to do an + * extra lstat() on firmlink directory to determine if the + * 'st_ino' matches with what we are looking for. + */ + bcopy(dp->d_name, bup, dp->d_namlen + 1); + + if (__check_for_firmlink(up) == 0) + continue; + + if (lstat(up, &s)) { + if (!save_errno) + save_errno = errno; + errno = 0; + continue; + } + if (s.st_dev == dev && s.st_ino == ino) + break; + } } } else for (;;) {