| #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; |
| } |