windows-nt/Source/XPSP1/NT/base/pnp/setupapi/sputils/fileutil.c
2020-09-26 16:20:57 +08:00

480 lines
11 KiB
C

/*++
Copyright (c) 1993-2000 Microsoft Corporation
Module Name:
fileutil.c
Abstract:
File-related functions for SPUTILS
Author:
Ted Miller (tedm) 11-Jan-1995
Revision History:
Jamie Hunter (JamieHun) Jun-27-2000
Moved various functions out of setupapi
--*/
#include "precomp.h"
#pragma hdrstop
DWORD
pSetupOpenAndMapFileForRead(
IN PCTSTR FileName,
OUT PDWORD FileSize,
OUT PHANDLE FileHandle,
OUT PHANDLE MappingHandle,
OUT PVOID *BaseAddress
)
/*++
Routine Description:
Open and map an existing file for read access.
Arguments:
FileName - supplies pathname to file to be mapped.
FileSize - receives the size in bytes of the file.
FileHandle - receives the win32 file handle for the open file.
The file will be opened for generic read access.
MappingHandle - receives the win32 handle for the file mapping
object. This object will be for read access.
BaseAddress - receives the address where the file is mapped.
Return Value:
NO_ERROR if the file was opened and mapped successfully.
The caller must unmap the file with pSetupUnmapAndCloseFile when
access to the file is no longer desired.
Win32 error code if the file was not successfully mapped.
--*/
{
DWORD rc;
//
// Open the file -- fail if it does not exist.
//
*FileHandle = CreateFile(
FileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if(*FileHandle == INVALID_HANDLE_VALUE) {
rc = GetLastError();
} else if((rc = pSetupMapFileForRead(*FileHandle,
FileSize,
MappingHandle,
BaseAddress)) != NO_ERROR) {
CloseHandle(*FileHandle);
}
return(rc);
}
#ifndef SPUTILSW
DWORD
pSetupMapFileForRead(
IN HANDLE FileHandle,
OUT PDWORD FileSize,
OUT PHANDLE MappingHandle,
OUT PVOID *BaseAddress
)
/*++
Routine Description:
Map an opened file for read access.
Arguments:
FileHandle - supplies the handle of the opened file to be mapped.
This handle must have been opened with at least read access.
FileSize - receives the size in bytes of the file.
MappingHandle - receives the win32 handle for the file mapping
object. This object will be for read access.
BaseAddress - receives the address where the file is mapped.
Return Value:
NO_ERROR if the file was mapped successfully. The caller must
unmap the file with pSetupUnmapAndCloseFile when access to the file
is no longer desired.
Win32 error code if the file was not successfully mapped.
--*/
{
DWORD rc;
//
// Get the size of the file.
//
*FileSize = GetFileSize(FileHandle, NULL);
if(*FileSize != (DWORD)(-1)) {
//
// Create file mapping for the whole file.
//
*MappingHandle = CreateFileMapping(
FileHandle,
NULL,
PAGE_READONLY,
0,
*FileSize,
NULL
);
if(*MappingHandle) {
//
// Map the whole file.
//
*BaseAddress = MapViewOfFile(
*MappingHandle,
FILE_MAP_READ,
0,
0,
*FileSize
);
if(*BaseAddress) {
return(NO_ERROR);
}
rc = GetLastError();
CloseHandle(*MappingHandle);
} else {
rc = GetLastError();
}
} else {
rc = GetLastError();
}
return(rc);
}
BOOL
pSetupUnmapAndCloseFile(
IN HANDLE FileHandle,
IN HANDLE MappingHandle,
IN PVOID BaseAddress
)
/*++
Routine Description:
Unmap and close a file.
Arguments:
FileHandle - supplies win32 handle to open file.
MappingHandle - supplies the win32 handle for the open file mapping
object.
BaseAddress - supplies the address where the file is mapped.
Return Value:
BOOLean value indicating success or failure.
--*/
{
BOOL b;
b = UnmapViewOfFile(BaseAddress);
b = b && CloseHandle(MappingHandle);
b = b && CloseHandle(FileHandle);
return(b);
}
#endif //!SPUTILSW
BOOL
pSetupFileExists(
IN PCTSTR FileName,
OUT PWIN32_FIND_DATA FindData OPTIONAL
)
/*++
Routine Description:
Determine if a file exists and is accessible.
Errormode is set (and then restored) so the user will not see
any pop-ups.
Arguments:
FileName - supplies full path of file to check for existance.
FindData - if specified, receives find data for the file.
Return Value:
TRUE if the file exists and is accessible.
FALSE if not. GetLastError() returns extended error info.
--*/
{
WIN32_FIND_DATA findData;
HANDLE FindHandle;
UINT OldMode;
DWORD Error;
OldMode = SetErrorMode(SEM_FAILCRITICALERRORS);
FindHandle = FindFirstFile(FileName,&findData);
if(FindHandle == INVALID_HANDLE_VALUE) {
Error = GetLastError();
} else {
FindClose(FindHandle);
if(FindData) {
*FindData = findData;
}
Error = NO_ERROR;
}
SetErrorMode(OldMode);
SetLastError(Error);
return (Error == NO_ERROR);
}
DWORD
pSetupMakeSurePathExists(
IN PCTSTR FullFilespec
)
/*++
Routine Description:
This routine ensures that a multi-level path exists by creating individual
levels one at a time. It is assumed that the caller will pass in a *filename*
whose path needs to exist. Some examples:
c:\x - C:\ is assumes to always exist.
c:\x\y\z - Ensure that c:\x\y exists.
\x\y\z - \x\y on current drive
x\y - x in current directory
d:x\y - d:x
\\server\share\p\file - \\server\share\p
\\?\GLOBALROOT\a\b\c - other more weird scenarios
\\?\C:\a\b\c
Arguments:
FullFilespec - supplies the *filename* of a file that the caller wants to
create. This routine creates the *path* to that file, in other words,
the final component is assumed to be a filename, and is not a
directory name. (This routine doesn't actually create this file.)
If this is invalid, then the results are undefined (for example,
passing \\server\share, C:\, or C:).
Return Value:
Win32 error code indicating outcome. If FullFilespec is invalid,
*may* return ERROR_INVALID_NAME.
--*/
{
TCHAR Buffer[MAX_PATH+2];
TCHAR c;
PTSTR filename;
PTSTR root;
PTSTR last;
PTSTR backtrack;
DWORD len;
DWORD attrib;
//
// normalize path
//
len = GetFullPathName(FullFilespec,MAX_PATH,Buffer,&filename);
if(len >= MAX_PATH) {
//
// directory name is longer than we can handle
//
return ERROR_INVALID_NAME;
}
if(!len) {
//
// other error
//
return GetLastError();
}
if(filename == NULL || filename == Buffer) {
//
// looks like no path specified
//
return ERROR_INVALID_NAME;
}
//
// chop off filename part
//
filename[0] = TEXT('\0');
//
// now do some other sanity checks
// to determine 'root' - a point we wont try to create
//
if(Buffer[0] && Buffer[1] == TEXT(':')) {
//
// looks like "d:" format
//
if(Buffer[2] != TEXT('\\')) {
return ERROR_INVALID_NAME;
}
root = Buffer+2;
}
if(Buffer[0] == TEXT('\\') &&
Buffer[1] == TEXT('\\')) {
//
// UNC style (\\machine\share\path \\?\d\path \\?\GLOBALROOT\path \\.\GLOBALROOT\path etc)
// root is 2nd slash after \\
//
root = _tcschr(Buffer+2,TEXT('\\')); // find first slash
if(root) {
root = _tcschr(root+1,TEXT('\\')); // find 2nd slash
}
if(!root) {
return ERROR_INVALID_NAME;
}
}
//
// see if the directory specified exists
// include the slash, since that helps scenarios like \\?\GLOBALROOT\Device\HarddiskVolume1\
// and works for all the other scenarios
// can't use findfirst/findnext though
//
attrib = GetFileAttributes(Buffer);
if(attrib != (DWORD)(-1)) {
if(attrib & FILE_ATTRIBUTE_DIRECTORY) {
//
// requested directory already exists
//
return NO_ERROR;
}
//
// directory was expected
//
return ERROR_DIRECTORY;
}
//
// now we have to step backwards until we find an existing directory
// change all '\' to nulls as we do so
// this will give us something like (c esc form) c:\\a\\b\\c\0d\0e\0f\0\0
// we know the last \0 is there from when we chopped filename
// first directory to be created is c:\\a\\b\\c
//
last = CharPrev(Buffer,filename); // to last slash
if(last == root) {
return ERROR_INVALID_NAME;
}
if(*last != TEXT('\\')) {
//
// should never be the case
//
return ERROR_INVALID_NAME;
}
while(last > root) {
*last = TEXT('\0');
backtrack = _tcsrchr(Buffer,TEXT('\\'));
if(!backtrack) {
return ERROR_INVALID_NAME;
}
c = backtrack[1];
backtrack[1] = TEXT('\0');
attrib = GetFileAttributes(Buffer); // does this part exist?
backtrack[1] = c; // but character back
if(attrib != (DWORD)(-1)) {
if(attrib & FILE_ATTRIBUTE_DIRECTORY) {
//
// requested directory already exists
// 'last' points to first NULL to replace to slash
// Buffer contains first directory to create
//
break;
}
//
// directory was expected
//
return ERROR_DIRECTORY;
}
//
// keep going
//
last = backtrack;
}
if(last <= root) {
return ERROR_INVALID_NAME;
}
//
// now begin create loop
//
while(CreateDirectory(Buffer,NULL)) {
if(!last[1]) {
//
// path created
//
return NO_ERROR;
}
last[0] = TEXT('\\');
last += lstrlen(last);
}
//
// failed for some other reason
//
return GetLastError();
}