|
|
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
copy.c
Abstract:
This module implements the file copy command.
Author:
Wesley Witt (wesw) 21-Oct-1998
Revision History:
--*/
#include "cmdcons.h"
#pragma hdrstop
BOOLEAN NoCopyPrompt; BOOLEAN AllowRemovableMedia;
NTSTATUS pRcGetDeviceInfo( IN PWSTR FileName, // must be an nt name
IN PFILE_FS_DEVICE_INFORMATION DeviceInfo ) { BOOLEAN Removable = FALSE; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING UnicodeString; HANDLE Handle; OBJECT_ATTRIBUTES Obja; NTSTATUS Status; PWSTR DeviceName; PWSTR s;
//
// get the device name from the file name
//
DeviceName = SpDupStringW( FileName ); if (DeviceName == NULL) { return STATUS_OBJECT_PATH_INVALID; }
s = wcschr(DeviceName+1,L'\\'); if (!s) { return STATUS_OBJECT_PATH_INVALID; } s = wcschr(s+1,L'\\'); if (s) { *s = 0; }
INIT_OBJA(&Obja,&UnicodeString,DeviceName);
Status = ZwCreateFile( &Handle, FILE_GENERIC_READ | SYNCHRONIZE, &Obja, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); SpMemFree(DeviceName); if(NT_SUCCESS(Status)) { Status = ZwQueryVolumeInformationFile( Handle, &IoStatusBlock, DeviceInfo, sizeof(FILE_FS_DEVICE_INFORMATION), FileFsDeviceInformation ); ZwClose(Handle); }
return Status; }
NTSTATUS RcIsFileOnRemovableMedia( IN PWSTR FileName, // must be an nt name
OUT PBOOLEAN Result ) { NTSTATUS Status; FILE_FS_DEVICE_INFORMATION DeviceInfo;
Status = pRcGetDeviceInfo( FileName, &DeviceInfo ); *Result = NT_SUCCESS(Status) && (DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA) != 0; return Status; }
NTSTATUS RcIsFileOnCDROM( IN PWSTR FileName // must be an nt name
) { NTSTATUS Status; FILE_FS_DEVICE_INFORMATION DeviceInfo;
Status = pRcGetDeviceInfo( FileName, &DeviceInfo ); if(NT_SUCCESS(Status)) { if (DeviceInfo.DeviceType != FILE_DEVICE_CD_ROM) { Status = STATUS_NO_MEDIA; } } return Status; }
NTSTATUS RcIsFileOnFloppy( IN PWSTR FileName // must be an nt name
) { NTSTATUS Status; FILE_FS_DEVICE_INFORMATION DeviceInfo;
Status = pRcGetDeviceInfo( FileName, &DeviceInfo ); if(NT_SUCCESS(Status)) { if ((DeviceInfo.Characteristics & FILE_FLOPPY_DISKETTE) == 0) { Status = STATUS_NO_MEDIA; } } return Status; }
BOOLEAN RcGetNTFileName( IN LPCWSTR DosPath, IN LPCWSTR NTPath ) { BOOLEAN bResult = FALSE; extern LPWSTR _NtDrivePrefixes[26]; WCHAR TempBuf[MAX_PATH*2]; ULONG len; ULONG len2; LPWSTR Prefix; PWSTR s = NULL;
Prefix = _NtDrivePrefixes[RcToUpper(DosPath[0])-L'A'];
if (!Prefix) { return bResult; }
GetDriveLetterLinkTarget((PWSTR)Prefix, &s);
if (s) { len = wcslen(s); len2 = wcslen(DosPath) - 2;
if (((len + len2) * sizeof(WCHAR)) < sizeof(TempBuf)){ RtlZeroMemory(TempBuf,sizeof(TempBuf)); RtlCopyMemory(TempBuf+len,DosPath+2,len2*sizeof(WCHAR)); RtlCopyMemory(TempBuf,s,len*sizeof(WCHAR));
TempBuf[len+len2] = 0;
wcscpy((PWSTR)NTPath,TempBuf); bResult = TRUE; } }
return bResult; }
ULONG RcCmdCopy( IN PTOKENIZED_LINE TokenizedLine ) { LPWSTR SrcFile; LPWSTR DstFile; LPWSTR SrcDosPath = NULL; LPWSTR SrcNtPath = NULL; LPWSTR DstDosPath = NULL; LPWSTR DstNtPath = NULL; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING UnicodeString; HANDLE Handle; OBJECT_ATTRIBUTES Obja; NTSTATUS Status; LPWSTR YesNo; WCHAR Text[3]; LPWSTR s; ULONG FileCount = 0; IO_STATUS_BLOCK status_block; FILE_BASIC_INFORMATION fileInfo; WCHAR * pos; ULONG CopyFlags = COPY_NOVERSIONCHECK; BOOLEAN OnRemovableMedia;
ASSERT(TokenizedLine->TokenCount >= 1);
if (RcCmdParseHelp( TokenizedLine, MSG_COPY_HELP )) { return 1; }
//
// create a good source & destination file name
//
if( TokenizedLine->TokenCount == 2 ) { SrcFile = TokenizedLine->Tokens->Next->String; DstFile = NULL; } else { SrcFile = TokenizedLine->Tokens->Next->String; DstFile = TokenizedLine->Tokens->Next->Next->String; }
if (RcDoesPathHaveWildCards(SrcFile)) { RcMessageOut(MSG_DIR_WILDCARD_NOT_SUPPORTED); goto exit; } //
// Canonicalize the name once to get a full DOS-style path
// we can print out, and another time to get the NT-style path
// we'll use to actually do the work.
//
if (!RcFormFullPath( SrcFile, _CmdConsBlock->TemporaryBuffer, FALSE )) { RcMessageOut(MSG_INVALID_PATH); return 1; }
if (!RcIsPathNameAllowed(_CmdConsBlock->TemporaryBuffer,TRUE,FALSE)) { RcMessageOut(MSG_ACCESS_DENIED); goto exit; }
SrcDosPath = SpDupStringW( _CmdConsBlock->TemporaryBuffer );
if (!RcFormFullPath( SrcFile, _CmdConsBlock->TemporaryBuffer, TRUE )) { RcMessageOut(MSG_INVALID_PATH); return 1; } SrcNtPath = SpDupStringW( _CmdConsBlock->TemporaryBuffer );
//
// see if the source file exists
//
INIT_OBJA( &Obja, &UnicodeString, SrcNtPath );
Status = ZwOpenFile( &Handle, FILE_READ_ATTRIBUTES, &Obja, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 );
if( NT_SUCCESS(Status) ) { // check to see if the destination is a directory
Status = ZwQueryInformationFile( Handle, &status_block, (PVOID)&fileInfo, sizeof( FILE_BASIC_INFORMATION ), FileBasicInformation );
ZwClose( Handle );
if( !NT_SUCCESS(Status) ) { // something went wrong
RcNtError( Status, MSG_CANT_COPY_FILE ); goto exit; }
if( fileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { RcMessageOut(MSG_DIR_WILDCARD_NOT_SUPPORTED); goto exit; } } else { RcMessageOut(MSG_FILE_NOT_FOUND2); goto exit; }
//
// create a destination file name when the user did not
// provide one. we use the source base file name and
// the current drive and directory.
//
if ((DstFile == NULL) || (wcscmp(DstFile, L".") == 0)) { s = wcsrchr( SrcDosPath, L'\\' ); if( s ) { RcGetCurrentDriveAndDir( _CmdConsBlock->TemporaryBuffer ); SpConcatenatePaths( _CmdConsBlock->TemporaryBuffer, s ); DstFile = SpDupStringW( _CmdConsBlock->TemporaryBuffer ); } else { RcMessageOut(MSG_INVALID_PATH); goto exit; } }
//
// create the destination paths
//
if (!RcFormFullPath( DstFile, _CmdConsBlock->TemporaryBuffer, FALSE )) { RcMessageOut(MSG_INVALID_PATH); return 1; }
if (!RcIsPathNameAllowed(_CmdConsBlock->TemporaryBuffer,FALSE,FALSE)) { RcMessageOut(MSG_ACCESS_DENIED); goto exit; }
DstDosPath = SpDupStringW( _CmdConsBlock->TemporaryBuffer );
if (!RcFormFullPath( DstFile, _CmdConsBlock->TemporaryBuffer, TRUE )) { RcMessageOut(MSG_INVALID_PATH); return 1; } DstNtPath = SpDupStringW( _CmdConsBlock->TemporaryBuffer );
//
// check for removable media
//
Status = RcIsFileOnRemovableMedia(DstNtPath, &OnRemovableMedia);
if (AllowRemovableMedia == FALSE && (!NT_SUCCESS(Status) || OnRemovableMedia)) { RcMessageOut(MSG_ACCESS_DENIED); goto exit; }
//
// see if the destination file already exists
//
INIT_OBJA( &Obja, &UnicodeString, DstNtPath );
Status = ZwOpenFile( &Handle, FILE_READ_ATTRIBUTES, &Obja, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 );
if( NT_SUCCESS(Status) ) { // the file exists!
// check to see if the destination is a directory
Status = ZwQueryInformationFile( Handle, &status_block, (PVOID)&fileInfo, sizeof( FILE_BASIC_INFORMATION ), FileBasicInformation );
ZwClose( Handle );
if( !NT_SUCCESS(Status) ) { // something went wrong
RcNtError( Status, MSG_CANT_COPY_FILE ); goto exit; }
if( fileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { // yep, it's a directory
// take the fully qualified source file path
// and get the file name from it by finding the
// last occurance of the \\ character
pos = wcsrchr( SrcNtPath, L'\\' );
SpMemFree( (PVOID)DstNtPath );
// append the file name to the directory so that the copy
// will work properly.
if( pos != NULL ) { wcscat( _CmdConsBlock->TemporaryBuffer, pos ); } else { wcscat( _CmdConsBlock->TemporaryBuffer, SrcNtPath ); }
DstNtPath = SpDupStringW( _CmdConsBlock->TemporaryBuffer );
// now check again for the file's existence
INIT_OBJA( &Obja, &UnicodeString, DstNtPath );
Status = ZwOpenFile( &Handle, FILE_READ_ATTRIBUTES, &Obja, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 );
if( NT_SUCCESS(Status) ) { ZwClose( Handle ); //
// Fetch yes/no text
//
if (InBatchMode == FALSE && NoCopyPrompt == FALSE) { YesNo = SpRetreiveMessageText( ImageBase, MSG_YESNOALL, NULL, 0 ); if( YesNo ) { s = wcsrchr( DstNtPath, L'\\' ); RcMessageOut( MSG_COPY_OVERWRITE, s ? s+1 : DstNtPath ); if( RcLineIn( Text, 2 ) ) { if( (Text[0] == YesNo[0]) || (Text[0] == YesNo[1]) ) { goto exit; } } else { goto exit; } SpMemFree( YesNo ); } } } } else { //
// If destination file was not compressed, copy it uncompressed.
//
if(!(fileInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED)) { CopyFlags |= COPY_FORCENOCOMP; } // nope the dest wasn't a dir, ask if we should overwrite
//
// Fetch yes/no text
//
if (InBatchMode == FALSE && NoCopyPrompt == FALSE) { YesNo = SpRetreiveMessageText( ImageBase, MSG_YESNOALL, NULL, 0 ); if( YesNo ) { s = wcsrchr( DstNtPath, L'\\' ); RcMessageOut( MSG_COPY_OVERWRITE, s ? s+1 : DstNtPath ); if( RcLineIn( Text, 2 ) ) { if( (Text[0] == YesNo[0]) || (Text[0] == YesNo[1]) ) { goto exit; } } else { goto exit; } SpMemFree( YesNo ); } } } }
Status = SpCopyFileUsingNames( SrcNtPath, DstNtPath, 0, CopyFlags ); if( NT_SUCCESS(Status) ) { FileCount += 1; } else { RcNtError( Status, MSG_CANT_COPY_FILE ); }
if( FileCount ) { RcMessageOut( MSG_COPY_COUNT, FileCount ); }
exit: if( DstFile && TokenizedLine->TokenCount == 2 ) { SpMemFree( DstFile ); } if( SrcDosPath ) { SpMemFree( SrcDosPath ); } if( SrcNtPath ) { SpMemFree( SrcNtPath ); } if( DstDosPath ) { SpMemFree( DstDosPath ); } if( DstNtPath ) { SpMemFree( DstNtPath ); }
return 1; }
|