mirror of
https://github.com/reactos/reactos.git
synced 2024-09-06 02:37:06 +00:00
534 lines
11 KiB
C
534 lines
11 KiB
C
/*
|
|
* COPYRIGHT: See COPYRIGHT.TXT
|
|
* PROJECT: Ext2 File System Driver for WinNT/2K/XP
|
|
* FILE: misc.c
|
|
* PROGRAMMER: Matt Wu <mattwu@163.com>
|
|
* HOMEPAGE: http://www.ext2fsd.com
|
|
* UPDATE HISTORY:
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include "ext2fs.h"
|
|
|
|
/* GLOBALS ***************************************************************/
|
|
|
|
extern PEXT2_GLOBAL Ext2Global;
|
|
|
|
/* DEFINITIONS *************************************************************/
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, Ext2Sleep)
|
|
#endif
|
|
|
|
ULONG
|
|
Ext2Log2(ULONG Value)
|
|
{
|
|
ULONG Order = 0;
|
|
|
|
ASSERT(Value > 0);
|
|
|
|
while (Value) {
|
|
Order++;
|
|
Value >>= 1;
|
|
}
|
|
|
|
return (Order - 1);
|
|
}
|
|
|
|
LARGE_INTEGER
|
|
Ext2NtTime (IN ULONG i_time)
|
|
{
|
|
LARGE_INTEGER SysTime;
|
|
|
|
SysTime.QuadPart = 0;
|
|
RtlSecondsSince1970ToTime(i_time, &SysTime);
|
|
|
|
return SysTime;
|
|
}
|
|
|
|
ULONG
|
|
Ext2LinuxTime (IN LARGE_INTEGER SysTime)
|
|
{
|
|
ULONG Ext2Time = 0;
|
|
|
|
if (!RtlTimeToSecondsSince1970(&SysTime, &Ext2Time)) {
|
|
LARGE_INTEGER NtTime;
|
|
KeQuerySystemTime(&NtTime);
|
|
RtlTimeToSecondsSince1970(&NtTime, &Ext2Time);
|
|
}
|
|
|
|
return Ext2Time;
|
|
}
|
|
|
|
|
|
ULONG
|
|
Ext2MbsToUnicode(
|
|
struct nls_table * PageTable,
|
|
IN OUT PUNICODE_STRING Unicode,
|
|
IN PANSI_STRING Mbs )
|
|
{
|
|
ULONG Length = 0;
|
|
int i, mbc = 0;
|
|
WCHAR uc;
|
|
|
|
/* Count the length of the resulting Unicode. */
|
|
for (i = 0; i < Mbs->Length; i += mbc) {
|
|
|
|
mbc = PageTable->char2uni(
|
|
(PUCHAR)&(Mbs->Buffer[i]),
|
|
Mbs->Length - i,
|
|
&uc
|
|
);
|
|
|
|
if (mbc <= 0) {
|
|
|
|
/* invalid character. */
|
|
if (mbc == 0 && Length > 0) {
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Length += 2;
|
|
}
|
|
|
|
if (Unicode) {
|
|
if (Unicode->MaximumLength < Length) {
|
|
|
|
DbgBreak();
|
|
return 0;
|
|
}
|
|
|
|
Unicode->Length = 0;
|
|
mbc = 0;
|
|
|
|
for (i = 0; i < Mbs->Length; i += mbc) {
|
|
|
|
mbc = PageTable->char2uni(
|
|
(PUCHAR)&(Mbs->Buffer[i]),
|
|
Mbs->Length - i,
|
|
&uc
|
|
);
|
|
Unicode->Buffer[Unicode->Length/2] = uc;
|
|
Unicode->Length += 2;
|
|
}
|
|
}
|
|
|
|
return Length;
|
|
}
|
|
|
|
ULONG
|
|
Ext2UnicodeToMbs (
|
|
struct nls_table * PageTable,
|
|
IN OUT PANSI_STRING Mbs,
|
|
IN PUNICODE_STRING Unicode)
|
|
{
|
|
ULONG Length = 0;
|
|
UCHAR mbs[0x10];
|
|
int i, mbc;
|
|
|
|
/* Count the length of the resulting mbc-8. */
|
|
for (i = 0; i < (Unicode->Length / 2); i++) {
|
|
|
|
RtlZeroMemory(mbs, 0x10);
|
|
mbc = PageTable->uni2char(
|
|
Unicode->Buffer[i],
|
|
mbs,
|
|
0x10
|
|
);
|
|
|
|
if (mbc <= 0) {
|
|
|
|
/* Invalid character. */
|
|
return 0;
|
|
}
|
|
|
|
Length += mbc;
|
|
}
|
|
|
|
if (Mbs) {
|
|
|
|
if (Mbs->MaximumLength < Length) {
|
|
|
|
DbgBreak();
|
|
return 0;
|
|
}
|
|
|
|
Mbs->Length = 0;
|
|
|
|
for (i = 0; i < (Unicode->Length / 2); i++) {
|
|
|
|
mbc = PageTable->uni2char(
|
|
Unicode->Buffer[i],
|
|
mbs,
|
|
0x10
|
|
);
|
|
|
|
RtlCopyMemory(
|
|
(PUCHAR)&(Mbs->Buffer[Mbs->Length]),
|
|
&mbs[0],
|
|
mbc
|
|
);
|
|
|
|
Mbs->Length += (USHORT)mbc;
|
|
}
|
|
}
|
|
|
|
return Length;
|
|
}
|
|
|
|
|
|
ULONG
|
|
Ext2OEMToUnicodeSize(
|
|
IN PEXT2_VCB Vcb,
|
|
IN PANSI_STRING Oem
|
|
)
|
|
{
|
|
ULONG Length = 0;
|
|
|
|
if (Vcb->Codepage.PageTable) {
|
|
Length = Ext2MbsToUnicode(Vcb->Codepage.PageTable, NULL, Oem);
|
|
if (Length > 0) {
|
|
goto errorout;
|
|
}
|
|
}
|
|
|
|
Length = RtlOemStringToCountedUnicodeSize(Oem);
|
|
|
|
errorout:
|
|
|
|
return Length;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2OEMToUnicode(
|
|
IN PEXT2_VCB Vcb,
|
|
IN OUT PUNICODE_STRING Unicode,
|
|
IN POEM_STRING Oem
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
|
|
if (Vcb->Codepage.PageTable) {
|
|
Status = Ext2MbsToUnicode(Vcb->Codepage.PageTable,
|
|
Unicode, Oem);
|
|
|
|
if (Status >0 && Status == Unicode->Length) {
|
|
Status = STATUS_SUCCESS;
|
|
goto errorout;
|
|
}
|
|
}
|
|
|
|
Status = RtlOemStringToUnicodeString(
|
|
Unicode, Oem, FALSE );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
DbgBreak();
|
|
goto errorout;
|
|
}
|
|
|
|
errorout:
|
|
|
|
return Status;
|
|
}
|
|
|
|
ULONG
|
|
Ext2UnicodeToOEMSize(
|
|
IN PEXT2_VCB Vcb,
|
|
IN PUNICODE_STRING Unicode
|
|
)
|
|
{
|
|
ULONG Length = 0;
|
|
|
|
if (Vcb->Codepage.PageTable) {
|
|
Length = Ext2UnicodeToMbs(Vcb->Codepage.PageTable,
|
|
NULL, Unicode);
|
|
if (Length > 0) {
|
|
return Length;
|
|
}
|
|
|
|
DbgBreak();
|
|
}
|
|
|
|
return RtlxUnicodeStringToOemSize(Unicode);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Ext2UnicodeToOEM (
|
|
IN PEXT2_VCB Vcb,
|
|
IN OUT POEM_STRING Oem,
|
|
IN PUNICODE_STRING Unicode)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
if (Vcb->Codepage.PageTable) {
|
|
|
|
Status = Ext2UnicodeToMbs(Vcb->Codepage.PageTable,
|
|
Oem, Unicode);
|
|
if (Status > 0 && Status == Oem->Length) {
|
|
Status = STATUS_SUCCESS;
|
|
} else {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
DbgBreak();
|
|
}
|
|
|
|
goto errorout;
|
|
}
|
|
|
|
Status = RtlUnicodeStringToOemString(
|
|
Oem, Unicode, FALSE );
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
DbgBreak();
|
|
goto errorout;
|
|
}
|
|
|
|
errorout:
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
Ext2Sleep(ULONG ms)
|
|
{
|
|
LARGE_INTEGER Timeout;
|
|
Timeout.QuadPart = (LONGLONG)ms*1000*(-10); /* ms/1000 sec*/
|
|
KeDelayExecutionThread(KernelMode, TRUE, &Timeout);
|
|
}
|
|
|
|
int Ext2LinuxError (NTSTATUS Status)
|
|
{
|
|
switch (Status) {
|
|
case STATUS_ACCESS_DENIED:
|
|
return (-EACCES);
|
|
|
|
case STATUS_ACCESS_VIOLATION:
|
|
return (-EFAULT);
|
|
|
|
case STATUS_BUFFER_TOO_SMALL:
|
|
return (-ETOOSMALL);
|
|
|
|
case STATUS_INVALID_PARAMETER:
|
|
return (-EINVAL);
|
|
|
|
case STATUS_NOT_IMPLEMENTED:
|
|
case STATUS_NOT_SUPPORTED:
|
|
return (-EOPNOTSUPP);
|
|
|
|
case STATUS_INVALID_ADDRESS:
|
|
case STATUS_INVALID_ADDRESS_COMPONENT:
|
|
return (-EADDRNOTAVAIL);
|
|
|
|
case STATUS_NO_SUCH_DEVICE:
|
|
case STATUS_NO_SUCH_FILE:
|
|
case STATUS_OBJECT_NAME_NOT_FOUND:
|
|
case STATUS_OBJECT_PATH_NOT_FOUND:
|
|
case STATUS_NETWORK_BUSY:
|
|
case STATUS_INVALID_NETWORK_RESPONSE:
|
|
case STATUS_UNEXPECTED_NETWORK_ERROR:
|
|
return (-ENETDOWN);
|
|
|
|
case STATUS_BAD_NETWORK_PATH:
|
|
case STATUS_NETWORK_UNREACHABLE:
|
|
case STATUS_PROTOCOL_UNREACHABLE:
|
|
return (-ENETUNREACH);
|
|
|
|
case STATUS_LOCAL_DISCONNECT:
|
|
case STATUS_TRANSACTION_ABORTED:
|
|
case STATUS_CONNECTION_ABORTED:
|
|
return (-ECONNABORTED);
|
|
|
|
case STATUS_REMOTE_DISCONNECT:
|
|
case STATUS_LINK_FAILED:
|
|
case STATUS_CONNECTION_DISCONNECTED:
|
|
case STATUS_CONNECTION_RESET:
|
|
case STATUS_PORT_UNREACHABLE:
|
|
return (-ECONNRESET);
|
|
|
|
case STATUS_INSUFFICIENT_RESOURCES:
|
|
return (-ENOMEM);
|
|
|
|
case STATUS_PAGEFILE_QUOTA:
|
|
case STATUS_NO_MEMORY:
|
|
case STATUS_CONFLICTING_ADDRESSES:
|
|
case STATUS_QUOTA_EXCEEDED:
|
|
case STATUS_TOO_MANY_PAGING_FILES:
|
|
case STATUS_WORKING_SET_QUOTA:
|
|
case STATUS_COMMITMENT_LIMIT:
|
|
case STATUS_TOO_MANY_ADDRESSES:
|
|
case STATUS_REMOTE_RESOURCES:
|
|
return (-ENOBUFS);
|
|
|
|
case STATUS_INVALID_CONNECTION:
|
|
return (-ENOTCONN);
|
|
|
|
case STATUS_PIPE_DISCONNECTED:
|
|
return (-ESHUTDOWN);
|
|
|
|
case STATUS_TIMEOUT:
|
|
case STATUS_IO_TIMEOUT:
|
|
case STATUS_LINK_TIMEOUT:
|
|
return (-ETIMEDOUT);
|
|
|
|
case STATUS_REMOTE_NOT_LISTENING:
|
|
case STATUS_CONNECTION_REFUSED:
|
|
return (-ECONNREFUSED);
|
|
|
|
case STATUS_HOST_UNREACHABLE:
|
|
return (-EHOSTUNREACH);
|
|
|
|
case STATUS_CANT_WAIT:
|
|
case STATUS_PENDING:
|
|
return (-EAGAIN);
|
|
|
|
case STATUS_DEVICE_NOT_READY:
|
|
return (-EIO);
|
|
|
|
case STATUS_CANCELLED:
|
|
case STATUS_REQUEST_ABORTED:
|
|
return (-EINTR);
|
|
|
|
case STATUS_BUFFER_OVERFLOW:
|
|
case STATUS_INVALID_BUFFER_SIZE:
|
|
return (-EMSGSIZE);
|
|
|
|
case STATUS_ADDRESS_ALREADY_EXISTS:
|
|
return (-EADDRINUSE);
|
|
}
|
|
|
|
if (NT_SUCCESS (Status))
|
|
return 0;
|
|
|
|
return (-EINVAL);
|
|
}
|
|
|
|
NTSTATUS Ext2WinntError(int rc)
|
|
{
|
|
switch (rc) {
|
|
|
|
case 0:
|
|
return STATUS_SUCCESS;
|
|
|
|
case -EPERM:
|
|
case -EACCES:
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
case -ENOENT:
|
|
return STATUS_OBJECT_NAME_NOT_FOUND;
|
|
|
|
case -EFAULT:
|
|
return STATUS_ACCESS_VIOLATION;
|
|
|
|
case -ETOOSMALL:
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
|
|
case -EBADMSG:
|
|
case -EBADF:
|
|
case -EINVAL:
|
|
case -EFBIG:
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
case -EBUSY:
|
|
return STATUS_DEVICE_BUSY;
|
|
|
|
case -ENOSYS:
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
case -ENOSPC:
|
|
return STATUS_DISK_FULL;
|
|
|
|
case -EOPNOTSUPP:
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
case -EDEADLK:
|
|
return STATUS_POSSIBLE_DEADLOCK;
|
|
|
|
case -EEXIST:
|
|
return STATUS_OBJECT_NAME_COLLISION;
|
|
|
|
case -EIO:
|
|
return STATUS_UNEXPECTED_IO_ERROR;
|
|
|
|
case -ENOTDIR:
|
|
return STATUS_NOT_A_DIRECTORY;
|
|
|
|
case -EISDIR:
|
|
return STATUS_FILE_IS_A_DIRECTORY;
|
|
|
|
case -ENOTEMPTY:
|
|
return STATUS_DIRECTORY_NOT_EMPTY;
|
|
|
|
case -ENODEV:
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
|
|
case -ENXIO:
|
|
return STATUS_INVALID_ADDRESS;
|
|
|
|
case -EADDRNOTAVAIL:
|
|
return STATUS_INVALID_ADDRESS;
|
|
|
|
case -ENETDOWN:
|
|
return STATUS_UNEXPECTED_NETWORK_ERROR;
|
|
|
|
case -ENETUNREACH:
|
|
return STATUS_NETWORK_UNREACHABLE;
|
|
|
|
case -ECONNABORTED:
|
|
return STATUS_CONNECTION_ABORTED;
|
|
|
|
case -ECONNRESET:
|
|
return STATUS_CONNECTION_RESET;
|
|
|
|
case -ENOMEM:
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
case -ENOBUFS:
|
|
return STATUS_NO_MEMORY;
|
|
|
|
case -ENOTCONN:
|
|
return STATUS_INVALID_CONNECTION;
|
|
|
|
case -ESHUTDOWN:
|
|
return STATUS_CONNECTION_DISCONNECTED;
|
|
|
|
case -ETIMEDOUT:
|
|
return STATUS_TIMEOUT;
|
|
|
|
case -ECONNREFUSED:
|
|
return STATUS_CONNECTION_REFUSED;
|
|
|
|
case -EHOSTUNREACH:
|
|
return STATUS_HOST_UNREACHABLE;
|
|
|
|
case -EAGAIN:
|
|
return STATUS_CANT_WAIT;
|
|
|
|
case -EINTR:
|
|
return STATUS_CANCELLED;
|
|
|
|
case -EMSGSIZE:
|
|
return STATUS_INVALID_BUFFER_SIZE;
|
|
|
|
case -EADDRINUSE:
|
|
return STATUS_ADDRESS_ALREADY_EXISTS;
|
|
}
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
BOOLEAN Ext2IsDot(PUNICODE_STRING name)
|
|
{
|
|
return (name->Length == 2 && name->Buffer[0] == L'.');
|
|
}
|
|
|
|
BOOLEAN Ext2IsDotDot(PUNICODE_STRING name)
|
|
{
|
|
return (name->Length == 4 && name->Buffer[0] == L'.' &&
|
|
name->Buffer[1] == L'.');
|
|
}
|