msvcrt: Fix fstat's handling of pipes and char devices.
For pipes/char devices, st_dev and st_rdev should be the fd, st_nlink is always 1, and st_mode is S_IFIFO and S_IFCHR respectively. Added tests to prove the new behaviour right.
This commit is contained in:
parent
fc5b795f7c
commit
2705d78876
|
@ -1126,6 +1126,7 @@ int CDECL MSVCRT__fileno(MSVCRT_FILE* file)
|
|||
int CDECL MSVCRT__fstat64(int fd, struct MSVCRT__stat64* buf)
|
||||
{
|
||||
DWORD dw;
|
||||
DWORD type;
|
||||
BY_HANDLE_FILE_INFORMATION hfi;
|
||||
HANDLE hand = msvcrt_fdtoh(fd);
|
||||
|
||||
|
@ -1142,31 +1143,39 @@ int CDECL MSVCRT__fstat64(int fd, struct MSVCRT__stat64* buf)
|
|||
|
||||
memset(&hfi, 0, sizeof(hfi));
|
||||
memset(buf, 0, sizeof(struct MSVCRT__stat64));
|
||||
if (!GetFileInformationByHandle(hand, &hfi))
|
||||
type = GetFileType(hand);
|
||||
if (type == FILE_TYPE_PIPE)
|
||||
{
|
||||
WARN(":failed-last error (%d)\n",GetLastError());
|
||||
msvcrt_set_errno(ERROR_INVALID_PARAMETER);
|
||||
return -1;
|
||||
buf->st_dev = buf->st_rdev = fd;
|
||||
buf->st_mode = S_IFIFO;
|
||||
buf->st_nlink = 1;
|
||||
}
|
||||
else if (type == FILE_TYPE_CHAR)
|
||||
{
|
||||
buf->st_dev = buf->st_rdev = fd;
|
||||
buf->st_mode = S_IFCHR;
|
||||
buf->st_nlink = 1;
|
||||
}
|
||||
else /* FILE_TYPE_DISK etc. */
|
||||
{
|
||||
if (!GetFileInformationByHandle(hand, &hfi))
|
||||
{
|
||||
WARN(":failed-last error (%d)\n",GetLastError());
|
||||
msvcrt_set_errno(ERROR_INVALID_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
buf->st_mode = S_IFREG | S_IREAD;
|
||||
if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||
buf->st_mode |= S_IWRITE;
|
||||
buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
|
||||
RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
|
||||
buf->st_atime = dw;
|
||||
RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
|
||||
buf->st_mtime = buf->st_ctime = dw;
|
||||
buf->st_nlink = hfi.nNumberOfLinks;
|
||||
}
|
||||
dw = GetFileType(hand);
|
||||
buf->st_mode = S_IREAD;
|
||||
if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
|
||||
buf->st_mode |= S_IWRITE;
|
||||
/* interestingly, Windows never seems to set S_IFDIR */
|
||||
if (dw == FILE_TYPE_CHAR)
|
||||
buf->st_mode |= S_IFCHR;
|
||||
else if (dw == FILE_TYPE_PIPE)
|
||||
buf->st_mode |= S_IFIFO;
|
||||
else
|
||||
buf->st_mode |= S_IFREG;
|
||||
TRACE(":dwFileAttributes = 0x%x, mode set to 0x%x\n",hfi.dwFileAttributes,
|
||||
buf->st_mode);
|
||||
buf->st_nlink = hfi.nNumberOfLinks;
|
||||
buf->st_size = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
|
||||
RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
|
||||
buf->st_atime = dw;
|
||||
RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
|
||||
buf->st_mtime = buf->st_ctime = dw;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <share.h>
|
||||
#include <sys/stat.h>
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <winnls.h>
|
||||
|
@ -796,6 +797,86 @@ static void test_setmaxstdio(void)
|
|||
ok(-1 == _setmaxstdio(2049),"_setmaxstdio returned %d instead of -1\n",_setmaxstdio(2049));
|
||||
}
|
||||
|
||||
static void test_stat(void)
|
||||
{
|
||||
int fd;
|
||||
int pipes[2];
|
||||
struct stat buf;
|
||||
|
||||
/* Tests for a file */
|
||||
fd = open("stat.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
|
||||
if (fd >= 0)
|
||||
{
|
||||
if (fstat(fd, &buf) == 0)
|
||||
{
|
||||
if (S_ISREG(buf.st_mode))
|
||||
{
|
||||
ok(buf.st_dev == 0, "st_dev is %d, expected 0\n", buf.st_dev);
|
||||
ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n",
|
||||
buf.st_dev, buf.st_rdev);
|
||||
ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n",
|
||||
buf.st_nlink);
|
||||
ok(buf.st_size == 0, "st_size is %d, expected 0\n",
|
||||
buf.st_size);
|
||||
}
|
||||
else
|
||||
skip("file is not a file?\n");
|
||||
}
|
||||
else
|
||||
skip("fstat failed, errno %d\n", errno);
|
||||
close(fd);
|
||||
remove("stat.tst");
|
||||
}
|
||||
else
|
||||
skip("open failed with errno %d\n", errno);
|
||||
|
||||
/* Tests for a char device */
|
||||
if (_dup2(0, 10) == 0)
|
||||
{
|
||||
if (fstat(10, &buf) == 0)
|
||||
{
|
||||
if (buf.st_mode == _S_IFCHR)
|
||||
{
|
||||
ok(buf.st_dev == 10, "st_dev is %d, expected 10\n", buf.st_dev);
|
||||
ok(buf.st_rdev == 10, "st_rdev is %d, expected 10\n", buf.st_rdev);
|
||||
ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
|
||||
}
|
||||
else
|
||||
skip("stdin is not a char device?\n");
|
||||
}
|
||||
else
|
||||
skip("fstat failed with errno %d\n", errno);
|
||||
close(10);
|
||||
}
|
||||
else
|
||||
skip("_dup2 failed with errno %d\n", errno);
|
||||
|
||||
/* Tests for pipes */
|
||||
if (_pipe(pipes, 1024, O_BINARY) == 0)
|
||||
{
|
||||
if (fstat(pipes[0], &buf) == 0)
|
||||
{
|
||||
if (buf.st_mode == _S_IFIFO)
|
||||
{
|
||||
ok(buf.st_dev == pipes[0], "st_dev is %d, expected %d\n",
|
||||
buf.st_dev, pipes[0]);
|
||||
ok(buf.st_rdev == pipes[0], "st_rdev is %d, expected %d\n",
|
||||
buf.st_rdev, pipes[0]);
|
||||
ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n",
|
||||
buf.st_nlink);
|
||||
}
|
||||
else
|
||||
skip("pipe() didn't make a pipe?\n");
|
||||
}
|
||||
else
|
||||
skip("fstat failed with errno %d\n", errno);
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
}
|
||||
else
|
||||
skip("pipe failed with errno %d\n", errno);
|
||||
}
|
||||
|
||||
START_TEST(file)
|
||||
{
|
||||
int arg_c;
|
||||
|
@ -813,6 +894,7 @@ START_TEST(file)
|
|||
test_file_inherit(arg_v[0]);
|
||||
test_file_write_read();
|
||||
test_chsize();
|
||||
test_stat();
|
||||
|
||||
/* testing stream I/O */
|
||||
test_fdopen();
|
||||
|
|
Loading…
Reference in New Issue