blob: 35bd20ad9ff780fce56137b108128de0fe3b18eb [file] [log] [blame] [raw]
/* A part of the Native C Library for Windows NT
Copyright 2007-2015 PC GO Ld.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/
#include <sys/stat.h>
#include <windows.h>
#include <nt.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <wchar.h>
#include <stdio.h>
static int is_in_do(int fd) {
size_t oni_size = sizeof(OBJECT_NAME_INFORMATION) + 256 * 2;
OBJECT_NAME_INFORMATION *oni = malloc(oni_size);
if(!oni) return 0;
long int status = NtQueryObject((void *)fd, ObjectNameInformation, oni, oni_size, NULL);
if(status < 0) {
free(oni);
return 0;
}
/*
printf("nativelibc debug: object name: ");
NtDisplayString(&oni->Name);
putchar('\n');
{
void *handle;
size_t len = oni->Name.Length / sizeof(wchar_t) - 1;
if(len && oni->Name.Buffer[len] != '\\') {
oni->Name.Buffer[++len] = L'\\';
oni->Name.Buffer[++len] = 0;
oni->Name.Length = len * sizeof(wchar_t);
oni->Name.MaximumLength = (len + 1) * sizeof(wchar_t);
}
printf("nativelibc debug: object name: ");
NtDisplayString(&oni->Name);
putchar('\n');
OBJECT_ATTRIBUTES object_attrib = { sizeof(OBJECT_ATTRIBUTES), NULL, &oni->Name, 0, NULL, NULL };
status = NtOpenDirectoryObject(&handle, DIRECTORY_QUERY, &object_attrib);
printf("nativelibc debug: is_in_do: status = 0x%lx\n", status);
if(status >= 0) NtClose(handle);
}
*/
// Truncate to upper directory
size_t len = oni->Name.Length / sizeof(wchar_t) - 1;
if(len && oni->Name.Buffer[len] == '\\') oni->Name.Buffer[len--] = 0;
do {
if(!len-- || !len) return 0;
} while(oni->Name.Buffer[len] != L'\\');
oni->Name.Length = len * sizeof(wchar_t);
oni->Name.MaximumLength = (len + 1) * sizeof(wchar_t);
oni->Name.Buffer[len] = 0;
//printf("nativelibc debug: truncated path: ");
//NtDisplayString(&oni->Name);
//putchar('\n');
void *handle;
OBJECT_ATTRIBUTES object_attrib = { sizeof(OBJECT_ATTRIBUTES), NULL, &oni->Name, 0, NULL, NULL };
status = NtOpenDirectoryObject(&handle, DIRECTORY_QUERY, &object_attrib);
//printf("nativelibc debug: is_in_do: status = 0x%lx\n", status);
free(oni);
if(status < 0) return 0;
NtClose(handle);
return 1;
}
static int fstat_f(int fd, struct stat *st) {
FILE_FS_DEVICE_INFORMATION ffsdi;
FILE_BASIC_INFORMATION fbi;
IO_STATUS_BLOCK io_status;
st->st_mode = S_IREAD | S_IEXEC;
long int status = NtQueryVolumeInformationFile((void *)fd, &io_status, &ffsdi, sizeof ffsdi, FileFsDeviceInformation);
//printf("nativelibc debug: fstat: NtQueryVolumeInformationFile status = 0x%lx\n", status);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
printf("nativelibc debug: fstat: ffsdi.DeviceType = 0x%lx, ffsdi.Characteristics = 0x%lx\n", ffsdi.DeviceType, ffsdi.Characteristics);
switch(ffsdi.DeviceType) {
case FILE_DEVICE_CD_ROM:
case FILE_DEVICE_DFS:
case FILE_DEVICE_DISK:
case FILE_DEVICE_VIRTUAL_DISK:
status = NtQueryInformationFile((void *)fd, &io_status, &fbi, sizeof fbi, FileBasicInformation);
//printf("nativelibc debug: fstat: status = 0x%lx\n", status);
if(status < 0) {
st->st_mode |= S_IFBLK;
st->st_blocks = 0;
st->st_size = 0;
st->st_rdev = ffsdi.Characteristics;
st->st_gid = 0;
st->st_uid = 0;
st->st_nlink = 1;
} else {
// File in file system
unsigned long int t;
st->st_ctime = RtlTimeToSecondsSince1970(&fbi.ChangeTime, &t) ? t : 0;
st->st_mtime = RtlTimeToSecondsSince1970(&fbi.LastWriteTime, &t) ? t : 0;
st->st_atime = RtlTimeToSecondsSince1970(&fbi.LastAccessTime, &t) ? t : 0;
if(!(fbi.FileAttributes & FILE_ATTRIBUTE_READONLY)) st->st_mode |= S_IWRITE;
FILE_STANDARD_INFORMATION fsi;
status = NtQueryInformationFile((void *)fd, &io_status, &fsi, sizeof fsi, FileStandardInformation);
//printf("nativelibc debug: fstat: status = 0x%lx\n", status);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
st->st_blocks = fsi.AllocationSize.QuadPart / 512;
st->st_size = fsi.EndOfFile.QuadPart;
st->st_rdev = 0;
st->st_gid = 0;
st->st_uid = 0;
st->st_nlink = fsi.NumberOfLinks;
st->st_mode |= fsi.Directory ? S_IFDIR : S_IFREG;
st->st_dev = 0;
FILE_INTERNAL_INFORMATION fii;
status = NtQueryInformationFile((void *)fd, &io_status, &fii, sizeof fii, FileInternalInformation);
//printf("nativelibc debug: fstat: status = 0x%lx\n", status);
st->st_ino = status < 0 ? 0 : fii.IndexNumber.QuadPart;
}
break;
case FILE_DEVICE_NAMED_PIPE:
st->st_mode |= is_in_do(fd) ? S_IFBLK : S_IFIFO;
st->st_blocks = 0;
st->st_size = 0;
st->st_rdev = 0;
st->st_gid = 0;
st->st_uid = 0;
st->st_nlink = 1;
break;
case FILE_DEVICE_NETWORK_FILE_SYSTEM:
st->st_mode |= S_IFBLK;
st->st_blocks = 0;
st->st_size = 0;
st->st_rdev = ffsdi.Characteristics;
st->st_gid = 0;
st->st_uid = 0;
st->st_nlink = 1;
break;
default:
st->st_mode |= S_IFCHR;
st->st_blocks = 0;
st->st_size = 0;
st->st_rdev = ffsdi.Characteristics;
st->st_gid = 0;
st->st_uid = 0;
st->st_nlink = 1;
break;
}
return 0;
#if 0
long int status1 = NtQueryInformationFile((void *)fd, &io_status, &fbi, sizeof fbi, FileBasicInformation);
printf("nativelibc debug: fstat: status1 = 0x%lx\n", status1);
if(status1 >= 0) {
unsigned long int t;
st->st_ctime = RtlTimeToSecondsSince1970(&fbi.ChangeTime, &t) ? t : 0;
st->st_mtime = RtlTimeToSecondsSince1970(&fbi.LastWriteTime, &t) ? t : 0;
st->st_atime = RtlTimeToSecondsSince1970(&fbi.LastAccessTime, &t) ? t : 0;
if(!(fbi.FileAttributes & FILE_ATTRIBUTE_READONLY)) st->st_mode |= S_IWRITE;
//printf("nativelibc debug: fstat: fbi.FileAttributes = 0x%lx\n", fbi.FileAttributes);
//if(st->st_ctime) printf("ctime = %lu\n", (unsigned long int)st->st_ctime);
}
long int status2 = NtQueryInformationFile((void *)fd, &io_status, &fsi, sizeof fsi, FileStandardInformation);
printf("nativelibc debug: fstat: status2 = 0x%lx\n", status2);
if(status2 < 0) {
if(status1 < 0) {
__set_errno_from_ntstatus(status2);
return -1;
}
st->st_blocks = 0;
st->st_size = 0;
st->st_rdev = 0;
st->st_gid = 0;
st->st_uid = 0;
st->st_nlink = 1;
} else {
if(status1 < 0) {
st->st_ctime = 0;
st->st_mtime = 0;
st->st_atime = 0;
}
st->st_blocks = fsi.AllocationSize.QuadPart / 512;
st->st_size = fsi.EndOfFile.QuadPart;
st->st_rdev = 0;
st->st_gid = 0;
st->st_uid = 0;
st->st_nlink = fsi.NumberOfLinks;
st->st_mode |= fsi.Directory ? S_IFDIR : S_IFREG;
}
st->st_dev = 0;
long int status3 = NtQueryInformationFile((void *)fd, &io_status, &fii, sizeof fii, FileInternalInformation);
//printf("nativelibc debug: fstat: status3 = 0x%lx\n", status3);
if(status3 < 0) st->st_ino = 0;
else st->st_ino = fii.IndexNumber.QuadPart;
return 0;
#endif
}
static int fstat_do(int fd, struct stat *st) {
OBJECT_BASIC_INFORMATION obi;
long int status = NtQueryObject((void *)fd, ObjectBasicInformation, &obi, sizeof obi, NULL);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
unsigned long int t;
st->st_mode = 0777 | S_IFDIR;
st->st_ctime = RtlTimeToSecondsSince1970(&obi.CreateTime, &t) ? t : 0;
st->st_mtime = 0;
st->st_atime = 0;
st->st_blocks = 0;
st->st_size = 0;
st->st_rdev = 0;
st->st_gid = 0;
st->st_uid = 0;
st->st_nlink = 1;
st->st_ino = 0;
return 0;
}
static int fstat_sl(int fd, struct stat *st) {
OBJECT_BASIC_INFORMATION obi;
long int status = NtQueryObject((void *)fd, ObjectBasicInformation, &obi, sizeof obi, NULL);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
unsigned long int t;
st->st_mode = 0777 | S_IFLNK;
st->st_ctime = RtlTimeToSecondsSince1970(&obi.CreateTime, &t) ? t : 0;
st->st_mtime = 0;
st->st_atime = 0;
st->st_blocks = 0;
st->st_size = 0;
st->st_rdev = 0;
st->st_gid = 0;
st->st_uid = 0;
st->st_nlink = 1;
st->st_ino = 0;
return 0;
}
int fstat(int fd, struct stat *st) {
//printf("function: fstat(%d, %p)\n", fd, st);
if(!st) {
errno = EFAULT;
return -1;
}
size_t oti_size = sizeof(OBJECT_TYPE_INFORMATION) + 256;
OBJECT_TYPE_INFORMATION *oti = malloc(oti_size);
if(!oti) return -1;
long int status = NtQueryObject((void *)fd, ObjectTypeInformation, oti, oti_size, NULL);
//printf("nativelibc debug: fstat: status = 0x%lx\n", status);
if(status < 0) {
free(oti);
__set_errno_from_ntstatus(status);
return -1;
}
//printf("TypeName: ");
//NtDisplayString(&oti->TypeName);
//putchar('\n');
//printf("PoolType: %lu\n", oti->PoolType);
int r = -1;
if(wcscmp(oti->TypeName.Buffer, L"File") == 0) r = fstat_f(fd, st);
else if(wcscmp(oti->TypeName.Buffer, L"Directory") == 0) r = fstat_do(fd, st);
else if(wcscmp(oti->TypeName.Buffer, L"SymbolicLink") == 0) r = fstat_sl(fd, st);
else errno = ENOSYS;
free(oti);
return r;
}
int stat(const char *path, struct stat *st) {
if(!path || !st) {
errno = EFAULT;
return -1;
}
if(!*path) {
errno = ENOENT;
return -1;
}
int fd = open(path, O_RDONLY);
if(fd == -1) return -1;
int r = fstat(fd, st);
int e = errno;
close(fd);
errno = e;
return r;
}
int lstat(const char *path, struct stat *st) {
if(!path || !st) {
errno = EFAULT;
return -1;
}
if(!*path) {
errno = ENOENT;
return -1;
}
int fd = open(path, O_RDONLY | O_NOFOLLOW);
if(fd == -1) return -1;
int r = fstat(fd, st);
int e = errno;
close(fd);
errno = e;
return r;
}