Skip to content

Commit

Permalink
win32: changes to stat(2) implementation
Browse files Browse the repository at this point in the history
- Use repeated calls to readlink(2) rather than xmalloc_realpath()
  when asked to follow symlinks.

- Drop the non-standard feature that caused readlink(2) to return
  only the target string length.

This improves compatibility with BusyBox on Linux at a cost of
16-32 bytes.
  • Loading branch information
rmyorston committed May 23, 2022
1 parent 70c17b9 commit 31467dd
Showing 1 changed file with 22 additions and 15 deletions.
37 changes: 22 additions & 15 deletions win32/mingw.c
Original file line number Diff line number Diff line change
Expand Up @@ -625,48 +625,58 @@ static int count_subdirs(const char *pathname)
*/
static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf)
{
int err = EINVAL;
int err;
WIN32_FILE_ATTRIBUTE_DATA fdata;
WIN32_FIND_DATAA findbuf;
DWORD low, high;
off64_t size;
ssize_t len;
char lname[PATH_MAX];
#if ENABLE_FEATURE_EXTRA_FILE_DATA
DWORD flags;
BY_HANDLE_FILE_INFORMATION hdata;
HANDLE fh;
#endif

while (file_name && !(err=get_file_attr(file_name, &fdata))) {
while (!(err=get_file_attr(file_name, &fdata))) {
buf->st_ino = 0;
buf->st_uid = DEFAULT_UID;
buf->st_gid = DEFAULT_GID;
buf->st_dev = buf->st_rdev = 0;
buf->st_tag =
get_symlink_data(fdata.dwFileAttributes, file_name, &findbuf);
buf->st_attr = fdata.dwFileAttributes;
buf->st_tag = get_symlink_data(buf->st_attr, file_name, &findbuf);

if (buf->st_tag) {
ssize_t len = readlink(file_name, lname, PATH_MAX);
if (len < 0) {
err = errno;
break;
} else if (len == PATH_MAX) {
errno = ENAMETOOLONG;
break;
}

if (follow) {
/* The file size and times are wrong when Windows follows
* a symlink. Use the canonicalized path instead. */
err = errno;
file_name = auto_string(xmalloc_realpath(file_name));
* a symlink. Use the symlink target instead. */
if (follow++ > MAXSYMLINKS) {
err = ELOOP;
break;
}
lname[len] = '\0';
file_name = lname;
continue;
}

/* Get the contents of a symlink, not its target. */
buf->st_mode = S_IFLNK|S_IRWXU|S_IRWXG|S_IRWXO;
buf->st_attr = fdata.dwFileAttributes;
len = readlink(file_name, NULL, 0);
buf->st_size = len == -1 ? 0 : len;
buf->st_size = len;
buf->st_atim = filetime_to_timespec(&(findbuf.ftLastAccessTime));
buf->st_mtim = filetime_to_timespec(&(findbuf.ftLastWriteTime));
buf->st_ctim = filetime_to_timespec(&(findbuf.ftCreationTime));
}
else {
/* The file is not a symlink. */
buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
buf->st_attr = fdata.dwFileAttributes;
if (S_ISREG(buf->st_mode) &&
!(buf->st_attr & FILE_ATTRIBUTE_DEVICE) &&
(has_exe_suffix(file_name) || has_exec_format(file_name)))
Expand Down Expand Up @@ -1524,7 +1534,6 @@ char *realpath(const char *path, char *resolved_path)
}

#define SRPB rptr->SymbolicLinkReparseBuffer
/* Non-standard feature: if buf is NULL just return the length. */
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz)
{
HANDLE h;
Expand Down Expand Up @@ -1552,8 +1561,6 @@ ssize_t readlink(const char *pathname, char *buf, size_t bufsiz)
}

if (name) {
if (buf == NULL)
return len;
if (len > bufsiz)
len = bufsiz;
len = WideCharToMultiByte(CP_ACP, 0, name, len, buf, bufsiz, 0, 0);
Expand Down

0 comments on commit 31467dd

Please sign in to comment.