|
|
#define UNICODE
#define _UNICODE
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <tchar.h>
#include "compdir.h"
#define SHARE_ALL (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)
#define lstrchr wcschr
typedef VOID (*RtlFreeUnicodeStringFunction)(); typedef ULONG (*RtlNtStatusToDosErrorFunction)(); typedef NTSTATUS (*NtCloseFunction)(); typedef NTSTATUS (*NtSetInformationFileFunction)(); typedef VOID (*RtlInitUnicodeStringFunction)(); typedef NTSTATUS (*NtOpenFileFunction)(); typedef BOOLEAN (*RtlCreateUnicodeStringFromAsciizFunction)(); typedef NTSTATUS (*NtQueryInformationFileFunction)(); typedef NTSTATUS (*NtFsControlFileFunction)(); typedef NTSTATUS (*RtlDosPathNameToNtPathName_UFunction)();
RtlFreeUnicodeStringFunction CDRtlFreeUnicodeString; RtlNtStatusToDosErrorFunction CDRtlNtStatusToDosError; NtCloseFunction CDNtClose; NtSetInformationFileFunction CDNtSetInformationFile; RtlInitUnicodeStringFunction CDRtlInitUnicodeString; NtOpenFileFunction CDNtOpenFile; RtlCreateUnicodeStringFromAsciizFunction CDRtlCreateUnicodeStringFromAsciiz; NtQueryInformationFileFunction CDNtQueryInformationFile; NtFsControlFileFunction CDNtFsControlFile; RtlDosPathNameToNtPathName_UFunction CDRtlDosPathNameToNtPathName_U;
BOOL InitializeNtDllFunctions() { CDRtlFreeUnicodeString = (RtlFreeUnicodeStringFunction) GetProcAddress( NtDll, "RtlFreeUnicodeString"); if (CDRtlFreeUnicodeString == NULL) return FALSE; CDRtlNtStatusToDosError = (RtlNtStatusToDosErrorFunction) GetProcAddress( NtDll, "RtlNtStatusToDosError"); if (CDRtlNtStatusToDosError == NULL) return FALSE; CDNtClose = (NtCloseFunction) GetProcAddress( NtDll, "NtClose"); if (CDNtClose == NULL) return FALSE; CDNtSetInformationFile = (NtSetInformationFileFunction) GetProcAddress( NtDll, "NtSetInformationFile"); if (CDNtSetInformationFile == NULL) return FALSE; CDRtlInitUnicodeString = (RtlInitUnicodeStringFunction) GetProcAddress( NtDll, "RtlInitUnicodeString"); if (CDRtlInitUnicodeString == NULL) return FALSE; CDNtOpenFile = (NtOpenFileFunction) GetProcAddress( NtDll, "NtOpenFile"); if (CDNtOpenFile == NULL) return FALSE; CDRtlCreateUnicodeStringFromAsciiz = (RtlCreateUnicodeStringFromAsciizFunction) GetProcAddress( NtDll, "RtlCreateUnicodeStringFromAsciiz"); if (CDRtlCreateUnicodeStringFromAsciiz == NULL) return FALSE; CDNtQueryInformationFile = (NtQueryInformationFileFunction) GetProcAddress( NtDll, "NtQueryInformationFile"); if (CDNtQueryInformationFile == NULL) return FALSE; CDNtFsControlFile = (NtFsControlFileFunction)GetProcAddress( NtDll, "NtFsControlFile"); if (CDNtFsControlFile == NULL) return FALSE; CDRtlDosPathNameToNtPathName_U = (RtlDosPathNameToNtPathName_UFunction)GetProcAddress( NtDll, "RtlDosPathNameToNtPathName_U"); if (CDRtlDosPathNameToNtPathName_U == NULL) return FALSE; return TRUE; }
BOOL MakeLink( char *src, char *dst, BOOL Output) { WCHAR OldNameBuf[MAX_PATH + 50]; WCHAR NewNameBuf[MAX_PATH + 50];
HANDLE FileHandle, NewFileHandle, RootDirHandle;
NTSTATUS Status; IO_STATUS_BLOCK Iosb; OBJECT_ATTRIBUTES Obj;
PFILE_LINK_INFORMATION pLinkInfo;
UNICODE_STRING u, uRel;
WCHAR *pch, ch; UNICODE_STRING uOldName; UNICODE_STRING uNewName;
UNICODE_STRING uSrc, uDst;
(CDRtlCreateUnicodeStringFromAsciiz)( &uSrc, src); (CDRtlCreateUnicodeStringFromAsciiz)( &uDst, dst);
lstrcpy( OldNameBuf, L"\\??\\"); lstrcat( OldNameBuf, uSrc.Buffer); (CDRtlInitUnicodeString)( &uOldName, OldNameBuf);
lstrcpy( NewNameBuf, L"\\??\\"); lstrcat( NewNameBuf, uDst.Buffer); (CDRtlInitUnicodeString)( &uNewName, NewNameBuf);
//
// Open the existing pathname.
//
InitializeObjectAttributes( &Obj, &uOldName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = (CDNtOpenFile)( &FileHandle, SYNCHRONIZE, &Obj, &Iosb, SHARE_ALL, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
if ( !NT_SUCCESS( Status)) { SetLastError( ( CDRtlNtStatusToDosError)( Status)); if ( Output) { fprintf( stderr, "Could not open %s", src); } return FALSE; }
//
// Now we need to get a handle on the root directory of the 'new'
// pathname; we'll pass that in the link information, and the
// rest of the path will be given relative to the root. We
// depend on paths looking like "\DosDevices\X:\path".
//
pch = lstrchr( uNewName.Buffer + 1, '\\'); ASSERT( NULL != pch); pch = lstrchr( pch + 1, '\\'); if (!pch) { SetLastError(ERROR_INVALID_PARAMETER); if ( Output) { fprintf( stderr, "Invalid path %S", uNewName.Buffer); } return FALSE; } ch = pch[1]; pch[1] = '\0'; uNewName.Length = (USHORT)(lstrlen( uNewName.Buffer) * sizeof( WCHAR));
InitializeObjectAttributes( &Obj, &uNewName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = (CDNtOpenFile)( &RootDirHandle, SYNCHRONIZE, &Obj, &Iosb, SHARE_ALL, FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
pch[1] = ch;
if ( !NT_SUCCESS( Status)) { SetLastError( (CDRtlNtStatusToDosError)( Status)); if ( Output) { fprintf( stderr, "Could not get directory handle for %s", dst); } return FALSE; }
//
// Now get the path relative to the root.
//
(CDRtlInitUnicodeString)( &uRel, &pch[1]);
pLinkInfo = _alloca( sizeof( *pLinkInfo) + uRel.Length); if ( NULL == pLinkInfo) { (CDNtClose)( RootDirHandle); (CDNtClose)( FileHandle); SetLastError( ERROR_NOT_ENOUGH_MEMORY); return FALSE; }
RtlMoveMemory( pLinkInfo->FileName, uRel.Buffer, uRel.Length); pLinkInfo->FileNameLength = uRel.Length;
pLinkInfo->ReplaceIfExists = TRUE; pLinkInfo->RootDirectory = RootDirHandle;
Status = (CDNtSetInformationFile)( FileHandle, &Iosb, pLinkInfo, sizeof( *pLinkInfo) + uRel.Length, FileLinkInformation);
// If file is already linked to an open file try to delete it
if ( Status == STATUS_ACCESS_DENIED) { _unlink( dst); Status = (CDNtSetInformationFile)( FileHandle, &Iosb, pLinkInfo, sizeof( *pLinkInfo) + uRel.Length, FileLinkInformation); }
(CDNtClose)( RootDirHandle); (CDNtClose)( FileHandle);
if ( !NT_SUCCESS( Status)) { SetLastError( (CDRtlNtStatusToDosError)( Status)); if ( Output) { fprintf( stderr, "Could not create link for %s", dst); } return FALSE; }
(CDRtlFreeUnicodeString)( &uSrc); (CDRtlFreeUnicodeString)( &uDst);
return TRUE;
}
int NumberOfLinks( char *FileName) {
FILE_STANDARD_INFORMATION FileInfo;
WCHAR FileNameBuf[MAX_PATH + 50];
HANDLE FileHandle;
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
OBJECT_ATTRIBUTES Obj;
UNICODE_STRING uPrelimFileName, uFileName;
(CDRtlCreateUnicodeStringFromAsciiz)( &uPrelimFileName, FileName);
lstrcpy( FileNameBuf, L"\\??\\"); lstrcat( FileNameBuf, uPrelimFileName.Buffer); (CDRtlInitUnicodeString)( &uFileName, FileNameBuf);
InitializeObjectAttributes( &Obj, &uFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = (CDNtOpenFile)( &FileHandle, SYNCHRONIZE, &Obj, &Iosb, SHARE_ALL, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
if ( !NT_SUCCESS( Status)) { SetLastError( (CDRtlNtStatusToDosError)( Status)); return 0; }
Status = (CDNtQueryInformationFile)( FileHandle, &Iosb, &FileInfo, sizeof( FileInfo), FileStandardInformation);
(CDNtClose)( FileHandle);
if ( !NT_SUCCESS( Status)) { SetLastError( (CDRtlNtStatusToDosError)( Status)); return 0; }
return FileInfo.NumberOfLinks;
}
BOOL SisCopyFile( LPCSTR lpExistingFileName, LPCSTR lpNewFileName, BOOL bFailIfExists, LPBOOL fTrySis ) { BOOL ok; DWORD err; NTSTATUS Status; HANDLE volHandle; UNICODE_STRING srcFileName, dstFileName; UNICODE_STRING srcDosFileName, dstDosFileName; PSI_COPYFILE copyFile; UCHAR Buffer[(sizeof(SI_COPYFILE) + MAX_PATH * 2) * sizeof(WCHAR)]; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatusBlock; int i;
copyFile = (PSI_COPYFILE)Buffer;
srcFileName.Buffer = NULL; dstFileName.Buffer = NULL; srcDosFileName.Buffer = NULL; srcDosFileName.Buffer = NULL;
//
// Convert the ansii names to unicode and place in the copyFile buffer.
//
ok = CDRtlCreateUnicodeStringFromAsciiz( &srcDosFileName, lpExistingFileName ); if (!ok) { return FALSE; } ok = CDRtlDosPathNameToNtPathName_U( srcDosFileName.Buffer, &srcFileName, NULL, NULL ); if (!ok) { goto error; } CDRtlFreeUnicodeString( &srcDosFileName );
ok = CDRtlCreateUnicodeStringFromAsciiz( &dstDosFileName, lpNewFileName ); if (!ok) { goto error; } ok = CDRtlDosPathNameToNtPathName_U( dstDosFileName.Buffer, &dstFileName, NULL, NULL ); if (!ok) { goto error; } CDRtlFreeUnicodeString( &dstDosFileName );
copyFile->SourceFileNameLength = srcFileName.Length + sizeof(WCHAR); copyFile->DestinationFileNameLength = dstFileName.Length + sizeof(WCHAR); copyFile->Flags = bFailIfExists ? 0 : COPYFILE_SIS_REPLACE;
RtlCopyMemory( ©File->FileNameBuffer[0], srcFileName.Buffer, copyFile->SourceFileNameLength);
RtlCopyMemory( ©File->FileNameBuffer[copyFile->SourceFileNameLength / sizeof(WCHAR)], dstFileName.Buffer, copyFile->DestinationFileNameLength);
CDRtlFreeUnicodeString( &dstFileName );
#define copyFileSize (FIELD_OFFSET(SI_COPYFILE, FileNameBuffer) + \
copyFile->SourceFileNameLength + \ copyFile->DestinationFileNameLength)
//
// Get a handle to the source file's containing directory to pass into
// FSCTL_SIS_COPYFILE,
//
for (i = srcFileName.Length / sizeof(WCHAR) - 1; i >= 0 && srcFileName.Buffer[i] != '\\'; --i) continue;
srcFileName.Length = (USHORT)(i * sizeof(WCHAR));
InitializeObjectAttributes( &objectAttributes, &srcFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
//
// Need to use NtOpenFile because Win32 doesn't let you open a directory.
//
Status = CDNtOpenFile( &volHandle, GENERIC_READ | SYNCHRONIZE, &objectAttributes, &ioStatusBlock, SHARE_ALL, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
CDRtlFreeUnicodeString( &srcFileName );
if (!NT_SUCCESS(Status)) { SetLastError(CDRtlNtStatusToDosError(Status)); return FALSE; }
//
// Invoke the SIS CopyFile FsCtrl.
//
Status = CDNtFsControlFile( volHandle, NULL, NULL, NULL, &ioStatusBlock, FSCTL_SIS_COPYFILE, copyFile, // Input buffer
copyFileSize, // Input buffer length
NULL, // Output buffer
0 ); // Output buffer length
CloseHandle( volHandle );
if (NT_SUCCESS( Status )) { return TRUE; }
if ((Status == STATUS_INVALID_DEVICE_REQUEST) || (Status == STATUS_INVALID_PARAMETER)) { *fTrySis = FALSE; }
SetLastError(CDRtlNtStatusToDosError(Status)); return FALSE;
error:
err = GetLastError();
CDRtlFreeUnicodeString( &srcDosFileName ); CDRtlFreeUnicodeString( &dstDosFileName ); CDRtlFreeUnicodeString( &srcFileName ); CDRtlFreeUnicodeString( &dstDosFileName );
SetLastError(err);
return FALSE; }
|