Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 1759: When uploading file to a symbolic link with enabled remote …
…recycle bin, the symbolic link should not be moved to the recycle bin

https://winscp.net/tracker/1759

Source commit: 77809f166c326b0ad055c37306d37200361ed5ca
  • Loading branch information
martinprikryl committed Jul 4, 2019
1 parent ec40323 commit 9c3603d
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 13 deletions.
65 changes: 52 additions & 13 deletions source/core/SftpFileSystem.cpp
Expand Up @@ -1849,6 +1849,7 @@ struct TOpenRemoteFileParams
RawByteString RemoteFileHandle; // output
TOverwriteFileParams * FileParams;
bool Confirmed;
bool DontRecycle;
};
//===========================================================================
__fastcall TSFTPFileSystem::TSFTPFileSystem(TTerminal * ATerminal,
Expand Down Expand Up @@ -3578,13 +3579,13 @@ void __fastcall TSFTPFileSystem::ReadDirectory(TRemoteFileList * FileList)
void __fastcall TSFTPFileSystem::ReadSymlink(TRemoteFile * SymlinkFile,
TRemoteFile *& File)
{
DebugAssert(SymlinkFile && SymlinkFile->IsSymLink);
DebugAssert(SymlinkFile != NULL);
DebugAssert(FVersion >= 3); // symlinks are supported with SFTP version 3 and later

// need to use full filename when resolving links within subdirectory
// (i.e. for download)
UnicodeString FileName = LocalCanonify(
SymlinkFile->Directory != NULL ? SymlinkFile->FullFileName : SymlinkFile->FileName);
SymlinkFile->HaveFullFileName ? SymlinkFile->FullFileName : SymlinkFile->FileName);

TSFTPPacket ReadLinkPacket(SSH_FXP_READLINK);
AddPathString(ReadLinkPacket, FileName);
Expand Down Expand Up @@ -4457,6 +4458,14 @@ bool TSFTPFileSystem::SFTPConfirmResume(const UnicodeString DestFileName,
return ResumeTransfer;
}
//---------------------------------------------------------------------------
bool __fastcall TSFTPFileSystem::DoesFileLookLikeSymLink(TRemoteFile * File)
{
return
(FVersion < 4) &&
((*File->Rights & TRights::rfAll) == TRights::rfAll) &&
(File->Size < 100);
}
//---------------------------------------------------------------------------
void __fastcall TSFTPFileSystem::Source(
TLocalFileHandle & Handle, const UnicodeString & TargetDir, UnicodeString & DestFileName,
const TCopyParamType * CopyParam, int Params,
Expand Down Expand Up @@ -4517,9 +4526,7 @@ void __fastcall TSFTPFileSystem::Source(
// if file has all permissions and is small, then it is likely symlink.
// also it is not likely that such a small file (if it is not symlink)
// gets overwritten by large file (that would trigger resumable transfer).
else if ((FVersion < 4) &&
((*File->Rights & TRights::rfAll) == TRights::rfAll) &&
(File->Size < 100))
else if (DoesFileLookLikeSymLink(File))
{
ResumeAllowed = false;
FTerminal->LogEvent(L"Existing file looks like a symbolic link, not doing resumable transfer.");
Expand Down Expand Up @@ -4606,6 +4613,7 @@ void __fastcall TSFTPFileSystem::Source(
OpenParams.Params = Params;
OpenParams.FileParams = &FileParams;
OpenParams.Confirmed = false;
OpenParams.DontRecycle = false;

FTerminal->LogEvent(0, L"Opening remote file.");
FTerminal->FileOperationLoop(SFTPOpenRemote, OperationProgress, folAllowSkip,
Expand Down Expand Up @@ -4946,7 +4954,7 @@ int __fastcall TSFTPFileSystem::SFTPOpenRemote(void * AOpenParams, void * /*Para
// when we want to preserve overwritten files, we need to find out that
// they exist first... even if overwrite confirmation is disabled.
// but not when we already know we are not going to overwrite (but e.g. to append)
if ((ConfirmOverwriting || FTerminal->SessionData->OverwrittenToRecycleBin) &&
if ((ConfirmOverwriting || (FTerminal->SessionData->OverwrittenToRecycleBin && !OpenParams->DontRecycle)) &&
(OpenParams->OverwriteMode == omOverwrite))
{
OpenType |= SSH_FXF_EXCL;
Expand All @@ -4972,25 +4980,25 @@ int __fastcall TSFTPFileSystem::SFTPOpenRemote(void * AOpenParams, void * /*Para
FTerminal->LogEvent(FORMAT(L"Cannot create new file \"%s\", checking if it exists already", (OpenParams->RemoteFileName)));

bool ThrowOriginal = false;
std::unique_ptr<TRemoteFile> File;

// When exclusive opening of file fails, try to detect if file exists.
// When file does not exist, failure was probably caused by 'permission denied'
// or similar error. In this case throw original exception.
try
{
OperationProgress->Progress();
TRemoteFile * File;
TRemoteFile * AFile;
UnicodeString RealFileName = LocalCanonify(OpenParams->RemoteFileName);
ReadFile(RealFileName, File);
DebugAssert(File);
ReadFile(RealFileName, AFile);
File.reset(AFile);
File->FullFileName = RealFileName;
OpenParams->DestFileSize = File->Size; // Resolve symlinks?
if (OpenParams->FileParams != NULL)
{
OpenParams->FileParams->DestTimestamp = File->Modification;
OpenParams->FileParams->DestSize = OpenParams->DestFileSize;
}
// file exists (otherwise exception was thrown)
SAFE_DESTROY(File);
}
catch(...)
{
Expand Down Expand Up @@ -5022,6 +5030,8 @@ int __fastcall TSFTPFileSystem::SFTPOpenRemote(void * AOpenParams, void * /*Para
{
OpenParams->RemoteFileName =
UnixExtractFilePath(OpenParams->RemoteFileName) + RemoteFileNameOnly;
// no longer points to a relevant file
File.reset(NULL);
}
OpenParams->Confirmed = true;
}
Expand All @@ -5034,8 +5044,37 @@ int __fastcall TSFTPFileSystem::SFTPOpenRemote(void * AOpenParams, void * /*Para
FTerminal->SessionData->OverwrittenToRecycleBin &&
!FTerminal->SessionData->RecycleBinPath.IsEmpty())
{
OperationProgress->Progress();
FTerminal->RecycleFile(OpenParams->RemoteFileName, NULL);
bool IsSymLink = (File.get() != NULL) && File->IsSymLink;
if (!IsSymLink && (File.get() != NULL) && DoesFileLookLikeSymLink(File.get()) && IsCapable(fcResolveSymlink))
{
FTerminal->LogEvent(L"Existing file looks like a symbolic link, checking if it really is.");
try
{
OperationProgress->Progress();
TRemoteFile * LinkedFile;
ReadSymlink(File.get(), LinkedFile);
delete LinkedFile;
IsSymLink = true;
}
catch (...)
{
if (!FTerminal->Active)
{
throw;
}
}
}

if (IsSymLink)
{
FTerminal->LogEvent(L"Existing file is a symbolic link, it will not be moved to a recycle bin.");
OpenParams->DontRecycle = true;
}
else
{
OperationProgress->Progress();
FTerminal->RecycleFile(OpenParams->RemoteFileName, NULL);
}
}
}
else if (FTerminal->Active)
Expand Down
1 change: 1 addition & 0 deletions source/core/SftpFileSystem.h
Expand Up @@ -198,6 +198,7 @@ friend class TSFTPBusy;
void __fastcall WriteLocalFile(
TStream * FileStream, TFileBuffer & BlockBuf, const UnicodeString & LocalFileName,
TFileOperationProgressType * OperationProgress);
bool __fastcall DoesFileLookLikeSymLink(TRemoteFile * File);
};
//---------------------------------------------------------------------------
#endif // SftpFileSystemH

0 comments on commit 9c3603d

Please sign in to comment.