Tesla.Angela 发表于 2014-7-17 10:29:14

编码技巧系列之一:抄代码的艺术

最近需要把一个工程从用WIN32API转换到用NATIVE API实现,可惜我在把CreateFile变成NtCreateFile的时候卡壳了。不过我可没什么时间慢慢来调试,直接祭出“屌爆绝招”之一:抄代码。

说起抄代码,其实这事我也做了不少了,不过以前都是抄所谓大牛的代码,抄了还被人喷(其实我心里想:抄你代码是看得起你)。而这次,我直接抄一个国外开源工程的代码:ReactOS。ReactOS是一个山寨操作系统,它的历史什么的我就不讲了,只说它的官网是www.reactos.org,感兴趣的请自己去看。

下面贴出我修改好的山寨版CreateFileW,加上NTDLL.LIB和NTDLL.H可以直接使用:
HANDLE MyCreateFileW
(
        LPCTSTR lpFileName,
        DWORD dwDesiredAccess,
        DWORD dwShareMode,
        LPSECURITY_ATTRIBUTES lpSecurityAttributes,
        DWORD dwCreationDisposition,
        DWORD dwFlagsAndAttributes,
        HANDLE hTemplateFile
)
{

        PVOID BaseAddr;
        OBJECT_ATTRIBUTES ObjectAttributes;
        IO_STATUS_BLOCK IoStatusBlock;
        UNICODE_STRING NtPathU;
        HANDLE FileHandle;
        NTSTATUS Status;
        ULONG FileAttributes, Flags = 0;
        PVOID EaBuffer = NULL;
        ULONG EaLength = 0;

        if (!lpFileName || !lpFileName)
        {
                SetLastError( ERROR_PATH_NOT_FOUND );
                return INVALID_HANDLE_VALUE;
        }

        //TRACE("CreateFileW(lpFileName %S)\n",lpFileName);
        //MessageBoxW(0,lpFileName,0,0);

        /* validate & translate the creation disposition */
        switch (dwCreationDisposition)
        {
        case CREATE_NEW:
                dwCreationDisposition = FILE_CREATE;
                break;

        case CREATE_ALWAYS:
                dwCreationDisposition = FILE_OVERWRITE_IF;
                break;

        case OPEN_EXISTING:
                dwCreationDisposition = FILE_OPEN;
                break;

        case OPEN_ALWAYS:
                dwCreationDisposition = FILE_OPEN_IF;
                break;

        case TRUNCATE_EXISTING:
                dwCreationDisposition = FILE_OVERWRITE;
                break;

        default:
                SetLastError(ERROR_INVALID_PARAMETER);
                return (INVALID_HANDLE_VALUE);
        }

        /* validate & translate the flags */

        /* translate the flags that need no validation */
        if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
        {
                /* yes, nonalert is correct! apc's are not delivered
                while waiting for file io to complete */
                Flags |= FILE_SYNCHRONOUS_IO_NONALERT;
        }

        if(dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
                Flags |= FILE_WRITE_THROUGH;

        if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
                Flags |= FILE_NO_INTERMEDIATE_BUFFERING;

        if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
                Flags |= FILE_RANDOM_ACCESS;

        if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
                Flags |= FILE_SEQUENTIAL_ONLY;

        if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
                Flags |= FILE_DELETE_ON_CLOSE;

        if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
        {
                if(dwDesiredAccess & GENERIC_ALL)
                        Flags |= FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REMOTE_INSTANCE;
                else
                {
                        if(dwDesiredAccess & GENERIC_READ)
                                Flags |= FILE_OPEN_FOR_BACKUP_INTENT;

                        if(dwDesiredAccess & GENERIC_WRITE)
                                Flags |= FILE_OPEN_REMOTE_INSTANCE;
                }
        }
        else
                Flags |= FILE_NON_DIRECTORY_FILE;

        if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
                Flags |= FILE_OPEN_REPARSE_POINT;

        if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
                Flags |= FILE_OPEN_NO_RECALL;

        FileAttributes = (dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY));

        /* handle may allways be waited on and querying attributes are allways allowed */
        dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;

        /* FILE_FLAG_POSIX_SEMANTICS is handled later */

        /* validate & translate the filename */
        if (!RtlDosPathNameToNtPathName_U ((PWSTR)lpFileName,
                &NtPathU,
                NULL,
                NULL))
        {
                //MessageBoxA(0,"Invalid path\n",0,0);
                SetLastError(ERROR_FILE_NOT_FOUND);
                return INVALID_HANDLE_VALUE;
        }

        //MessageBoxW(0,NtPathU.Buffer,0,0);
        //TRACE("NtPathU \'%wZ\'\n", &NtPathU);


        if (hTemplateFile != NULL)
        {
                FILE_EA_INFORMATION EaInformation;

                for (;;)
                {
                        /* try to get the size of the extended attributes, if we fail just continue
                        creating the file without copying the attributes! */
                        Status = NtQueryInformationFile(hTemplateFile,
                                &IoStatusBlock,
                                &EaInformation,
                                sizeof(FILE_EA_INFORMATION),
                                FileEaInformation);
                        if (NT_SUCCESS(Status) && (EaInformation.EaSize != 0))
                        {
                                /* there's extended attributes to read, let's give it a try */
                                /*EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
                                0,
                                EaInformation.EaSize);*/
                                EaBuffer = malloc(EaInformation.EaSize);

                                if (EaBuffer == NULL)
                                {
                                        /*RtlFreeHeap(RtlGetProcessHeap(),
                                        0,
                                        NtPathU.Buffer);*/
                                        BaseAddr=NtPathU.Buffer;
                                        RtlFreeUnicodeString(&NtPathU);

                                        /* the template file handle is valid and has extended attributes,
                                        however we seem to lack some memory here. We should fail here! */
                                        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                                        return INVALID_HANDLE_VALUE;
                                }

                                Status = NtQueryEaFile(hTemplateFile,
                                        &IoStatusBlock,
                                        EaBuffer,
                                        EaInformation.EaSize,
                                        FALSE,
                                        NULL,
                                        0,
                                        NULL,
                                        TRUE);

                                if (NT_SUCCESS(Status))
                                {
                                        /* we successfully read the extended attributes, break the loop
                                        and continue */
                                        EaLength = EaInformation.EaSize;
                                        break;
                                }
                                else
                                {
                                        /*RtlFreeHeap(RtlGetProcessHeap(),
                                        0,
                                        EaBuffer);*/
                                        free(EaBuffer);
                                        EaBuffer = NULL;

                                        if (Status != STATUS_BUFFER_TOO_SMALL)
                                        {
                                                /* unless we just allocated not enough memory, break the loop
                                                and just continue without copying extended attributes */
                                                break;
                                        }
                                }
                        }
                        else
                        {
                                /* we either failed to get the size of the extended attributes or
                                they're empty, just continue as there's no need to copy
                                attributes */
                                break;
                        }
                }
        }

        /* build the object attributes */
        InitializeObjectAttributes(&ObjectAttributes,
                &NtPathU,
                0,
                NULL,
                NULL);

        if (lpSecurityAttributes)
        {
                if(lpSecurityAttributes->bInheritHandle)
                        ObjectAttributes.Attributes |= OBJ_INHERIT;

                ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
        }

        if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS))
                ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;

        /* perform the call */
        Status = NtCreateFile (&FileHandle,
                dwDesiredAccess,
                &ObjectAttributes,
                &IoStatusBlock,
                NULL,
                FileAttributes,
                dwShareMode,
                dwCreationDisposition,
                Flags,
                EaBuffer,
                EaLength);

        //RtlFreeHeap(RtlGetProcessHeap(),
        //            0,
        //            NtPathU.Buffer);
        BaseAddr=NtPathU.Buffer;
        RtlFreeUnicodeString(&NtPathU);

        /* free the extended attributes buffer if allocated */
        if (EaBuffer != NULL)
        {
                //RtlFreeHeap(RtlGetProcessHeap(),
                //            0,
                //            EaBuffer);
                BaseAddr=EaBuffer;
                free(EaBuffer);
        }

        /* error */
        if (!NT_SUCCESS(Status))
        {
                /* In the case file creation was rejected due to CREATE_NEW flag
                * was specified and file with that name already exists, correct
                * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
                * Note: RtlNtStatusToDosError is not the subject to blame here.
                */
                if (Status == STATUS_OBJECT_NAME_COLLISION &&
                        dwCreationDisposition == FILE_CREATE)
                {
                        SetLastError( ERROR_FILE_EXISTS );
                }
                else
                {
                        //BaseSetLastNTError (Status);
                        SetLastError(RtlNtStatusToDosError(Status));
                }

                return INVALID_HANDLE_VALUE;
        }

        /*
        create with OPEN_ALWAYS (FILE_OPEN_IF) returns info = FILE_OPENED or FILE_CREATED
        create with CREATE_ALWAYS (FILE_OVERWRITE_IF) returns info = FILE_OVERWRITTEN or FILE_CREATED
        */
        if (dwCreationDisposition == FILE_OPEN_IF)
        {
                SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
        }
        else if (dwCreationDisposition == FILE_OVERWRITE_IF)
        {
                SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
        }
        else
        {
                SetLastError(ERROR_SUCCESS);
        }

        return FileHandle;
}

ugvjewxf 发表于 2014-7-17 13:56:55

能抄当然抄了{:soso_e113:}
页: [1]
查看完整版本: 编码技巧系列之一:抄代码的艺术