blob: a5686c81c08dfc2e6d6a17a11d569dd6ffe08752 [file] [log] [blame] [raw]
#include <windows.h>
#include <nt.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <errno.h>
#include <pathname.h>
#include <ntstatus.h>
#include <assert.h>
#include <stdio.h> // For debug messages
int vopen(const char *pathname, int flags, va_list ap) {
unsigned long int fileaccess;
switch(flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
case O_RDONLY:
fileaccess = GENERIC_READ;
break;
case O_WRONLY:
fileaccess = GENERIC_WRITE;
break;
case O_RDWR:
fileaccess = GENERIC_READ | GENERIC_WRITE;
break;
default:
errno = EINVAL;
return -1;
}
if(flags & O_APPEND) {
if(!(fileaccess & GENERIC_WRITE)) {
errno = EINVAL;
return -1;
}
fileaccess = FILE_APPEND_DATA;
}
if(/*(flags & O_SYNC) || */!(flags & O_NONBLOCK)) fileaccess |= SYNCHRONIZE;
unsigned long int file_create_disposition;
switch(flags & (O_CREAT | O_EXCL | O_TRUNC)) {
case 0:
case O_EXCL: // O_EXCL without O_CREAT: ignored
// Open file if it exist, or fail if not
file_create_disposition = FILE_OPEN;
break;
case O_CREAT:
// Open file if it exist, or create it if not
file_create_disposition = FILE_OPEN_IF;
break;
case O_CREAT | O_EXCL:
case O_CREAT | O_TRUNC | O_EXCL:
// Create file if it not exist, otherwise fail
file_create_disposition = FILE_CREATE;
break;
case O_TRUNC:
case O_TRUNC | O_EXCL: // O_EXCL without O_CREAT: ignored
// Open and truncate file if it exist, or fail if not
file_create_disposition = FILE_OVERWRITE;
break;
case O_CREAT | O_TRUNC:
// Open and truncate file if it exist, or create it if not
file_create_disposition = FILE_OVERWRITE_IF;
break;
default:
/* this can't happen ... all cases are covered */
assert(!flags);
return -1;
}
unsigned long int fileshare = FILE_SHARE_READ | FILE_SHARE_DELETE;
unsigned long int fileattrib = 0;
if(flags & O_CREAT) {
int pmode = va_arg(ap, int);
if((pmode & S_IWRITE) != S_IWRITE) fileattrib |= FILE_ATTRIBUTE_READONLY;
}
if(!fileattrib) fileattrib = FILE_ATTRIBUTE_NORMAL;
unsigned long int file_create_options = 0;
if(!(flags & O_NONBLOCK)) {
if(flags & O_ASYNC) file_create_options |= FILE_SYNCHRONOUS_IO_ALERT;
else file_create_options |= FILE_SYNCHRONOUS_IO_NONALERT;
}
if(flags & O_DIRECTORY) {
fileaccess = SYNCHRONIZE;
file_create_options |= FILE_DIRECTORY_FILE;
} else file_create_options |= FILE_NON_DIRECTORY_FILE;
if(flags & O_RANDOM) file_create_options |= FILE_RANDOM_ACCESS;
else if(flags & O_SEQUENTIAL) file_create_options |= FILE_SEQUENTIAL_ONLY;
if(flags & O_TEMPORARY) file_create_options |= FILE_DELETE_ON_CLOSE;
if(flags & O_DIRECT) file_create_options |= FILE_NO_INTERMEDIATE_BUFFERING;
if(flags & O_NOFOLLOW) file_create_options |= FILE_OPEN_REPARSE_POINT;
int requset_dir = 0;
UNICODE_STRING ntpathname;
RtlCreateUnicodeStringFromAsciiz(&ntpathname, pathname);
if(ntpathname.Buffer[ntpathname.Length / 2 - 1] == L'/') requset_dir = 1;
PATHNAME_UNIX2NT_UTF16_STRUCT(ntpathname);
OBJECT_ATTRIBUTES objectattrib = { sizeof(OBJECT_ATTRIBUTES), NULL, &ntpathname, OBJ_INHERIT, NULL, NULL };
void *r;
IO_STATUS_BLOCK io_status;
if(flags & O_NOFOLLOW) {
//objectattrib.Attributes |= OBJ_OPENLINK;
long int status = NtOpenSymbolicLinkObject(&r, fileaccess & ~SYNCHRONIZE, &objectattrib);
printf("nativelibc debug: open: status = 0x%lx\n", status);
//if(status >= 0) return (int)r;
if(status != STATUS_OBJECT_TYPE_MISMATCH) return ntstatus_to_errno(status) ? -1 : (int)r;
//objectattrib.Attributes &= ~OBJ_OPENLINK;
}
long int status = NtCreateFile(&r, fileaccess, &objectattrib, &io_status, NULL, fileattrib, fileshare, file_create_disposition, file_create_options, NULL, 0);
printf("nativelibc debug: open: status = 0x%lx\n", status);
if(status == STATUS_OBJECT_NAME_INVALID && requset_dir && !(flags & O_CREAT)) {
void *handle;
long int status = NtCreateFile(&handle, fileaccess, &objectattrib, &io_status, NULL, 0, fileshare, FILE_OPEN, FILE_DIRECTORY_FILE, NULL, 0);
printf("nativelibc debug: open: inner status = 0x%lx\n", status);
if(status == STATUS_NOT_A_DIRECTORY) {
errno = ENOTDIR;
return -1;
}
if(status >= 0) NtClose(handle);
}
return ntstatus_to_errno(status) ? -1 : (int)r;
//return status ? -1 : (int)r; // TODO: implemente the errno
}
int open(const char *pathname, int flags, ...) {
va_list ap;
va_start(ap, flags);
int r = vopen(pathname, flags, ap);
va_end(ap);
return r;
}