windows: improve uv_fs_unlink

* It's now more efficient, the file is not opened twice.
* It no longer allows deletion of non-symlink directory reparse points.
This commit is contained in:
Bert Belder 2012-07-31 16:52:31 +02:00
parent 7edc29a414
commit 7f6b86c687
2 changed files with 59 additions and 26 deletions

View File

@ -338,17 +338,20 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
return -1;
}
/* Compute the length of the target. */
target_len = WideCharToMultiByte(CP_UTF8,
0,
w_target,
w_target_len,
NULL,
0,
NULL,
NULL);
if (target_len == 0) {
return -1;
/* If needed, compute the length of the target. */
if (target_ptr != NULL || target_len_ptr != NULL) {
/* Compute the length of the target. */
target_len = WideCharToMultiByte(CP_UTF8,
0,
w_target,
w_target_len,
NULL,
0,
NULL,
NULL);
if (target_len == 0) {
return -1;
}
}
/* If requested, allocate memory and convert to UTF8. */
@ -615,14 +618,15 @@ void fs__rmdir(uv_fs_t* req) {
void fs__unlink(uv_fs_t* req) {
const WCHAR* pathw = req->pathw;
int result;
HANDLE handle;
BY_HANDLE_FILE_INFORMATION info;
int is_dir_symlink;
FILE_DISPOSITION_INFORMATION disposition;
IO_STATUS_BLOCK iosb;
NTSTATUS status;
handle = CreateFileW(pathw,
0,
0,
FILE_READ_ATTRIBUTES | DELETE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
@ -639,19 +643,44 @@ void fs__unlink(uv_fs_t* req) {
return;
}
is_dir_symlink = (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT);
if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
/* Do not allow deletion of directories, unless it is a symlink. When */
/* the path refers to a non-symlink directory, report EPERM as mandated */
/* by POSIX.1. */
/* Check if it is a reparse point. If it's not, it's a normal directory. */
if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
CloseHandle(handle);
return;
}
/* Read the reparse point and check if it is a valid symlink. */
/* If not, don't unlink. */
if (fs__readlink_handle(handle, NULL, NULL) < 0) {
DWORD error = GetLastError();
if (error == ERROR_SYMLINK_NOT_SUPPORTED)
error = ERROR_ACCESS_DENIED;
SET_REQ_WIN32_ERROR(req, error);
CloseHandle(handle);
return;
}
}
/* Try to set the delete flag. */
disposition.DeleteFile = TRUE;
status = pNtSetInformationFile(handle,
&iosb,
&disposition,
sizeof disposition,
FileDispositionInformation);
if (NT_SUCCESS(status)) {
SET_REQ_SUCCESS(req);
} else {
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
}
CloseHandle(handle);
/* Todo: very inefficient; fix this. */
if (is_dir_symlink) {
int result = _wrmdir(req->pathw);
SET_REQ_RESULT(req, result);
} else {
result = _wunlink(pathw);
SET_REQ_RESULT(req, result);
}
}

View File

@ -4132,6 +4132,10 @@ typedef struct _FILE_BASIC_INFORMATION {
DWORD FileAttributes;
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
typedef struct _FILE_DISPOSITION_INFORMATION {
BOOLEAN DeleteFile;
} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;
typedef struct _FILE_MODE_INFORMATION {
ULONG Mode;
} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION;