extern "C" int link( char* source, char* dest ) { HANDLE fh; enableprivs(); // in case we aren't admin fh = CreateFile( source, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL ); if ( fh == INVALID_HANDLE_VALUE || fh == NULL ) return 4; static char buf1[MAX_PATH]; static wchar_t buf2[MAX_PATH * 2]; char *p; void *ctx = NULL; WIN32_STREAM_ID wsi; DWORD numwritten; GetFullPathName( dest, MAX_PATH, &buf1[0], &p ); wsi.dwStreamId = BACKUP_LINK; wsi.dwStreamAttributes = 0; wsi.dwStreamNameSize = 0; wsi.Size.QuadPart = strlen( buf1 ) * 2 + 2; MultiByteToWideChar( CP_ACP, 0, buf1, strlen( buf1 ) + 1, buf2, MAX_PATH ); if ( ! BackupWrite( fh, (byte *) &wsi, 20, &numwritten, FALSE, FALSE, &ctx ) ) return 5; if ( numwritten != 20 ) return 6; if ( ! BackupWrite( fh, (byte *) buf2, wsi.Size.LowPart, &numwritten, FALSE, FALSE, &ctx ) ) return 7; if ( numwritten != wsi.Size.LowPart ) return 8; // make NT release the context BackupWrite( fh, (byte *) &buf1[0], 0, &numwritten, TRUE, FALSE, &ctx ); CloseHandle( fh ); return 0; }
static void finalize_backup(struct nt_sid *sid) { DWORD dummy; if(sid->lpcontext!=NULL) { if(sid->is_write) BackupWrite(sid->hf, NULL, 0, &dummy, TRUE, FALSE, &sid->lpcontext); #if SFX_LEVEL>=ARJ else BackupRead(sid->hf, NULL, 0, &dummy, TRUE, FALSE, &sid->lpcontext); #endif sid->lpcontext=NULL; } }
unsigned long write_stream(unsigned char *src, unsigned long bytes, struct nt_sid *sid) { unsigned long bw, rc; if(!sid->is_write) return(0); /* This is crucial to prevent overflow */ bw=(sid->rem.HighPart==0&&sid->rem.LowPart<bytes)?sid->rem.LowPart:bytes; if(bw==0) return(0); if(!BackupWrite(sid->hf, src, bw, &rc, FALSE, TRUE, &sid->lpcontext)) return(0); sid->rem=LargeIntegerSubtract(sid->rem, ConvertUlongToLargeInteger(rc)); return(rc); }
BOOL My_BackupWrite() { HANDLE hFile=NULL; LPBYTE lpBuffer=NULL; DWORD nNumberofBytesToWrite=NULL; LPDWORD lpNumberOfBytesWritten=NULL; BOOL bAbort=NULL; BOOL bProcessSecurity=NULL; LPVOID * lpContext=NULL; BOOL returnVal_Real = NULL; BOOL returnVal_Intercepted = NULL; DWORD error_Real = 0; DWORD error_Intercepted = 0; __try{ disableInterception(); returnVal_Real = BackupWrite (hFile,lpBuffer,nNumberofBytesToWrite,lpNumberOfBytesWritten,bAbort,bProcessSecurity,lpContext); error_Real = GetLastError(); enableInterception(); returnVal_Intercepted = BackupWrite (hFile,lpBuffer,nNumberofBytesToWrite,lpNumberOfBytesWritten,bAbort,bProcessSecurity,lpContext); error_Intercepted = GetLastError(); }__except(puts("in filter"), 1){puts("exception caught");} return ((returnVal_Real == returnVal_Intercepted) && (error_Real == error_Intercepted)); }
int create_stream(WIN32_STREAM_ID *src, struct nt_sid *sid) { DWORD lo, hi, b; if(!sid->is_write) return(-1); if(sid->rem.LowPart!=0&&sid->rem.HighPart!=0) { if(!BackupSeek(sid->hf, sid->rem.LowPart, sid->rem.HighPart, &lo, &hi, &sid->lpcontext)) return(-1); if(lo!=sid->rem.LowPart||hi!=sid->rem.HighPart) return(-1); sid->rem.LowPart=sid->rem.HighPart=0; } if(!BackupWrite(sid->hf, (unsigned char *)src, W32_SID_HEADER_SIZE, &b, FALSE, TRUE, &sid->lpcontext)) return(-1); if(b!=W32_SID_HEADER_SIZE) return(-1); sid->rem=src->Size; return(0); }
NET_API_STATUS ReplCopyFile( IN LPCTSTR SourcePath, IN LPCTSTR DestPath, IN BOOL bFailIfExists ) /*++ Routine Description: ReplCopyFile copies everthing contained in a file. ("Everything" includes data, alternate data, extended attributes, attributes, timestamps, and security info.) Arguments: SourcePath - Points to source file path, which might be a UNC name. DestPath - Points to destination file path name. bFailIfExists - a boolean which is TRUE iff this routine should fail if the destination already exists. Return Value: NET_API_STATUS Threads: Used by client and syncer threads. --*/ { NET_API_STATUS ApiStatus; BOOL DestExists; HANDLE DestHandle = INVALID_HANDLE_VALUE; PSECURITY_ATTRIBUTES DestSecurityAttr = NULL; DWORD SourceAttributes = (DWORD) (-1); #ifdef USE_BACKUP_APIS DWORD ActualBufferSizeRead = 0; DWORD ActualBufferSizeWritten; LPVOID BackupBuffer = NULL; LPVOID DestContext = NULL; LPVOID SourceContext = NULL; HANDLE SourceHandle = INVALID_HANDLE_VALUE; #endif // // Check for caller errors. // NetpAssert( SourcePath != NULL ); NetpAssert( (*SourcePath) != TCHAR_EOS ); NetpAssert( STRLEN(SourcePath) <= PATHLEN ); NetpAssert( DestPath != NULL ); NetpAssert( (*DestPath) != TCHAR_EOS ); NetpAssert( STRLEN(DestPath) <= PATHLEN ); DestExists = ReplFileOrDirExists( DestPath ); if (bFailIfExists && DestExists) { // DON'T GOTO CLEANUP FROM HERE, AS IT WOULD DELETE FILE!!! return (ERROR_ALREADY_EXISTS); } // // What kind of source (file/directory) is it? // SourceAttributes = GetFileAttributes( (LPTSTR) SourcePath ); if ( SourceAttributes == (DWORD) -1 ) { // // File doesn't exist, bad syntax, or something along those lines. // ApiStatus = (NET_API_STATUS) GetLastError(); NetpAssert( ApiStatus != NO_ERROR ); // DON'T GOTO CLEANUP FROM HERE, AS IT WOULD DELETE FILE!!! return (ApiStatus); } else if ((SourceAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { // // Source is a directory tree. We don't handle this! // NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: source is directory! path: '" FORMAT_LPTSTR "', src attr " FORMAT_HEX_DWORD ".\n", SourcePath, SourceAttributes )); ApiStatus = NERR_InternalError; // DON'T GOTO CLEANUP FROM HERE, AS IT WOULD DELETE FILE!!! return (ApiStatus); } else { // // Simple case: source exists and is just a single file. // Start off by setting desired destination security attributes. // ApiStatus = ReplMakeSecurityAttributes( SourcePath, &DestSecurityAttr ); // alloc and set ptr if (ApiStatus==ERROR_NOT_SUPPORTED) { // Just downlevel master, so set default security and continue. DestSecurityAttr = NULL; } else if (ApiStatus != NO_ERROR) { // DON'T GOTO CLEANUP FROM HERE, AS IT WOULD DELETE FILE!!! return (ApiStatus); } else { NetpAssert( ApiStatus == NO_ERROR ); NetpAssert( DestSecurityAttr != NULL ); } #ifdef USE_BACKUP_APIS // // Open source file. // SourceHandle = CreateFile( SourcePath, GENERIC_READ, // desired access FILE_SHARE_READ, // share mode NULL, // no security attributes OPEN_EXISTING, // open if exists; fail if not. FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN, // flags (HANDLE) NULL // no template ); if (SourceHandle == INVALID_HANDLE_VALUE) { ApiStatus = (NET_API_STATUS) GetLastError(); NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: open of source '" FORMAT_LPTSTR "' gave status " FORMAT_API_STATUS ".\n", SourcePath, ApiStatus )); NetpAssert( ApiStatus != NO_ERROR ); if (DestSecurityAttr != NULL) { NetpMemoryFree( DestSecurityAttr ); } // DON'T GOTO CLEANUP FROM HERE, AS IT WOULD DELETE FILE!!! return (ApiStatus); } #endif // // Delete the destination file. Why? Because... // We're going to set the security on destination file using // the CreateFile API. This will ignore setting the security if the // file already exists. So, we need to delete it to force this to // happen. // if (DestExists) { ApiStatus = ReplDeleteFile( DestPath ); if (ApiStatus != NO_ERROR) { goto Cleanup; } } NetpAssert( !ReplFileOrDirExists( DestPath ) ); // // Open dest file. Since we already deleted any existing one, we know // this will create the file from scratch. This is important, because // we're depending on CreateFile's use of DestSecurityAttr to set // security on the file. // DestHandle = CreateFile( DestPath, GENERIC_WRITE // desired... | WRITE_DAC // ... | WRITE_OWNER, // access FILE_SHARE_WRITE, // share mode: none DestSecurityAttr, // desired security attributes CREATE_NEW, // disposition create new (fail exist) #ifdef USE_BACKUP_APIS FILE_FLAG_BACKUP_SEMANTICS, // flags #else 0, // flags #endif (HANDLE) NULL // no template ); if (DestHandle == INVALID_HANDLE_VALUE) { ApiStatus = (NET_API_STATUS) GetLastError(); NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: open of dest '" FORMAT_LPTSTR "' gave status " FORMAT_API_STATUS ".\n", DestPath, ApiStatus )); NetpAssert( ApiStatus != NO_ERROR ); goto Cleanup; } #ifndef USE_BACKUP_APIS // // Close the dest file and copy the data. // (In this case, we're using CopyFile API, which is not handle-based.) // NetpAssert( DestHandle != INVALID_HANDLE_VALUE ); (VOID) CloseHandle( DestHandle ); DestHandle = INVALID_HANDLE_VALUE; if ( !CopyFile( (LPTSTR) SourcePath, (LPTSTR) DestPath, FALSE /* don't fail if exists */ ) ) { ApiStatus = (NET_API_STATUS) GetLastError(); NetpAssert( ApiStatus != NO_ERROR ); goto Cleanup; } NetpAssert( ReplFileOrDirExists( DestPath ) ); // Timestamps and attributes will be copied below. // BUGBUG no way to copy EAs, alt data. ApiStatus = NO_ERROR; #else // defined(USE_BACKUP_APIS) BackupBuffer = NetpMemoryAllocate( REPL_BACKUP_BUFFER_SIZE ); if (BackupBuffer == NULL) { ApiStatus = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; } IF_DEBUG( SYNC ) { NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: copying" )); } for (;;) { // until end of file... IF_DEBUG( SYNC ) { NetpKdPrint(( "<" )); } if ( !BackupRead( SourceHandle, BackupBuffer, REPL_BACKUP_BUFFER_SIZE, & ActualBufferSizeRead, FALSE, // don't abort yet REPL_PROCESS_SECURITY, & SourceContext ) ) { // Process read error. ApiStatus = (NET_API_STATUS) GetLastError(); NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: BackupRead" " gave status " FORMAT_API_STATUS ".\n", ApiStatus )); NetpAssert( ApiStatus != NO_ERROR ); goto Cleanup; } // No error on read, how about EOF? if (ActualBufferSizeRead == 0) { // normal end of file. ApiStatus = NO_ERROR; IF_DEBUG( SYNC ) { NetpKdPrint(( "DONE(OK)\n" )); } break; } IF_DEBUG( SYNC ) { NetpKdPrint(( ">" )); } if ( !BackupWrite( DestHandle, BackupBuffer, ActualBufferSizeRead, & ActualBufferSizeWritten, FALSE, // don't abort yet REPL_PROCESS_SECURITY, & DestContext ) ) { ApiStatus = (NET_API_STATUS) GetLastError(); NetpKdPrint(( PREFIX_REPL_CLIENT "ReplCopyFile: BackupWrite" " gave status " FORMAT_API_STATUS ".\n", ApiStatus )); NetpAssert( ApiStatus != NO_ERROR ); goto Cleanup; } } // until end of file ApiStatus = NO_ERROR; #endif } // else (just single file)