diff options
| author | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2009-11-29 16:29:03 +0100 |
|---|---|---|
| committer | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2009-11-29 16:29:03 +0100 |
| commit | 959269c4432632e9228a5fa148eed2255e508554 (patch) | |
| tree | 090517465da49e84c7b3ec117f88d52ccd903107 | |
| parent | 9883e3b4eec8e457b49cb70ca006f5f7601332da (diff) | |
| download | tuxcmd-959269c4432632e9228a5fa148eed2255e508554.tar.xz | |
Introduce copy operation start/stop callsv0.6.73
This is the first step for a rapid extraction speed increase as we
don't need to open&seek for every file. Sorting by inode is still
need to be written but most archives work fine as they are.
TODO: writing into the archive needs special care (see TODO in zip plugin)
| -rw-r--r-- | UConfig.pas | 4 | ||||
| -rw-r--r-- | UCoreWorkers.pas | 89 | ||||
| -rw-r--r-- | vfs/UVFSCore.pas | 91 | ||||
| -rw-r--r-- | vfs/uVFSprototypes.pas | 4 |
4 files changed, 126 insertions, 62 deletions
diff --git a/UConfig.pas b/UConfig.pas index a4a9978..a8dc5b6 100644 --- a/UConfig.pas +++ b/UConfig.pas @@ -25,8 +25,8 @@ uses Classes, ULocale; resourcestring ConstAppTitle = 'Tux Commander'; - ConstAboutVersion = '0.6.72-dev'; - ConstAboutBuildDate = '2009-11-28'; + ConstAboutVersion = '0.6.73-dev'; + ConstAboutBuildDate = '2009-11-29'; {$IFDEF FPC} {$INCLUDE fpcver.inc} diff --git a/UCoreWorkers.pas b/UCoreWorkers.pas index b2b6479..2b5c4d5 100644 --- a/UCoreWorkers.pas +++ b/UCoreWorkers.pas @@ -996,16 +996,14 @@ var DefResponse: integer; // Global variables for this function if (SrcEngine is TLocalTreeEngine) and (DestEngine is TVFSEngine) then begin AEngine := DestEngine; - Result := (DestEngine as TVFSEngine).CopyFileInEx(SenderThread, SourceFile, DestFile, @CopyFilesWorker_ErrorFunc, Append, - @vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_progress_callback, SenderThread); + Result := (DestEngine as TVFSEngine).CopyFileInEx(SenderThread, SourceFile, DestFile, @CopyFilesWorker_ErrorFunc, Append); end else // from VFS engine to local (most common use) if (SrcEngine is TVFSEngine) and (DestEngine is TLocalTreeEngine) then begin AEngine := SrcEngine; - Result := (SrcEngine as TVFSEngine).CopyFileOutEx(SenderThread, SourceFile, DestFile, @CopyFilesWorker_ErrorFunc, Append, - @vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_progress_callback, SenderThread); + Result := (SrcEngine as TVFSEngine).CopyFileOutEx(SenderThread, SourceFile, DestFile, @CopyFilesWorker_ErrorFunc, Append); end // VFS to VFS (not supported yet) @@ -1322,6 +1320,7 @@ var i: longint; List: TList; CurrPath, SaveDestPath, SaveSrcPath, s: string; MaxSize: Int64; + StartPassed: boolean; begin List := TList.Create; List.Clear; @@ -1395,45 +1394,59 @@ begin ParamBool2 := False; if MaxSize < 2 then ParamFloat1 := 1 else ParamFloat1 := 100 / (MaxSize - 1); - if List.Count > 0 then - for i := 0 to List.Count - 1 do begin - if Assigned(PDataItemSL(List[i])^.ADestination) - then s := string(PDataItemSL(List[i])^.ADestination) - else - begin - s := ProcessPattern(DestEngine, ParamString1, CurrPath, Copy(PDataItemSL(List[i])^.DataItem^.FName, Length(CurrPath) + 1, Length(PDataItemSL(List[i])^.DataItem^.FName) - Length(CurrPath)), - PDataItemSL(List[i])^.DataItem^.IsDir and (not PDataItemSL(List[i])^.DataItem^.IsLnk)); -// DebugMsg(['s2 = ', Copy(PDataItemSL(List[i])^.AName, Length(CurrPath) + 1, Length(PDataItemSL(List[i])^.AName) - Length(CurrPath)), ', s = ', s]); - end; + if List.Count > 0 then begin + StartPassed := True; + if (SrcEngine is TVFSEngine) and (SrcEngine as TVFSEngine).ArchiveMode then + StartPassed := StartPassed and (SrcEngine as TVFSEngine).StartCopyOperation(SenderThread, @CopyFilesWorker_ErrorFunc, @vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_progress_callback, SenderThread); + if (DestEngine is TVFSEngine) and (DestEngine as TVFSEngine).ArchiveMode then + StartPassed := StartPassed and (DestEngine as TVFSEngine).StartCopyOperation(SenderThread, @CopyFilesWorker_ErrorFunc, @vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_progress_callback, SenderThread); + + if StartPassed then + for i := 0 to List.Count - 1 do begin + if Assigned(PDataItemSL(List[i])^.ADestination) + then s := string(PDataItemSL(List[i])^.ADestination) + else + begin + s := ProcessPattern(DestEngine, ParamString1, CurrPath, Copy(PDataItemSL(List[i])^.DataItem^.FName, Length(CurrPath) + 1, Length(PDataItemSL(List[i])^.DataItem^.FName) - Length(CurrPath)), + PDataItemSL(List[i])^.DataItem^.IsDir and (not PDataItemSL(List[i])^.DataItem^.IsLnk)); + // DebugMsg(['s2 = ', Copy(PDataItemSL(List[i])^.AName, Length(CurrPath) + 1, Length(PDataItemSL(List[i])^.AName) - Length(CurrPath)), ', s = ', s]); + end; - if not (SrcEngine is TVFSEngine) then UpdateCaption1(Format(LANGFromS, [string(PDataItemSL(List[i])^.DataItem^.FDisplayName)])) else - if (SrcEngine as TVFSEngine).ArchiveMode then UpdateCaption1(Format(LANGFromS, [Format(ConstFullPathFormatStr, [(SrcEngine as TVFSEngine).ArchivePath, string(PDataItemSL(List[i])^.DataItem^.FDisplayName)])])) - else UpdateCaption1(Format(LANGFromS, [GetURIPrefix((SrcEngine as TVFSEngine).GetPathURI) + StrToUTF8(string(PDataItemSL(List[i])^.DataItem^.FDisplayName))])); - if not (DestEngine is TVFSEngine) then UpdateCaption2(Format(LANGToS, [StrToUTF8(s)])) else - if (DestEngine as TVFSEngine).ArchiveMode then UpdateCaption2(Format(LANGToS, [Format(ConstFullPathFormatStr, [(DestEngine as TVFSEngine).ArchivePath, StrToUTF8(s)])])) - else UpdateCaption2(Format(LANGToS, [GetURIPrefix((DestEngine as TVFSEngine).GetPathURI) + StrToUTF8(s)])); - CommitGUIUpdate; - if TwoSameFiles(s, string(PDataItemSL(List[i])^.DataItem^.FName), ParamBool3) and (not PDataItemSL(List[i])^.DataItem^.IsDir) then begin - FCancelMessage := LANGCannotCopyFileToItself; - FShowCancelMessage := True; - ErrorHappened := True; - Break; - end; -// * FIXME: why the hell we had something like this here?? -// if s <> string(PDataItemSL(List[i])^.DataItem^.FName) then - if not HandleCopy(List[i], s) then begin + if not (SrcEngine is TVFSEngine) then UpdateCaption1(Format(LANGFromS, [string(PDataItemSL(List[i])^.DataItem^.FDisplayName)])) else + if (SrcEngine as TVFSEngine).ArchiveMode then UpdateCaption1(Format(LANGFromS, [Format(ConstFullPathFormatStr, [(SrcEngine as TVFSEngine).ArchivePath, string(PDataItemSL(List[i])^.DataItem^.FDisplayName)])])) + else UpdateCaption1(Format(LANGFromS, [GetURIPrefix((SrcEngine as TVFSEngine).GetPathURI) + StrToUTF8(string(PDataItemSL(List[i])^.DataItem^.FDisplayName))])); + if not (DestEngine is TVFSEngine) then UpdateCaption2(Format(LANGToS, [StrToUTF8(s)])) else + if (DestEngine as TVFSEngine).ArchiveMode then UpdateCaption2(Format(LANGToS, [Format(ConstFullPathFormatStr, [(DestEngine as TVFSEngine).ArchivePath, StrToUTF8(s)])])) + else UpdateCaption2(Format(LANGToS, [GetURIPrefix((DestEngine as TVFSEngine).GetPathURI) + StrToUTF8(s)])); + CommitGUIUpdate; + if TwoSameFiles(s, string(PDataItemSL(List[i])^.DataItem^.FName), ParamBool3) and (not PDataItemSL(List[i])^.DataItem^.IsDir) then begin + FCancelMessage := LANGCannotCopyFileToItself; + FShowCancelMessage := True; + ErrorHappened := True; + Break; + end; + // * FIXME: why the hell we had something like this here?? + // if s <> string(PDataItemSL(List[i])^.DataItem^.FName) then + if not HandleCopy(List[i], s) then begin + ErrorHappened := True; + Break; + end; + if (not PDataItemSL(List[i])^.DataItem^.IsDir) and (not PDataItemSL(List[i])^.DataItem^.IsLnk) + then Inc(ParamInt64, PDataItemSL(List[i])^.DataItem^.Size); + if Cancelled then begin + FCancelMessage := LANGUserCancelled; + FShowCancelMessage := True; ErrorHappened := True; Break; end; - if (not PDataItemSL(List[i])^.DataItem^.IsDir) and (not PDataItemSL(List[i])^.DataItem^.IsLnk) - then Inc(ParamInt64, PDataItemSL(List[i])^.DataItem^.Size); - if Cancelled then begin - FCancelMessage := LANGUserCancelled; - FShowCancelMessage := True; - ErrorHappened := True; - Break; end; - end; + + // We need to ensure these to be called in case of error + if (SrcEngine is TVFSEngine) and (SrcEngine as TVFSEngine).ArchiveMode then + (SrcEngine as TVFSEngine).StopCopyOperation(SenderThread, @CopyFilesWorker_ErrorFunc); + if (DestEngine is TVFSEngine) and (DestEngine as TVFSEngine).ArchiveMode then + (DestEngine as TVFSEngine).StopCopyOperation(SenderThread, @CopyFilesWorker_ErrorFunc); + end; // Free the objects if List.Count > 0 then diff --git a/vfs/UVFSCore.pas b/vfs/UVFSCore.pas index 2bccea7..ff5445d 100644 --- a/vfs/UVFSCore.pas +++ b/vfs/UVFSCore.pas @@ -66,6 +66,8 @@ type FVFSGetPasswordRequired: TVFSGetPasswordRequired; FVFSSetCallbacks: TVFSSetCallbacks; FVFSResetPassword: TVFSResetPassword; + FVFSStartCopyOperation: TVFSStartCopyOperation; + FVFSStopCopyOperation: TVFSStopCopyOperation; function GetHandlesArchives: boolean; function GetHandlesNetwork: boolean; public @@ -152,11 +154,11 @@ type function GetPasswordRequired: boolean; procedure ResetPassword; - // the callbacks here are used for next volume prompts, password prompts (encrypted archives) - as long as this is specific to each file - function CopyFileInEx(Sender: Pointer; const SourceFile, DestFile: string; ErrorFunc: TEngineErrorFunc; Append: boolean; - AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; - function CopyFileOutEx(Sender: Pointer; const SourceFile, DestFile: string; ErrorFunc: TEngineErrorFunc; Append: boolean; - AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; + // callbacks here are used for next volume prompts, password prompts (encrypted archives) + function StartCopyOperation(Sender: Pointer; ErrorFunc: TEngineErrorFunc; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; + function StopCopyOperation(Sender: Pointer; ErrorFunc: TEngineErrorFunc): boolean; + function CopyFileInEx(Sender: Pointer; const SourceFile, DestFile: string; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; + function CopyFileOutEx(Sender: Pointer; const SourceFile, DestFile: string; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; published property Path: string read GetPath write SetPath; property BlockSize: Cardinal read GetBlockSize write SetBlockSize; @@ -242,6 +244,8 @@ begin @FVFSGetPasswordRequired := dlsym(ModuleHandle, 'VFSGetPasswordRequired'); @FVFSSetCallbacks := dlsym(ModuleHandle, 'VFSSetCallbacks'); @FVFSResetPassword := dlsym(ModuleHandle, 'VFSResetPassword'); + @FVFSStartCopyOperation := dlsym(ModuleHandle, 'VFSStartCopyOperation'); + @FVFSStopCopyOperation := dlsym(ModuleHandle, 'VFSStopCopyOperation'); // Initialize the extensions list SetLength(Extensions, 0); @@ -766,37 +770,34 @@ end; (********************************************************************************************************************************) function TVFSEngine.CopyFileIn(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; begin - Result := CopyFileInEx(Sender, SourceFile, DestFile, ErrorFunc, Append, nil, nil, nil, nil); + Result := StartCopyOperation(Sender, ErrorFunc, nil, nil, nil, nil); + Result := Result and CopyFileInEx(Sender, SourceFile, DestFile, ErrorFunc, Append); + Result := Result and StopCopyOperation(Sender, ErrorFunc); end; function TVFSEngine.CopyFileOut(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; begin - Result := CopyFileInEx(Sender, SourceFile, DestFile, ErrorFunc, Append, nil, nil, nil, nil); + Result := StartCopyOperation(Sender, ErrorFunc, nil, nil, nil, nil); + Result := Result and CopyFileInEx(Sender, SourceFile, DestFile, ErrorFunc, Append); + Result := Result and StopCopyOperation(Sender, ErrorFunc); end; -function TVFSEngine.CopyFileOutEx(Sender: Pointer; const SourceFile, DestFile: string; ErrorFunc: TEngineErrorFunc; Append: boolean; - AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; +function TVFSEngine.CopyFileOutEx(Sender: Pointer; const SourceFile, DestFile: string; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; var Res: TVFSResult; begin Result := False; try if @FSourcePlugin.FVFSCopyToLocal <> nil then begin -// DebugMsg(['0 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$']); -// DebugMsg([' Pointer(FGlobs) = 0x', IntToHex(Int64(FGlobs), 16), ', Pointer(@NewVFSCopyCallBackFunc) = 0x', IntToHex(Int64(@NewVFSCopyCallBackFunc), 16), ', Pointer(Self) = 0x', IntToHex(Int64(Self), 16)]); try - if @FSourcePlugin.FVFSSetCallbacks <> nil then - FSourcePlugin.FVFSSetCallbacks(FGlobs, AskQuestionCallback, AskPasswordCallback, ProgressCallback, CallbackData); Res := FSourcePlugin.FVFSCopyToLocal(FGlobs, PChar(SourceFile), PChar(DestFile), Append); - if @FSourcePlugin.FVFSSetCallbacks <> nil then - FSourcePlugin.FVFSSetCallbacks(FGlobs, nil, nil, nil, nil); except on E: Exception do begin DebugMsg(['*** Exception raised in TVFSEngine.CopyFileOut(Sender=', QWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]); Res := cVFS_WriteErr; end; end; -// DebugMsg(['1 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$']); Result := Res = cVFS_OK; + // * TODO: Port to GError if (Res <> cVFS_OK) and Assigned(ErrorFunc) then case Res of cVFS_ReadErr: Result := ErrorFunc(Sender, 6, 0, SourceFile); @@ -810,19 +811,14 @@ begin end; end; -function TVFSEngine.CopyFileInEx(Sender: Pointer; const SourceFile, DestFile: string; ErrorFunc: TEngineErrorFunc; - Append: boolean; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; +function TVFSEngine.CopyFileInEx(Sender: Pointer; const SourceFile, DestFile: string; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; var Res: TVFSResult; begin Result := False; try if @FSourcePlugin.FVFSCopyFromLocal <> nil then begin try - if @FSourcePlugin.FVFSSetCallbacks <> nil then - FSourcePlugin.FVFSSetCallbacks(FGlobs, AskQuestionCallback, AskPasswordCallback, ProgressCallback, CallbackData); Res := FSourcePlugin.FVFSCopyFromLocal(FGlobs, PChar(SourceFile), PChar(DestFile), Append); - if @FSourcePlugin.FVFSSetCallbacks <> nil then - FSourcePlugin.FVFSSetCallbacks(FGlobs, nil, nil, nil, nil); except on E: Exception do begin DebugMsg(['*** Exception raised in TVFSEngine.CopyFileIn(Sender=', QWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]); @@ -830,6 +826,7 @@ begin end; end; Result := Res = cVFS_OK; + // * TODO: Port to GError if (Res <> cVFS_OK) and Assigned(ErrorFunc) then case Res of cVFS_ReadErr: Result := ErrorFunc(Sender, 6, 0, SourceFile); @@ -843,6 +840,56 @@ begin end; end; +function TVFSEngine.StartCopyOperation(Sender: Pointer; ErrorFunc: TEngineErrorFunc; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; +var Res: TVFSResult; +begin + Result := False; + try + if @FSourcePlugin.FVFSSetCallbacks <> nil then + FSourcePlugin.FVFSSetCallbacks(FGlobs, AskQuestionCallback, AskPasswordCallback, ProgressCallback, CallbackData); + if @FSourcePlugin.FVFSStartCopyOperation <> nil then begin + Res := FSourcePlugin.FVFSStartCopyOperation(FGlobs); + Result := Res = cVFS_OK; + // * TODO: Port to GError + if (Res <> cVFS_OK) and Assigned(ErrorFunc) then + case Res of + cVFS_ReadErr: Result := ErrorFunc(Sender, 6, 0, 'StartCopyOperation'); + cVFS_WriteErr: Result := ErrorFunc(Sender, 7, 0, 'StartCopyOperation'); + cVFS_mallocFailed: ErrorFunc(Sender, 1, 0, 'StartCopyOperation'); + cVFS_Cancelled: ErrorFunc(Sender, 0, 0, 'StartCopyOperation'); + end; + end else + ErrorFunc(Sender, 2, 0, 'StartCopyOperation not supported'); + except + on E: Exception do DebugMsg(['*** Exception raised in TVFSEngine.StartCopyOperation(Sender=', QWord(Sender), '): (', E.ClassName, '): ', E.Message]); + end; +end; + +function TVFSEngine.StopCopyOperation(Sender: Pointer; ErrorFunc: TEngineErrorFunc): boolean; +var Res: TVFSResult; +begin + Result := False; + try + if @FSourcePlugin.FVFSSetCallbacks <> nil then + FSourcePlugin.FVFSSetCallbacks(FGlobs, nil, nil, nil, nil); + if @FSourcePlugin.FVFSStopCopyOperation <> nil then begin + Res := FSourcePlugin.FVFSStopCopyOperation(FGlobs); + Result := Res = cVFS_OK; + // * TODO: Port to GError + if (Res <> cVFS_OK) and Assigned(ErrorFunc) then + case Res of + cVFS_ReadErr: Result := ErrorFunc(Sender, 6, 0, 'StopCopyOperation'); + cVFS_WriteErr: Result := ErrorFunc(Sender, 7, 0, 'StopCopyOperation'); + cVFS_mallocFailed: ErrorFunc(Sender, 1, 0, 'StopCopyOperation'); + cVFS_Cancelled: ErrorFunc(Sender, 0, 0, 'StopCopyOperation'); + end; + end else + ErrorFunc(Sender, 5, 0, 'StopCopyOperation not supported'); + except + on E: Exception do DebugMsg(['*** Exception raised in TVFSEngine.StopCopyOperation(Sender=', QWord(Sender), '): (', E.ClassName, '): ', E.Message]); + end; +end; + (********************************************************************************************************************************) (********************************************************************************************************************************) diff --git a/vfs/uVFSprototypes.pas b/vfs/uVFSprototypes.pas index bef0246..bd33726 100644 --- a/vfs/uVFSprototypes.pas +++ b/vfs/uVFSprototypes.pas @@ -238,6 +238,10 @@ type TVFSCopyToLocal = function (g:TVFSGlobs; const sSrcName, sDstName: PChar; Append: gboolean): TVFSResult; cdecl; // Performs the copy process from local filesystem into the module TVFSCopyFromLocal = function (g:TVFSGlobs; const sSrcName, sDstName: PChar; Append: gboolean): TVFSResult; cdecl; + // Start the copy operation - open the archive and prepare internal structures + TVFSStartCopyOperation = function (g:TVFSGlobs): TVFSResult; cdecl; + // Stop the copy operation - close the archive and free memory + TVFSStopCopyOperation = function (g:TVFSGlobs): TVFSResult; cdecl; // TODO: Prototype function for packing new files into archive |
