diff options
| -rw-r--r-- | UChecksum.pas | 70 | ||||
| -rw-r--r-- | UChecksumDruid.pas | 103 | ||||
| -rw-r--r-- | UConfig.pas | 4 | ||||
| -rw-r--r-- | UConnectionManager.pas | 17 | ||||
| -rw-r--r-- | UCore.pas | 119 | ||||
| -rw-r--r-- | UCoreUtils.pas | 30 | ||||
| -rw-r--r-- | UCoreWorkers.pas | 406 | ||||
| -rw-r--r-- | UEngines.pas | 539 | ||||
| -rw-r--r-- | UError.pas | 25 | ||||
| -rw-r--r-- | UMain.pas | 75 | ||||
| -rw-r--r-- | UQuickConnect.pas | 11 | ||||
| -rw-r--r-- | USearch.pas | 34 | ||||
| -rw-r--r-- | vfs/UVFSCore.pas | 469 | ||||
| -rw-r--r-- | vfs/uVFSprototypes.pas | 86 |
14 files changed, 1085 insertions, 903 deletions
diff --git a/UChecksum.pas b/UChecksum.pas index b7ef508..0de5fda 100644 --- a/UChecksum.pas +++ b/UChecksum.pas @@ -63,7 +63,7 @@ var implementation -uses ULocale, UCoreUtils, ULibc, UCore, DateUtils, md5, crc; +uses ULocale, UCoreUtils, ULibc, UCore, UError, DateUtils, md5, crc; type TFileListItem = class public @@ -198,18 +198,27 @@ end; function TFChecksum.ProcessFile(FileName: string): boolean; const ChksumBlockSize = 32768; // Maximum of PByteArray var FD: TEngineFileDes; - Error, Count, i, Start: integer; + Count, i, Start: integer; Buffer: Pointer; s: string; Stat: PDataItem; IsMD5: boolean; + Error: PGError; begin Result := False; - Stat := Engine.GetFileInfo(FileName, True, True); + Error := nil; + Stat := Engine.GetFileInfo(FileName, True, True, @Error); + if Stat = nil then begin + if Error <> nil then begin + ShowError(Self, Format('An error occured while opening file ''%s''', [StrToUTF8(ExtractFileName(FileName))]), Error); + g_error_free(Error); + end; + Exit; + end; if (Stat <> nil) and (Stat.Size > 128*1024) then begin i := integer(Application.MessageBox(Format(LANGTheFileSYouAreTryingToOpenIsQuiteBig, [StrToUTF8(ExtractFileName(FileName))]), [mbYes, mbNo], mbWarning, mbNone, mbNo)); - if (i = integer(mbNo)) or (i = 251) then Exit; FreeDataItem(Stat); + if (i = integer(mbNo)) or (i = 251) then Exit; end; IsMD5 := (Pos('MD5', WideUpperCase(ExtractFileName(FileName))) > 0) or ((Pos('SFV', WideUpperCase(ExtractFileName(FileName))) = 0) and (Pos('SUM', WideUpperCase(ExtractFileName(FileName))) > 0)); if IsMD5 then MD5Present := True @@ -225,20 +234,23 @@ begin Application.MessageBox(LANGAnErrorOccuredWhileInitializingMemoryBlock, [mbOK], mbError, mbNone, mbOK); Exit; end; - Error := 0; - FD := Engine.OpenFile(FileName, omRead, Error); - if Error <> 0 then begin - Application.MessageBox(Format(LANGAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(ExtractFileName(FileName)), GetErrorString(Error)]), [mbOK], mbError, mbNone, mbOK); + FD := Engine.OpenFile(FileName, omRead, @Error); + if FD = nil then begin + if Error <> nil then begin + ShowError(Self, Format('An error occured while opening file ''%s''', [StrToUTF8(ExtractFileName(FileName))]), Error); + g_error_free(Error); + end; libc_free(Buffer); Exit; end; s := ''; CommentOpen := True; repeat - Count := Engine.ReadFile(FD, Buffer, ChksumBlockSize, Error); - if Error <> 0 then begin - Application.MessageBox(Format(LANGAnErrorOccuredWhileReadingFileSS, [StrToUTF8(ExtractFileName(FileName)), GetErrorString(Error)]), [mbOK], mbError, mbNone, mbOK); - Engine.CloseFile(FD); + Count := Engine.ReadFile(FD, Buffer, ChksumBlockSize, @Error); + if Error <> nil then begin + ShowError(Self, Format('An error occured while reading file ''%s''', [StrToUTF8(ExtractFileName(FileName))]), Error); + g_error_free(Error); + Engine.CloseFile(FD, nil); libc_free(Buffer); Exit; end; @@ -259,7 +271,7 @@ begin if Length(s) > 0 then ProcessLine(s, ExtractFilePath(FileName), IsMD5); CommentOpen := False; - Engine.CloseFile(FD); + Engine.CloseFile(FD, nil); libc_free(Buffer); Result := True; end; @@ -270,6 +282,7 @@ var Item: TFileListItem; S1, S2: string; i: integer; Stat: PDataItem; + Error: PGError; begin TrimCRLFESC(s); if Length(s) < 1 then Exit; @@ -312,7 +325,8 @@ begin Item.Name := ExtractFileName(s2); Item.FullPath := IncludeTrailingPathDelimiter(Path) + s2; end; - Stat := Engine.GetFileInfo(Item.FullPath, True, True); + Error := nil; + Stat := Engine.GetFileInfo(Item.FullPath, True, True, nil); if Assigned(Stat) then begin Item.Size := Stat.Size; FreeDataItem(Stat); @@ -373,7 +387,7 @@ end; procedure TFChecksum.GoProcess; const ChksumBlockSize = 65536*4; -var i, Error, Count: integer; +var i, ErrNum, Count: integer; FD: TEngineFileDes; Buffer: Pointer; MaxSize, OldPos: Int64; @@ -382,6 +396,7 @@ var i, Error, Count: integer; CRC: LongWord; MDContext: TMDContext; MDDigest: TMDDigest; + Error: PGError; begin if List.Count = 0 then Exit; CheckButton.Caption := LANGCheckButtonCaptionStop; @@ -417,18 +432,21 @@ begin Data := List[i]; CRC := 0; if Data.IsMD5 then MDInit(MDContext, MD_VERSION_5); - Error := 0; - FD := Engine.OpenFile(Data.FullPath, omRead, Error); - if Error <> 0 then begin + Error := nil; + FD := Engine.OpenFile(Data.FullPath, omRead, @Error); + if Error <> nil then begin Data.Status := 3; + g_error_free(Error); Continue; end; repeat - Count := Engine.ReadFile(FD, Buffer, ChksumBlockSize, Error); - if Error <> 0 then begin + Error := nil; + Count := Engine.ReadFile(FD, Buffer, ChksumBlockSize, @Error); + if Error <> nil then begin Data.Status := 3; - Engine.CloseFile(FD); - Continue; + g_error_free(Error); + Engine.CloseFile(FD, nil); + Break; end; if not Data.IsMD5 then CRC := CRC32(CRC, Buffer, Count) else MDUpdate(MDContext, Buffer^, Count); @@ -436,7 +454,7 @@ begin ProgressBar.Text := Format('%d %%', [Trunc(ProgressBar.Fraction * 100)]); Application.ProcessMessages; until (Count < ChksumBlockSize) or Stop; - Engine.CloseFile(FD); + Engine.CloseFile(FD, nil); if Stop then Break; if not Data.IsMD5 then Data.Status := Ord(not (CRC = Data.CRC)) + 1 else begin MDFinal(MDContext, MDDigest); @@ -455,11 +473,11 @@ begin StatLabel.Caption := LANGChecksumInterrupted; CheckButton.SetFocus; end else begin - Error := 0; + ErrNum := 0; if List.Count > 0 then for i := 0 to List.Count - 1 do - if TFileListItem(List[i]).Status <> 1 then Inc(Error); - StatLabel.Caption := Format(LANGChecksumDOK, [Round(100 * (List.Count - Error) / List.Count)]); + if TFileListItem(List[i]).Status <> 1 then Inc(ErrNum); + StatLabel.Caption := Format(LANGChecksumDOK, [Round(100 * (List.Count - ErrNum) / List.Count)]); ActionArea.SetFocus; end; StatLabel.UseMarkup := True; diff --git a/UChecksumDruid.pas b/UChecksumDruid.pas index 7745fad..fb62775 100644 --- a/UChecksumDruid.pas +++ b/UChecksumDruid.pas @@ -76,7 +76,7 @@ var implementation -uses ULocale, UCoreUtils, ULibc, UCore, DateUtils, UConfig, StrUtils, md5, crc; +uses ULocale, UCoreUtils, ULibc, UCore, DateUtils, UConfig, UError, StrUtils, md5, crc; procedure TFChecksumDruid.FormCreate(Sender: TObject); @@ -306,19 +306,22 @@ procedure TFChecksumDruid.SetCurrentPage(const Num: integer; const GoingForward: const Ext: array[boolean] of string = ('.md5', '.sfv'); var s: string; i: TEngineFileDes; - Error: integer; + Error: PGError; begin // A simple test before we can continue if (CurrentPage = 3) and (not SeparateFileCheckBox.Checked) and GoingForward then begin - s := UTF8ToStr(FileNameEntry.Text); - i := Engine.OpenFile(s, omWrite, Error); - if Error <> 0 then begin - Application.MessageBox(PGtkWindow(FWidget), Format(LANGCCHKSUMAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(ExtractFileName(s)), GetErrorString(Error)]), - [mbOK], mbError, mbNone, mbOK); + s := ProcessPattern(Engine, StrToUTF8(FileNameEntry.Text), IncludeTrailingPathDelimiter(ExtractFilePath(FileNames[0])), '', False); + Error := nil; + i := Engine.OpenFile(s, omWrite, @Error); + if i = nil then begin + if Error <> nil then begin + ShowError(Self, Format('An error occured while opening file ''%s''', [StrToUTF8(ExtractFileName(s))]), Error); + g_error_free(Error); + end; Exit; end; - Engine.CloseFile(i); - Engine.Remove(s); + Engine.CloseFile(i, nil); + Engine.Remove(s, nil); end; DebugMsg(['TFChecksumDruid.SetCurrentPage: CurrentPage = ', CurrentPage, ', new = ', Num]); @@ -443,7 +446,7 @@ begin // Compute maximal size of selected files MaxSize := 0; for i := 0 to FileNames.Count - 1 do begin - Stat := Engine.GetFileInfo(FileNames[i], True, True); + Stat := Engine.GetFileInfo(FileNames[i], True, True, nil); if Assigned(Stat) then begin Inc(MaxSize, Stat.Size); FreeDataItem(Stat); @@ -458,7 +461,7 @@ begin for i := 0 to FileNames.Count - 1 do begin ProcessingLabel.Caption := Format(LANGCCHKSUMNowProcessingFileS, [StrToUTF8(ExtractFileName(FileNames[i]))]); LastValue := Progress.Value; - Stat := Engine.GetFileInfo(FileNames[i], True, True); + Stat := Engine.GetFileInfo(FileNames[i], True, True, nil); Application.ProcessMessages; try if ProcessFile(FileNames[i], SFVRadioButton.Checked, s) then begin @@ -490,11 +493,12 @@ end; function TFChecksumDruid.ProcessFile(const FName: string; const IsItSFV: boolean; var HashString: string): boolean; const ChksumBlockSize = 65536*4; var FD: TEngineFileDes; - Error, Count: integer; + Count: integer; Buffer: Pointer; CRC: LongWord; MDContext: TMDContext; MDDigest: TMDDigest; + Error: PGError; begin HashString := ''; Result := False; @@ -508,16 +512,21 @@ begin CRC := 0; if not IsItSFV then MDInit(MDContext, MD_VERSION_5); - FD := Engine.OpenFile(FName, omRead, Error); - if Error <> 0 then begin - ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(ExtractFileName(FName)), GetErrorString(Error)]); + Error := nil; + FD := Engine.OpenFile(FName, omRead, @Error); + if FD = nil then begin + if Error <> nil then begin + ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(ExtractFileName(FName)), Error^.message]); + g_error_free(Error); + end; Exit; end; repeat - Count := Engine.ReadFile(FD, Buffer, ChksumBlockSize, Error); - if Error <> 0 then begin - ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileReadingFileSS, [StrToUTF8(ExtractFileName(FName)), GetErrorString(Error)]); - Engine.CloseFile(FD); + Count := Engine.ReadFile(FD, Buffer, ChksumBlockSize, @Error); + if Error <> nil then begin + ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileReadingFileSS, [StrToUTF8(ExtractFileName(FName)), Error^.message]); + g_error_free(Error); + Engine.CloseFile(FD, nil); Exit; end; if IsItSFV then CRC := CRC32(CRC, Buffer, Count) @@ -527,7 +536,7 @@ begin Application.ProcessMessages; CheckStop; until (Count < ChksumBlockSize) or Stop; - Engine.CloseFile(FD); + Engine.CloseFile(FD, nil); libc_free(Buffer); if IsItSFV then HashString := IntToHex(CRC, 8) else @@ -541,13 +550,18 @@ end; const ChksumBlockSize = 32768; // Maximum of PByteArray procedure TFChecksumDruid.WriteLine(const FName, CheckedFName, HashString: string; const IsItSFV, CreateFile, CloseFile: boolean); -var i, Error, Count: integer; +var i, Count: integer; s: string; + Error: PGError; begin if CreateFile then begin - FileDes := Engine.OpenFile(FName, omWrite, Error); - if Error <> 0 then begin - ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(ExtractFileName(FName)), GetErrorString(Error)]); + Error := nil; + FileDes := Engine.OpenFile(FName, omWrite, @Error); + if FileDes = nil then begin + if Error <> nil then begin + ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(ExtractFileName(FName)), Error^.message]); + g_error_free(Error); + end; Exit; end; try @@ -565,10 +579,12 @@ begin else s := Format('%s %s'#10, [Trim(AnsiLowerCase(HashString)), ExtractFileName(CheckedFName)]); for i := 1 to Length(s) do begin if BufferPos + 1 >= ChksumBlockSize then begin - Count := Engine.WriteFile(FileDes, Buffer, ChksumBlockSize, Error); + Error := nil; + Count := Engine.WriteFile(FileDes, Buffer, ChksumBlockSize, @Error); BufferPos := -1; - if (Error <> 0) or (Count <> ChksumBlockSize) then begin - ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileWritingFileSS, [StrToUTF8(ExtractFileName(FName)), GetErrorString(Error)]); + if (Error <> nil) { or (Count <> ChksumBlockSize) } then begin + ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileWritingFileSS, [StrToUTF8(ExtractFileName(FName)), Error^.message]); + g_error_free(Error); Exit; end; end; @@ -578,25 +594,32 @@ begin if CloseFile then begin Inc(BufferPos); // Counting with zero-starting element - Count := Engine.WriteFile(FileDes, Buffer, BufferPos, Error); - if (Error <> 0) or (Count <> BufferPos) then begin - ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileWritingFileSS, [StrToUTF8(ExtractFileName(FName)), GetErrorString(Error)]); + Error := nil; + Count := Engine.WriteFile(FileDes, Buffer, BufferPos, @Error); + if (Error <> nil) { or (Count <> BufferPos) } then begin + ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileWritingFileSS, [StrToUTF8(ExtractFileName(FName)), Error^.message]); + g_error_free(Error); Exit; end; BufferPos := -1; - Engine.CloseFile(FileDes); + Engine.CloseFile(FileDes, nil); libc_free(Buffer); end; end; procedure TFChecksumDruid.WriteSFVComment(const FName: string); -var i, Error, Count: integer; +var i, Count: integer; Stat: PDataItem; s: string; + Error: PGError; begin - FileDes := Engine.OpenFile(FName, omWrite, Error); - if Error <> 0 then begin - ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(ExtractFileName(FName)), GetErrorString(Error)]); + Error := nil; + FileDes := Engine.OpenFile(FName, omWrite, @Error); + if FileDes = nil then begin + if Error <> nil then begin + ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(ExtractFileName(FName)), Error^.message]); + g_error_free(Error); + end; Exit; end; try @@ -613,7 +636,7 @@ begin '; http://tuxcmd.sourceforge.net/'#13#10'; '#13#10'; /----'#13#10, [ConstAboutVersion, ConstAboutBuildDate, SysUtils.FormatDateTime('mm.dd.yyyy "at" hh:nn:ss', Now)]); for i := 0 to FileNames.Count - 1 do begin - Stat := Engine.GetFileInfo(FileNames[i], True, True); + Stat := Engine.GetFileInfo(FileNames[i], True, True, nil); if Assigned(Stat) then begin s := s + Format('; %s %s %s'#13#10, [PadRightStr(IntToStr(Stat^.Size), 11), FormatDate(Stat^.mtime, True, True, 999, 999, 1, '%Y-%m-%d', '%k:%M.%S'), ExtractFileName(FileNames[i])]); @@ -624,10 +647,12 @@ begin for i := 1 to Length(s) do begin if BufferPos + 1 >= ChksumBlockSize then begin - Count := Engine.WriteFile(FileDes, Buffer, ChksumBlockSize, Error); + Error := nil; + Count := Engine.WriteFile(FileDes, Buffer, ChksumBlockSize, @Error); BufferPos := -1; - if (Error <> 0) or (Count <> ChksumBlockSize) then begin - ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileWritingFileSS, [StrToUTF8(ExtractFileName(FName)), GetErrorString(Error)]); + if (Error <> nil) { or (Count <> ChksumBlockSize) } then begin + ErrorLabel.Caption := ErrorLabel.Caption + Format(LANGCCHKSUMAnErrorOccuredWhileWritingFileSS, [StrToUTF8(ExtractFileName(FName)), Error^.message]); + g_error_free(Error); Exit; end; end; diff --git a/UConfig.pas b/UConfig.pas index a8dc5b6..112ca1d 100644 --- a/UConfig.pas +++ b/UConfig.pas @@ -25,8 +25,8 @@ uses Classes, ULocale; resourcestring ConstAppTitle = 'Tux Commander'; - ConstAboutVersion = '0.6.73-dev'; - ConstAboutBuildDate = '2009-11-29'; + ConstAboutVersion = '0.6.74-dev'; + ConstAboutBuildDate = '2009-12-13'; {$IFDEF FPC} {$INCLUDE fpcver.inc} diff --git a/UConnectionManager.pas b/UConnectionManager.pas index a89147d..7109cc3 100644 --- a/UConnectionManager.pas +++ b/UConnectionManager.pas @@ -66,7 +66,7 @@ type Thread: TOpenConnectionThread; SourcePanelEngine: TPanelEngine; ConnectedEngine: TVFSEngine; - function DoConnectInternal(const URI: string; Engine: TVFSEngine; VFSDialogsParentWindow: PGtkWidget; VFSQuickConnectMode: boolean): boolean; + function DoConnectInternal(const URI: string; Engine: TVFSEngine; VFSDialogsParentWindow: PGtkWidget; VFSQuickConnectMode: boolean; Error: PPGError): boolean; end; var @@ -74,7 +74,7 @@ var implementation -uses ULocale, UCoreUtils, UConfig, UConnectionProperties, UGnome, UQuickConnect; +uses ULocale, UCoreUtils, UConfig, UConnectionProperties, UGnome, UQuickConnect, UError; procedure TFConnectionManager.FormCreate(Sender: TObject); @@ -539,6 +539,7 @@ var Engine: TVFSEngine; FActiveConnInfo: TConnMgrItem; DontShowAgain: boolean; res: TMessageButton; + Error: PGError; begin FActiveConnInfo := nil; if ListView.Selected <> nil then FActiveConnInfo := ListView.Selected.AsPointer(0); @@ -599,8 +600,10 @@ begin Engine.Password := FActiveConnInfo.Password; Engine.PasswordUsed := False; - if not DoConnectInternal(UTF8ToStr(FActiveConnInfo.GetURI(False)), Engine, FWidget, False) then begin - if not FSilenceError then Application.MessageBox(PGtkWindow(FWidget), LANGCouldntOpenURI, [mbOK], mbError, mbOK, mbOK); + Error := nil; + if not DoConnectInternal(UTF8ToStr(FActiveConnInfo.GetURI(False)), Engine, FWidget, False, @Error) then begin + if not FSilenceError then + ShowError(Self, 'Couldn''t open the URI specified', Error); ListViewTable.Enabled := True; CloseButton.Enabled := True; ConnectButton.Enabled := True; @@ -609,6 +612,8 @@ begin StopButton.Enabled := False; ListView.SetFocus; Engine.Free; + if Error <> nil then + g_error_free(Error); Exit; end; @@ -619,7 +624,7 @@ begin ModalResult := mbOK; end; -function TFConnectionManager.DoConnectInternal(const URI: string; Engine: TVFSEngine; VFSDialogsParentWindow: PGtkWidget; VFSQuickConnectMode: boolean): boolean; +function TFConnectionManager.DoConnectInternal(const URI: string; Engine: TVFSEngine; VFSDialogsParentWindow: PGtkWidget; VFSQuickConnectMode: boolean; Error: PPGError): boolean; begin Result := False; FSilenceError := False; @@ -658,6 +663,8 @@ begin end; until Thread.Finished; Result := Thread.OpenResult; + if Thread.OpenError <> nil then + g_propagate_error(Error, Thread.OpenError); FSilenceError := Thread.VFSCallbackCancelled; Thread.Free; Thread := nil; @@ -46,7 +46,7 @@ procedure GetDirSize(AListView: TGTKListView; Engine: TPanelEngine; DataList: TL procedure FillDefaultFstabMounterItems; function CRCGetInfo(FileName: string; Engine: TPanelEngine; var TargetName: string; var TargetCRC: LongWord; var Size: Int64): boolean; -function WriteCRCFile(Engine: TPanelEngine; TargetFile, SplitFileName: string; const FileSize: Int64; const FileCRC: Longword): boolean; +function WriteCRCFile(Sender: TObject; Engine: TPanelEngine; TargetFile, SplitFileName: string; const FileSize: Int64; const FileCRC: Longword): boolean; function ComputeBlockSize(TotalSize: Int64): longint; @@ -110,7 +110,7 @@ var LeftLocalEngine, RightLocalEngine: TPanelEngine; implementation (********************************************************************************************************************************) uses SysUtils, DateUtils, StrUtils, UConfig, UDirDelete, UOverwrite, ULocale, - UNewDir, UFileAssoc, USymlink, UCoreClasses, URemoteWait, UMain, UGnome; + UNewDir, UFileAssoc, USymlink, UCoreClasses, URemoteWait, UMain, UGnome, UError; @@ -416,9 +416,11 @@ var DirStage1List, FilesList, DirStage2List: TList; Item: PDataItem; ItemSL: PDataItemSL; ParentDir: string; + Error: PGError; begin LocalList := TList.Create; - if Engine.GetListing(LocalList, LocalPath, True, False, True) = 0 then begin + Error := nil; + if Engine.GetListing(LocalList, LocalPath, True, False, True, @Error) then begin if not SortForStream then FillDirFiles_sort(LocalList); for i := 0 to LocalList.Count - 1 do begin Item := LocalList[i]; @@ -436,8 +438,14 @@ var DirStage1List, FilesList, DirStage2List: TList; if Item^.IsDir then begin // Recurse to parent ParentDir := IncludeTrailingPathDelimiter(string(Item^.FName)); - if Engine.ChangeDir(ParentDir) = 0 then - FillDirFiles_Recurse(ParentDir, ALevel + 1); + Error := nil; + if Engine.ChangeDir(ParentDir, @Error) then + FillDirFiles_Recurse(ParentDir, ALevel + 1) + else begin + // * TODO: report and handle errors? we should make sure that user knows some of his data won't be copied + DebugMsg(['*** FillDirFiles_Recurse: error changing dir to ''', LocalPath, ''': ', Error^.message]); + g_error_free(Error); + end; // Add end stage ItemSL := DuplicateDataItem(ItemSL); ItemSL^.Stage1 := False; @@ -446,6 +454,9 @@ var DirStage1List, FilesList, DirStage2List: TList; end; end; end else begin + // * TODO: report and handle errors? we should make sure that user knows some of his data won't be copied + DebugMsg(['*** FillDirFiles_Recurse: error getting listing of ''', LocalPath, ''': ', Error^.message]); + g_error_free(Error); // Clear remaining items (in case of error) for i := 0 to LocalList.Count - 1 do FreeDataItem(PDataItem(LocalList[i])); @@ -511,7 +522,8 @@ var ItemSL: PDataItemSL; begin ItemSL := malloc(sizeof(TDataItemSL)); memset(ItemSL, 0, sizeof(TDataItemSL)); - ItemSL^.DataItem := Engine.GetFileInfo(APath, False, True); + // * TODO: report errors? same way as for FillDirFiles + ItemSL^.DataItem := Engine.GetFileInfo(APath, False, True, nil); ItemSL^.Stage1 := True; ItemSL^.Level := 1; Result := ItemSL; @@ -584,21 +596,13 @@ end; (********************************************************************************************************************************) (********************************************************************************************************************************) function MakeDirectory(ListView: TGTKListView; Engine: TPanelEngine; LeftPanel: boolean; NewDir: string): boolean; -var Error: integer; +var Error: PGError; begin - Result := False; - try - Error := Engine.MakeDir(IncludeTrailingPathDelimiter(Engine.Path) + NewDir); - if Error <> 0 then begin - Application.MessageBox(Format(LANGErrorCreatingNewDirectorySInSPanel, [StrToUTF8(NewDir), LANGPanelStrings[LeftPanel], GetErrorString(Error)]), [mbOK], mbError, mbNone, mbOK); - Exit; - end; - Result := True; - except - on E: Exception do begin - Application.MessageBox(Format(LANGErrorCreatingNewDirectorySInSPanelNoPath, [LANGPanelStrings[LeftPanel], E.Message]), [mbOK], mbError, mbNone, mbOK); - Exit; - end; + Error := nil; + Result := Engine.MakeDir(IncludeTrailingPathDelimiter(Engine.Path) + NewDir, @Error); + if not Result then begin + ShowError(FMain, Format('Error creating new directory ''%s'' in %s panel', [StrToUTF8(NewDir), LANGPanelStrings[LeftPanel]]), Error); + g_error_free(Error); end; end; @@ -607,10 +611,11 @@ function CreateSymlink(const FileName, PossibleNewName: string; Engine: TPanelEn var AFSymLink: TFSymlink; function HandleCreateSymlink(const OldName, NewName: string): boolean; - var Res, Response: integer; + var Response: integer; + Error: PGError; begin - Res := Engine.MakeSymLink(NewName, OldName); - Result := Res = 0; + Error := nil; + Result := Engine.MakeSymLink(NewName, OldName, @Error); if not Result then begin try FDirDelete := TFDirDelete.Create(AFSymlink); @@ -618,9 +623,10 @@ var AFSymLink: TFSymlink; FDirDelete.AddButtons(2); FDirDelete.Label1.Caption := LANGTheSymbolicLink; FDirDelete.Label2.Caption := NewName; - FDirDelete.Label3.Caption := Format(LANGCouldNotBeCreatedS, [GetErrorString(Res)]); + FDirDelete.Label3.Caption := Format(LANGCouldNotBeCreatedS, [Error^.message]); FDirDelete.Label3.Visible := True; Response := Integer(FDirDelete.Run); + g_error_free(Error); finally FDirDelete.Free; end; @@ -657,10 +663,11 @@ var Data: PDataItem; AFSymLink: TFSymlink; function HandleEditSymlink(const ExistingName, PointTo: string): boolean; - var Res, Response: integer; + var Response: integer; + Error: PGError; begin - Res := Engine.Remove(ExistingName); - Result := Res = 0; + Error := nil; + Result := Engine.Remove(ExistingName, @Error); if not Result then begin try FDirDelete := TFDirDelete.Create(AFSymlink); @@ -668,9 +675,10 @@ var Data: PDataItem; FDirDelete.AddButtons(2); FDirDelete.Label1.Caption := LANGTheSymbolicLink; FDirDelete.Label2.Caption := StrToUTF8(ExistingName); - FDirDelete.Label3.Caption := Format(LANGCouldNotBeDeletedS, [GetErrorString(Res)]); + FDirDelete.Label3.Caption := Format(LANGCouldNotBeDeletedS, [Error^.message]); FDirDelete.Label3.Visible := True; Response := Integer(FDirDelete.Run); + g_error_free(Error); finally FDirDelete.Free; end; @@ -679,8 +687,9 @@ var Data: PDataItem; end; Exit; end; - Res := Engine.MakeSymLink(ExistingName, PointTo); - Result := Res = 0; + + Error := nil; + Result := Engine.MakeSymLink(ExistingName, PointTo, @Error); if not Result then begin try FDirDelete := TFDirDelete.Create(AFSymlink); @@ -688,9 +697,10 @@ var Data: PDataItem; FDirDelete.AddButtons(2); FDirDelete.Label1.Caption := LANGTheSymbolicLink; FDirDelete.Label2.Caption := StrToUTF8(ExistingName); - FDirDelete.Label3.Caption := Format(LANGCouldNotBeCreatedS, [GetErrorString(Res)]); + FDirDelete.Label3.Caption := Format(LANGCouldNotBeCreatedS, [Error^.message]); FDirDelete.Label3.Visible := True; Response := Integer(FDirDelete.Run); + g_error_free(Error); finally FDirDelete.Free; end; @@ -703,7 +713,7 @@ var Data: PDataItem; begin Result := False; - Data := Engine.GetFileInfo(FileName, False, True); + Data := Engine.GetFileInfo(FileName, False, True, nil); if Data = nil then begin Result := False; Exit; @@ -869,10 +879,11 @@ function CRCGetInfo(FileName: string; Engine: TPanelEngine; var TargetName: stri end; const CRCBlockSize = 32768; -var i, Error, Count, Start: integer; +var i, Count, Start: integer; FD: TEngineFileDes; Buffer: Pointer; s: string; + Error: PGError; begin Result := False; if Pos('.', FileName) > 1 then FileName := ChangeFileExt(FileName, '.crc') @@ -884,15 +895,21 @@ begin Application.MessageBox(LANGAnErrorOccuredWhileInitializingMemoryBlock, [mbOK], mbError, mbNone, mbOK); Exit; end; - FD := Engine.OpenFile(FileName, omRead, Error); - if Error <> 0 then Exit; + Error := nil; + FD := Engine.OpenFile(FileName, omRead, @Error); + if Error <> nil then begin + g_error_free(nil); + Exit; + end; s := ''; repeat - Count := Engine.ReadFile(FD, Buffer, CRCBlockSize, Error); - if Error <> 0 then begin + Error := nil; + Count := Engine.ReadFile(FD, Buffer, CRCBlockSize, @Error); + if Error <> nil then begin libc_free(Buffer); - Engine.CloseFile(FD); + g_error_free(nil); + Engine.CloseFile(FD, nil); Exit; end; // processing begins @@ -911,33 +928,39 @@ begin until Count < CRCBlockSize; if Length(s) > 0 then ProcessLine(s); - Engine.CloseFile(FD); + Engine.CloseFile(FD, nil); libc_free(Buffer); Result := True; end; (********************************************************************************************************************************) -function WriteCRCFile(Engine: TPanelEngine; TargetFile, SplitFileName: string; const FileSize: Int64; const FileCRC: Longword): boolean; +function WriteCRCFile(Sender: TObject; Engine: TPanelEngine; TargetFile, SplitFileName: string; const FileSize: Int64; const FileCRC: Longword): boolean; var FD: TEngineFileDes; - Error, Count: integer; + Count: integer; s: string; + Error: PGError; begin Result := False; if Pos('.', TargetFile) > 1 then TargetFile := ChangeFileExt(TargetFile, '.crc') else TargetFile := TargetFile + '.crc'; - FD := Engine.OpenFile(TargetFile, omWrite, Error); - if Error <> 0 then begin - Application.MessageBox(Format(LANGAnErrorOccuredWhileOpeningFileSS, [TargetFile, GetErrorString(Error)]), [mbOK], mbError, mbNone, mbOK); + Error := nil; + FD := Engine.OpenFile(TargetFile, omWrite, @Error); + if FD = nil then begin + if Error <> nil then begin + ShowError(TCustomGTKForm(Sender), Format('An error occured while opening file ''%s''', [TargetFile]), Error); + g_error_free(Error); + end; Exit; end; s := Format('filename=%s'#13#10'size=%d'#13#10'crc32=%s'#13#10, [SplitFileName, FileSize, WideUpperCase(IntToHex(FileCRC, 8))]); - Count := Engine.WriteFile(FD, @s[1], Length(s), Error); - if (Error <> 0) or (Count <> Length(s)) then begin - Application.MessageBox(Format(LANGAnErrorOccuredWhileWritingFileSS, [TargetFile, GetErrorString(Error)]), [mbOK], mbError, mbNone, mbOK); + Count := Engine.WriteFile(FD, @s[1], Length(s), @Error); + if (Error <> nil) { or (Count <> Length(s)) } then begin + ShowError(TCustomGTKForm(Sender), Format('An error occured while writing file ''%s''', [TargetFile]), Error); + g_error_free(Error); Exit; end; - Engine.CloseFile(FD); + Engine.CloseFile(FD, nil); Result := True; end; diff --git a/UCoreUtils.pas b/UCoreUtils.pas index f319d44..faf6eb5 100644 --- a/UCoreUtils.pas +++ b/UCoreUtils.pas @@ -34,9 +34,6 @@ const ConstERRSpawn = 26; ConstQuotationCharacters = [' ', '"', '''', '(', ')', ':', '&']; ConstURIIllegalCharacters = '%:@/'; -function GetErrorString(ErrorNo: integer): string; -function GetSignalString(SignalNo: integer): string; - function FormatSize(Value: Int64; Base: integer; OverrideSizeFormat: integer = -1): string; function FormatDate(Value: time_t; const FormatTime, FormatDate: boolean; OverrideTimeFormat: integer = -1; OverrideDateFormat: integer = -1; OverrideDateTimeFormat: integer = -1; OverrideCustomDateFormat: string = ''; OverrideCustomTimeFormat: string = ''): string; function StripDate(Value: time_t): time_t; @@ -144,24 +141,6 @@ implementation uses DateUtils, GTKForms, GTKUtils, GTKView, ULocale, UConfig, UCore, UGnome, UMain, UFileAssoc; (********************************************************************************************************************************) -function GetErrorString(ErrorNo: integer): string; -begin - if ErrorNo >= 0 then Result := StrToUTF8(String(strerror(ErrorNo))) - else - case ErrorNo of - ERRException : Result := LANGUnknownException; - ERRNoAccess : Result := LANGNoAccess; - else Result := LANGUnknownError; - end; -end; - -(********************************************************************************************************************************) -function GetSignalString(SignalNo: integer): string; -begin - Result := StrToUTF8(strsignal(SignalNo)); -end; - -(********************************************************************************************************************************) function FormatFloat64(Value: Int64; Sep: string): string; var i : integer; Orig : string; @@ -1127,13 +1106,18 @@ end; (********************************************************************************************************************************) procedure DebugMsg(Params: array of const); -var - I: Integer; +var I: Integer; + P: PChar; begin if ParamDebug then begin for I := 0 to High(Params) do with Params[I] do case VType of + vtPointer: begin + P := g_strdup_printf('%p', VPointer); + Write(ErrOutput, P); + g_free(P); + end; vtInteger: Write(ErrOutput, IntToStr(VInteger)); vtBoolean: Write(ErrOutput, VBoolean); vtChar: Write(ErrOutput, VChar); diff --git a/UCoreWorkers.pas b/UCoreWorkers.pas index 6eabc1e..72dd60f 100644 --- a/UCoreWorkers.pas +++ b/UCoreWorkers.pas @@ -26,6 +26,7 @@ type TVFSCallbackThread = class(TThread) private FThreadID: __pthread_t; FCopyProgressFunc: TEngineProgressFunc; + // * TODO: move to Create() ? procedure PrepareExecute; // Call this right after thread has been started public AEngine: TPanelEngine; @@ -143,7 +144,7 @@ type TVFSCallbackThread = class(TThread) TOpenDirThread = class(TVFSCallbackThread) private - function ChangeDir(Engine: TPanelEngine; Path: string; var SelItem: string; const AutoFallBack: boolean): integer; + function ChangeDir(Engine: TPanelEngine; Path: string; var SelItem: string; const AutoFallBack: boolean): boolean; protected procedure Execute; override; public @@ -151,10 +152,11 @@ type TVFSCallbackThread = class(TThread) ASelItem: string; AAutoFallBack: boolean; ADirList: TList; - ChDirResult, ListingResult, VFSOpenResult: integer; Finished, CancelIt: boolean; RunningTime: Int64; AFullPath, AHighlightItem: string; + ChDirResult, ListingResult, VFSOpenResult: boolean; + ChDirError, ListingError, VFSOpenError: PGError; constructor Create; destructor Destroy; override; end; @@ -167,6 +169,7 @@ type TVFSCallbackThread = class(TThread) URI: string; Finished: boolean; OpenResult: boolean; + OpenError: PGError; constructor Create; destructor Destroy; override; end; @@ -349,16 +352,17 @@ begin password_save^ := VFS_PASSWORD_SAVE_NEVER; end; -function vfs_progress_callback(position, max: guint64; user_data: Pointer): gboolean; cdecl; +// Keep in sync with uVFSprototypes.pas/TVFSProgressCallback +function vfs_copy_progress_callback(position: guint64; error: PGError; user_data: Pointer): gboolean; cdecl; begin // DebugMsg(['VFSCopyCallBackFunc called (iPos = ', iPos, ', iMax = ', iMax, ')']); Result := True; if not Assigned(user_data) then Exit; if Assigned(TVFSCallbackThread(user_data).FCopyProgressFunc) then try - Result := TVFSCallbackThread(user_data).FCopyProgressFunc(user_data, position); + Result := TVFSCallbackThread(user_data).FCopyProgressFunc(user_data, position, error); except - on E: Exception do DebugMsg(['*** Exception raised in vfs_progress_callback(position=', position, ', max=', max, ', user_data=', user_data, '): (', E.ClassName, '): ', E.Message]); + on E: Exception do DebugMsg(['*** Exception raised in vfs_copy_progress_callback(position=', position, ', user_data=', user_data, '): (', E.ClassName, '): ', E.Message]); end; end; @@ -729,19 +733,23 @@ end; procedure DeleteFilesWorker(SenderThread: TWorkerThread); var SkipAll: boolean; + // Return False to break the operation function HandleDelete(AFileRec: PDataItemSL): boolean; - var Res, Response: integer; + var Response: integer; + Res: boolean; + Error: PGError; begin Result := True; + Error := nil; // DebugMsg(['Debug: IsDir: ', AFileRec^.IsDir, ', Stage1: ', AFileRec^.Stage1, ', IsLnk: ', AFileRec^.IsLnk, '; Result = ', AFileRec^.IsDir and AFileRec^.Stage1 and (not AFileRec^.IsLnk)]); if AFileRec^.DataItem^.IsDir and AFileRec^.Stage1 and (not AFileRec^.DataItem^.IsLnk) then Exit; - Res := SenderThread.Engine.Remove(String(AFileRec^.DataItem^.FName)); + Res := SenderThread.Engine.Remove(String(AFileRec^.DataItem^.FName), @Error); // DebugMsg(['Result : ', Res]); - if Res <> 0 then + if not Res then if SkipAll then Result := True else begin Response := SenderThread.ShowDirDeleteDialog(1, LANGTheFileDirectory, String(AFileRec^.DataItem^.FDisplayName), - Format(LANGCouldNotBeDeletedS, [GetErrorString(Res)])); + Format(LANGCouldNotBeDeletedS, [Error^.message])); case Response of 1 : Result := True; 3 : begin @@ -752,6 +760,8 @@ var SkipAll: boolean; else Result := False; end; end; + if Error <> nil then + g_error_free(Error); end; var i: longint; @@ -766,7 +776,9 @@ begin with SenderThread do begin CurrPath := IncludeTrailingPathDelimiter(Engine.Path); PrepareJobFilesFromPanel(AList, False); - if Engine.ChangeDir(CurrPath) <> 0 then DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour might occur.']); + // * TODO: catch the error + if not Engine.ChangeDir(CurrPath, nil) then + DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour might occur.']); libc_chdir('/'); SetProgress1Params(AList.Count); @@ -814,7 +826,9 @@ begin for i := AList.Count - 1 downto 0 do FreeDataItem(PDataItemSL(AList[i])); AList.Clear; AList.Free; - if Engine.ChangeDir(CurrPath) <> 0 then DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour might occur.']); + // * TODO: catch the error + if not Engine.ChangeDir(CurrPath, nil) then + DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour might occur.']); end; SenderThread.FDoneThread := True; end; @@ -825,8 +839,8 @@ end; (********************************************************************************************************************************) (********************************************************************************************************************************) - // Return False to break the process - function CopyFilesWorker_ProgressFunc(Sender: Pointer; BytesDone: Int64): boolean; cdecl; + // Keep in sync with UEngines.pas/TEngineProgressFunc + function CopyFilesWorker_ProgressFunc(Sender: Pointer; BytesDone: Int64; Error: PGError): boolean; cdecl; begin Result := True; // DebugMsg(['*** CopyFilesWorker: ProgressFunc called (Sender=', QWord(Sender), ', BytesDone=', BytesDone, ')']); @@ -872,7 +886,8 @@ end; if ErrorType <> 1 then s3 := StrToUTF8(FileName) else s3 := ''; - case ShowDirDeleteDialog(3, s, s3, GetErrorString(ErrorNum), s2) of + // * TODO: fix error string + case ShowDirDeleteDialog(3, s, s3, 'ahoj' { GetErrorString(ErrorNum)} , s2) of 0, 252 : begin // Cancel button, Escape Result := False; CancelIt; @@ -908,25 +923,28 @@ var DefResponse: integer; // Global variables for this function // Returns True if file was successfully copied, if not, the file will be deleted in LocalCopyFile function ManualCopyFile(SourceFile, DestFile: string; Append: boolean): boolean; var fsrc, fdst: TEngineFileDes; - Error, BSize: integer; + BSize: integer; Buffer: Pointer; BytesDone, BytesRead, BytesWritten: Int64; Res: boolean; + Error: PGError; begin DebugMsg(['ManualCopyFile: ', SourceFile, ' ---> ', DestFile]); with SenderThread do begin Result := False; - Error := 0; - fsrc := SrcEngine.OpenFile(SourceFile, omRead, Error); - if Error <> 0 then begin - CopyFilesWorker_ErrorFunc(SenderThread, 2, Error, SourceFile); // Cannot open source file + Error := nil; + fsrc := SrcEngine.OpenFile(SourceFile, omRead, @Error); + if fsrc = nil then begin + // * TODO: set real error, also free it + CopyFilesWorker_ErrorFunc(SenderThread, 2, 1 { Error }, SourceFile); // Cannot open source file Exit; end; - if Append then fdst := DestEngine.OpenFile(DestFile, omAppend, Error) - else fdst := DestEngine.OpenFile(DestFile, omWrite, Error); - if Error <> 0 then begin - SrcEngine.CloseFile(fsrc); - CopyFilesWorker_ErrorFunc(SenderThread, 3, Error, SourceFile); // Cannot open target file + if Append then fdst := DestEngine.OpenFile(DestFile, omAppend, @Error) + else fdst := DestEngine.OpenFile(DestFile, omWrite, @Error); + if fdst = nil then begin + // * TODO: set real error, also free it + SrcEngine.CloseFile(fsrc, nil); + CopyFilesWorker_ErrorFunc(SenderThread, 3, 1 { Error }, SourceFile); // Cannot open target file Exit; end; @@ -944,27 +962,32 @@ var DefResponse: integer; // Global variables for this function BytesWritten := 0; repeat - BytesRead := SrcEngine.ReadFile(fsrc, Buffer, BSize, Error); - if (BytesRead = 0) and (Error <> 0) then - Res := CopyFilesWorker_ErrorFunc(SenderThread, 6, Error, SourceFile); // Cannot read from source file + BytesRead := SrcEngine.ReadFile(fsrc, Buffer, BSize, @Error); + if (BytesRead = 0) and (Error <> nil) then + // * TODO: set real error, also free it + Res := CopyFilesWorker_ErrorFunc(SenderThread, 6, 1 { Error }, SourceFile); // Cannot read from source file if BytesRead > 0 then begin - BytesWritten := DestEngine.WriteFile(fdst, Buffer, BytesRead, Error); + Error := nil; + BytesWritten := DestEngine.WriteFile(fdst, Buffer, BytesRead, @Error); if (BytesWritten < BytesRead) then - Res := CopyFilesWorker_ErrorFunc(SenderThread, 7, Error, DestFile); // Cannot write to source file + // * TODO: set real error, also free it + Res := CopyFilesWorker_ErrorFunc(SenderThread, 7, 1 { Error }, DestFile); // Cannot write to source file end; Inc(BytesDone, BytesRead); - if not CopyFilesWorker_ProgressFunc(SenderThread, BytesDone) then begin + if not CopyFilesWorker_ProgressFunc(SenderThread, BytesDone, nil) then begin Res := False; Break; end; until (BytesRead = 0) or (BytesWritten < BytesRead); libc_free(Buffer); - if DestEngine.CloseFile(fdst) <> 0 then begin + // * TODO: set real error, also free it + if not DestEngine.CloseFile(fdst, nil) then begin CopyFilesWorker_ErrorFunc(SenderThread, 4, errno, DestFile); // Cannot close target file Exit; end; - if SrcEngine.CloseFile(fsrc) <> 0 then begin + // * TODO: set real error, also free it + if not SrcEngine.CloseFile(fsrc, nil) then begin CopyFilesWorker_ErrorFunc(SenderThread, 5, errno, SourceFile); // Cannot close source file Exit; end; @@ -984,21 +1007,21 @@ var DefResponse: integer; // Global variables for this function // local -> local if (SrcEngine is TLocalTreeEngine) and (DestEngine is TLocalTreeEngine) - then Result := DestEngine.CopyFileIn(SenderThread, SourceFile, DestFile, @CopyFilesWorker_ProgressFunc, @CopyFilesWorker_ErrorFunc, Append) + then Result := DestEngine.CopyFileIn(SourceFile, DestFile, Append, @CopyFilesWorker_ProgressFunc, SenderThread) else // from local engine to VFS engine if (SrcEngine is TLocalTreeEngine) and (DestEngine is TVFSEngine) then begin AEngine := DestEngine; - Result := (DestEngine as TVFSEngine).CopyFileInEx(SenderThread, SourceFile, DestFile, @CopyFilesWorker_ErrorFunc, Append); + Result := (DestEngine as TVFSEngine).CopyFileInEx(SourceFile, DestFile, 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); + Result := (SrcEngine as TVFSEngine).CopyFileOutEx(SourceFile, DestFile, Append); end // VFS to VFS (not supported yet) @@ -1011,11 +1034,14 @@ var DefResponse: integer; // Global variables for this function // Copy OK? (check size, otherwise delete target file) if (not Append) and (not Result) then begin - DataSrc := SrcEngine.GetFileInfo(SourceFile, False, True); + // * TODO: check error + DataSrc := SrcEngine.GetFileInfo(SourceFile, False, True, nil); if DataSrc = nil then Exit; - DataDest := DestEngine.GetFileInfo(DestFile, False, True); + // * TODO: check error + DataDest := DestEngine.GetFileInfo(DestFile, False, True, nil); if (DataDest <> nil) and (DataSrc^.Size <> DataDest^.Size) then - DestEngine.Remove(DestFile); + // * TODO: check error + DestEngine.Remove(DestFile, nil); FreeDataItem(DataSrc); FreeDataItem(DataDest); end; @@ -1066,41 +1092,47 @@ var DefResponse: integer; // Global variables for this function if DataItem^.IsLnk then begin // Explicit copy the file if ParamBool3 or (not IsOnSameFS(String(DataItem^.FName), ExtractFileDir(Dst))) then begin - ErrorKind := DestEngine.MakeSymLink(Dst, String(DataItem^.LnkPointTo)); - if ErrorKind <> 0 then Result := ERRCreateLink; + // * TODO: check error + ErrorKind := Ord(DestEngine.MakeSymLink(Dst, String(DataItem^.LnkPointTo), nil)); +// if ErrorKind <> 0 then Result := ERRCreateLink; if not ParamBool3 then begin - ErrorKind := SrcEngine.Remove(String(DataItem^.FName)); - if ErrorKind <> 0 then Result := ERRRemove; + // * TODO: check error + ErrorKind := Ord(SrcEngine.Remove(String(DataItem^.FName), nil)); +// if ErrorKind <> 0 then Result := ERRRemove; end; end else begin // Move the file - ErrorKind := DestEngine.RenameFile(String(DataItem^.FName), Dst); - if ErrorKind <> 0 then Result := ERRCopyMove; + // * TODO: check error + ErrorKind := Ord(DestEngine.RenameFile(String(DataItem^.FName), Dst, nil)); +// if ErrorKind <> 0 then Result := ERRCopyMove; end; end else // is not link if ParamBool3 then begin // Copy mode if LocalCopyFile(String(DataItem^.FName), Dst, Append) then begin if IsOnRO and ConfClearReadOnlyAttr and (DataItem^.Mode and S_IWUSR = 0) then DataItem^.Mode := DataItem^.Mode or S_IWUSR; - DestEngine.Chmod(Dst, DataItem^.Mode); - DestEngine.Chown(Dst, DataItem^.UID, DataItem^.GID); - DestEngine.ChangeTimes(Dst, DataItem^.mtime, DataItem^.atime); + // * TODO: check error + DestEngine.Chmod(Dst, DataItem^.Mode, nil); + DestEngine.Chown(Dst, DataItem^.UID, DataItem^.GID, nil); + DestEngine.ChangeTimes(Dst, DataItem^.mtime, DataItem^.atime, nil); end; end else // Move mode if IsOnSameFS(String(DataItem^.FName), ExtractFileDir(Dst)) then begin if TwoSameFiles(String(DataItem^.FName), Dst, True) and (not TwoSameFiles(String(DataItem^.FName), Dst, False)) then begin DebugMsg(['*** Activating double-rename due to renaming on case-insensitive FS']); - ErrorKind := DestEngine.RenameFile(String(DataItem^.FName), Dst + '_tcmd'); - if ErrorKind = 0 then ErrorKind := DestEngine.RenameFile(Dst + '_tcmd', Dst); - end else ErrorKind := DestEngine.RenameFile(String(DataItem^.FName), Dst); - if ErrorKind <> 0 then Result := ERRCopyMove; + // * TODO: check error + ErrorKind := Ord(DestEngine.RenameFile(String(DataItem^.FName), Dst + '_tcmd', nil)); + if ErrorKind = 0 then ErrorKind := Ord(DestEngine.RenameFile(Dst + '_tcmd', Dst, nil)); + end else ErrorKind := Ord(DestEngine.RenameFile(String(DataItem^.FName), Dst, nil)); +// if ErrorKind <> 0 then Result := ERRCopyMove; end else begin if LocalCopyFile(String(DataItem^.FName), Dst, Append) then begin if IsOnRO and ConfClearReadOnlyAttr and (DataItem^.Mode and S_IWUSR = 0) then DataItem^.Mode := DataItem^.Mode or S_IWUSR; - DestEngine.Chmod(Dst, DataItem^.Mode); - DestEngine.Chown(Dst, DataItem^.UID, DataItem^.GID); - DestEngine.ChangeTimes(Dst, DataItem^.mtime, DataItem^.atime); + // * TODO: check error + DestEngine.Chmod(Dst, DataItem^.Mode, nil); + DestEngine.Chown(Dst, DataItem^.UID, DataItem^.GID, nil); + DestEngine.ChangeTimes(Dst, DataItem^.mtime, DataItem^.atime, nil); if not Cancelled then begin - ErrorKind := SrcEngine.Remove(String(DataItem^.FName)); - if ErrorKind <> 0 then Result := ERRRemove; + ErrorKind := Ord(SrcEngine.Remove(String(DataItem^.FName), nil)); +// if ErrorKind <> 0 then Result := ERRRemove; end; end; end; @@ -1126,10 +1158,11 @@ var DefResponse: integer; // Global variables for this function if (not AFileRec^.Stage1) and (ParamBool3 or ((not ParamBool3) and (not AFileRec^.ForceMove))) then with AFileRec^ do begin if IsOnRO and ConfClearReadOnlyAttr and (DataItem^.Mode and S_IWUSR = 0) then DataItem^.Mode := DataItem^.Mode or S_IWUSR; - DestEngine.Chmod(NewFilePath, DataItem^.Mode); - DestEngine.Chown(NewFilePath, DataItem^.UID, DataItem^.GID); - DestEngine.ChangeTimes(NewFilePath, DataItem^.mtime, DataItem^.atime); - if not ParamBool3 then SrcEngine.Remove(String(DataItem^.FName)); // Remove directory + // * TODO: check error + DestEngine.Chmod(NewFilePath, DataItem^.Mode, nil); + DestEngine.Chown(NewFilePath, DataItem^.UID, DataItem^.GID, nil); + DestEngine.ChangeTimes(NewFilePath, DataItem^.mtime, DataItem^.atime, nil); + if not ParamBool3 then SrcEngine.Remove(String(DataItem^.FName), nil); // Remove directory Exit; end; @@ -1142,28 +1175,33 @@ var DefResponse: integer; // Global variables for this function TwoSameFiles(ExcludeTrailingPathDelimiter(string(AFileRec^.DataItem^.FName)), ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)), False)) then begin DebugMsg(['*** Activating double-rename due to renaming on case-insensitive FS']); - ErrorKind := DestEngine.RenameFile(string(AFileRec^.DataItem^.FName), ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)) + '_tcmd'); - if ErrorKind = 0 then ErrorKind := DestEngine.RenameFile(ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)) + '_tcmd', ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination))); - end else ErrorKind := DestEngine.RenameFile(string(AFileRec^.DataItem^.FName), string(AFileRec^.ADestination)); - if ErrorKind <> 0 then Res := ERRCopyMove - else Res := 0; + // * TODO: check error + ErrorKind := Ord(DestEngine.RenameFile(string(AFileRec^.DataItem^.FName), ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)) + '_tcmd', nil)); + if ErrorKind = 0 then ErrorKind := ord(DestEngine.RenameFile(ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)) + '_tcmd', ExcludeTrailingPathDelimiter(string(AFileRec^.ADestination)), nil)); + end else ErrorKind := Ord(DestEngine.RenameFile(string(AFileRec^.DataItem^.FName), string(AFileRec^.ADestination), nil)); +{ if ErrorKind <> 0 then Res := ERRCopyMove + else Res := 0; } end else if not DestEngine.DirectoryExists(NewFilePath, False) then begin - ErrorKind := DestEngine.MakeDir(NewFilePath); - if ErrorKind <> 0 then Res := ERRMkDir - else Res := 0; + // * TODO: check error + ErrorKind := Ord(DestEngine.MakeDir(NewFilePath, nil)); +{ if ErrorKind <> 0 then Res := ERRMkDir + else Res := 0; } end; end else begin // not a directory - if not DestEngine.DirectoryExists(ExtractFileDir(NewFilePath), False) then DestEngine.MakeDir(ExtractFileDir(NewFilePath)); + if not DestEngine.DirectoryExists(ExtractFileDir(NewFilePath), False) then + // * TODO: check error + DestEngine.MakeDir(ExtractFileDir(NewFilePath), nil); SetProgress1Params(AFileRec^.DataItem^.Size + Ord(AFileRec^.DataItem^.Size = 0)); if AFileRec^.DataItem^.Size <= 1 then ParamFloat2 := 1 else ParamFloat2 := 100 / (AFileRec^.DataItem^.Size - 1); - CopyFilesWorker_ProgressFunc(SenderThread, 0); + CopyFilesWorker_ProgressFunc(SenderThread, 0, nil); Res := 0; if DestEngine.FileExists(NewFilePath, False) and (not (not ParamBool3 and (not TwoSameFiles(NewFilePath, AFileRec^.DataItem^.FName, False)) and TwoSameFiles(NewFilePath, AFileRec^.DataItem^.FName, True))) then begin Response := DefResponse; - Item := DestEngine.GetFileInfo(NewFilePath, False, True); + // * TODO: check error + Item := DestEngine.GetFileInfo(NewFilePath, False, True, nil); if Item = nil then begin DebugMsg(['Something went terribly wrong during copy - Item := DestEngine.GetFileInfoSL(NewFilePath) == NULL!']); Result := False; @@ -1201,16 +1239,19 @@ var DefResponse: integer; // Global variables for this function // Remove destination file if exists and should be overwritten if (Response in [1, 2]) or ((Response = 5) and (Item^.mtime < AFileRec^.DataItem^.mtime)) then begin - r := DestEngine.Remove(NewFilePath); + // * TODO: check error + r := ord(DestEngine.Remove(NewFilePath, nil)); while r <> 0 do begin + // * TODO: check error Res := ShowDirDeleteDialog(1, LANGTheFile, StrToUTF8(String(NewFilePath)), - Format(LANGCouldNotBeDeletedS, [GetErrorString(r)]), LANGCopyError); + Format(LANGCouldNotBeDeletedS, ['ahoj' {GetErrorString(r)}]), LANGCopyError); case Res of 1: begin Result := True; Exit; end; - 2: r := DestEngine.Remove(NewFilePath); + // * TODO: check error + 2: r := Ord(DestEngine.Remove(NewFilePath, nil)); 0, 124, 255: begin Result := False; Exit; @@ -1226,7 +1267,8 @@ var DefResponse: integer; // Global variables for this function if (Res <> 0) and (not SkipAll) then begin if ParamBool3 then cap := LANGCopy else cap := LANGMove; - case Res of + // * TODO: port to GError +{ case Res of ERRCreateLink: begin s1 := LANGTheSymbolicLink; if ErrorKind = 0 then s3 := LANGCouldNotBeCreated else @@ -1250,7 +1292,7 @@ var DefResponse: integer; // Global variables for this function if ErrorKind = 0 then s3 := '' else s3 := GetErrorString(ErrorKind); end; - end; + end; } Response := ShowDirDeleteDialog(1, s1, StrToUTF8(String(NewFilePath)), s3, cap); case Response of 1 : Result := True; // Skip @@ -1396,9 +1438,9 @@ begin if List.Count > 0 then begin StartPassed := True; if SrcEngine is TVFSEngine then - StartPassed := StartPassed and (SrcEngine as TVFSEngine).StartCopyOperation(SenderThread, @CopyFilesWorker_ErrorFunc, @vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_progress_callback, SenderThread); + StartPassed := StartPassed and (SrcEngine as TVFSEngine).StartCopyOperation(@vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_copy_progress_callback, SenderThread); if DestEngine is TVFSEngine then - StartPassed := StartPassed and (DestEngine as TVFSEngine).StartCopyOperation(SenderThread, @CopyFilesWorker_ErrorFunc, @vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_progress_callback, SenderThread); + StartPassed := StartPassed and (DestEngine as TVFSEngine).StartCopyOperation(@vfs_ask_question_callback, @vfs_ask_password_callback, @vfs_copy_progress_callback, SenderThread); if StartPassed then for i := 0 to List.Count - 1 do begin @@ -1442,9 +1484,9 @@ begin // We need to ensure these to be called in case of error if SrcEngine is TVFSEngine then - (SrcEngine as TVFSEngine).StopCopyOperation(SenderThread, @CopyFilesWorker_ErrorFunc); + (SrcEngine as TVFSEngine).StopCopyOperation(@vfs_copy_progress_callback, SenderThread); if DestEngine is TVFSEngine then - (DestEngine as TVFSEngine).StopCopyOperation(SenderThread, @CopyFilesWorker_ErrorFunc); + (DestEngine as TVFSEngine).StopCopyOperation(@vfs_copy_progress_callback, SenderThread); end; // Free the objects @@ -1452,9 +1494,13 @@ begin for i := List.Count - 1 downto 0 do FreeDataItem(PDataItemSL(List[i])); List.Clear; List.Free; - if DestEngine.ChangeDir(SaveDestPath) <> 0 then DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour might occur.']); + // * TODO: check error + if not DestEngine.ChangeDir(SaveDestPath, nil) then + DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour might occur.']); if SaveSrcPath <> '' then CurrPath := SaveSrcPath; - if SrcEngine.ChangeDir(CurrPath) <> 0 then DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour might occur.']); + // * TODO: check error + if not SrcEngine.ChangeDir(CurrPath, nil) then + DebugMsg(['*** WARNING: Cannot change to the origin location, strange behaviour might occur.']); end; SenderThread.FDoneThread := True; DebugMsg(['(II) CopyFilesWorker: finished']); @@ -1474,12 +1520,13 @@ procedure MergeFilesWorker(SenderThread: TWorkerThread); // ParamInt64 = TargetSize var FD: TEngineFileDes; - Error, Count, MergeBlockSize: integer; + Count, MergeBlockSize: integer; Buffer: Pointer; CurrentCRC: LongWord; PrivateCancel: boolean; SizeDone: Int64; TargetName: string; + Error: PGError; function PasteFile(FName: string): boolean; @@ -1493,21 +1540,26 @@ var FD: TEngineFileDes; else UpdateCaption1(Format(LANGFromS, [StrToUTF8(FName)])); UpdateProgress1(0, '0 %'); CommitGUIUpdate; - Stat := Engine.GetFileInfo(FName, True, True); + // * TODO: check error + Stat := Engine.GetFileInfo(FName, True, True, nil); if not Assigned(Stat) then Exit; SetProgress1Params(Stat^.Size); FreeDataItem(Stat); - FDR := Engine.OpenFile(FName, omRead, Error); - if Error <> 0 then Exit; + // * TODO: check error + Error := nil; + FDR := Engine.OpenFile(FName, omRead, @Error); + if FDR = nil then Exit; repeat - Count := Engine.ReadFile(FDR, Buffer, MergeBlockSize, Error); - if Error <> 0 then begin - Engine.CloseFile(FD); + // * TODO: check error + Count := Engine.ReadFile(FDR, Buffer, MergeBlockSize, @Error); + if Error <> nil then begin + Engine.CloseFile(FD, nil); Exit; end; - wCount := Engine.WriteFile(FD, Buffer, Count, Error); - if (Error <> 0) or (Count <> wCount) then begin - FCancelMessage := Format(LANGAnErrorOccuredWhileWritingFileSS, [ExtractFileName(TargetName), GetErrorString(Error)]); + // * TODO: check error + wCount := Engine.WriteFile(FD, Buffer, Count, @Error); + if (Error <> nil) or (Count <> wCount) then begin + FCancelMessage := Format(LANGAnErrorOccuredWhileWritingFileSS, [ExtractFileName(TargetName), Error^.message]); FShowCancelMessage := True; PrivateCancel := True; Result := True; // Fake this to don't show next disc dialog @@ -1519,7 +1571,8 @@ var FD: TEngineFileDes; if ParamBool1 then UpdateProgress2(SizeDone, Format('%d %%', [Trunc(SizeDone / FProgress2Max * 100)])); CommitGUIUpdate; until (Count < MergeBlockSize) or Cancelled; - Engine.CloseFile(FDR); + // * TODO: set real error, also free it + Engine.CloseFile(FDR, nil); end; Result := True; end; @@ -1541,15 +1594,17 @@ begin if Engine.FileExists(TargetName, False) then if ShowMessageBox(Format(LANGTheTargetFileSAlreadyExistsDoYouWantToOverwriteIt, [StrToUTF8(TargetName)]), [mbYes, mbNo], mbQuestion, mbNone, mbNo) = mbYes then begin - Error := Engine.Remove(TargetName); + // * TODO: check error +{ Error := Ord(Engine.Remove(TargetName, nil)); if Error <> 0 then begin FCancelMessage := Format(LANGTheTargetFileSCannotBeRemovedS, [StrToUTF8(ExtractFileName(TargetName)), GetErrorString(Error)]); FShowCancelMessage := True; Exit; - end; + end; } end else Exit; - Stat := Engine.GetFileInfo(ParamString2, True, True); + // * TODO: check error + Stat := Engine.GetFileInfo(ParamString2, True, True, nil); if Assigned(Stat) then MergeBlockSize := ComputeBlockSize(Stat^.Size) else MergeBlockSize := 65536*4; FreeDataItem(Stat); @@ -1561,9 +1616,10 @@ begin FShowCancelMessage := True; Exit; end; - FD := Engine.OpenFile(TargetName, omWrite, Error); - if Error <> 0 then begin - FCancelMessage := Format(LANGAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(TargetName), GetErrorString(Error)]); + // * TODO: check error + FD := Engine.OpenFile(TargetName, omWrite, @Error); + if Error <> nil then begin + FCancelMessage := Format(LANGAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(TargetName), Error^.message]); FShowCancelMessage := True; libc_free(Buffer); Exit; @@ -1600,7 +1656,8 @@ begin CurrFile := ''; end; until (SizeDone = ParamInt64) or Cancelled or PrivateCancel {or ((not b) and (not HasInitialCRC))} or (CurrFile = ''); - if (not ParamBool1) and HasFinalCRC then Engine.RenameFile(TargetName, IncludeTrailingPathDelimiter(ExtractFilePath(TargetName)) + TargetFinalName); + // * TODO: check error + if (not ParamBool1) and HasFinalCRC then Engine.RenameFile(TargetName, IncludeTrailingPathDelimiter(ExtractFilePath(TargetName)) + TargetFinalName, nil); if Cancelled and (not PrivateCancel) then begin FCancelMessage := LANGUserCancelled; FShowCancelMessage := True; @@ -1611,7 +1668,8 @@ begin then ShowMessageBox(Format(LANGMergeOfSSucceeded, [StrToUTF8(ExtractFileName(TargetFinalName))]), [mbOK], mbInfo, mbNone, mbOK) else ShowMessageBox(LANGWarningCreatedFileFailsCRCCheck, [mbOK], mbWarning, mbNone, mbOK); end else ShowMessageBox(Format(LANGMergeOfSSucceeded_NoCRCFileAvailable, [StrToUTF8(ExtractFileName(TargetFinalName))]), [mbOK], mbInfo, mbNone, mbOK); - Engine.CloseFile(FD); + // * TODO: set real error, also free it + Engine.CloseFile(FD, nil); end; libc_free(Buffer); SenderThread.FDoneThread := True; @@ -1630,7 +1688,7 @@ procedure SplitFilesWorker(SenderThread: TWorkerThread); const SplitBlockSize = 65536*4; var FD: TEngineFileDes; - Error: integer; + Error: PGError; FileCRC: LongWord; Buffer: Pointer; PrivateCancel: boolean; @@ -1645,9 +1703,10 @@ var FD: TEngineFileDes; Result := False; Written := 0; with SenderThread do begin - FDW := Engine.OpenFile(TargetFile, omWrite, Error); + // * TODO: check error + FDW := Engine.OpenFile(TargetFile, omWrite, @Error); DebugMsg(['-- Opening file ', ExtractFileName(TargetFile), ', PartSize = ', PartSize]); - if Error <> 0 then Exit; + if Error <> nil then Exit; if ParamInt64 > 0 then begin UpdateCaption2(Format(LANGToS, [StrToUTF8(TargetFile)])); SetProgress1Params(PartSize); @@ -1655,30 +1714,37 @@ var FD: TEngineFileDes; end else UpdateCaption1(Format(LANGToS, [StrToUTF8(TargetFile)])); CommitGUIUpdate; repeat - DebugMsg(['Seek to ', Engine.FileSeek(FD, SizeDone + Written, Error), ', Written = ', Written]); + // * TODO: check error + DebugMsg(['Seek to ', Engine.FileSeek(FD, SizeDone + Written, @Error), ', Written = ', Written]); if Written + SplitBlockSize > PartSize then bl := PartSize - Written else bl := SplitBlockSize; - Count := Engine.ReadFile(FD, Buffer, bl, Error); - if (Error <> 0) or (Count <> bl) then begin - Engine.CloseFile(FDW); - DebugMsg(['Read Error: ', GetErrorString(Error), ', Count = ', Count, ', bl = ', bl]); - if (Count <> bl) and (Error = 0) then Error := EIO; + // * TODO: check error + Count := Engine.ReadFile(FD, Buffer, bl, @Error); + if (Error <> nil) or (Count <> bl) then begin + // * TODO: set real error, also free it + Engine.CloseFile(FDW, nil); + DebugMsg(['Read Error: ', Error^.message, ', Count = ', Count, ', bl = ', bl]); +// if (Count <> bl) and (Error = 0) then Error := EIO; Exit; end; - wCount := Engine.WriteFile(FDW, Buffer, Count, Error); + // * TODO: check error + wCount := Engine.WriteFile(FDW, Buffer, Count, @Error); Inc(Written, wCount); FileCRC := CRC32(FileCRC, Buffer, wCount); - if (Error <> 0) or (Count <> wCount) then begin - Engine.CloseFile(FDW); - DebugMsg(['Write Error: ', GetErrorString(Error), ', Count = ', Count, ', wCount = ', wCount]); - if (wCount <> Count) and (Error = 0) then Error := ENOSPC; + if (Error <> nil) or (Count <> wCount) then begin + // * TODO: set real error, also free it + Engine.CloseFile(FDW, nil); + // * TODO: check error + DebugMsg(['Write Error: ', Error^.message, ', Count = ', Count, ', wCount = ', wCount]); +// if (wCount <> Count) and (Error = 0) then Error := ENOSPC; Exit; end; UpdateProgress1(FProgress1Pos + wCount, Format('%d %%', [Trunc((FProgress1Pos + wCount) / FProgress1Max * 100)])); if ParamInt64 > 0 then UpdateProgress2(FProgress2Pos + wCount, Format('%d %%', [Trunc((FProgress2Pos + wCount) / FProgress2Max * 100)])); CommitGUIUpdate; until (Written = PartSize) or Cancelled or PrivateCancel; - Engine.CloseFile(FDW); + // * TODO: set real error, also free it + Engine.CloseFile(FDW, nil); end; DebugMsg(['-- Closing file ', ExtractFileName(TargetFile), ', PartSize = ', PartSize, ', Written = ', Written]); Result := True; @@ -1721,7 +1787,8 @@ var i: integer; xx: string; begin with SenderThread do begin - Stat := Engine.GetFileInfo(ParamString1, True, True); + // * TODO: check error + Stat := Engine.GetFileInfo(ParamString1, True, True, nil); if not Assigned(Stat) then begin FCancelMessage := Format(LANGCannotOpenFileS, [StrToUTF8(ParamString1)]); FShowCancelMessage := True; @@ -1746,9 +1813,10 @@ begin FShowCancelMessage := True; Exit; end; - FD := Engine.OpenFile(ParamString1, omRead, Error); - if Error <> 0 then begin - FCancelMessage := Format(LANGAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(ParamString1), GetErrorString(Error)]); + // * TODO: check error + FD := Engine.OpenFile(ParamString1, omRead, @Error); + if Error <> nil then begin + FCancelMessage := Format(LANGAnErrorOccuredWhileOpeningFileSS, [StrToUTF8(ParamString1), Error^.message]); libc_free(Buffer); Exit; end; @@ -1777,7 +1845,8 @@ begin for i := List.Count - 1 downto 0 do FreeDataItem(PDataItem(List[i])); List.Clear; - Error := Engine.GetListing(List, FilePath, ConfShowDotFiles, False, False); + // * TODO: check error +{ Error := Engine.GetListing(List, FilePath, ConfShowDotFiles, False, False, nil); if (Error = 0) and (List.Count > 0) then begin st := ''; if List.Count < 6 then begin @@ -1790,19 +1859,20 @@ begin Error := Engine.Remove(IncludeTrailingPathDelimiter(FilePath) + string(PDataItem(List[i])^.FName)); if Error <> 0 then ShowMessageBox(Format(LANGTheTargetFileSCannotBeRemovedS, [StrToUTF8(IncludeTrailingPathDelimiter(FilePath)) + string(PDataItem(List[i])^.FDisplayName), GetErrorString(Error)]), [mbOK], mbError, mbNone, mbOK); end; - end; + end; } except end; // Test for target file existence if Engine.FileExists(IncludeTrailingPathDelimiter(FilePath) + FileName, False) then begin b := ShowMessageBox(Format(LANGTheTargetFileSAlreadyExistsDoYouWantToOverwriteIt, [StrToUTF8(IncludeTrailingPathDelimiter(FilePath) + FileName)]), [mbYes, mbNo], mbQuestion, mbNone, mbNo) = mbYes; if b then begin - Error := Engine.Remove(IncludeTrailingPathDelimiter(FilePath) + FileName); + // * TODO: check error +{ Error := Engine.Remove(IncludeTrailingPathDelimiter(FilePath) + FileName); if Error <> 0 then begin FCancelMessage := Format(LANGTheTargetFileSCannotBeRemovedS, [StrToUTF8(IncludeTrailingPathDelimiter(FilePath) + FileName), GetErrorString(Error)]); FShowCancelMessage := True; PrivateCancel := True; Break; - end; + end; } end else begin PrivateCancel := True; Break; @@ -1815,7 +1885,7 @@ begin if (CurrSize >= 512) and (TDF >= CurrSize) then begin b := WriteSplitPart(IncludeTrailingPathDelimiter(FilePath) + FileName, CurrSize, ws); if (not b) and (ParamInt64 > 0) then begin - FCancelMessage := Format(LANGAnErrorOccuredWhileOperationS, [GetErrorString(Error)]); + FCancelMessage := Format(LANGAnErrorOccuredWhileOperationS, [Error^.message]); FShowCancelMessage := True; PrivateCancel := True; Break; @@ -1845,14 +1915,15 @@ begin Engine.GetFileSystemInfo(FilePath, x, TDF, xx); if (TDF < 512) and (not NewDiskQuestion) then Break; until (TDF >= 512) or PrivateCancel or Cancelled; - if WriteCRCFile(Engine, IncludeTrailingPathDelimiter(FilePath) + FileName, OriginalFName, SizeDone, FileCRC) + if WriteCRCFile(ProgressForm, Engine, IncludeTrailingPathDelimiter(FilePath) + FileName, OriginalFName, SizeDone, FileCRC) then ShowMessageBox(Format(LANGSplitOfSSucceeded, [StrToUTF8(OriginalFName)]), [mbOK], mbInfo, mbNone, mbOK) else begin FCancelMessage := Format(LANGSplitOfSFailed, [StrToUTF8(OriginalFName)]); FShowCancelMessage := True; end; end; - Engine.CloseFile(FD); + // * TODO: set real error, also free it + Engine.CloseFile(FD, nil); end; if List.Count > 0 then for i := List.Count - 1 downto 0 do @@ -1874,7 +1945,8 @@ procedure ChmodFilesWorker(SenderThread: TWorkerThread); var SkipAll: boolean; function HandleChmod(AFileRec: PDataItemSL): boolean; - var Res, Response: integer; + var Response: integer; + Res: boolean; begin Result := True; with SenderThread do begin @@ -1882,13 +1954,15 @@ var SkipAll: boolean; if AFileRec^.DataItem^.IsDir and ParamBool1 and AFileRec^.Stage1 and (not AFileRec^.DataItem^.IsLnk) then Exit; if (not AFileRec^.DataItem^.IsDir) and ParamBool1 and (ParamInt1 = 1) then Exit; // Directories only if AFileRec^.DataItem^.IsDir and ParamBool1 and (ParamInt1 = 2) then Exit; // Files only - Res := Engine.Chmod(String(AFileRec^.DataItem^.FName), ParamCardinal1); + // * TODO: check error + Res := Engine.Chmod(String(AFileRec^.DataItem^.FName), ParamCardinal1, nil); // DebugMsg(['Result : ', Res]); - if Res <> 0 then + if not Res then if SkipAll then Result := True else begin + // * TODO: check error Response := ShowDirDeleteDialog(1, LANGTheFileDirectory, String(AFileRec^.DataItem^.FDisplayName), Format(LANGCouldNotBeChmoddedS, - [GetErrorString(Res)]), LANGDialogChangePermissions); + ['ahoj' {GetErrorString(Res)}]), LANGDialogChangePermissions); case Response of 1 : Result := True; 3 : begin @@ -1953,20 +2027,23 @@ procedure ChownFilesWorker(SenderThread: TWorkerThread); var SkipAll: boolean; function HandleChown(AFileRec: PDataItemSL): boolean; - var Res, Response: integer; + var Response: integer; + Res: boolean; begin Result := True; with SenderThread do begin // DebugMsg(['Chown Debug: IsDir: ', AFileRec^.IsDir, ', Stage1: ', AFileRec^.Stage1, ', IsLnk: ', AFileRec^.IsLnk, '; Result = ', AFileRec^.IsDir and AFileRec^.Stage1 and (not AFileRec^.IsLnk)]); if (AFileRec^.DataItem^.IsDir and ParamBool1 and AFileRec^.Stage1 and (not AFileRec^.DataItem^.IsLnk)) or ((not AFileRec^.DataItem^.IsDir) and ParamBool1) then Exit; - Res := Engine.Chown(String(AFileRec^.DataItem^.FName), ParamCardinal1, ParamCardinal2); + // * TODO: check error + Res := Engine.Chown(String(AFileRec^.DataItem^.FName), ParamCardinal1, ParamCardinal2, nil); // DebugMsg(['Result : ', Res]); - if Res <> 0 then + if not Res then if SkipAll then Result := True else begin + // * TODO: check error Response := ShowDirDeleteDialog(1, LANGTheFileDirectory, String(AFileRec^.DataItem^.FDisplayName), Format(LANGCouldNotBeChownedS, - [GetErrorString(Res)]), LANGDialogChangeOwner); + ['ahoj' {GetErrorString(Res)}]), LANGDialogChangeOwner); case Response of 1 : Result := True; 3 : begin @@ -2060,19 +2137,28 @@ begin FreeOnTerminate := False; Finished := False; CancelIt := False; - ChDirResult := 0; - ListingResult := 0; - VFSOpenResult := 0; + ChDirResult := False; + ListingResult := False; + VFSOpenResult := False; + ChDirError := nil; + ListingError := nil; + VFSOpenError := nil; RunningTime := 0; end; destructor TOpenDirThread.Destroy; begin + if VFSOpenError <> nil then + g_error_free(VFSOpenError); + if ChDirError <> nil then + g_error_free(ChDirError); + if ListingError <> nil then + g_error_free(ListingError); inherited Destroy; end; (********************************************************************************************************************************) -function TOpenDirThread.ChangeDir(Engine: TPanelEngine; Path: string; var SelItem: string; const AutoFallBack: boolean): integer; +function TOpenDirThread.ChangeDir(Engine: TPanelEngine; Path: string; var SelItem: string; const AutoFallBack: boolean): boolean; procedure GoUp(var NewPath: string); var x: integer; @@ -2087,8 +2173,8 @@ function TOpenDirThread.ChangeDir(Engine: TPanelEngine; Path: string; var SelIte end; var APath: string; - Error : integer; begin + Result := False; try APath := Engine.Path; if Path = '..' then GoUp(APath) @@ -2102,28 +2188,19 @@ begin end; // AutoFallback loop - if Engine is TVFSEngine - then Error := (Engine as TVFSEngine).ChangeDirEx(APath, @vfs_ask_question_callback, @vfs_ask_password_callback, nil, Self) - else Error := Engine.ChangeDir(APath); - - while AutoFallback and (Error <> 0) and (APath <> '/') do begin - GoUp(APath); + repeat if Engine is TVFSEngine - then Error := (Engine as TVFSEngine).ChangeDirEx(APath, @vfs_ask_question_callback, @vfs_ask_password_callback, nil, Self) - else Error := Engine.ChangeDir(APath); - end; - // Going on... - if Error <> 0 then begin - Result := Error; - DebugMsg(['*** UCore.ChangeDir: error during Engine.ChangeDir: ', GetErrorString(Error)]); - Exit; - end; - Engine.Path := APath; - Result := 0; + then Result := (Engine as TVFSEngine).ChangeDirEx(APath, @vfs_ask_question_callback, @vfs_ask_password_callback, nil, Self, @ChDirError) + else Result := Engine.ChangeDir(APath, @ChDirError); + if not Result then + GoUp(APath); + until Result or (not AutoFallback) or (Length(APath) <= 1); + if Result then + Engine.Path := APath; except on E: Exception do begin + Result := False; DebugMsg(['*** Exception raised in UCore.ChangeDir (', E.ClassName, '): ', E.Message]); - Result := 1; end; end; end; @@ -2143,13 +2220,13 @@ begin xEngine.SavePath := AEngine.Path; // AEngine must be set here since VFSOpenEx callbacks will reference it AEngine := xEngine; - VFSOpenResult := (AEngine as TVFSEngine).VFSOpenEx(AFullPath, @vfs_ask_question_callback, @vfs_ask_password_callback, nil, Self); - end else VFSOpenResult := 0; + VFSOpenResult := (AEngine as TVFSEngine).VFSOpenEx(AFullPath, @vfs_ask_question_callback, @vfs_ask_password_callback, nil, Self, @VFSOpenError); + end else VFSOpenResult := True; - if (VFSOpenResult = 0) and (not CancelIt) then begin + if VFSOpenResult and (not CancelIt) then begin ChDirResult := ChangeDir(AEngine, APath, ASelItem, AAutoFallBack); - if (ChDirResult = 0) and (not CancelIt) then - ListingResult := AEngine.GetListing(ADirList, AEngine.GetPath, ConfShowDotFiles, True, False); + if ChDirResult and (not CancelIt) then + ListingResult := AEngine.GetListing(ADirList, AEngine.GetPath, ConfShowDotFiles, True, False, @ListingError); end; except on E: Exception do DebugMsg(['*** Exception raised in TOpenDirThread.Execute (', E.ClassName, '): ', E.Message]); @@ -2171,6 +2248,7 @@ begin FreeOnTerminate := False; Finished := False; OpenResult := False; + OpenError := nil; end; destructor TOpenConnectionThread.Destroy; @@ -2182,7 +2260,7 @@ procedure TOpenConnectionThread.Execute; begin PrepareExecute; try - OpenResult := (AEngine as TVFSEngine).VFSOpenURI(URI, @vfs_ask_question_callback, @vfs_ask_password_callback, nil, Self); + OpenResult := (AEngine as TVFSEngine).VFSOpenURI(URI, @vfs_ask_question_callback, @vfs_ask_password_callback, nil, Self, @OpenError); finally Finished := True; end; diff --git a/UEngines.pas b/UEngines.pas index a8f1923..66dd9ea 100644 --- a/UEngines.pas +++ b/UEngines.pas @@ -24,14 +24,7 @@ interface uses glib2, gdk2, Classes, ULibc; -const ERRException = -1; - ERRNoAccess = -2; - ERRCreateLink = -3; - ERRCopyMove = -4; - ERRRemove = -5; - ERRMkDIr = -6; - - omRead = 0; +const omRead = 0; omWrite = 1; omAppend = 2; @@ -66,8 +59,12 @@ type ForceMove, IsOnRO: boolean; end; - TEngineProgressFunc = function (Sender: Pointer; BytesDone: Int64): boolean; cdecl; // Return False to break the copy process - TEngineErrorFunc = function (Sender: Pointer; ErrorType, ErrorNum: integer; FileName: string): boolean; cdecl; // Return + // Progress callback, return False to break the copy process + // If an Error is set, returning True means to ignore error (don't delete broken file if possible) + // If an Error is set, BytesDone may contain random value + // Do not free Error, it belongs to the copy operation + TEngineProgressFunc = function (Sender: Pointer; BytesDone: Int64; Error: PGError): boolean; cdecl; + // * TODO: file handle TEngineFileDes = pointer; TPanelEngine = class @@ -79,10 +76,10 @@ type constructor Create; destructor Destroy; override; - function GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean): integer; virtual; abstract; // Returns errorcode - function GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean): PDataItem; virtual; abstract; + function GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean; Error: PPGError): boolean; virtual; abstract; + function GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean; Error: PPGError): PDataItem; virtual; abstract; - function ChangeDir(const NewPath: string): integer; virtual; abstract; // Returns errorcode + function ChangeDir(const NewPath: string; Error: PPGError): boolean; virtual; abstract; function GetPath: string; virtual; abstract; procedure SetPath(Value: string); virtual; abstract; @@ -95,28 +92,28 @@ type function FileCanRun(const FileName: string): boolean; virtual; abstract; // Operations - function MakeDir(const NewDir: string): integer; virtual; abstract; // Returns errorcode - function Remove(const APath: string): integer; virtual; abstract; // Returns errorcode - function MakeSymLink(const NewFileName, PointTo: string): integer; virtual; abstract; // Returns errorcode - function Chmod(const FileName: string; Mode: cuLong): integer; virtual; abstract; // Returns errorcode - function Chown(const FileName: string; UID, GID: cuLong): integer; virtual; abstract; // Returns errorcode - function RenameFile(const SourceFile, DestFile: string): integer; virtual; abstract; // Returns errorcode - function ChangeTimes(const APath: string; mtime, atime: time_t): integer; virtual; abstract; // Returns errorcode + function MakeDir(const NewDir: string; Error: PPGError): boolean; virtual; abstract; + function Remove(const APath: string; Error: PPGError): boolean; virtual; abstract; + function MakeSymLink(const NewFileName, PointTo: string; Error: PPGError): boolean; virtual; abstract; + function Chmod(const FileName: string; Mode: cuLong; Error: PPGError): boolean; virtual; abstract; + function Chown(const FileName: string; UID, GID: cuLong; Error: PPGError): boolean; virtual; abstract; + function RenameFile(const SourceFile, DestFile: string; Error: PPGError): boolean; virtual; abstract; + function ChangeTimes(const APath: string; mtime, atime: time_t; Error: PPGError): boolean; virtual; abstract; // Copy-related routines function GetBlockSize: guint32; virtual; abstract; procedure SetBlockSize(Value: guint32); virtual; abstract; - function CopyFileIn(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; virtual; abstract; // returns True if file is successfully copied - function CopyFileOut(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; virtual; abstract; // returns True if file is successfully copied + function CopyFileIn(const SourceFile, DestFile: string; Append: boolean; ProgressFunc: TEngineProgressFunc; Sender: Pointer): boolean; virtual; abstract; // returns True if file is successfully copied + function CopyFileOut(const SourceFile, DestFile: string; Append: boolean; ProgressFunc: TEngineProgressFunc; Sender: Pointer): boolean; virtual; abstract; // returns True if file is successfully copied function IsOnSameFS(const Path1, Path2: string; FollowSymlinks: boolean): boolean; virtual; abstract; function TwoSameFiles(const Path1, Path2: string; FollowSymlinks: boolean): boolean; virtual; abstract; // Separate file read/write routines, not supported on most backends - function OpenFile(const APath: string; Mode: integer; var Error: integer): TEngineFileDes; virtual; abstract; // Returns filedescriptor - function ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; var Error: integer): integer; virtual; abstract; // Returns number of bytes read - function WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; var Error: integer): integer; virtual; abstract; // Returns number of bytes written - function CloseFile(const FileDescriptor: TEngineFileDes): integer; virtual; abstract; // Returns errorcode - function FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; var Error: integer): Int64; virtual; abstract; // Returns errorcode + function OpenFile(const APath: string; Mode: integer; Error: PPGError): TEngineFileDes; virtual; abstract; // Returns filedescriptor + function ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; Error: PPGError): integer; virtual; abstract; // Returns number of bytes read + function WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; Error: PPGError): integer; virtual; abstract; // Returns number of bytes written + function CloseFile(const FileDescriptor: TEngineFileDes; Error: PPGError): boolean; virtual; abstract; + function FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; Error: PPGError): Int64; virtual; abstract; published property Path: string read GetPath write SetPath; property BlockSize: guint32 read GetBlockSize write SetBlockSize; @@ -130,10 +127,10 @@ type constructor Create; destructor Destroy; override; - function GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean): integer; override; - function GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean): PDataItem; override; + function GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean; Error: PPGError): boolean; override; + function GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean; Error: PPGError): PDataItem; override; - function ChangeDir(const NewPath: string): integer; override; + function ChangeDir(const NewPath: string; Error: PPGError): boolean; override; function GetPath: string; override; procedure SetPath(Value: string); override; @@ -145,29 +142,26 @@ type function IsOnROMedium(const FileName: string): boolean; override; function FileCanRun(const FileName: string): boolean; override; - function MakeDir(const NewDir: string): integer; override; - function Remove(const APath: string): integer; override; - function MakeSymLink(const NewFileName, PointTo: string): integer; override; - function Chmod(const FileName: string; Mode: cuLong): integer; override; - function Chown(const FileName: string; UID, GID: cuLong): integer; override; - function RenameFile(const SourceFile, DestFile: string): integer; override; - function ChangeTimes(const APath: string; mtime, atime: time_t): integer; override; + function MakeDir(const NewDir: string; Error: PPGError): boolean; override; + function Remove(const APath: string; Error: PPGError): boolean; override; + function MakeSymLink(const NewFileName, PointTo: string; Error: PPGError): boolean; override; + function Chmod(const FileName: string; Mode: cuLong; Error: PPGError): boolean; override; + function Chown(const FileName: string; UID, GID: cuLong; Error: PPGError): boolean; override; + function RenameFile(const SourceFile, DestFile: string; Error: PPGError): boolean; override; + function ChangeTimes(const APath: string; mtime, atime: time_t; Error: PPGError): boolean; override; function GetBlockSize: guint32; override; procedure SetBlockSize(Value: guint32); override; - function CopyFileIn(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; override; - function CopyFileOut(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; override; + function CopyFileIn(const SourceFile, DestFile: string; Append: boolean; ProgressFunc: TEngineProgressFunc; Sender: Pointer): boolean; override; + function CopyFileOut(const SourceFile, DestFile: string; Append: boolean; ProgressFunc: TEngineProgressFunc; Sender: Pointer): boolean; override; function IsOnSameFS(const Path1, Path2: string; FollowSymlinks: boolean): boolean; override; function TwoSameFiles(const Path1, Path2: string; FollowSymlinks: boolean): boolean; override; - function OpenFile(const APath: string; Mode: integer; var Error: integer): TEngineFileDes; override; - function ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; var Error: integer): integer; override; - function WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; var Error: integer): integer; override; - function CloseFile(const FileDescriptor: TEngineFileDes): integer; override; - function FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; var Error: integer): Int64; override; - - // Local extra functions - function CopyFile(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; + function OpenFile(const APath: string; Mode: integer; Error: PPGError): TEngineFileDes; override; + function ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; Error: PPGError): integer; override; + function WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; Error: PPGError): integer; override; + function CloseFile(const FileDescriptor: TEngineFileDes; Error: PPGError): boolean; override; + function FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; Error: PPGError): Int64; override; published property Path; property BlockSize; @@ -182,7 +176,7 @@ function DuplicateDataItem(DataItem: PDataItemSL): PDataItemSL; overload; implementation -uses SysUtils, UCoreUtils, UGnome; +uses SysUtils, UCoreUtils, UGnome, UError; (********************************************************************************************************************************) constructor TPanelEngine.Create; @@ -235,26 +229,31 @@ begin end; end; -function TLocalTreeEngine.GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean): integer; +function TLocalTreeEngine.GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean; Error: PPGError): boolean; var Item: PDataItem; Handle: PDIR; DirEnt: PDirent64; Buf: PChar; + saved_errno: integer; + FError: PGError; begin - Result := 0; + Result := False; try if libc_chdir(PChar(APath)) <> 0 then begin - Result := errno; - DebugMsg(['*** TLocalTreeEngine.GetListing(APath=', APath, '): chdir error: ', strerror(Result)]); + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error changing directory to ''''%s'''': %s', StrToUTF8(PChar(APath)), g_strerror(saved_errno)); + DebugMsg(['*** TLocalTreeEngine.GetListing(APath=', APath, '): chdir error: ', strerror(saved_errno)]); Exit; end; Handle := opendir(PChar(APath)); if Handle = nil then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error opening directory ''''%s'''': %s', StrToUTF8(PChar(APath)), g_strerror(saved_errno)); DebugMsg(['*** TLocalTreeEngine.GetListing(APath=', APath, '): opendir() handle == NULL: ', strerror(errno)]); - Result := ERRNoAccess; Exit; end; + FError := nil; repeat DirEnt := readdir64(Handle); if (DirEnt <> nil) and (DirEnt^.d_name[0] <> #0) then begin @@ -262,32 +261,37 @@ begin if (Buf <> '.') and (Buf <> '..') and (strlen(Buf) > 0) and (AddDotFiles or (Buf[0] <> '.')) then begin - Item := GetFileInfo(IncludeTrailingPathDelimiter(APath) + string(Buf), FollowSymlinks, AddFullPath); + Item := GetFileInfo(IncludeTrailingPathDelimiter(APath) + string(Buf), FollowSymlinks, AddFullPath, @FError); List.Add(Item); end; end; - until DirEnt = nil; - // TODO: check errno? + until (DirEnt = nil) or (FError <> nil); closedir(Handle); + + if FError <> nil then g_propagate_error(Error, FError) + else Result := True; except on E: Exception do begin - Result := ERRException; + Result := False; DebugMsg(['*** TLocalTreeEngine.GetListing(APath=', APath, ') -Exception: ', E.Message]); Exit; end; end; end; -function TLocalTreeEngine.GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean): PDataItem; +function TLocalTreeEngine.GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean; Error: PPGError): PDataItem; var Item: PDataItem; StatBuf: Pstat64; LnkBuf: array[0..65535] of char; i: integer; + saved_errno: integer; begin StatBuf := malloc(sizeof(Tstat64)); memset(StatBuf, 0, sizeof(Tstat64)); if lstat64(PChar(APath), StatBuf) <> 0 then begin - DebugMsg(['*** TLocalTreeEngine.GetFileInfo(APath=', APath, '): Error reading file via lstat64: ', strerror(errno)]); + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error getting file info for ''''%s'''': %s', StrToUTF8(PChar(APath)), g_strerror(saved_errno)); + DebugMsg(['*** TLocalTreeEngine.GetFileInfo(APath=', APath, '): Error reading file via lstat64: ', strerror(saved_errno)]); libc_free(StatBuf); Result := nil; Exit; @@ -342,19 +346,23 @@ begin Result := Item; end; -function TLocalTreeEngine.ChangeDir(const NewPath: string): integer; +function TLocalTreeEngine.ChangeDir(const NewPath: string; Error: PPGError): boolean; var APath: string; Handle : PDIR; + saved_errno: integer; begin + Result := False; try APath := IncludeTrailingPathDelimiter(NewPath); if libc_chdir(PChar(APath)) <> 0 then begin - Result := errno; + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error changing directory to ''''%s'''': %s', StrToUTF8(PChar(NewPath)), g_strerror(saved_errno)); Exit; end; Handle := opendir(PChar(APath)); - if not Assigned(Handle) then begin - Result := ERRNoAccess; + if Handle = nil then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error changing directory to ''''%s'''': %s', StrToUTF8(PChar(NewPath)), g_strerror(saved_errno)); Exit; end; { if not Assigned(readdir(Handle)) then begin @@ -362,13 +370,14 @@ begin Exit; end; } if closedir(Handle) <> 0 then begin - Result := ERRNoAccess; + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error changing directory to ''''%s'''': %s', StrToUTF8(PChar(NewPath)), g_strerror(saved_errno)); Exit; end; - Result := 0; + Result := True; except on E: Exception do begin - Result := ERRException; + Result := False; DebugMsg(['*** TLocalTreeEngine.ChangeDir(APath=', APath, ') -Exception: ', E.Message]); Exit; end; @@ -376,26 +385,6 @@ begin end; (********************************************************************************************************************************) -function TLocalTreeEngine.MakeDir(const NewDir: string): integer; -begin -// DebugMsg(['(II) TLocalTreeEngine.MakeDir: begin']); - Result := __mkdir(PChar(NewDir), OctalToAttr(ConfDefaultDirCreationMask)); -// DebugMsg(['(II) TLocalTreeEngine.MakeDir: Result = ', Result]); -// if Result <> 0 then Result := errno; - - if Result <> 0 then try - if Self.DirectoryExists(NewDir, False) or (g_mkdir_with_parents(PChar(NewDir), OctalToAttr(ConfDefaultDirCreationMask)) <> 0) {ForceDirectories(NewDir))} - then Result := errno - else Result := 0; - except - Result := -1; - DebugMsg(['(II) TLocalTreeEngine.MakeDir: Exception']); - end; - -// DebugMsg(['(II) TLocalTreeEngine.MakeDir: end']); -end; - -(********************************************************************************************************************************) function TLocalTreeEngine.GetDirSize(const APath: string): Int64; function InternalGetDirSize(APath: string): Int64; @@ -447,157 +436,202 @@ begin end; (********************************************************************************************************************************) -function TLocalTreeEngine.Remove(const APath: string): integer; +function TLocalTreeEngine.MakeDir(const NewDir: string; Error: PPGError): boolean; +var saved_errno: integer; begin - Result := libc_remove(PChar(ExcludeTrailingPathDelimiter(APath))); - if Result <> 0 then Result := errno; + Result := False; + if __mkdir(PChar(NewDir), OctalToAttr(ConfDefaultDirCreationMask)) <> 0 then begin + if Self.DirectoryExists(NewDir, False) or (@g_mkdir_with_parents = nil) or (g_mkdir_with_parents(PChar(NewDir), OctalToAttr(ConfDefaultDirCreationMask)) <> 0) then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error creating directory ''''%s'''': %s', StrToUTF8(PChar(NewDir)), g_strerror(saved_errno)); + end else Result := True; + end else Result := True; end; (********************************************************************************************************************************) +function TLocalTreeEngine.Remove(const APath: string; Error: PPGError): boolean; +var saved_errno: integer; +begin + Result := False; + if libc_remove(PChar(ExcludeTrailingPathDelimiter(APath))) <> 0 then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error deleting ''''%s'''': %s', StrToUTF8(PChar(APath)), g_strerror(saved_errno)); + end else Result := True; +end; -function TLocalTreeEngine.CopyFileIn(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; +(********************************************************************************************************************************) +function TLocalTreeEngine.MakeSymLink(const NewFileName, PointTo: string; Error: PPGError): boolean; +var saved_errno: integer; begin - Result := CopyFile(Sender, SourceFile, DestFile, ProgressFunc, ErrorFunc, Append); + Result := False; + if symlink(PChar(PointTo), PChar(NewFileName)) <> 0 then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error creating symlink ''''%s'''': %s', StrToUTF8(PChar(NewFileName)), g_strerror(saved_errno)); + end else Result := True; end; -function TLocalTreeEngine.CopyFileOut(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; +(********************************************************************************************************************************) +function TLocalTreeEngine.Chmod(const FileName: string; Mode: cuLong; Error: PPGError): boolean; +var saved_errno: integer; begin - Result := CopyFile(Sender, SourceFile, DestFile, ProgressFunc, ErrorFunc, Append); + Result := False; + if libc_chmod(PChar(FileName), Mode) <> 0 then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error during chmod of ''''%s'''': %s', StrToUTF8(PChar(FileName)), g_strerror(saved_errno)); + end else Result := True; end; -function TLocalTreeEngine.CopyFile(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; -var fsrc, fdest: PFILE; - BytesDone, BytesRead: Int64; -// offset: __off_t; +(********************************************************************************************************************************) +function TLocalTreeEngine.Chown(const FileName: string; UID, GID: cuLong; Error: PPGError): boolean; +var saved_errno: integer; +begin + Result := False; + if libc_chown(PChar(FileName), UID, GID) <> 0 then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error during chown of ''''%s'''': %s', StrToUTF8(PChar(FileName)), g_strerror(saved_errno)); + end else Result := True; +end; +(********************************************************************************************************************************) +function TLocalTreeEngine.RenameFile(const SourceFile, DestFile: string; Error: PPGError): boolean; +var saved_errno: integer; +begin + Result := False; + if libc_rename(PChar(SourceFile), PChar(DestFile)) <> 0 then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error renaming file ''''%s'''': %s', StrToUTF8(PChar(SourceFile)), g_strerror(saved_errno)); + end else Result := True; +end; - // Used due to sendfile bug while copying from NTFS and some 2.6.x kernels - function OldCopyRoutine: boolean; - var Buffer: Pointer; - BytesWritten: Int64; - Res: boolean; - begin - Result := False; - Res := True; - try -// DebugMsg(['*** Using old copy function due to bug in sendfile']); -// WriteLn('x1'); - Buffer := malloc(FBlockSize); -// WriteLn('x2'); - if Buffer = nil then begin - ErrorFunc(Sender, 1, errno, SourceFile); // Memory allocation failed -// libc_free(Buffer); +(********************************************************************************************************************************) +function TLocalTreeEngine.ChangeTimes(const APath: string; mtime, atime: time_t; Error: PPGError): boolean; +var timebuf: Putimbuf; + saved_errno: integer; +begin + Result := False; + try + timebuf := malloc(sizeof(Tutimbuf)); + memset(timebuf, 0, sizeof(Tutimbuf)); + timebuf^.actime := atime; + timebuf^.modtime := mtime; + if utime(PChar(APath), timebuf) <> 0 then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error while changing timestamps of ''''%s'''': %s', StrToUTF8(PChar(APath)), g_strerror(saved_errno)); + end else Result := True; + libc_free(timebuf); + except + on E: Exception do DebugMsg(['*** Exception raised in TLocalTreeEngine.ChangeTimes(APath=', APath, '): (', E.ClassName, '): ', E.Message]); + end; +end; + +(********************************************************************************************************************************) + +function TLocalTreeEngine.CopyFileIn(const SourceFile, DestFile: string; Append: boolean; ProgressFunc: TEngineProgressFunc; Sender: Pointer): boolean; +begin + Result := CopyFileOut(SourceFile, DestFile, Append, ProgressFunc, Sender); +end; + +function TLocalTreeEngine.CopyFileOut(const SourceFile, DestFile: string; Append: boolean; ProgressFunc: TEngineProgressFunc; Sender: Pointer): boolean; +var fsrc, fdest: PFILE; + Buffer: Pointer; + BytesDone, BytesRead, BytesWritten: Int64; + Ignore: boolean; + saved_errno: integer; + Error: PGError; +begin + Result := False; + Error := nil; + try + // Open source file for reading + fsrc := fopen64(PChar(SourceFile), 'r'); + if fsrc = nil then begin + if @ProgressFunc <> nil then begin + saved_errno := errno; + g_set_error(@Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error opening source file ''''%s'''': %s', StrToUTF8(PChar(SourceFile)), g_strerror(saved_errno)); + ProgressFunc(Sender, 0, Error); + g_error_free(Error); + end; Exit; end; - memset(Buffer, 0, FBlockSize); + // Open target file for writing/appending + if Append then fdest := fopen64(PChar(DestFile), 'a') + else fdest := fopen64(PChar(DestFile), 'w'); + if fsrc = nil then begin + if @ProgressFunc <> nil then begin + saved_errno := errno; + g_set_error(@Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error opening target file ''''%s'''': %s', StrToUTF8(PChar(DestFile)), g_strerror(saved_errno)); + ProgressFunc(Sender, 0, Error); + g_error_free(Error); + end; + fclose(fsrc); + Exit; + end; + + BytesDone := 0; + Buffer := malloc(FBlockSize); -// WriteLn('x3'); while feof(fsrc) = 0 do begin -// WriteLn('x4'); + Error := nil; + + // Read block BytesRead := fread(Buffer, 1, FBlockSize, fsrc); if (BytesRead < FBlockSize) and (feof(fsrc) = 0) then begin - Res := ErrorFunc(Sender, 6, errno, SourceFile); // Cannot read from source file - Break; + Ignore := False; + if @ProgressFunc <> nil then begin + saved_errno := errno; + g_set_error(@Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error reading from source file ''''%s'''': %s', StrToUTF8(PChar(SourceFile)), g_strerror(saved_errno)); + Ignore := ProgressFunc(Sender, BytesDone + BytesRead, Error); + g_error_free(Error); + end; + if Ignore then Continue + else Break; end; -// WriteLn('x5'); + + // Write block BytesWritten := fwrite(Buffer, 1, BytesRead, fdest); if BytesWritten < BytesRead then begin - Res := ErrorFunc(Sender, 7, ferror(fdest), DestFile); // Cannot write to source file - Break; + if @ProgressFunc <> nil then begin + saved_errno := ferror(fdest); + g_set_error(@Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error writing to target file ''''%s'''': %s', StrToUTF8(PChar(DestFile)), g_strerror(saved_errno)); + ProgressFunc(Sender, BytesDone + BytesWritten, Error); + g_error_free(Error); + end; + Break; // We cannot ignore write errors end; + Inc(BytesDone, BytesRead); -// WriteLn('x6'); - try - if Assigned(ProgressFunc) and (not ProgressFunc(Sender, BytesDone)) then begin - Res := False; + if (@ProgressFunc <> nil) and (not ProgressFunc(Sender, BytesDone, nil)) then Break; - end; - except - on E: Exception do DebugMsg(['*** ProgressFunc ! Exception raised in TLocalTreeEngine.CopyFile.OldCopyRoutine(Sender=', DWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]); - end; -// WriteLn('x7'); end; -// WriteLn('x8'); + Result := feof(fsrc) <> 0; libc_free(Buffer); -// WriteLn('x9'); - Result := Res; - except - on E: Exception do DebugMsg(['*** Exception raised in TLocalTreeEngine.CopyFile.OldCopyRoutine(Sender=', DWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]); - end; - end; -(* - function NewCopyRoutine: boolean; - var Res: boolean; - StatBuf: Pstat64; - begin - try - Res := True; - repeat - DebugMsg(['Copy(sendfile): offset = ', offset, ', BytesDone = ', BytesDone, ', ftell(fsrc) = ', ftell(fsrc)]); - BytesRead := sendfile(fileno(fdest), fileno(fsrc), offset, FBlockSize); - if BytesRead = -1 then begin - if errno = EINVAL then begin - Result := OldCopyRoutine; - Exit; - end else Res := ErrorFunc(Sender, 6, errno, SourceFile); // Cannot read from source file - Break; + + if fclose(fdest) <> 0 then begin + fclose(fsrc); + Result := False; + if @ProgressFunc <> nil then begin + Error := nil; + saved_errno := errno; + g_set_error(@Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error closing target file ''''%s'''': %s', StrToUTF8(PChar(DestFile)), g_strerror(saved_errno)); + Result := ProgressFunc(Sender, BytesDone, Error); + g_error_free(Error); end; - Inc(BytesDone, BytesRead); - if Assigned(ProgressFunc) and (not ProgressFunc(Sender, BytesDone)) then begin - Res := False; - Break; + Exit; + end; + if fclose(fsrc) <> 0 then begin + Result := False; + if @ProgressFunc <> nil then begin + Error := nil; + saved_errno := errno; + g_set_error(@Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error closing source file ''''%s'''': %s', StrToUTF8(PChar(SourceFile)), g_strerror(saved_errno)); + Result := ProgressFunc(Sender, BytesDone, Error); + g_error_free(Error); end; - until BytesRead < FBlockSize; - - StatBuf := malloc(sizeof(Tstat64)); - memset(StatBuf, 0, sizeof(Tstat64)); - if lstat64(PChar(SourceFile), StatBuf) <> 0 then begin - DebugMsg(['*** TLocalTreeEngine.CopyFile.NewCopyRoutine(Sender=', DWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): Error reading file via lstat64: ', strerror(errno)]); - Res := ErrorFunc(Sender, 6, errno, SourceFile); - end else - if (BytesDone < StatBuf^.st_size) and Res then - Res := ErrorFunc(Sender, 6, errno, SourceFile); - libc_free(StatBuf); - Result := Res; - except - on E: Exception do DebugMsg(['*** Exception raised in TLocalTreeEngine.CopyFile.NewCopyRoutine(Sender=', DWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]); + Exit; end; - end; -*) -begin - Result := False; - try - fsrc := fopen64(PChar(SourceFile), 'r'); - if fsrc = nil then begin - ErrorFunc(Sender, 2, errno, SourceFile); // Cannot open source file - Exit; - end; - if Append then fdest := fopen64(PChar(DestFile), 'a') - else fdest := fopen64(PChar(DestFile), 'w'); - if fdest = nil then begin - fclose(fsrc); - ErrorFunc(Sender, 3, errno, DestFile); // Cannot open target file - Exit; - end; - - BytesDone := 0; -// offset := 0; - - Result := OldCopyRoutine; - - if fclose(fdest) <> 0 then begin - fclose(fsrc); - ErrorFunc(Sender, 4, errno, DestFile); // Cannot close target file - Exit; - end; - if fclose(fsrc) <> 0 then begin - ErrorFunc(Sender, 5, errno, SourceFile); // Cannot close source file - Exit; - end; except - on E: Exception do DebugMsg(['*** Exception raised in TLocalTreeEngine.CopyFile(Sender=', DWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]); + on E: Exception do DebugMsg(['*** Exception raised in TLocalTreeEngine.CopyFile(Sender=', Sender, ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]); end; -// DebugMsg(['(II) TLocalTreeEngine.CopyFile: finished']); end; (********************************************************************************************************************************) @@ -624,28 +658,6 @@ begin end; (********************************************************************************************************************************) -function TLocalTreeEngine.MakeSymLink(const NewFileName, PointTo: string): integer; -begin -// DebugMsg(['TLocalTreeEngine.MakeSymLink(NewFileName = "', NewFileName, '", PointTo = "', PointTo, '"']); - Result := symlink(PChar(PointTo), PChar(NewFileName)); - if Result <> 0 then Result := errno; -end; - -(********************************************************************************************************************************) -function TLocalTreeEngine.Chmod(const FileName: string; Mode: cuLong): integer; -begin - Result := libc_chmod(PChar(FileName), Mode); - if Result <> 0 then Result := errno; -end; - -(********************************************************************************************************************************) -function TLocalTreeEngine.Chown(const FileName: string; UID, GID: cuLong): integer; -begin - Result := libc_chown(PChar(FileName), UID, GID); - if Result <> 0 then Result := errno; -end; - -(********************************************************************************************************************************) procedure TLocalTreeEngine.BreakProcessing(ProcessingKind: integer); begin BreakProcessingType := ProcessingKind; @@ -698,31 +710,6 @@ begin end; (********************************************************************************************************************************) -function TLocalTreeEngine.RenameFile(const SourceFile, DestFile: string): integer; -begin - Result := libc_rename(PChar(SourceFile), PChar(DestFile)); - if Result <> 0 then Result := errno; -end; - -(********************************************************************************************************************************) -function TLocalTreeEngine.ChangeTimes(const APath: string; mtime, atime: time_t): integer; -var timebuf: Putimbuf; -begin - Result := errno; - try - timebuf := malloc(sizeof(Tutimbuf)); - memset(timebuf, 0, sizeof(Tutimbuf)); - timebuf^.actime := atime; - timebuf^.modtime := mtime; - Result := utime(PChar(APath), timebuf); - if Result <> 0 then Result := errno; - libc_free(timebuf); - except - on E: Exception do DebugMsg(['*** Exception raised in TLocalTreeEngine.ChangeTimes(APath=', APath, '): (', E.ClassName, '): ', E.Message]); - end; -end; - -(********************************************************************************************************************************) procedure TLocalTreeEngine.GetFileSystemInfo(const APath: string; var FSSize, FSFree: Int64; var FSName: string); var Stat: Pstatfs64; fd: PFILE; @@ -774,10 +761,10 @@ begin end; (********************************************************************************************************************************) -function TLocalTreeEngine.OpenFile(const APath: string; Mode: integer; var Error: integer): TEngineFileDes; +function TLocalTreeEngine.OpenFile(const APath: string; Mode: integer; Error: PPGError): TEngineFileDes; var m: PChar; + saved_errno: integer; begin - Error := 0; case Mode of omRead: m := 'r'; omWrite: m := 'w'; @@ -785,40 +772,54 @@ begin else m := 'r'; end; Result := fopen64(PChar(APath), m); - if Result = nil then Error := errno; + if Result = nil then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error opening file ''''%s'''': %s', StrToUTF8(PChar(APath)), g_strerror(saved_errno)); + end; end; (********************************************************************************************************************************) -function TLocalTreeEngine.ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; var Error: integer): integer; +function TLocalTreeEngine.ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; Error: PPGError): integer; +var saved_errno: integer; begin - Error := 0; Result := fread(Buffer, 1, ABlockSize, FileDescriptor); - if (Result = 0) and (feof(FileDescriptor) = 0) then Error := errno; + if (Result = 0) and (feof(FileDescriptor) = 0) then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error reading from file: %s', g_strerror(saved_errno)); + end; end; (********************************************************************************************************************************) -function TLocalTreeEngine.WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; var Error: integer): integer; +function TLocalTreeEngine.WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; Error: PPGError): integer; +var saved_errno: integer; begin - Error := 0; -{ Result := __write(fileno(FileDescriptor), Buffer^, BytesCount); - if Result < BytesCount then Error := errno; } Result := fwrite(Buffer, 1, BytesCount, FileDescriptor); - if Result < BytesCount then Error := ferror(FileDescriptor); + if Result < BytesCount then begin + saved_errno := ferror(FileDescriptor); + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error writing to file: %s', g_strerror(saved_errno)); + end; end; (********************************************************************************************************************************) -function TLocalTreeEngine.CloseFile(const FileDescriptor: TEngineFileDes): integer; +function TLocalTreeEngine.CloseFile(const FileDescriptor: TEngineFileDes; Error: PPGError): boolean; +var saved_errno: integer; begin - Result := fclose(FileDescriptor); - if Result <> 0 then Result := errno; + Result := fclose(FileDescriptor) = 0; + if not Result then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error closing file: %s', g_strerror(saved_errno)); + end; end; (********************************************************************************************************************************) -function TLocalTreeEngine.FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; var Error: integer): Int64; +function TLocalTreeEngine.FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; Error: PPGError): Int64; +var saved_errno: integer; begin - Error := 0; Result := fseeko64(FileDescriptor, AbsoluteOffset, SEEK_SET); - if Result = -1 then Error := errno; + if Result = -1 then begin + saved_errno := errno; + g_set_error(Error, G_IO_ERROR, gint(g_io_error_from_errno(saved_errno)), 'Error seeking in file: %s', g_strerror(saved_errno)); + end; end; (********************************************************************************************************************************) @@ -21,7 +21,7 @@ unit UError; interface -uses glib2, gdk2, Classes, ULibc; +uses glib2, gtk2, Classes, ULibc, GTKForms; // Ported from gioerror.h @@ -68,6 +68,8 @@ function G_IO_ERROR: TGQuark; function g_io_error_from_errno(err_no: gint): GIOErrorEnum; +procedure ShowError(Parent: TCustomGTKForm; const Text: string; Error: PGError); + implementation uses SysUtils, UCoreUtils, UGnome; @@ -111,5 +113,26 @@ begin end; end; + +(********************************************************************************************************************************) +procedure ShowError(Parent: TCustomGTKForm; const Text: string; Error: PGError); +var Dialog: PGtkWidget; + error_str: PChar; +begin + if Error <> nil then error_str := Error^.message + else error_str := ''; + if @gtk_message_dialog_new_with_markup <> nil + then dialog := gtk_message_dialog_new_with_markup (PGtkWindow(Parent.FWidget), GTK_DIALOG_MODAL or GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + '<span size="large" weight="ultrabold">%s</span>'#10#10'%s', + PChar(Text), error_str) + else dialog := gtk_message_dialog_new (PGtkWindow(Parent.FWidget), GTK_DIALOG_MODAL or GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + '%s'#10#10'%s', PChar(Text), error_str); + gtk_window_set_title (PGtkWindow(dialog), ''); + gtk_dialog_run (PGtkDialog(Dialog)); + gtk_widget_destroy (PGtkWidget(Dialog)); +end; + end. @@ -265,7 +265,7 @@ uses ULibc, UPreferences, UViewer, UToolTips, UMounterPrefs, UColumns, UTestPlugin, UConnectionManager, USearch, UProperties, URemoteWait, URunFromVFS, uVFSprototypes, UQuickConnect, - UConnectionProperties; + UConnectionProperties, UError; @@ -1125,7 +1125,8 @@ procedure TFMain.FormClose(Sender: TObject; var Action: TCloseAction); if not Assigned(Engine.ParentEngine) or (not (Engine is TVFSEngine)) then Exit; Result := Engine.ParentEngine; CheckForUnsavedConnection(Engine as TVFSEngine, False); - if not TVFSEngine(Engine).VFSClose then DebugMsg(['Error closing the engine...']); + if not TVFSEngine(Engine).VFSClose(nil) then + DebugMsg(['Error closing the engine...']); Engine.Free; end; @@ -1170,7 +1171,7 @@ begin if b then begin if (not LeftPanelNotebook.Visible) and (LeftPanelEngine is TVFSEngine) then begin while LeftPanelEngine is TVFSEngine do s := CloseVFS(True, True); - if LeftPanelEngine is TLocalTreeEngine then LeftPanelEngine.ChangeDir(s); + if LeftPanelEngine is TLocalTreeEngine then LeftPanelEngine.ChangeDir(s, nil); end else for i := 0 to LeftTabEngines.Count - 1 do if (TPanelEngine(LeftTabEngines[i]) <> nil) and (TPanelEngine(LeftTabEngines[i]) is TVFSEngine) then @@ -1189,7 +1190,7 @@ begin if (not RightPanelNotebook.Visible) and (RightPanelEngine is TVFSEngine) then begin while RightPanelEngine is TVFSEngine do s := CloseVFS(False, True); - if RightPanelEngine is TLocalTreeEngine then RightPanelEngine.ChangeDir(s); + if RightPanelEngine is TLocalTreeEngine then RightPanelEngine.ChangeDir(s, nil); end else for i := 0 to RightTabEngines.Count - 1 do if (TPanelEngine(RightTabEngines[i]) <> nil) and (TPanelEngine(RightTabEngines[i]) is TVFSEngine) then @@ -1872,26 +1873,25 @@ begin HiliString1 := ''; HiliString2 := ''; end; - if OpenDirThread.VFSOpenResult <> 0 then begin + if not OpenDirThread.VFSOpenResult then begin // Silence the error if password dialog has been cancelled if not OpenDirThread.VFSCallbackCancelled then - Application.MessageBox(LANGCouldntOpenURIArchive, [mbOK], mbError, mbOK, mbOK); + ShowError(Self, LANGCouldntOpenURIArchive, OpenDirThread.VFSOpenError); DebugMsg(['TFMain.ChangingDir: Freeing thread...']); OpenDirThread.Free; end else - if OpenDirThread.ChDirResult <> 0 then begin - if not OpenDirThread.VFSCallbackCancelled then begin - // Drop the error message if one of the callback dialogs were cancelled - if OpenDirThread.ChDirResult = 1 then Application.MessageBox(Format(LANGErrorGettingListingForSPanelNoPath, [LANGPanelStrings[LeftPanel], 'Exception']), [mbOK], mbError, mbNone, mbOK) - else Application.MessageBox(Format(LANGErrorGettingListingForSPanel, [LANGPanelStrings[LeftPanel], GetErrorString(OpenDirThread.ChDirResult), NewPath]), [mbOK], mbError, mbNone, mbOK); - end; + if not OpenDirThread.ChDirResult then begin + // Drop the error message if one of the callback dialogs were cancelled + if not OpenDirThread.VFSCallbackCancelled then + ShowError(Self, 'Error changing directory', OpenDirThread.ChDirError); + DebugMsg(['TFMain.ChangingDir: Freeing thread...']); + OpenDirThread.Free; + end else + if not OpenDirThread.ListingResult then begin + ShowError(Self, Format('Error getting listing for %s panel', [LANGPanelStrings[LeftPanel]]), OpenDirThread.ListingError); DebugMsg(['TFMain.ChangingDir: Freeing thread...']); OpenDirThread.Free; end else begin - if OpenDirThread.ListingResult <> 0 then begin - Application.MessageBox(Format(LANGErrorGettingListingForSPanel, [LANGPanelStrings[LeftPanel], GetErrorString(OpenDirThread.ListingResult), Engine.Path]), [mbOK], mbError, mbNone, mbOK); - Exit; - end; s := OpenDirThread.ASelItem; Engine := OpenDirThread.AEngine; // set current Engine from the thread (might have been modified due to VFS) if LeftPanel then LeftPanelEngine := Engine @@ -3607,7 +3607,7 @@ var s: string; // AViewer: TViewerThread; AViewer: TFViewer; begin - Stat := Engine.GetFileInfo(Filename, True, True); + Stat := Engine.GetFileInfo(Filename, True, True, nil); if Assigned(Stat) and (Stat^.Size > ConfEditViewFileSizeLimit) and (Application.MessageBox(LANGTheFileYouAreTryingToOpenIsQuiteBig, [mbYes, mbNo], mbWarning, mbNone, mbNo) = mbNo) then begin @@ -3710,7 +3710,7 @@ begin DebugMsg(['Some strange error occured...']); Exit; end; - Stat := Engine.GetFileInfo(Path, True, True); + Stat := Engine.GetFileInfo(Path, True, True, nil); if Assigned(Stat) and Stat^.IsExecutable then begin b := True; if Engine is TVFSEngine then b := HandleRunFromArchive(Path, Engine, Command, FileTypeDesc, False); // not a local engine, extract to local first @@ -4084,7 +4084,7 @@ begin if AFile <> '' then try FChmod := TFChmod.Create(Self); - Stat := Engine.GetFileInfo(IncludeTrailingPathDelimiter(Engine.Path) + AFile, True, True); + Stat := Engine.GetFileInfo(IncludeTrailingPathDelimiter(Engine.Path) + AFile, True, True, nil); if not Assigned(Stat) then Exit; UsrManager := TUserManager.Create; try @@ -4182,7 +4182,7 @@ begin if AFile <> '' then try FChown := TFChown.Create(Self); - Stat := Engine.GetFileInfo(IncludeTrailingPathDelimiter(Engine.Path) + AFile, True, True); + Stat := Engine.GetFileInfo(IncludeTrailingPathDelimiter(Engine.Path) + AFile, True, True, nil); if not Assigned(Stat) then Exit; FChown.AssignMode(Stat^.Mode, AFile, Stat^.UID, Stat^.GID); if FChown.Run = mbOK then begin @@ -4320,6 +4320,7 @@ var Item: TGTKMenuItem; UpDir, Found: boolean; i, j: integer; Assoc: TFileAssoc; + Error: PGError; begin ClearPopupMenu(FilePopupMenu); if LeftLastFocused then begin @@ -4333,9 +4334,11 @@ begin if Assigned(AListView.Selected) and Assigned(AListView.Selected.Data) and (not PDataItem(AListView.Selected.Data)^.UpDir) then FileName := FileName + PDataItem(AListView.Selected.Data)^.FName; ShortFName := ExtractFileName(ExcludeTrailingPathDelimiter(FileName)); - DataItem := Engine.GetFileInfo(FileName, True, True); + Error := nil; + DataItem := Engine.GetFileInfo(FileName, True, True, @Error); if not Assigned(DataItem) then begin - DebugMsg(['Error: File data not assigned. Bug ???! FileName = ', FileName]); + DebugMsg(['Error: File data not assigned. Bug ???! FileName = ', FileName, ', Error = ', Error^.message]); + g_error_free(Error); Exit; end; UpDir := PDataItem(AListView.Selected.Data)^.UpDir; @@ -4480,7 +4483,8 @@ var Engine: TPanelEngine; DataItem: PDataItem; AListView: TGTKListView; FileName, ShortFName, s: string; - Error: integer; + SpawnError: integer; + Error: PGError; b: boolean; begin try @@ -4501,9 +4505,11 @@ begin if Assigned(AListView.Selected) and Assigned(AListView.Selected.Data) and (not PDataItem(AListView.Selected.Data)^.UpDir) then FileName := FileName + PDataItem(AListView.Selected.Data)^.FName; ShortFName := ExtractFileName(ExcludeTrailingPathDelimiter(FileName)); - DataItem := Engine.GetFileInfo(FileName, True, True); + Error := nil; + DataItem := Engine.GetFileInfo(FileName, True, True, @Error); if not Assigned(DataItem) then begin - DebugMsg(['Error: File data not assigned. Bug ???! FileName = ', FileName]); + DebugMsg(['Error: File data not assigned. Bug ???! FileName = ', FileName, ', Error = ', Error^.message]); + g_error_free(Error); Exit; end; @@ -4514,7 +4520,7 @@ begin if Engine is TVFSEngine then b := HandleRunFromArchive(FileName, Engine, '', '', False); // not a local engine, extract to local first if b then begin libc_chdir(PChar(ExtractFilePath(FileName))); - b := ExecuteProgram(QuoteStr(FileName), ExtractFilePath(FileName), True, False, Error); + b := ExecuteProgram(QuoteStr(FileName), ExtractFilePath(FileName), True, False, SpawnError); libc_chdir(PChar('/')); end else b := True; // Mask cancelled extraction from VFS if not b then Application.MessageBox(LANGErrorExecutingCommand, [mbOK], mbError, mbNone, mbOK); @@ -4531,7 +4537,7 @@ begin if b then begin libc_chdir(PChar(ExtractFilePath(FileName))); b := ExecuteProgram(s, ExtractFilePath(FileName), TAssocAction((Sender as TGTKMenuItem).Data).AutodetectGUI, - TAssocAction((Sender as TGTKMenuItem).Data).RunInTerminal, Error); + TAssocAction((Sender as TGTKMenuItem).Data).RunInTerminal, SpawnError); libc_chdir(PChar('/')); end else b := True; // Mask cancelled extraction from VFS if not b then Application.MessageBox(Format(LANGCannotExecuteSPleaseCheckTheConfiguration, [FileName]), [mbOK], mbError, mbNone, mbOK); @@ -5392,7 +5398,7 @@ begin FTestPlugin := TFTestPlugin.Create(Self); if (FTestPlugin.Run = mbOK) and (PluginList.Count > 0) then begin Engine := TVFSEngine.Create(PluginList[FTestPlugin.PluginOptionMenu.ItemIndex]); - if not Engine.VFSOpenURI(FTestPlugin.CommandEntry.Text, nil, nil, nil, nil) then begin + if not Engine.VFSOpenURI(FTestPlugin.CommandEntry.Text, nil, nil, nil, nil, nil) then begin Application.MessageBox(LANGCouldntOpenURI, [mbOK], mbError, mbOK, mbOK); Exit; end; @@ -5728,7 +5734,8 @@ begin try xEngine := Engine; Engine := xEngine.ParentEngine; - if not TVFSEngine(xEngine).VFSClose then DebugMsg(['Error closing the engine...']); + if not TVFSEngine(xEngine).VFSClose(nil) then + DebugMsg(['Error closing the engine...']); xEngine.Free; except end; @@ -5756,7 +5763,8 @@ begin if (i <> TabNo) and (not CheckForUnsavedConnection(Engine as TVFSEngine, False)) then Exit; xEngine := Engine; Engine := xEngine.ParentEngine; - if not TVFSEngine(xEngine).VFSClose then DebugMsg(['Error closing the engine...']); + if not TVFSEngine(xEngine).VFSClose(nil) then + DebugMsg(['Error closing the engine...']); xEngine.Free; except end; end; @@ -6072,7 +6080,8 @@ begin if not SuppressRefresh then ChangingDir(LeftPanel, Engine.SavePath, Engine.ParentEngine.LastHighlightItem, Engine.ParentEngine.LastHighlightItem, False, True); - if not TVFSEngine(Engine).VFSClose then DebugMsg(['Error closing the engine...']); + if not TVFSEngine(Engine).VFSClose(nil) then + DebugMsg(['Error closing the engine...']); Engine.Free; end; @@ -6368,7 +6377,7 @@ begin if AFile <> '' then try FProperties := TFProperties.Create(Self); - Stat := Engine.GetFileInfo(IncludeTrailingPathDelimiter(Engine.Path) + AFile, True, True); + Stat := Engine.GetFileInfo(IncludeTrailingPathDelimiter(Engine.Path) + AFile, True, True, nil); if not Assigned(Stat) then Exit; // FProperties.AssignMode(Stat^.Mode, AFile, Stat^.UID, Stat^.GID); FProperties.DisplayFileName := AFile; @@ -6493,7 +6502,7 @@ begin Result := False; try if not BypassDialog then begin - Stat := Engine.GetFileInfo(APath, True, True); + Stat := Engine.GetFileInfo(APath, True, True, nil); FRunFromVFS := TFRunFromVFS.Create(Self); FRunFromVFS.FileNameLabel2.Caption := Format('%s<span weight="ultrabold"> </span>', [StrToUTF8(APath)]); if FileTypeDesc = '' then FileTypeDesc := LANGHandleRunFromArchive_FileTypeDesc_Unknown; diff --git a/UQuickConnect.pas b/UQuickConnect.pas index e6d7d5f..89a2439 100644 --- a/UQuickConnect.pas +++ b/UQuickConnect.pas @@ -63,7 +63,7 @@ var implementation -uses ULocale, UCoreUtils, UConfig, UConnectionProperties, UGnome, uVFSprototypes; +uses ULocale, UCoreUtils, UConfig, UConnectionProperties, UGnome, UError, uVFSprototypes; procedure TFQuickConnect.FormCreate(Sender: TObject); @@ -273,6 +273,7 @@ var Engine: TVFSEngine; URI, Scheme: string; DontShowAgain: boolean; res: TMessageButton; + Error: PGError; begin if ConnectionManager <> nil then AFConnectionManager := ConnectionManager else AFConnectionManager := TFConnectionManager.Create(Self); @@ -332,8 +333,10 @@ begin URI := URIComboBox.Entry.Text; Engine.Password := URIRipPassword(URI, True); - if not AFConnectionManager.DoConnectInternal(URI, Engine, FWidget, True) then begin - if not AFConnectionManager.FSilenceError then Application.MessageBox(PGtkWindow(FWidget), LANGCouldntOpenURI, [mbOK], mbError, mbOK, mbOK); + Error := nil; + if not AFConnectionManager.DoConnectInternal(URI, Engine, FWidget, True, @Error) then begin + if not AFConnectionManager.FSilenceError then + ShowError(Self, 'Couldn''t open the URI specified', Error); Table.Enabled := True; CloseButton.Enabled := True; ConnectButton.Enabled := True; @@ -342,6 +345,8 @@ begin StopButton.Enabled := False; URIComboBox.Entry.SetFocus; Engine.Free; + if Error <> nil then + g_error_free(Error); Exit; end; diff --git a/USearch.pas b/USearch.pas index 9794e4c..edf4403 100644 --- a/USearch.pas +++ b/USearch.pas @@ -594,7 +594,7 @@ begin if b then begin DebugMsg(['Found plugin ''', Plugin.ModuleID, ''', trying to open the archive ''', archive, '''']); AEngine := TVFSEngine.Create(Plugin); - b := b and ((AEngine as TVFSEngine).VFSOpenEx(archive, nil, nil, nil, nil) = 0); + b := b and (AEngine as TVFSEngine).VFSOpenEx(archive, nil, nil, nil, nil, nil); end; end; end else begin @@ -603,7 +603,8 @@ begin end; if b then FMain.EditViewFileInternal(Self, string(PDataItem(FileList.Selected.AsPointer(0))^.FDisplayName), AEngine, True, False) else Application.MessageBox(Format(LANGCannotLoadFile, [string(PDataItem(FileList.Selected.AsPointer(0))^.FDisplayName)]), [mbOK], mbError, mbNone, mbOK); - if AEngine is TVFSEngine then (AEngine as TVFSEngine).VFSClose; + if AEngine is TVFSEngine then + (AEngine as TVFSEngine).VFSClose(nil); AEngine.Free; end; @@ -829,7 +830,8 @@ begin Processing := False; Stop := False; if FileList.Items.Count > 0 then FileList.SetFocus; - if Engine.ChangeDir(OldDir) <> 0 then DebugMsg(['DoSearch: cannot change back to saved directory']); + if not Engine.ChangeDir(OldDir, nil) then + DebugMsg(['DoSearch: cannot change back to saved directory']); // Enable the UI Table1.Enabled := True; @@ -904,7 +906,7 @@ var LocalList: TList; Data: PDataItem; Plugin: TVFSPlugin; xEngine: TVFSEngine; - VFSOpenResult: integer; + VFSOpenResult: boolean; begin try if CancelIt then Exit; @@ -915,9 +917,9 @@ begin CurrentDir := StartDir; GUIMutex.Release; - if FEngine.ChangeDir(StartDir) <> 0 then Exit; + if not FEngine.ChangeDir(StartDir, nil) then Exit; LocalList := TList.Create; - if FEngine.GetListing(LocalList, StartDir, True, True, False) = 0 then begin + if FEngine.GetListing(LocalList, StartDir, True, True, False, nil) then begin // Processing... StartDir := IncludeTrailingPathDelimiter(StartDir); @@ -991,10 +993,11 @@ begin xEngine.ParentEngine := FEngine; xEngine.SavePath := StartDir + FileName; FEngine := xEngine; - VFSOpenResult := (FEngine as TVFSEngine).VFSOpenEx(IncludeTrailingPathDelimiter(StartDir) + FileName, nil, nil, nil, nil); - if (VFSOpenResult = 0) and (not CancelIt) then DoRecurse('/'); + VFSOpenResult := (FEngine as TVFSEngine).VFSOpenEx(IncludeTrailingPathDelimiter(StartDir) + FileName, nil, nil, nil, nil, nil); + if VFSOpenResult and (not CancelIt) then DoRecurse('/'); FEngine := FEngine.ParentEngine; - if not (xEngine as TVFSEngine).VFSClose then DebugMsg(['Error closing the engine...']); + if not (xEngine as TVFSEngine).VFSClose(nil) then + DebugMsg(['Error closing the engine...']); xEngine.Free; end; end; @@ -1011,22 +1014,21 @@ end; function TSearchThread.FindText(FileName: string): boolean; const BlockSize = 65536; var fd: TEngineFileDes; - i, Error, Read, Pos: integer; + i, Read, Pos: integer; Buffer: PByteArray; x: boolean; begin Result := False; try - Error := 0; Buffer := malloc(BlockSize); if Buffer = nil then Exit; memset(Buffer, 0, BlockSize); - fd := FEngine.OpenFile(FileName, omRead, Error); - if (fd = nil) or (Error <> 0) then Exit; + fd := FEngine.OpenFile(FileName, omRead, nil); + if fd = nil then Exit; Pos := 1; repeat - Read := FEngine.ReadFile(fd, Buffer, BlockSize, Error); + Read := FEngine.ReadFile(fd, Buffer, BlockSize, nil); if Read > 0 then for i := 0 to Read - 1 do begin if FCaseSensitiveStrings then x := Buffer^[i] = byte(FStringFind[Pos]) @@ -1035,7 +1037,7 @@ begin Inc(Pos); if Pos > Length(FStringFind) then begin Result := True; - FEngine.CloseFile(fd); + FEngine.CloseFile(fd, nil); libc_free(Buffer); Exit; end; @@ -1045,7 +1047,7 @@ begin // DebugMsg(['Read : ', Read, ' bytes.']); if CancelIt then Break; until Read < BlockSize; - FEngine.CloseFile(fd); + FEngine.CloseFile(fd, nil); libc_free(Buffer); except end; diff --git a/vfs/UVFSCore.pas b/vfs/UVFSCore.pas index cf3e36a..d875b83 100644 --- a/vfs/UVFSCore.pas +++ b/vfs/UVFSCore.pas @@ -97,6 +97,8 @@ type FBlockSize: Cardinal; FArchiveMode: boolean; FArchivePath: string; + FCopyProgressCallback: PVFSProgressCallback; + FCopyCallbackData: Pointer; function GetPluginID: string; function GetDataItemFromVFSItem(P: PVFSItem): PDataItem; function GetArchiveStreamingType: boolean; @@ -109,10 +111,10 @@ type constructor Create(SourcePlugin: TVFSPlugin); destructor Destroy; override; - function GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean): integer; override; - function GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean): PDataItem; override; + function GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean; Error: PPGError): boolean; override; + function GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean; Error: PPGError): PDataItem; override; - function ChangeDir(const NewPath: string): integer; override; + function ChangeDir(const NewPath: string; Error: PPGError): boolean; override; function GetPath: string; override; procedure SetPath(Value: string); override; @@ -124,32 +126,32 @@ type function IsOnROMedium(const FileName: string): boolean; override; function FileCanRun(const FileName: string): boolean; override; - function MakeDir(const NewDir: string): integer; override; - function Remove(const APath: string): integer; override; - function MakeSymLink(const NewFileName, PointTo: string): integer; override; - function Chmod(const FileName: string; Mode: cuLong): integer; override; - function Chown(const FileName: string; UID, GID: cuLong): integer; override; - function RenameFile(const SourceFile, DestFile: string): integer; override; - function ChangeTimes(const APath: string; mtime, atime: time_t): integer; override; + function MakeDir(const NewDir: string; Error: PPGError): boolean; override; + function Remove(const APath: string; Error: PPGError): boolean; override; + function MakeSymLink(const NewFileName, PointTo: string; Error: PPGError): boolean; override; + function Chmod(const FileName: string; Mode: cuLong; Error: PPGError): boolean; override; + function Chown(const FileName: string; UID, GID: cuLong; Error: PPGError): boolean; override; + function RenameFile(const SourceFile, DestFile: string; Error: PPGError): boolean; override; + function ChangeTimes(const APath: string; mtime, atime: time_t; Error: PPGError): boolean; override; function GetBlockSize: guint32; override; procedure SetBlockSize(Value: guint32); override; - function CopyFileIn(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; override; - function CopyFileOut(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; override; + function CopyFileIn(const SourceFile, DestFile: string; Append: boolean; ProgressFunc: TEngineProgressFunc; Sender: Pointer): boolean; override; + function CopyFileOut(const SourceFile, DestFile: string; Append: boolean; ProgressFunc: TEngineProgressFunc; Sender: Pointer): boolean; override; function IsOnSameFS(const Path1, Path2: string; FollowSymlinks: boolean): boolean; override; function TwoSameFiles(const Path1, Path2: string; FollowSymlinks: boolean): boolean; override; - function OpenFile(const APath: string; Mode: integer; var Error: integer): TEngineFileDes; override; - function ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; var Error: integer): integer; override; - function WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; var Error: integer): integer; override; - function CloseFile(const FileDescriptor: TEngineFileDes): integer; override; - function FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; var Error: integer): Int64; override; + function OpenFile(const APath: string; Mode: integer; Error: PPGError): TEngineFileDes; override; + function ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; Error: PPGError): integer; override; + function WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; Error: PPGError): integer; override; + function CloseFile(const FileDescriptor: TEngineFileDes; Error: PPGError): boolean; override; + function FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; Error: PPGError): Int64; override; // VFS additions - function VFSOpenURI(const URI: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; - function VFSOpenEx(const OpenFile: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): TVFSResult; - function VFSClose: boolean; - function ChangeDirEx(const NewPath: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): integer; + function VFSOpenURI(const URI: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer; Error: PPGError): boolean; + function VFSOpenEx(const OpenFile: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer; Error: PPGError): boolean; + function VFSClose(Error: PPGError): boolean; + function ChangeDirEx(const NewPath: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer; Error: PPGError): boolean; function GetPathURI: string; @@ -157,10 +159,10 @@ type procedure ResetPassword; // 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; + function StartCopyOperation(AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; + function StopCopyOperation(ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; + function CopyFileOutEx(const SourceFile, DestFile: string; Append: boolean): boolean; + function CopyFileInEx(const SourceFile, DestFile: string; Append: boolean): boolean; published property PluginID: string read GetPluginID; property ArchiveMode: boolean read FArchiveMode; @@ -176,7 +178,7 @@ var PluginList: TList; implementation -uses SysUtils, UConfig, ULocale; +uses SysUtils, UConfig, ULocale, UError; const ConstGlobalModulePath1 = '/usr/lib/tuxcmd'; @@ -359,6 +361,8 @@ begin RemoveFileOnClose := ''; OpenedFromQuickConnect := False; CustomPluginIDSave := ''; + FCopyProgressCallback := nil; + FCopyCallbackData := nil; if @FSourcePlugin.FVFSNew <> nil then FGlobs := FSourcePlugin.FVFSNew(@VFSLogFunc); end; @@ -375,13 +379,13 @@ begin end; end; -function TVFSEngine.VFSOpenURI(const URI: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; +function TVFSEngine.VFSOpenURI(const URI: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer; Error: PPGError): boolean; begin Result := False; if (FGlobs <> nil) and (@FSourcePlugin.FVFSOpenURI <> nil) then begin if @FSourcePlugin.FVFSSetCallbacks <> nil then FSourcePlugin.FVFSSetCallbacks(FGlobs, AskQuestionCallback, AskPasswordCallback, ProgressCallback, CallbackData); - Result := FSourcePlugin.FVFSOpenURI(FGlobs, PChar(URI)) = cVFS_OK; + Result := FSourcePlugin.FVFSOpenURI(FGlobs, PChar(URI), Error); FArchiveMode := False; FArchivePath := ''; if @FSourcePlugin.FVFSSetCallbacks <> nil then @@ -389,27 +393,27 @@ begin end; end; -function TVFSEngine.VFSOpenEx(const OpenFile: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): TVFSResult; +function TVFSEngine.VFSOpenEx(const OpenFile: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer; Error: PPGError): boolean; begin - Result := cVFS_OK; + Result := False; if (FGlobs <> nil) and (@FSourcePlugin.FVFSOpenArchive <> nil) then begin if @FSourcePlugin.FVFSSetCallbacks <> nil then FSourcePlugin.FVFSSetCallbacks(FGlobs, AskQuestionCallback, AskPasswordCallback, ProgressCallback, CallbackData); - Result := FSourcePlugin.FVFSOpenArchive(FGlobs, PChar(OpenFile)); + Result := FSourcePlugin.FVFSOpenArchive(FGlobs, PChar(OpenFile), Error); FArchiveMode := True; - if Result = cVFS_OK then FArchivePath := OpenFile - else FArchivePath := ''; + if Result then FArchivePath := OpenFile + else FArchivePath := ''; if @FSourcePlugin.FVFSSetCallbacks <> nil then FSourcePlugin.FVFSSetCallbacks(FGlobs, nil, nil, nil, nil); end; end; (********************************************************************************************************************************) -function TVFSEngine.VFSClose: boolean; +function TVFSEngine.VFSClose(Error: PPGError): boolean; begin Result := False; - if (FGlobs <> nil) and (@FSourcePlugin.FVFSClose <> nil) - then Result := FSourcePlugin.FVFSClose(FGlobs) = cVFS_OK; + if (FGlobs <> nil) and (@FSourcePlugin.FVFSClose <> nil) then + Result := FSourcePlugin.FVFSClose(FGlobs, Error); end; function TVFSEngine.GetDataItemFromVFSItem(P: PVFSItem): PDataItem; @@ -444,30 +448,21 @@ begin Result := Item; end; -function TVFSEngine.GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean): integer; +function TVFSEngine.GetListing(List: TList; const APath: string; AddDotFiles, FollowSymlinks, AddFullPath: boolean; Error: PPGError): boolean; var P: PVFSItem; Item: PDataItem; - Res: integer; + FError: PGError; begin DebugMsg(['^^VFS (II): GetListing begin']); - Result := 0; + Result := False; try - if @FSourcePlugin.FVFSListFirst = nil then begin - Result := ERRNoAccess; - Exit; - end; - P := real_libc_malloc(sizeof(TVFSItem)); - memset(P, 0, sizeof(TVFSItem)); - Res := FSourcePlugin.FVFSListFirst(FGlobs, PChar(APath), P, FollowSymlinks, AddFullPath); - if Res <> cVFS_OK then begin - FSourcePlugin.FVFSListClose(FGlobs); - if Res = cVFS_Not_More_Files then Result := 0 - else Result := Res; - real_libc_free(P); + if (@FSourcePlugin.FVFSListFirst = nil) or (@FSourcePlugin.FVFSListNext = nil) or (@FSourcePlugin.FVFSListClose = nil) then begin + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'File listing not supported by the VFS module.'); Exit; end; - - repeat + FError := nil; + P := FSourcePlugin.FVFSListFirst(FGlobs, PChar(APath), FollowSymlinks, AddFullPath, @FError); + while (P <> nil) and (BreakProcessingType <> 2) do begin if (strlen(P^.FName) > 0) and (AddDotFiles or (P^.FName[0] <> '.')) then begin Item := GetDataItemFromVFSItem(P); List.Add(Item); @@ -475,14 +470,22 @@ begin if P^.FName <> nil then real_libc_free(P^.FName); if P^.FDisplayName <> nil then real_libc_free(P^.FDisplayName); if P^.sLinkTo <> nil then real_libc_free(P^.sLinkTo); - memset(P, 0, sizeof(TVFSItem)); - Res := FSourcePlugin.FVFSListNext(FGlobs, P); - until (Res <> cVFS_OK) or (BreakProcessingType = 2); - if BreakProcessingType <> 0 then DebugMsg(['^^VFS (WW): GetListing: stopped by BreakProcessing']); - + real_libc_free(P); + P := FSourcePlugin.FVFSListNext(FGlobs, @FError); + end; + Result := FError = nil; + if BreakProcessingType <> 0 then begin + DebugMsg(['^^VFS (WW): GetListing: stopped by BreakProcessing']); + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_CANCELLED), '%s', 'The operation has been cancelled.'); + Result := False; + end else begin + if (Error <> nil) and (FError <> nil) then + Error^ := g_error_copy(FError); + end; + if FError <> nil then + g_error_free(FError); real_libc_free(P); - FSourcePlugin.FVFSListClose(FGlobs); - if Res <> cVFS_Not_More_Files then Result := Res; + FSourcePlugin.FVFSListClose(FGlobs, nil); except on E: Exception do DebugMsg(['^^VFS (EE): GetListing: Exception: ', E.Message]); @@ -491,18 +494,19 @@ begin DebugMsg(['^^VFS (II): GetListing end.']); end; -function TVFSEngine.GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean): PDataItem; +function TVFSEngine.GetFileInfo(const APath: string; FollowSymlinks, AddFullPath: boolean; Error: PPGError): PDataItem; var P: PVFSItem; - Res: integer; begin DebugMsg(['^^VFS (II): GetFileInfo begin']); Result := nil; - if @FSourcePlugin.FVFSFileInfo = nil then Exit; + + if @FSourcePlugin.FVFSFileInfo = nil then begin + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Querying file info is not supported by the VFS module.'); + Exit; + end; try - P := real_libc_malloc(sizeof(TVFSItem)); - memset(P, 0, sizeof(TVFSItem)); - Res := FSourcePlugin.FVFSFileInfo(FGlobs, PChar(APath), P, FollowSymlinks, AddFullPath); - if Res = cVFS_OK then + P := FSourcePlugin.FVFSFileInfo(FGlobs, PChar(APath), FollowSymlinks, AddFullPath, Error); + if P <> nil then Result := GetDataItemFromVFSItem(P); if P^.FName <> nil then real_libc_free(P^.FName); if P^.FDisplayName <> nil then real_libc_free(P^.FDisplayName); @@ -527,13 +531,12 @@ begin AFSSize := -1; AFSFree := -1; AFSName := nil; - if FSourcePlugin.FVFSGetFileSystemInfo(FGlobs, PChar(APath), @AFSSize, @AFSFree, @AFSName) = cVFS_OK then begin - FSSize := AFSSize; - FSFree := AFSFree; - if AFSName <> nil then begin - FSName := string(AFSName); - real_libc_free(AFSName); - end; + FSourcePlugin.FVFSGetFileSystemInfo(FGlobs, PChar(APath), @AFSSize, @AFSFree, @AFSName); + FSSize := AFSSize; + FSFree := AFSFree; + if AFSName <> nil then begin + FSName := string(AFSName); + real_libc_free(AFSName); end; end; end; @@ -546,7 +549,7 @@ end; function TVFSEngine.FileCanRun(const FileName: string): boolean; var Item: PDataItem; begin - Item := GetFileInfo(FileName, True, True); + Item := GetFileInfo(FileName, True, True, nil); Result := (Item <> nil) and Item^.IsExecutable; FreeDataItem(Item); end; @@ -577,26 +580,23 @@ begin end; end; -function TVFSEngine.ChangeDir(const NewPath: string): integer; +function TVFSEngine.ChangeDir(const NewPath: string; Error: PPGError): boolean; begin - DebugMsg(['^^VFS (II): ChangeDir begin']); - Result := 0; + Result := False; try - Result := FSourcePlugin.FVFSChangeDir(FGlobs, PChar(NewPath)); -// Sleep(3000); + Result := FSourcePlugin.FVFSChangeDir(FGlobs, PChar(NewPath), Error); except on E: Exception do DebugMsg(['^^VFS (EE): ChangeDir: Exception: ', E.Message]); end; - DebugMsg(['^^VFS (II): ChangeDir end.']); end; -function TVFSEngine.ChangeDirEx(const NewPath: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): integer; +function TVFSEngine.ChangeDirEx(const NewPath: string; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer; Error: PPGError): boolean; begin - Result := ERRNoAccess; + Result := False; if (FGlobs <> nil) and (@FSourcePlugin.FVFSChangeDir <> nil) then begin if @FSourcePlugin.FVFSSetCallbacks <> nil then FSourcePlugin.FVFSSetCallbacks(FGlobs, AskQuestionCallback, AskPasswordCallback, ProgressCallback, CallbackData); - Result := ChangeDir(NewPath); + Result := ChangeDir(NewPath, Error); if @FSourcePlugin.FVFSSetCallbacks <> nil then FSourcePlugin.FVFSSetCallbacks(FGlobs, nil, nil, nil, nil); end; @@ -604,7 +604,7 @@ end; procedure TVFSEngine.SetPath(Value: string); begin - ChangeDir(Value); + ChangeDir(Value, nil); end; function TVFSEngine.FileExists(const FileName: string; FollowSymlinks: boolean): boolean; @@ -614,9 +614,8 @@ begin if (FGlobs = nil) or (@FSourcePlugin.FVFSFileInfo = nil) then Exit; try - P := real_libc_malloc(sizeof(TVFSItem)); - memset(P, 0, sizeof(TVFSItem)); - Result := FSourcePlugin.FVFSFileInfo(FGlobs, PChar(FileName), P, FollowSymlinks, False) = cVFS_OK; + P := FSourcePlugin.FVFSFileInfo(FGlobs, PChar(FileName), FollowSymlinks, False, nil); + Result := P <> nil; real_libc_free(P); except on E: Exception do @@ -626,16 +625,13 @@ end; function TVFSEngine.DirectoryExists(const FileName: string; FollowSymlinks: boolean): boolean; var P: PVFSItem; - Res: integer; begin Result := False; if (FGlobs = nil) or (@FSourcePlugin.FVFSFileInfo = nil) then Exit; try - P := real_libc_malloc(sizeof(TVFSItem)); - memset(P, 0, sizeof(TVFSItem)); - Res := FSourcePlugin.FVFSFileInfo(FGlobs, PChar(FileName), P, FollowSymlinks, False); - Result := (Res = cVFS_OK) and (TVFSItemType(P^.ItemType) = vDirectory); + P := FSourcePlugin.FVFSFileInfo(FGlobs, PChar(FileName), FollowSymlinks, False, nil); + Result := (P <> nil) and (TVFSItemType(P^.ItemType) = vDirectory); real_libc_free(P); except on E: Exception do @@ -643,46 +639,74 @@ begin end; end; -function TVFSEngine.MakeDir(const NewDir: string): integer; +function TVFSEngine.MakeDir(const NewDir: string; Error: PPGError): boolean; begin - if @FSourcePlugin.FVFSMkDir <> nil then Result := FSourcePlugin.FVFSMkDir(FGlobs, PChar(NewDir)) - else Result := cVFS_Failed; + if @FSourcePlugin.FVFSMkDir <> nil then + Result := FSourcePlugin.FVFSMkDir(FGlobs, PChar(NewDir), Error) + else begin + Result := False; + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Creating directories is not supported by the VFS module.'); + end; end; -function TVFSEngine.Remove(const APath: string): integer; +function TVFSEngine.Remove(const APath: string; Error: PPGError): boolean; begin - if @FSourcePlugin.FVFSRemove <> nil then Result := FSourcePlugin.FVFSRemove(FGlobs, PChar(APath)) - else Result := cVFS_Failed; + if @FSourcePlugin.FVFSRemove <> nil then + Result := FSourcePlugin.FVFSRemove(FGlobs, PChar(APath), Error) + else begin + Result := False; + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Removing files is not supported by the VFS module.'); + end; end; -function TVFSEngine.RenameFile(const SourceFile, DestFile: string): integer; +function TVFSEngine.RenameFile(const SourceFile, DestFile: string; Error: PPGError): boolean; begin - if @FSourcePlugin.FVFSRename <> nil then Result := FSourcePlugin.FVFSRename(FGlobs, PChar(SourceFile), PChar(DestFile)) - else Result := cVFS_Failed; + if @FSourcePlugin.FVFSRename <> nil then + Result := FSourcePlugin.FVFSRename(FGlobs, PChar(SourceFile), PChar(DestFile), Error) + else begin + Result := False; + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Renaming files is not supported by the VFS module.'); + end; end; -function TVFSEngine.MakeSymLink(const NewFileName, PointTo: string): integer; +function TVFSEngine.MakeSymLink(const NewFileName, PointTo: string; Error: PPGError): boolean; begin - if @FSourcePlugin.FVFSMakeSymLink <> nil then Result := FSourcePlugin.FVFSMakeSymLink(FGlobs, PChar(NewFileName), PChar(PointTo)) - else Result := cVFS_Failed; + if @FSourcePlugin.FVFSMakeSymLink <> nil then + Result := FSourcePlugin.FVFSMakeSymLink(FGlobs, PChar(NewFileName), PChar(PointTo), Error) + else begin + Result := False; + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Creating symbolic links is not supported by the VFS module.'); + end; end; -function TVFSEngine.Chmod(const FileName: string; Mode: cuLong): integer; +function TVFSEngine.Chmod(const FileName: string; Mode: cuLong; Error: PPGError): boolean; begin - if @FSourcePlugin.FVFSChmod <> nil then Result := FSourcePlugin.FVFSChmod(FGlobs, PChar(FileName), Mode) - else Result := cVFS_Failed; + if @FSourcePlugin.FVFSChmod <> nil then + Result := FSourcePlugin.FVFSChmod(FGlobs, PChar(FileName), Mode, Error) + else begin + Result := False; + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Chmod is not supported by the VFS module.'); + end; end; -function TVFSEngine.Chown(const FileName: string; UID, GID: cuLong): integer; +function TVFSEngine.Chown(const FileName: string; UID, GID: cuLong; Error: PPGError): boolean; begin - if @FSourcePlugin.FVFSChown <> nil then Result := FSourcePlugin.FVFSChown(FGlobs, PChar(FileName), UID, GID) - else Result := cVFS_Failed; + if @FSourcePlugin.FVFSChown <> nil then + Result := FSourcePlugin.FVFSChown(FGlobs, PChar(FileName), UID, GID, Error) + else begin + Result := False; + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Chown is not supported by the VFS module.'); + end; end; -function TVFSEngine.ChangeTimes(const APath: string; mtime, atime: time_t): integer; +function TVFSEngine.ChangeTimes(const APath: string; mtime, atime: time_t; Error: PPGError): boolean; begin - if @FSourcePlugin.FVFSChangeTimes <> nil then Result := FSourcePlugin.FVFSChangeTimes(FGlobs, PChar(APath), mtime, atime) - else Result := cVFS_Failed; + if @FSourcePlugin.FVFSChangeTimes <> nil then + Result := FSourcePlugin.FVFSChangeTimes(FGlobs, PChar(APath), mtime, atime, Error) + else begin + Result := False; + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Changing timestamps is not supported by the VFS module.'); + end; end; function TVFSEngine.GetDirSize(const APath: string): Int64; @@ -719,46 +743,51 @@ begin else Result := True; end; -function TVFSEngine.OpenFile(const APath: string; Mode: integer; var Error: integer): TEngineFileDes; -var i: integer; +function TVFSEngine.OpenFile(const APath: string; Mode: integer; Error: PPGError): TEngineFileDes; begin - if @FSourcePlugin.FVFSOpenFile <> nil then begin - Result := FSourcePlugin.FVFSOpenFile(FGlobs, PChar(APath), Mode, @i); - Error := i; - end else Result := nil; + if @FSourcePlugin.FVFSOpenFile <> nil then + Result := FSourcePlugin.FVFSOpenFile(FGlobs, PChar(APath), Mode, Error) + else begin + Result := nil; + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Manual opening files is not supported by the VFS module.'); + end; end; -function TVFSEngine.ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; var Error: integer): integer; -var i: integer; +function TVFSEngine.ReadFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; ABlockSize: integer; Error: PPGError): integer; begin - if @FSourcePlugin.FVFSReadFile <> nil then begin - Result := FSourcePlugin.FVFSReadFile(FGlobs, FileDescriptor, Buffer, ABlockSize, @i); - Error := i; - end else Result := -1; + if @FSourcePlugin.FVFSReadFile <> nil then + Result := FSourcePlugin.FVFSReadFile(FGlobs, FileDescriptor, Buffer, ABlockSize, Error) + else begin + Result := -1; + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Manual read is not supported by the VFS module.'); + end; end; -function TVFSEngine.WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; var Error: integer): integer; -var i: integer; +function TVFSEngine.WriteFile(const FileDescriptor: TEngineFileDes; Buffer: Pointer; BytesCount: integer; Error: PPGError): integer; begin - if @FSourcePlugin.FVFSWriteFile <> nil then begin - Result := FSourcePlugin.FVFSWriteFile(FGlobs, FileDescriptor, Buffer, BytesCount, @i); - Error := i; - end else Result := -1; + if @FSourcePlugin.FVFSWriteFile <> nil then + Result := FSourcePlugin.FVFSWriteFile(FGlobs, FileDescriptor, Buffer, BytesCount, Error) + else begin + Result := -1; + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Manual write is not supported by the VFS module.'); + end; end; -function TVFSEngine.CloseFile(const FileDescriptor: TEngineFileDes): integer; +function TVFSEngine.CloseFile(const FileDescriptor: TEngineFileDes; Error: PPGError): boolean; begin - if @FSourcePlugin.FVFSCloseFile <> nil then Result := FSourcePlugin.FVFSCloseFile(FGlobs, FileDescriptor) - else Result := 0; + if @FSourcePlugin.FVFSCloseFile <> nil then + Result := FSourcePlugin.FVFSCloseFile(FGlobs, FileDescriptor, nil) + else Result := False; end; -function TVFSEngine.FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; var Error: integer): Int64; -var i: integer; +function TVFSEngine.FileSeek(const FileDescriptor: TEngineFileDes; const AbsoluteOffset: Int64; Error: PPGError): Int64; begin - if @FSourcePlugin.FVFSFileSeek <> nil then begin - Result := FSourcePlugin.FVFSFileSeek(FGlobs, FileDescriptor, AbsoluteOffset, @i); - Error := i; - end else Result := -1; + if @FSourcePlugin.FVFSFileSeek <> nil then + Result := FSourcePlugin.FVFSFileSeek(FGlobs, FileDescriptor, AbsoluteOffset, Error) + else begin + Result := -1; + g_set_error(Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'Manual seek is not supported by the VFS module.'); + end; end; function TVFSEngine.TwoSameFiles(const Path1, Path2: string; FollowSymlinks: boolean): boolean; @@ -770,129 +799,123 @@ end; (********************************************************************************************************************************) -function TVFSEngine.CopyFileIn(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; +function TVFSEngine.CopyFileIn(const SourceFile, DestFile: string; Append: boolean; ProgressFunc: TEngineProgressFunc; Sender: Pointer): boolean; begin - Result := StartCopyOperation(Sender, ErrorFunc, nil, nil, nil, nil); - Result := Result and CopyFileInEx(Sender, SourceFile, DestFile, ErrorFunc, Append); - Result := Result and StopCopyOperation(Sender, ErrorFunc); + DebugMsg(['** (WW): deprecated method CopyFileIn called from a TVFSEngine instance!']); + Result := StartCopyOperation(nil, nil, nil, nil); + Result := Result and CopyFileInEx(SourceFile, DestFile, Append); + Result := Result and StopCopyOperation(nil, nil); end; -function TVFSEngine.CopyFileOut(Sender: Pointer; const SourceFile, DestFile: string; ProgressFunc: TEngineProgressFunc; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; +function TVFSEngine.CopyFileOut(const SourceFile, DestFile: string; Append: boolean; ProgressFunc: TEngineProgressFunc; Sender: Pointer): boolean; begin - Result := StartCopyOperation(Sender, ErrorFunc, nil, nil, nil, nil); - Result := Result and CopyFileInEx(Sender, SourceFile, DestFile, ErrorFunc, Append); - Result := Result and StopCopyOperation(Sender, ErrorFunc); + DebugMsg(['** (WW): deprecated method CopyFileOut called from a TVFSEngine instance!']); + Result := StartCopyOperation(nil, nil, nil, nil); + Result := Result and CopyFileOutEx(SourceFile, DestFile, Append); + Result := Result and StopCopyOperation(nil, nil); end; -function TVFSEngine.CopyFileOutEx(Sender: Pointer; const SourceFile, DestFile: string; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; -var Res: TVFSResult; +function TVFSEngine.CopyFileOutEx(const SourceFile, DestFile: string; Append: boolean): boolean; +var Error: PGError; + ACopyProgressCallback: TVFSProgressCallback; begin Result := False; try - if @FSourcePlugin.FVFSCopyToLocal <> nil then begin - try - Res := FSourcePlugin.FVFSCopyToLocal(FGlobs, PChar(SourceFile), PChar(DestFile), Append); - 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; + Error := nil; + if @FSourcePlugin.FVFSCopyToLocal <> nil then + Result := FSourcePlugin.FVFSCopyToLocal(FGlobs, PChar(SourceFile), PChar(DestFile), Append, @Error) + else + g_set_error(@Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'VFSCopyToLocal not supported by the VFS module.'); + if Error <> nil then begin + if FCopyProgressCallback <> nil then begin + @ACopyProgressCallback := FCopyProgressCallback; + Result := ACopyProgressCallback(0, Error, FCopyCallbackData); 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); - cVFS_WriteErr: Result := ErrorFunc(Sender, 7, 0, DestFile); - cVFS_mallocFailed: ErrorFunc(Sender, 1, 0, SourceFile); - cVFS_Cancelled: ErrorFunc(Sender, 0, 0, SourceFile); - end; - end else Result := False; + g_error_free(Error); + end; except - on E: Exception do DebugMsg(['*** Exception raised in TVFSEngine.CopyFileOut(Sender=', QWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]); + on E: Exception do begin + DebugMsg(['*** Exception raised in TVFSEngine.CopyFileOutEx(SourceFile=', SourceFile, ', DestFile=', DestFile, ', Append=', Append,'): (', E.ClassName, '): ', E.Message]); + Result := False; + end; end; end; -function TVFSEngine.CopyFileInEx(Sender: Pointer; const SourceFile, DestFile: string; ErrorFunc: TEngineErrorFunc; Append: boolean): boolean; -var Res: TVFSResult; +function TVFSEngine.CopyFileInEx(const SourceFile, DestFile: string; Append: boolean): boolean; +var Error: PGError; +ACopyProgressCallback: TVFSProgressCallback; begin Result := False; try - if @FSourcePlugin.FVFSCopyFromLocal <> nil then begin - try - Res := FSourcePlugin.FVFSCopyFromLocal(FGlobs, PChar(SourceFile), PChar(DestFile), Append); - except - on E: Exception do begin - DebugMsg(['*** Exception raised in TVFSEngine.CopyFileIn(Sender=', QWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]); - Res := cVFS_WriteErr; - end; + Error := nil; + if @FSourcePlugin.FVFSCopyFromLocal <> nil then + Result := FSourcePlugin.FVFSCopyFromLocal(FGlobs, PChar(SourceFile), PChar(DestFile), Append, @Error) + else + g_set_error(@Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'VFSCopyFromLocal not supported by the VFS module.'); + if Error <> nil then begin + if FCopyProgressCallback <> nil then begin + @ACopyProgressCallback := FCopyProgressCallback; + Result := ACopyProgressCallback(0, Error, FCopyCallbackData); 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); - cVFS_WriteErr: Result := ErrorFunc(Sender, 7, 0, DestFile); - cVFS_mallocFailed: ErrorFunc(Sender, 1, 0, SourceFile); - cVFS_Cancelled: ErrorFunc(Sender, 0, 0, SourceFile); - end; - end else Result := False; + g_error_free(Error); + end; except - on E: Exception do DebugMsg(['*** Exception raised in TVFSEngine.CopyFileIn(Sender=', QWord(Sender), ', SourceFile=', SourceFile, ', DestFile=', DestFile, '): (', E.ClassName, '): ', E.Message]); + on E: Exception do begin + DebugMsg(['*** Exception raised in TVFSEngine.CopyFileInEx(SourceFile=', SourceFile, ', DestFile=', DestFile, ', Append=', Append,'): (', E.ClassName, '): ', E.Message]); + Result := False; + end; end; end; -function TVFSEngine.StartCopyOperation(Sender: Pointer; ErrorFunc: TEngineErrorFunc; AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; -var Res: TVFSResult; +function TVFSEngine.StartCopyOperation(AskQuestionCallback: PVFSAskQuestionCallback; AskPasswordCallback: PVFSAskPasswordCallback; ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; +var Error: PGError; begin Result := not ArchiveMode; try if @FSourcePlugin.FVFSSetCallbacks <> nil then FSourcePlugin.FVFSSetCallbacks(FGlobs, AskQuestionCallback, AskPasswordCallback, ProgressCallback, CallbackData); + FCopyProgressCallback := ProgressCallback; + FCopyCallbackData := CallbackData; if ArchiveMode then begin - 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'); + Error := nil; + if @FSourcePlugin.FVFSStartCopyOperation <> nil then + Result := FSourcePlugin.FVFSStartCopyOperation(FGlobs, @Error) + else + g_set_error(@Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'VFSStartCopyOperation not supported by the VFS module.'); + if Error <> nil then begin + if ProgressCallback <> nil then + Result := ProgressCallback^(0, Error, CallbackData); + g_error_free(Error); + end; end; except - on E: Exception do DebugMsg(['*** Exception raised in TVFSEngine.StartCopyOperation(Sender=', QWord(Sender), '): (', E.ClassName, '): ', E.Message]); + on E: Exception do DebugMsg(['*** Exception raised in TVFSEngine.StartCopyOperation(CallbackData=', CallbackData, '): (', E.ClassName, '): ', E.Message]); end; end; -function TVFSEngine.StopCopyOperation(Sender: Pointer; ErrorFunc: TEngineErrorFunc): boolean; -var Res: TVFSResult; +function TVFSEngine.StopCopyOperation(ProgressCallback: PVFSProgressCallback; CallbackData: Pointer): boolean; +var Error: PGError; begin Result := not ArchiveMode; try if @FSourcePlugin.FVFSSetCallbacks <> nil then FSourcePlugin.FVFSSetCallbacks(FGlobs, nil, nil, nil, nil); if ArchiveMode then begin - 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'); + Error := nil; + if @FSourcePlugin.FVFSStopCopyOperation <> nil then + Result := FSourcePlugin.FVFSStopCopyOperation(FGlobs, @Error) + else + g_set_error(@Error, G_IO_ERROR, gint(G_IO_ERROR_NOT_SUPPORTED), '%s', 'VFSStopCopyOperation not supported by the VFS module.'); + if Error <> nil then begin + if ProgressCallback <> nil then + Result := ProgressCallback^(0, Error, CallbackData); + g_error_free(Error); + end; end; + FCopyProgressCallback := nil; + FCopyCallbackData := nil; except - on E: Exception do DebugMsg(['*** Exception raised in TVFSEngine.StopCopyOperation(Sender=', QWord(Sender), '): (', E.ClassName, '): ', E.Message]); + on E: Exception do DebugMsg(['*** Exception raised in TVFSEngine.StopCopyOperation(CallbackData=', CallbackData, '): (', E.ClassName, '): ', E.Message]); end; end; diff --git a/vfs/uVFSprototypes.pas b/vfs/uVFSprototypes.pas index 8beacdd..9ed0844 100644 --- a/vfs/uVFSprototypes.pas +++ b/vfs/uVFSprototypes.pas @@ -36,24 +36,7 @@ uses glib2; const cVFSVersion = 5; // current version of the VFS API - // Error codes (TVFSResult) - cVFS_OK = 0; - cVFS_Failed = 1; // also No such file - cVFS_Cancelled = 2; - cVFS_Not_Supported = 3; - cVFS_Not_More_Files = 4; // returned while directory listing - cVFS_ReadErr = 5; - cVFS_WriteErr = 6; // also ReadOnlyFileSystem - cVFS_LoginFailed = 7; - cVFS_PermissionDenied = 8; - cVFS_NoSpaceLeft = 9; - cVFS_mallocFailed = 10; - cVFS_BadPassword = 11; - cVFS_MissingVolume = 12; - cVFS_CorruptedArchive = 13; - - - // Open modes (for VFSOpenFile function) + // Open modes (for VFSOpenFile function) cVFS_OpenRead = 0; cVFS_OpenWrite = 1; cVFS_OpenAppend = 2; @@ -76,8 +59,6 @@ const type - TVFSResult = longint; - // Plugin private data for each connection/instance TVFSGlobs = Pointer; @@ -94,7 +75,6 @@ type TVFSItemType = (vRegular=0, vChardev=1, vBlockdev=2, vDirectory=3, vFifo=4, vSock=5, vOther=6); - PVFSItem = ^TVFSItem; TVFSItem = record FName: PChar; @@ -149,10 +129,14 @@ type password_save: PVFSPasswordSave; user_data: Pointer): gboolean; cdecl; - // Return False to break the operation + // Progress callback, return False to break the copy process + // If an Error is set, returning True means to ignore error (don't delete broken file if possible) + // If an Error is set, Position may contain random value + // Do not free Error, it belongs to the copy operation PVFSProgressCallback = ^TVFSProgressCallback; + // Keep in sync with UCoreWorkers.pas/vfs_progress_callback TVFSProgressCallback = function (position: guint64; - max: guint64; + error: PGError; user_data: Pointer): gboolean; cdecl; type @@ -192,33 +176,33 @@ type // Opens specified archive. This will also switch engine into an archiving mode - TVFSOpenArchive = function (g:TVFSGlobs; const sName: PChar): TVFSResult; cdecl; + TVFSOpenArchive = function (g:TVFSGlobs; const sName: PChar; Error: PPGError): gboolean; cdecl; // Opens specified network location. This will also switch engine into a networking mode // In case of URI, do not supply password encoded in the string; plugin will automatically spawn the TVFSAskPasswordCallback callback when needed - TVFSOpenURI = function (g:TVFSGlobs; const sURI: PChar): TVFSResult; cdecl; + TVFSOpenURI = function (g:TVFSGlobs; const sURI: PChar; Error: PPGError): gboolean; cdecl; // Closes the file or connection to the server - TVFSClose = function (g:TVFSGlobs): TVFSResult; cdecl; + TVFSClose = function (g:TVFSGlobs; Error: PPGError): gboolean; cdecl; // These functions serves for listing contents of a directory // Before calling VFSListFirst, it is recommended to change target directory (VFSChangeDir) to check it really exists // First call the VFSListFirst function and then repeat call of VFSListNext until it returns NULL. // Then call VFSListClose to make cleanup - TVFSListFirst = function (g:TVFSGlobs; const sDir: PChar; VFSItem: PVFSItem; FollowSymlinks, AddFullPath: gboolean): TVFSResult; cdecl; - TVFSListNext = function (g:TVFSGlobs; VFSItem: PVFSItem): TVFSResult; cdecl; - TVFSListClose = function (g:TVFSGlobs): TVFSResult; cdecl; + TVFSListFirst = function (g:TVFSGlobs; const sDir: PChar; FollowSymlinks, AddFullPath: gboolean; Error: PPGError): PVFSItem; cdecl; + TVFSListNext = function (g:TVFSGlobs; Error: PPGError): PVFSItem; cdecl; + TVFSListClose = function (g:TVFSGlobs; Error: PPGError): gboolean; cdecl; // Gets a single info item without need to list a whole directory - TVFSFileInfo = function (g:TVFSGlobs; const AFileName: PChar; VFSItem: PVFSItem; FollowSymlinks, AddFullPath: gboolean): TVFSResult; cdecl; + TVFSFileInfo = function (g:TVFSGlobs; const AFileName: PChar; FollowSymlinks, AddFullPath: gboolean; Error: PPGError): PVFSItem; cdecl; // Try to change directory, checks real access - TVFSChangeDir = function (g:TVFSGlobs; const NewPath: PChar): TVFSResult; cdecl; + TVFSChangeDir = function (g:TVFSGlobs; const NewPath: PChar; Error: PPGError): gboolean; cdecl; // Returns current working path, tuxcmd will take care of memory deallocation TVFSGetPath = function (g:TVFSGlobs): PChar; cdecl; // Returns the current working path in the URI form, tuxcmd will take care of memory deallocation TVFSGetPathURI = function (g:TVFSGlobs): PChar; cdecl; // Gets filesystem info; tuxcmd will take care of memory deallocation - TVFSGetFileSystemInfo = function (g:TVFSGlobs; const APath: PChar; FSSize, FSFree: PInt64; FSLabel: PPChar): TVFSResult; cdecl; + TVFSGetFileSystemInfo = procedure (g:TVFSGlobs; const APath: PChar; FSSize, FSFree: PInt64; FSLabel: PPChar); cdecl; TVFSIsOnSameFS = function (g:TVFSGlobs; const Path1, Path2: PChar; FollowSymlinks: gboolean): gboolean; cdecl; // Checks if the two files are simmilar (used to test the case-insensitive filesystem - or hardlinks) TVFSTwoSameFiles = function (g:TVFSGlobs; const Path1, Path2: PChar; FollowSymlinks: gboolean): gboolean; cdecl; @@ -228,34 +212,34 @@ type TVFSBreakGetDirSize = procedure (g:TVFSGlobs); cdecl; // Operations - TVFSMkDir = function (g:TVFSGlobs; const sDirName: PChar): TVFSResult; cdecl; + TVFSMkDir = function (g:TVFSGlobs; const sDirName: PChar; Error: PPGError): gboolean; cdecl; // Rename/Move, the two files/directories have to be on the same filesystem (do manual copy and delete otherway) - TVFSRename = function (g:TVFSGlobs; const sSrcName, sDstName: PChar): TVFSResult; cdecl; + TVFSRename = function (g:TVFSGlobs; const sSrcName, sDstName: PChar; Error: PPGError): gboolean; cdecl; // Removes file/directory (empty only!) - TVFSRemove = function (g:TVFSGlobs; const APath: PChar): TVFSResult; cdecl; - TVFSMakeSymLink = function (g:TVFSGlobs; const NewFileName, PointTo: PChar): TVFSResult; cdecl; + TVFSRemove = function (g:TVFSGlobs; const APath: PChar; Error: PPGError): gboolean; cdecl; + TVFSMakeSymLink = function (g:TVFSGlobs; const NewFileName, PointTo: PChar; Error: PPGError): gboolean; cdecl; // Mode is classic unix format (glibc) - a bit mask - TVFSChmod = function (g:TVFSGlobs; const FileName: PChar; Mode: guint32): TVFSResult; cdecl; - TVFSChown = function (g:TVFSGlobs; const FileName: PChar; UID, GID: guint32): TVFSResult; cdecl; + TVFSChmod = function (g:TVFSGlobs; const FileName: PChar; Mode: guint32; Error: PPGError): gboolean; cdecl; + TVFSChown = function (g:TVFSGlobs; const FileName: PChar; UID, GID: guint32; Error: PPGError): gboolean; cdecl; // Changes times for the file/directory - mtime and atime are __time_t parameters (glibc) - TVFSChangeTimes = function (g:TVFSGlobs; const APath: PChar; mtime, atime: guint32): TVFSResult; cdecl; + TVFSChangeTimes = function (g:TVFSGlobs; const APath: PChar; mtime, atime: guint32; Error: PPGError): gboolean; cdecl; // Performs the copy process from inside of module to local filesystem // (thus sSrcName is a path from inside of module and sDstName is path in the local filesystem where the file should be copied) // Note: if you need to transfer a file between two VFS modules, you need to do it manually - // - either first copy to local FS or use the Open, Read, Write functions of the module (NOTE: both VFS modules have to support these functions) - TVFSCopyToLocal = function (g:TVFSGlobs; const sSrcName, sDstName: PChar; Append: gboolean): TVFSResult; cdecl; + TVFSCopyToLocal = function (g:TVFSGlobs; const sSrcName, sDstName: PChar; Append: gboolean; Error: PPGError): gboolean; 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; + TVFSCopyFromLocal = function (g:TVFSGlobs; const sSrcName, sDstName: PChar; Append: gboolean; Error: PPGError): gboolean; cdecl; + // Start the copy operation - open the archive and prepare internal structures (called only in archive mode) + TVFSStartCopyOperation = function (g:TVFSGlobs; Error: PPGError): gboolean; cdecl; + // Stop the copy operation - close the archive and free memory (called only in archive mode) + TVFSStopCopyOperation = function (g:TVFSGlobs; Error: PPGError): gboolean; cdecl; // TODO: Prototype function for packing new files into archive - TVFSPack = function (g:TVFSGlobs; const sSrcName, sDstName: PChar; CompressionLevel: integer; const Password: PChar): TVFSResult; cdecl; + TVFSPack = function (g:TVFSGlobs; const sSrcName, sDstName: PChar; CompressionLevel: integer; const Password: PChar; Error: PPGError): gboolean; cdecl; // TODO: not implemented at all @@ -263,14 +247,14 @@ type // There is a TVFSFileDes object which identifies the processed file (filedescriptor) // All these functions needs a pointer to an int variable to store the error code // NOTE: not all modules could support this set of functions due to its design (unable to set a solid block size) - TVFSOpenFile = function (g:TVFSGlobs; const APath: PChar; Mode: integer; Error: Pinteger): TVFSFileDes; cdecl; + TVFSOpenFile = function (g:TVFSGlobs; const APath: PChar; Mode: integer; Error: PPGError): TVFSFileDes; cdecl; // Opens a file or creates new (the values for the Mode parameter are described above) and returns the assigned filedescriptor - TVFSReadFile = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; Buffer: Pointer; ABlockSize: integer; Error: Pinteger): integer; cdecl; + TVFSReadFile = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; Buffer: Pointer; ABlockSize: integer; Error: PPGError): integer; cdecl; // Returns number of bytes read; the buffer needs to be allocated by a blocksize (set it by VFSSetBlockSize function) - TVFSWriteFile = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; Buffer: Pointer; BytesCount: integer; Error: Pinteger): integer; cdecl; + TVFSWriteFile = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; Buffer: Pointer; BytesCount: integer; Error: PPGError): integer; cdecl; // Returns number of bytes written - TVFSCloseFile = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes): TVFSResult; cdecl; - TVFSFileSeek = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; const AbsoluteOffset: Int64; Error: Pinteger): Int64; cdecl; + TVFSCloseFile = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; Error: PPGError): gboolean; cdecl; + TVFSFileSeek = function (g:TVFSGlobs; const FileDescriptor: TVFSFileDes; const AbsoluteOffset: Int64; Error: PPGError): Int64; cdecl; // Sets the position in the file from the start and returns real current position |
