Ok, here is what I want to do:
I want to be able to know when a file has been closed for reading(download) and writing (upload)
The OnCloseFile should be the optimal place to do this but the problem is with
TScHandle, it only exposes it's Fhandle field via the property Handle. It's has the fullfilename there as well, but it is protected and no property exits to get at it.
Ok, I had to modify the source code to add the FullFilename property to TScHandle, now in the OnCloseFile I have this: (I am not sure if this correct as the default Onclosefile has some stuff in there about tsearchrec which I don't' have in my handler.
procedure TForm1.ScSFTPServer1CloseFile(Sender: TObject;
SFTPSessionInfo: TScSFTPSessionInfo; Data: TObject; var Error: TScSFTPError);
var
afilename:string;
begin
if Data <> nil then
if Data is TScHandle then
begin
afilename:=TScHandle(Data).FullFileName;
FileClose(TScHandle(Data).Handle);
InitError(Error, erOk);
end;
end;
The only problem now is I dont' know if the file was opened for reading or writing.
This seems like it could be solved if another field could be added to TscHandle with a property to expose it that would indicate the mode the file was opened in.
Would someone at Devart be able to assist me with this? I think I am on the correct track here.
Having some issues with sftpserver (Onclosefile)
Re: Having some issues with sftpserver (Onclosefile)
I think I got this working:
First I had to modify TscHandle in ScSFTPServer:
TScHandle = class
protected
FHandle: THandle;
FFullFileName: string;
FInAppendMode: boolean;
FInTextMode: boolean;
FBlockMode:TScSFTPBlockMode;
public
constructor Create(Handle: THandle);
property Handle: THandle read FHandle write FHandle;
property FullFileName:string read FFullFileName write FFullFileName;
property InAppendMode:boolean read FInAppendMode write FInAppendMode;
property InTextMode:boolean read FInTextMode write FInTextMode;
Property BlockMode:TScSFTPBlockMode read FBlockMode write FBlockMode;
end;
Then:
procedure TForm1.ScSFTPServer1OpenFile(Sender: TObject;
SFTPSessionInfo: TScSFTPSessionInfo; const FileName: string;
const OpenAttributes: TScSFTPFileOpenAttributes; var Data: TObject;
var Error: TScSFTPError);
const
FILE_FLAG_OPEN_REPARSE_POINT = $00200000;
var
dwDesiredAccess, dwShareMode, dwCreationDisposition, dwFlagsAndAttributes: DWORD;
Blockmode:TScSFTPBlockMode;
FullFileName: string;
aHandle: THandle;
begin
FullFileName := TScSFTPServer(sender).GetFullPath(SFTPSessionInfo, FileName);
dwDesiredAccess := ConvertAceMaskToSFTPValue(OpenAttributes.DesiredAccess);
dwShareMode := 0;
if not (bmRead in OpenAttributes.BlockModes) then
begin
blockmode:=bmRead;
dwShareMode := dwShareMode or FILE_SHARE_READ;
end;
if not (bmWrite in OpenAttributes.BlockModes) then
begin
blockmode:=bmwrite;
dwShareMode := dwShareMode or FILE_SHARE_WRITE;
end;
if not (bmDelete in OpenAttributes.BlockModes) then
dwShareMode := dwShareMode or FILE_SHARE_DELETE;
case OpenAttributes.Mode of
fmCreateNew:
dwCreationDisposition := CREATE_NEW;
fmCreateOrTruncate:
dwCreationDisposition := CREATE_ALWAYS;
fmOpenExisting:
dwCreationDisposition := OPEN_EXISTING;
fmOpenOrCreate:
dwCreationDisposition := OPEN_ALWAYS;
fmTruncateExisting:
dwCreationDisposition := TRUNCATE_EXISTING;
else
dwCreationDisposition := 0;
Assert(False);
end;
dwFlagsAndAttributes := FILE_ATTRIBUTE_NORMAL;
if ofDeleteOnClose in OpenAttributes.Flags then
dwFlagsAndAttributes := dwFlagsAndAttributes or FILE_FLAG_DELETE_ON_CLOSE;
if ofNoFollow in OpenAttributes.Flags then
dwFlagsAndAttributes := dwFlagsAndAttributes or FILE_FLAG_OPEN_REPARSE_POINT;
aHandle := CreateFile(PChar(FullFileName),
dwDesiredAccess, dwShareMode, nil, dwCreationDisposition, dwFlagsAndAttributes, 0);
if Handle <> INVALID_HANDLE_VALUE then begin
Data := TScHandle.Create(aHandle);
TScHandle(Data).FullFileName := FullFileName;
TScHandle(Data).InAppendMode := (ofAppendData in OpenAttributes.Flags) or (ofAppendDataAtomic in OpenAttributes.Flags);
TScHandle(Data).InTextMode := ofTextMode in OpenAttributes.Flags;
TScHandle(Data).BlockMode:=blockmode;
InitError(Error, erOk);
end
else
InitError(Error, erFailure, SysErrorMessage(GetLastError));
end;
then:
procedure TForm1.ScSFTPServer1CloseFile(Sender: TObject;
SFTPSessionInfo: TScSFTPSessionInfo; Data: TObject; var Error: TScSFTPError);
var
afilename:string;
arec:TSearchRec;
begin
if Data is TScSearchRec then
begin
arec:= TScSearchRec(data).SearchRec;
SysUtils.FindClose(arec);
InitError(Error, erOk);
end else
if Data is TScHandle then
begin
FileClose(TScHandle(Data).Handle);
afilename:=TScHandle(Data).FullFileName;
if TScHandle(data).BlockMode = bmread then
begin
showmessage('File Uploaded');
end;
InitError(Error, erOk);
end;
end;
Does this look correct? It seems to work but I have no idea if it's how devart would have done it.
First I had to modify TscHandle in ScSFTPServer:
TScHandle = class
protected
FHandle: THandle;
FFullFileName: string;
FInAppendMode: boolean;
FInTextMode: boolean;
FBlockMode:TScSFTPBlockMode;
public
constructor Create(Handle: THandle);
property Handle: THandle read FHandle write FHandle;
property FullFileName:string read FFullFileName write FFullFileName;
property InAppendMode:boolean read FInAppendMode write FInAppendMode;
property InTextMode:boolean read FInTextMode write FInTextMode;
Property BlockMode:TScSFTPBlockMode read FBlockMode write FBlockMode;
end;
Then:
procedure TForm1.ScSFTPServer1OpenFile(Sender: TObject;
SFTPSessionInfo: TScSFTPSessionInfo; const FileName: string;
const OpenAttributes: TScSFTPFileOpenAttributes; var Data: TObject;
var Error: TScSFTPError);
const
FILE_FLAG_OPEN_REPARSE_POINT = $00200000;
var
dwDesiredAccess, dwShareMode, dwCreationDisposition, dwFlagsAndAttributes: DWORD;
Blockmode:TScSFTPBlockMode;
FullFileName: string;
aHandle: THandle;
begin
FullFileName := TScSFTPServer(sender).GetFullPath(SFTPSessionInfo, FileName);
dwDesiredAccess := ConvertAceMaskToSFTPValue(OpenAttributes.DesiredAccess);
dwShareMode := 0;
if not (bmRead in OpenAttributes.BlockModes) then
begin
blockmode:=bmRead;
dwShareMode := dwShareMode or FILE_SHARE_READ;
end;
if not (bmWrite in OpenAttributes.BlockModes) then
begin
blockmode:=bmwrite;
dwShareMode := dwShareMode or FILE_SHARE_WRITE;
end;
if not (bmDelete in OpenAttributes.BlockModes) then
dwShareMode := dwShareMode or FILE_SHARE_DELETE;
case OpenAttributes.Mode of
fmCreateNew:
dwCreationDisposition := CREATE_NEW;
fmCreateOrTruncate:
dwCreationDisposition := CREATE_ALWAYS;
fmOpenExisting:
dwCreationDisposition := OPEN_EXISTING;
fmOpenOrCreate:
dwCreationDisposition := OPEN_ALWAYS;
fmTruncateExisting:
dwCreationDisposition := TRUNCATE_EXISTING;
else
dwCreationDisposition := 0;
Assert(False);
end;
dwFlagsAndAttributes := FILE_ATTRIBUTE_NORMAL;
if ofDeleteOnClose in OpenAttributes.Flags then
dwFlagsAndAttributes := dwFlagsAndAttributes or FILE_FLAG_DELETE_ON_CLOSE;
if ofNoFollow in OpenAttributes.Flags then
dwFlagsAndAttributes := dwFlagsAndAttributes or FILE_FLAG_OPEN_REPARSE_POINT;
aHandle := CreateFile(PChar(FullFileName),
dwDesiredAccess, dwShareMode, nil, dwCreationDisposition, dwFlagsAndAttributes, 0);
if Handle <> INVALID_HANDLE_VALUE then begin
Data := TScHandle.Create(aHandle);
TScHandle(Data).FullFileName := FullFileName;
TScHandle(Data).InAppendMode := (ofAppendData in OpenAttributes.Flags) or (ofAppendDataAtomic in OpenAttributes.Flags);
TScHandle(Data).InTextMode := ofTextMode in OpenAttributes.Flags;
TScHandle(Data).BlockMode:=blockmode;
InitError(Error, erOk);
end
else
InitError(Error, erFailure, SysErrorMessage(GetLastError));
end;
then:
procedure TForm1.ScSFTPServer1CloseFile(Sender: TObject;
SFTPSessionInfo: TScSFTPSessionInfo; Data: TObject; var Error: TScSFTPError);
var
afilename:string;
arec:TSearchRec;
begin
if Data is TScSearchRec then
begin
arec:= TScSearchRec(data).SearchRec;
SysUtils.FindClose(arec);
InitError(Error, erOk);
end else
if Data is TScHandle then
begin
FileClose(TScHandle(Data).Handle);
afilename:=TScHandle(Data).FullFileName;
if TScHandle(data).BlockMode = bmread then
begin
showmessage('File Uploaded');
end;
InitError(Error, erOk);
end;
end;
Does this look correct? It seems to work but I have no idea if it's how devart would have done it.
Re: Having some issues with sftpserver (Onclosefile)
If your test shows that the code works correctly, then you can use it in your projects.
Re: Having some issues with sftpserver (Onclosefile)
Seems to be working ok.
What I ended up doing so as not to modify SB code, I just made a new class called
MyTScHandle that inherits from TScHandle, then I just added the missing properties and added a new one for file size.
I only see a couple of issues now:
1. OnCheckKey is being called twice when the client uses Pub Key auth.
2. The time between establishing a session and get the directory listing can be very slow.
It seems faster if I connect and then disconnect, then on the second connection it's fast. I don't see
why the first connection would be slower at establishing the session. If Keyboard interactive is disabled it's even slower with up to 6 seconds between session and dir listing with both server and client on localhost.
What I ended up doing so as not to modify SB code, I just made a new class called
MyTScHandle that inherits from TScHandle, then I just added the missing properties and added a new one for file size.
I only see a couple of issues now:
1. OnCheckKey is being called twice when the client uses Pub Key auth.
2. The time between establishing a session and get the directory listing can be very slow.
It seems faster if I connect and then disconnect, then on the second connection it's fast. I don't see
why the first connection would be slower at establishing the session. If Keyboard interactive is disabled it's even slower with up to 6 seconds between session and dir listing with both server and client on localhost.
Re: Having some issues with sftpserver (Onclosefile)
We have answered your questions at our forum: http://forums.devart.com/viewtopic.php?f=27&t=33288, http://forums.devart.com/viewtopic.php?f=27&t=33287