blob: 1cd0b6037d63859a2717daeec2c34f618c5a0ecd [file] [log] [blame] [raw]
/* A part of the Native C Library for Windows NT
Copyright 2007-2015 PC GO Ld.
Copyright 2015-2017 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 <windows.h>
#include <nt.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <pathname.h>
#include <ntstatus.h>
// Handle will be closed
static int unlink_object(void *handle) {
OBJECT_BASIC_INFORMATION obi;
long int status = NtQueryObject(handle, ObjectBasicInformation, &obi, sizeof obi, NULL);
if(status < 0) {
NtClose(handle);
__set_errno_from_ntstatus(status);
return -1;
}
if(obi.HandleCount > 1) {
NtClose(handle);
errno = EBUSY;
return -1;
}
status = NtMakeTemporaryObject(handle);
long int close_status = NtClose(handle);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
if(close_status < 0) {
__set_errno_from_ntstatus(close_status);
return -1;
}
return 0;
}
int unlink(const char *name) {
if(!name) {
errno = EFAULT;
return -1;
}
if(!*name) {
errno = ENOENT;
return -1;
}
if(*name != '/') {
errno = ENOSYS;
return -1;
}
if(!name[1]) {
#ifdef _ALLOW_UNLINK_DIRECTORIES
errno = EBUSY;
#else
errno = EPERM;
#endif
return -1;
}
UNICODE_STRING name1;
RtlCreateUnicodeStringFromAsciiz(&name1, name);
int request_dir = 0;
if(name1.Length > sizeof(wchar_t) && name1.Buffer[name1.Length / sizeof(wchar_t) - 1] == L'/') {
// This function may not allow unlinking of a directory and will fail anyways; just continue for setting errno.
request_dir = 1;
name1.Buffer[name1.Length / sizeof(wchar_t) - 1] = 0;
name1.Length -= sizeof(wchar_t);
name1.MaximumLength -= sizeof(wchar_t);
}
PATHNAME_UNIX2NT_UTF16_STRUCT(name1);
OBJECT_ATTRIBUTES o = { sizeof(OBJECT_ATTRIBUTES), NULL, &name1, 0, NULL, NULL };
void *handle;
if(!request_dir) {
long int status = NtOpenSymbolicLinkObject(&handle, DELETE, &o);
//printf("nativelibc debug: unlink: status = 0x%lx\n", status);
if(status != STATUS_OBJECT_TYPE_MISMATCH) {
RtlFreeUnicodeString(&name1);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
return unlink_object(handle);
}
}
long int status = NtOpenDirectoryObject(&handle, 0, &o);
//printf("nativelibc debug: unlink: status = 0x%lx\n", status);
if(status != STATUS_OBJECT_TYPE_MISMATCH) {
RtlFreeUnicodeString(&name1);
#ifdef _ALLOW_UNLINK_DIRECTORIES
if(status < 0) __set_errno_from_ntstatus(status);
else return unlink_object(handle);
#else
if(status >= 0 || status == STATUS_ACCESS_DENIED) {
if(status >= 0) NtClose(handle);
errno = EPERM;
} else __set_errno_from_ntstatus(status);
#endif
return -1;
}
IO_STATUS_BLOCK io_status;
unsigned long int file_share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
unsigned long int options = FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT;
status = NtOpenFile(&handle, DELETE | SYNCHRONIZE, &o, &io_status, file_share, options);
RtlFreeUnicodeString(&name1);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
if(request_dir) {
NtClose(handle);
errno = ENOTDIR;
return -1;
}
//status = NtDeleteFile(&o);
FILE_DISPOSITION_INFORMATION fdi;
fdi.DeleteFile = 1;
status = NtSetInformationFile(handle, &io_status, &fdi, sizeof fdi, FileDispositionInformation);
if(__set_errno_from_ntstatus(NtClose(handle))) return -1;
return __set_errno_from_ntstatus(status) ? -1 : 0;
}