| /* 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 <windows.h> |
| #include <nt.h> |
| #include <sys/stat.h> |
| #include <pathname.h> |
| #include <errno.h> |
| #include <stdio.h> |
| #include <ntstatus.h> |
| #include <string.h> |
| |
| int mkdir(const char *pathname, mode_t mode) { |
| if(!pathname) { |
| errno = EFAULT; |
| return -1; |
| } |
| if(!*pathname) { |
| errno = ENOENT; |
| return -1; |
| } |
| |
| if(*pathname != '/') { |
| if(strcmp(pathname, ".") == 0 || strcmp(pathname, "./") == 0) { |
| errno = EEXIST; |
| return -1; |
| } |
| errno = ENOSYS; |
| return -1; |
| } |
| |
| if(!pathname[1]) { |
| // mkdir / ?? |
| errno = EEXIST; |
| return -1; |
| } |
| |
| UNICODE_STRING ntpathname; |
| if(!RtlCreateUnicodeStringFromAsciiz(&ntpathname, pathname)) { |
| errno = ENOMEM; |
| return -1; |
| } |
| if(ntpathname.Buffer[ntpathname.Length / sizeof(wchar_t) - 1] == L'/') { |
| ntpathname.Buffer[ntpathname.Length / sizeof(wchar_t) - 1] = 0; |
| ntpathname.Length -= sizeof(wchar_t); |
| ntpathname.MaximumLength -= sizeof(wchar_t); |
| } |
| PATHNAME_UNIX2NT_UTF16_STRUCT(ntpathname); |
| void *handle; |
| OBJECT_ATTRIBUTES object_attrib = { sizeof(OBJECT_ATTRIBUTES), NULL, &ntpathname, OBJ_PERMANENT, NULL, NULL }; |
| |
| // Try to create a directory object first |
| long int status = NtCreateDirectoryObject(&handle, 0, &object_attrib); |
| //printf("nativelibc debug: mkdir: status = 0x%lx\n", status); |
| if(status != STATUS_OBJECT_TYPE_MISMATCH) { |
| RtlFreeUnicodeString(&ntpathname); |
| if(status >= 0) NtClose(handle); |
| return __set_errno_from_ntstatus(status) ? -1 : 0; |
| } |
| |
| // Try to create a directory file in a regular file system |
| unsigned long int file_access = SYNCHRONIZE; |
| unsigned long int file_attrib = 0; |
| unsigned long int file_share = 0; |
| unsigned long int file_create_disposition = FILE_CREATE; |
| unsigned long int file_create_options = FILE_DIRECTORY_FILE; |
| IO_STATUS_BLOCK io_status; |
| object_attrib.Attributes = 0; |
| switch(mode & (S_IREAD | S_IWRITE | S_IEXEC)) { |
| case 0: // XXX |
| case S_IREAD: |
| file_attrib |= FILE_ATTRIBUTE_READONLY; |
| break; |
| case S_IWRITE: // XXX |
| case S_IREAD | S_IWRITE: |
| file_attrib |= FILE_ATTRIBUTE_NORMAL; |
| break; |
| case S_IEXEC: |
| //file_access |= FILE_TRAVERSE; |
| file_attrib |= FILE_ATTRIBUTE_READONLY; // ? |
| break; |
| case S_IREAD | S_IEXEC: |
| //file_access |= FILE_LIST_DIRECTORY; |
| file_attrib |= FILE_ATTRIBUTE_READONLY; |
| break; |
| case S_IREAD | S_IWRITE | S_IEXEC: |
| //file_access |= FILE_LIST_DIRECTORY; |
| case S_IWRITE | S_IEXEC: |
| //file_access |= FILE_TRAVERSE; |
| file_attrib |= FILE_ATTRIBUTE_NORMAL; |
| break; |
| default: |
| puts("nativelibc fatal: " __FILE__ ": Surprising code path"); |
| abort(); |
| } |
| status = NtCreateFile(&handle, file_access, &object_attrib, &io_status, NULL, file_attrib, file_share, file_create_disposition, file_create_options, NULL, 0); |
| //printf("nativelibc debug: mkdir: status = 0x%lx\n", status); |
| RtlFreeUnicodeString(&ntpathname); |
| if(status >= 0) NtClose(handle); |
| return __set_errno_from_ntstatus(status) ? -1 : 0; |
| } |