blob: 27324145cdb6cf66d5251b7df6f9eafee0c8b6cc [file] [log] [blame] [raw]
/* A part of the Native C Library for Windows NT
Copyright 2007-2015 PC GO Ld.
Copyright 2015-2016 Rivoreo
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/statvfs.h>
#include <windows.h>
#include <nt.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <ntstatus.h>
#include <pathname.h>
#include <stdio.h>
static int truncate_to_device(UNICODE_STRING *path) {
void *handle;
size_t len = path->Length / sizeof(wchar_t) - 1;
if(len && path->Buffer[len] == '\\') path->Buffer[len--] = 0;
//while(path->Buffer[--len] != L'/') if(!len) return -1;
do {
if(!len-- || !len) return -1;
} while(path->Buffer[len] != L'\\');
UNICODE_STRING up_path = { len * sizeof(wchar_t), (len + 1) * sizeof(wchar_t), malloc((len + 1) * sizeof(wchar_t)) };
if(!up_path.Buffer) return -1;
memcpy(up_path.Buffer, path->Buffer, len * sizeof(wchar_t));
up_path.Buffer[len] = 0;
OBJECT_ATTRIBUTES object_attrib = { sizeof(OBJECT_ATTRIBUTES), NULL, &up_path, 0, NULL, NULL };
long int status = NtOpenDirectoryObject(&handle, DIRECTORY_QUERY, &object_attrib);
free(up_path.Buffer);
if(status == STATUS_OBJECT_TYPE_MISMATCH) {
path->Length = len * sizeof(wchar_t);
path->MaximumLength = (len + 1) * sizeof(wchar_t);
path->Buffer[len] = 0;
return truncate_to_device(path);
}
if(status < 0) return -1;
NtClose(handle);
return 0;
}
int fstatvfs(int fd, struct statvfs *buffer) {
if(!buffer) {
errno = EFAULT;
return -1;
}
IO_STATUS_BLOCK io_status;
//FILE_FS_SIZE_INFORMATION ffssi;
FILE_FS_FULL_SIZE_INFORMATION ffsfsi;
//long int status = NtQueryVolumeInformationFile((void *)fd, &io_status, &ffssi, sizeof ffssi, FileFsSizeInformation);
//printf("nativelibc debug: fstatfs: status = 0x%lx\n", status);
long int status = NtQueryVolumeInformationFile((void *)fd, &io_status, &ffsfsi, sizeof ffsfsi, FileFsFullSizeInformation);
if(status < 0) {
if(status != STATUS_OBJECT_TYPE_MISMATCH) {
__set_errno_from_ntstatus(status);
return -1;
}
buffer->f_bsize = 0;
buffer->f_frsize = 0;
buffer->f_blocks = 0;
buffer->f_bfree = 0;
buffer->f_bavail = 0;
} else {
printf("nativelibc debug: BytesPerSector = %lu, SectorsPerAllocationUnit = %lu\n", ffsfsi.BytesPerSector, ffsfsi.SectorsPerAllocationUnit);
printf("nativelibc debug: ActualAvailableAllocationUnits = %lld, CallerAvailableAllocationUnits = %lld\n", ffsfsi.ActualAvailableAllocationUnits.QuadPart, ffsfsi.CallerAvailableAllocationUnits.QuadPart);
buffer->f_bsize = ffsfsi.SectorsPerAllocationUnit * ffsfsi.BytesPerSector;
buffer->f_frsize = ffsfsi.BytesPerSector;
buffer->f_blocks = ffsfsi.TotalAllocationUnits.QuadPart * ffsfsi.SectorsPerAllocationUnit;
buffer->f_bfree = ffsfsi.ActualAvailableAllocationUnits.QuadPart * ffsfsi.SectorsPerAllocationUnit;
buffer->f_bavail = ffsfsi.CallerAvailableAllocationUnits.QuadPart * ffsfsi.SectorsPerAllocationUnit;
}
buffer->f_files = 0;
buffer->f_ffree = 0;
buffer->f_favail = 0;
buffer->f_fsid = 0;
buffer->f_flag = 0;
buffer->f_namemax = 0;
*buffer->f_fstypename = 0;
size_t oni_size = sizeof(OBJECT_NAME_INFORMATION) + MNAMELEN * 2;
OBJECT_NAME_INFORMATION *oni = malloc(oni_size);
if(!oni) return -1;
status = NtQueryObject((void *)fd, ObjectNameInformation, oni, oni_size, NULL);
//printf("nativelibc debug: fstatfs: status = 0x%lx\n", status);
if(status < 0) *buffer->f_mntfromname = 0;
else {
if(truncate_to_device(&oni->Name) < 0) strcpy(buffer->f_mntfromname, "obfs");
else {
PATHNAME_NT2UNIX_UTF16_STRUCT(oni->Name);
if(wcstombs(buffer->f_mntfromname, oni->Name.Buffer, oni->Name.MaximumLength) == (size_t)-1) {
*buffer->f_mntfromname = 0;
}
}
}
free(oni);
return 0;
}
int statvfs(const char *path, struct statvfs *buffer) {
if(!path || !buffer) {
errno = EFAULT;
return -1;
}
if(!*path) {
errno = ENOENT;
return -1;
}
int fd = open(path, O_RDONLY);
if(fd == -1) return -1;
int r = fstatvfs(fd, buffer);
int e = errno;
close(fd);
errno = e;
return r;
}