mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
Bug 1641: Support ACL for S3
https://winscp.net/tracker/1641 Source commit: 03a0b16e1a553b6a2791a2276e94a4547ab3451f
This commit is contained in:
@@ -388,7 +388,7 @@ static S3Status convertAclXmlCallback(const char *elementPath,
|
||||
strcpy(grant->grantee.amazonCustomerByEmail.emailAddress,
|
||||
caData->emailAddress);
|
||||
}
|
||||
else if (caData->userId[0] && caData->userDisplayName[0]) {
|
||||
else if (caData->userId[0]) {
|
||||
grant->granteeType = S3GranteeTypeCanonicalUser;
|
||||
strcpy(grant->grantee.canonicalUser.id, caData->userId);
|
||||
strcpy(grant->grantee.canonicalUser.displayName,
|
||||
|
||||
@@ -1908,6 +1908,7 @@ bool __fastcall TFTPFileSystem::IsCapable(int Capability) const
|
||||
case fcCheckingSpaceAvailable:
|
||||
return FBytesAvailableSupported || SupportsCommand(AvblCommand) || SupportsCommand(XQuotaCommand);
|
||||
|
||||
case fcAclChangingFiles:
|
||||
case fcModeChangingUpload:
|
||||
case fcLoadingAdditionalProperties:
|
||||
case fcShellAnyCommand:
|
||||
|
||||
@@ -2058,11 +2058,47 @@ void __fastcall TRights::Assign(const TRights * Source)
|
||||
FUnknown = Source->FUnknown;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TRights::TRight TRights::CalculateRight(TRightGroup Group, TRightLevel Level)
|
||||
{
|
||||
int Result;
|
||||
if (Level == rlSpecial)
|
||||
{
|
||||
Result = rrUserIDExec + Group;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugAssert(rlRead == 0);
|
||||
Result = rrUserRead + Level + (Group * 3);
|
||||
}
|
||||
return static_cast<TRight>(Result);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TRights::TFlag __fastcall TRights::RightToFlag(TRights::TRight Right)
|
||||
{
|
||||
return static_cast<TFlag>(1 << (rrLast - Right));
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TRights::TFlag TRights::CalculateFlag(TRightGroup Group, TRightLevel Level)
|
||||
{
|
||||
return RightToFlag(CalculateRight(Group, Level));
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
unsigned short TRights::CalculatePermissions(TRightGroup Group, TRightLevel Level, TRightLevel Level2, TRightLevel Level3)
|
||||
{
|
||||
unsigned int Permissions = CalculateFlag(Group, Level);
|
||||
if (Level2 != rlNone)
|
||||
{
|
||||
Permissions |= CalculateFlag(Group, Level2);
|
||||
}
|
||||
if (Level3 != rlNone)
|
||||
{
|
||||
Permissions |= CalculateFlag(Group, Level3);
|
||||
}
|
||||
unsigned short Result = static_cast<unsigned short>(Permissions);
|
||||
DebugAssert((Permissions - Result) == 0);
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool __fastcall TRights::operator ==(const TRights & rhr) const
|
||||
{
|
||||
if (AllowUndef || rhr.AllowUndef)
|
||||
@@ -2246,6 +2282,15 @@ void __fastcall TRights::SetText(const UnicodeString & value)
|
||||
FUnknown = false;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TRights::SetTextOverride(const UnicodeString & value)
|
||||
{
|
||||
if (FText != value)
|
||||
{
|
||||
FText = value;
|
||||
FUnknown = false;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
UnicodeString __fastcall TRights::GetText() const
|
||||
{
|
||||
if (!FText.IsEmpty())
|
||||
@@ -2330,6 +2375,7 @@ void __fastcall TRights::SetOctal(UnicodeString value)
|
||||
((AValue[2] - L'0') << 6) +
|
||||
((AValue[3] - L'0') << 3) +
|
||||
((AValue[4] - L'0') << 0));
|
||||
FText = L"";
|
||||
}
|
||||
FUnknown = false;
|
||||
}
|
||||
@@ -2539,6 +2585,7 @@ void __fastcall TRights::AddExecute()
|
||||
(RightUndef[static_cast<TRight>(rrUserWrite + (Group * 3))] == rsYes))
|
||||
{
|
||||
Right[static_cast<TRight>(rrUserExec + (Group * 3))] = true;
|
||||
FText = L"";
|
||||
}
|
||||
}
|
||||
FUnknown = false;
|
||||
@@ -2569,6 +2616,14 @@ __fastcall TRights::operator unsigned long() const
|
||||
{
|
||||
return Number;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
TRights TRights::Combine(const TRights & Other) const
|
||||
{
|
||||
TRights Result = (*this);
|
||||
Result |= Other.NumberSet;
|
||||
Result &= (unsigned short)~Other.NumberUnset;
|
||||
return Result;
|
||||
}
|
||||
//=== TRemoteProperties -------------------------------------------------------
|
||||
__fastcall TRemoteProperties::TRemoteProperties()
|
||||
{
|
||||
|
||||
@@ -325,6 +325,17 @@ public:
|
||||
static const wchar_t CombinedSymbols[];
|
||||
static const wchar_t ExtendedSymbols[];
|
||||
static const wchar_t ModeGroups[];
|
||||
enum TRightLevel {
|
||||
rlNone = -1,
|
||||
rlRead, rlWrite, rlExec, rlSpecial,
|
||||
rlFirst = rlRead, rlLastNormal = rlExec, rlLastWithSpecial = rlSpecial,
|
||||
rlS3Read = rlRead, rlS3Write = rlWrite, rlS3ReadACP = rlExec, rlS3WriteACP = rlSpecial, rlLastAcl = rlLastWithSpecial,
|
||||
};
|
||||
enum TRightGroup {
|
||||
rgUser, rgGroup, rgOther,
|
||||
rgFirst = rgUser, rgLast = rgOther,
|
||||
rgS3AllAwsUsers = rgGroup, rgS3AllUsers = rgOther,
|
||||
};
|
||||
enum TRight {
|
||||
rrUserIDExec, rrGroupIDExec, rrStickyBit,
|
||||
rrUserRead, rrUserWrite, rrUserExec,
|
||||
@@ -338,13 +349,18 @@ public:
|
||||
rfOtherRead = 00004, rfOtherWrite = 00002, rfOtherExec = 00001,
|
||||
rfRead = 00444, rfWrite = 00222, rfExec = 00111,
|
||||
rfNo = 00000, rfDefault = 00644, rfAll = 00777,
|
||||
rfSpecials = 07000, rfAllSpecials = 07777 };
|
||||
rfSpecials = 07000, rfAllSpecials = 07777,
|
||||
rfS3Read = rfOtherRead, rfS3Write = rfOtherWrite, rfS3ReadACP = rfOtherExec, rfS3WriteACP = rfStickyBit,
|
||||
};
|
||||
enum TUnsupportedFlag {
|
||||
rfDirectory = 040000 };
|
||||
enum TState { rsNo, rsYes, rsUndef };
|
||||
|
||||
public:
|
||||
static TFlag __fastcall RightToFlag(TRight Right);
|
||||
static TRight CalculateRight(TRightGroup Group, TRightLevel Level);
|
||||
static TFlag CalculateFlag(TRightGroup Group, TRightLevel Level);
|
||||
static unsigned short CalculatePermissions(TRightGroup Group, TRightLevel Level, TRightLevel Level2 = rlNone, TRightLevel Level3 = rlNone);
|
||||
|
||||
__fastcall TRights();
|
||||
__fastcall TRights(const TRights & Source);
|
||||
@@ -352,6 +368,8 @@ public:
|
||||
void __fastcall Assign(const TRights * Source);
|
||||
void __fastcall AddExecute();
|
||||
void __fastcall AllUndef();
|
||||
TRights Combine(const TRights & Other) const;
|
||||
void SetTextOverride(const UnicodeString & value);
|
||||
|
||||
bool __fastcall operator ==(const TRights & rhr) const;
|
||||
bool __fastcall operator ==(unsigned short rhr) const;
|
||||
|
||||
@@ -763,6 +763,8 @@ bool __fastcall TS3FileSystem::IsCapable(int Capability) const
|
||||
case fcMoveToQueue:
|
||||
case fcSkipTransfer:
|
||||
case fcParallelTransfers:
|
||||
case fcLoadingAdditionalProperties:
|
||||
case fcAclChangingFiles:
|
||||
return true;
|
||||
|
||||
case fcPreservingTimestampUpload:
|
||||
@@ -780,7 +782,6 @@ bool __fastcall TS3FileSystem::IsCapable(int Capability) const
|
||||
case fcNativeTextMode:
|
||||
case fcNewerOnlyUpload:
|
||||
case fcTimestampChanging:
|
||||
case fcLoadingAdditionalProperties:
|
||||
case fcIgnorePermErrors:
|
||||
case fcCalculatingChecksum:
|
||||
case fcSecondaryShell:
|
||||
@@ -1316,17 +1317,314 @@ void __fastcall TS3FileSystem::CreateLink(const UnicodeString FileName,
|
||||
DebugFail();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TS3FileSystem::ChangeFileProperties(const UnicodeString FileName,
|
||||
const TRemoteFile * /*File*/, const TRemoteProperties * /*Properties*/,
|
||||
TChmodSessionAction & /*Action*/)
|
||||
struct TS3FileProperties
|
||||
{
|
||||
DebugFail();
|
||||
char OwnerId[S3_MAX_GRANTEE_USER_ID_SIZE];
|
||||
char OwnerDisplayName[S3_MAX_GRANTEE_DISPLAY_NAME_SIZE];
|
||||
int AclGrantCount;
|
||||
S3AclGrant AclGrants[S3_MAX_ACL_GRANT_COUNT];
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
static TRights::TRightLevel S3PermissionToRightLevel(S3Permission Permission)
|
||||
{
|
||||
TRights::TRightLevel Result;
|
||||
switch (Permission)
|
||||
{
|
||||
case S3PermissionRead: Result = TRights::rlS3Read; break;
|
||||
case S3PermissionWrite: Result = TRights::rlS3Write; break;
|
||||
case S3PermissionReadACP: Result = TRights::rlS3ReadACP; break;
|
||||
case S3PermissionWriteACP: Result = TRights::rlS3WriteACP; break;
|
||||
default: DebugFail(); Result = TRights::rlNone; break;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool __fastcall TS3FileSystem::LoadFilesProperties(TStrings * /*FileList*/)
|
||||
bool TS3FileSystem::ParsePathForPropertiesRequests(
|
||||
const UnicodeString & Path, const TRemoteFile * File, UnicodeString & BucketName, UnicodeString & Key)
|
||||
{
|
||||
DebugFail();
|
||||
return false;
|
||||
UnicodeString FileName = AbsolutePath(Path, false);
|
||||
|
||||
ParsePath(FileName, BucketName, Key);
|
||||
|
||||
bool Result = !Key.IsEmpty();
|
||||
if (Result && File->IsDirectory)
|
||||
{
|
||||
Key = GetFolderKey(Key);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool TS3FileSystem::DoLoadFileProperties(
|
||||
const UnicodeString & AFileName, const TRemoteFile * File, TS3FileProperties & Properties)
|
||||
{
|
||||
UnicodeString BucketName, Key;
|
||||
bool Result = ParsePathForPropertiesRequests(AFileName, File, BucketName, Key);
|
||||
if (Result)
|
||||
{
|
||||
TLibS3BucketContext BucketContext = GetBucketContext(BucketName, Key);
|
||||
|
||||
S3ResponseHandler ResponseHandler = CreateResponseHandler();
|
||||
|
||||
TLibS3CallbackData Data;
|
||||
RequestInit(Data);
|
||||
|
||||
S3_get_acl(
|
||||
&BucketContext, StrToS3(Key), Properties.OwnerId, Properties.OwnerDisplayName,
|
||||
&Properties.AclGrantCount, Properties.AclGrants,
|
||||
FRequestContext, FTimeout, &ResponseHandler, &Data);
|
||||
|
||||
CheckLibS3Error(Data);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
typedef std::vector<S3AclGrant> TAclGrantsVector;
|
||||
static void AddAclGrant(
|
||||
TRights::TRightGroup Group, unsigned short & Permissions, TAclGrantsVector & AclGrants,
|
||||
const S3AclGrant & AclGrantTemplate, S3Permission Permission)
|
||||
{
|
||||
TRights::TRightLevel Level = S3PermissionToRightLevel(Permission);
|
||||
TRights::TFlag Flag = TRights::CalculateFlag(Group, Level);
|
||||
if (FLAGSET(Permissions, Flag))
|
||||
{
|
||||
S3AclGrant AclGrant(AclGrantTemplate);
|
||||
AclGrant.permission = Permission;
|
||||
AclGrants.push_back(AclGrant);
|
||||
Permissions -= static_cast<short int>(Flag);
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TS3FileSystem::ChangeFileProperties(const UnicodeString FileName,
|
||||
const TRemoteFile * File, const TRemoteProperties * Properties,
|
||||
TChmodSessionAction & /*Action*/)
|
||||
{
|
||||
TValidProperties ValidProperties = Properties->Valid;
|
||||
if (DebugAlwaysTrue(ValidProperties.Contains(vpRights)))
|
||||
{
|
||||
ValidProperties >> vpRights;
|
||||
|
||||
DebugAssert(!Properties->AddXToDirectories);
|
||||
|
||||
TS3FileProperties FileProperties;
|
||||
if (DebugAlwaysTrue(!File->IsDirectory) &&
|
||||
DebugAlwaysTrue(DoLoadFileProperties(FileName, File, FileProperties)))
|
||||
{
|
||||
TAclGrantsVector NewAclGrants;
|
||||
|
||||
unsigned short Permissions = File->Rights->Combine(Properties->Rights);
|
||||
for (int GroupI = TRights::rgFirst; GroupI <= TRights::rgLast; GroupI++)
|
||||
{
|
||||
TRights::TRightGroup Group = static_cast<TRights::TRightGroup>(GroupI);
|
||||
S3AclGrant NewAclGrant;
|
||||
memset(&NewAclGrant, 0, sizeof(NewAclGrant));
|
||||
if (Group == TRights::rgUser)
|
||||
{
|
||||
NewAclGrant.granteeType = S3GranteeTypeCanonicalUser;
|
||||
DebugAssert(sizeof(NewAclGrant.grantee.canonicalUser.id) == sizeof(FileProperties.OwnerId));
|
||||
strcpy(NewAclGrant.grantee.canonicalUser.id, FileProperties.OwnerId);
|
||||
}
|
||||
else if (Group == TRights::rgS3AllAwsUsers)
|
||||
{
|
||||
NewAclGrant.granteeType = S3GranteeTypeAllAwsUsers;
|
||||
}
|
||||
else if (DebugAlwaysTrue(Group == TRights::rgS3AllUsers))
|
||||
{
|
||||
NewAclGrant.granteeType = S3GranteeTypeAllUsers;
|
||||
}
|
||||
unsigned short AllGroupPermissions =
|
||||
TRights::CalculatePermissions(Group, TRights::rlS3Read, TRights::rlS3ReadACP, TRights::rlS3WriteACP);
|
||||
if (FLAGSET(Permissions, AllGroupPermissions))
|
||||
{
|
||||
NewAclGrant.permission = S3PermissionFullControl;
|
||||
NewAclGrants.push_back(NewAclGrant);
|
||||
Permissions -= AllGroupPermissions;
|
||||
}
|
||||
else
|
||||
{
|
||||
#define ADD_ACL_GRANT(PERM) AddAclGrant(Group, Permissions, NewAclGrants, NewAclGrant, PERM)
|
||||
ADD_ACL_GRANT(S3PermissionRead);
|
||||
ADD_ACL_GRANT(S3PermissionWrite);
|
||||
ADD_ACL_GRANT(S3PermissionReadACP);
|
||||
ADD_ACL_GRANT(S3PermissionWriteACP);
|
||||
}
|
||||
}
|
||||
|
||||
DebugAssert(Permissions == 0);
|
||||
|
||||
// Preserve unrecognized permissions
|
||||
for (int Index = 0; Index < FileProperties.AclGrantCount; Index++)
|
||||
{
|
||||
S3AclGrant & AclGrant = FileProperties.AclGrants[Index];
|
||||
unsigned short Permission = AclGrantToPermissions(AclGrant, FileProperties);
|
||||
if (Permission == 0)
|
||||
{
|
||||
NewAclGrants.push_back(AclGrant);
|
||||
}
|
||||
}
|
||||
|
||||
UnicodeString BucketName, Key;
|
||||
if (DebugAlwaysTrue(ParsePathForPropertiesRequests(FileName, File, BucketName, Key)))
|
||||
{
|
||||
TLibS3BucketContext BucketContext = GetBucketContext(BucketName, Key);
|
||||
|
||||
S3ResponseHandler ResponseHandler = CreateResponseHandler();
|
||||
|
||||
TLibS3CallbackData Data;
|
||||
RequestInit(Data);
|
||||
|
||||
S3_set_acl(
|
||||
&BucketContext, StrToS3(Key), FileProperties.OwnerId, FileProperties.OwnerDisplayName,
|
||||
NewAclGrants.size(), &NewAclGrants[0],
|
||||
FRequestContext, FTimeout, &ResponseHandler, &Data);
|
||||
|
||||
CheckLibS3Error(Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DebugAssert(ValidProperties.Empty());
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
unsigned short TS3FileSystem::AclGrantToPermissions(S3AclGrant & AclGrant, const TS3FileProperties & Properties)
|
||||
{
|
||||
TRights::TRightGroup RightGroup = static_cast<TRights::TRightGroup>(-1);
|
||||
if (AclGrant.granteeType == S3GranteeTypeCanonicalUser)
|
||||
{
|
||||
if (strcmp(Properties.OwnerId, AclGrant.grantee.canonicalUser.id) == 0)
|
||||
{
|
||||
RightGroup = TRights::rgUser;
|
||||
}
|
||||
else
|
||||
{
|
||||
FTerminal->LogEvent(1, FORMAT(L"Unspported permission for canonical user %s", (StrFromS3(Properties.OwnerId))));
|
||||
}
|
||||
}
|
||||
else if (AclGrant.granteeType == S3GranteeTypeAllAwsUsers)
|
||||
{
|
||||
RightGroup = TRights::rgS3AllAwsUsers;
|
||||
}
|
||||
else if (AclGrant.granteeType == S3GranteeTypeAllUsers)
|
||||
{
|
||||
RightGroup = TRights::rgS3AllUsers;
|
||||
}
|
||||
unsigned short Result;
|
||||
if (RightGroup < 0)
|
||||
{
|
||||
Result = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AclGrant.permission == S3PermissionFullControl)
|
||||
{
|
||||
Result = TRights::CalculatePermissions(RightGroup, TRights::rlS3Read, TRights::rlS3ReadACP, TRights::rlS3WriteACP);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugAssert(AclGrant.permission != S3PermissionWrite);
|
||||
TRights::TRightLevel RightLevel = S3PermissionToRightLevel(AclGrant.permission);
|
||||
if (RightLevel == TRights::rlNone)
|
||||
{
|
||||
Result = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = TRights::CalculateFlag(RightGroup, RightLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TS3FileSystem::LoadFileProperties(const UnicodeString AFileName, const TRemoteFile * File, void * Param)
|
||||
{
|
||||
bool & Result = *static_cast<bool *>(Param);
|
||||
TS3FileProperties Properties;
|
||||
Result = DoLoadFileProperties(AFileName, File, Properties);
|
||||
if (Result)
|
||||
{
|
||||
bool AdditionalRights;
|
||||
unsigned short Permissions = 0;
|
||||
for (int Index = 0; Index < Properties.AclGrantCount; Index++)
|
||||
{
|
||||
S3AclGrant & AclGrant = Properties.AclGrants[Index];
|
||||
unsigned short Permission = AclGrantToPermissions(AclGrant, Properties);
|
||||
if (Permission == 0)
|
||||
{
|
||||
AdditionalRights = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Permissions |= Permission;
|
||||
}
|
||||
}
|
||||
|
||||
UnicodeString Delimiter(L",");
|
||||
UnicodeString HumanRights;
|
||||
for (int GroupI = TRights::rgFirst; GroupI <= TRights::rgLast; GroupI++)
|
||||
{
|
||||
TRights::TRightGroup Group = static_cast<TRights::TRightGroup>(GroupI);
|
||||
#define RIGHT_LEVEL_SET(LEVEL) FLAGSET(Permissions, TRights::CalculateFlag(Group, TRights::LEVEL))
|
||||
bool ReadRight = RIGHT_LEVEL_SET(rlS3Read);
|
||||
bool WriteRight = DebugAlwaysFalse(RIGHT_LEVEL_SET(rlS3Write));
|
||||
bool ReadACPRight = RIGHT_LEVEL_SET(rlS3ReadACP);
|
||||
bool WriteACPRight = RIGHT_LEVEL_SET(rlS3WriteACP);
|
||||
UnicodeString Desc;
|
||||
if (ReadRight && ReadACPRight && WriteACPRight)
|
||||
{
|
||||
Desc = L"F";
|
||||
}
|
||||
else if (ReadRight)
|
||||
{
|
||||
Desc = L"R";
|
||||
if (ReadACPRight || WriteACPRight || WriteRight)
|
||||
{
|
||||
Desc += L"+";
|
||||
}
|
||||
}
|
||||
|
||||
if (!Desc.IsEmpty())
|
||||
{
|
||||
UnicodeString GroupDesc;
|
||||
switch (Group)
|
||||
{
|
||||
case TRights::rgUser: GroupDesc = L"O"; break;
|
||||
case TRights::rgS3AllAwsUsers: GroupDesc = L"U"; break;
|
||||
case TRights::rgS3AllUsers: GroupDesc = L"E"; break;
|
||||
default: DebugFail(); break;
|
||||
}
|
||||
|
||||
if (!GroupDesc.IsEmpty())
|
||||
{
|
||||
Desc = GroupDesc + L":" + Desc;
|
||||
AddToList(HumanRights, Desc, Delimiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (AdditionalRights)
|
||||
{
|
||||
AddToList(HumanRights, L"+", Delimiter);
|
||||
}
|
||||
|
||||
File->Rights->Number = Permissions;
|
||||
File->Rights->SetTextOverride(HumanRights);
|
||||
Result = true;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool __fastcall TS3FileSystem::LoadFilesProperties(TStrings * FileList)
|
||||
{
|
||||
bool Result = false;
|
||||
FTerminal->BeginTransaction();
|
||||
try
|
||||
{
|
||||
FTerminal->ProcessFiles(FileList, foGetProperties, LoadFileProperties, &Result);
|
||||
}
|
||||
__finally
|
||||
{
|
||||
FTerminal->EndTransaction();
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TS3FileSystem::CalculateFilesChecksum(const UnicodeString & /*Alg*/,
|
||||
|
||||
@@ -13,6 +13,7 @@ struct TLibS3TransferObjectDataCallbackData;
|
||||
struct TLibS3PutObjectDataCallbackData;
|
||||
struct TLibS3GetObjectDataCallbackData;
|
||||
struct ssl_st;
|
||||
struct TS3FileProperties;
|
||||
#ifdef NEED_LIBS3
|
||||
// resolve clash
|
||||
#define S3Protocol _S3Protocol
|
||||
@@ -26,8 +27,10 @@ struct S3RequestContext;
|
||||
struct S3ErrorDetails;
|
||||
struct S3ListBucketContent;
|
||||
struct S3ResponseHandler;
|
||||
struct S3AclGrant;
|
||||
enum S3Status { };
|
||||
enum _S3Protocol { };
|
||||
enum S3Permission { };
|
||||
#endif
|
||||
//------------------------------------------------------------------------------
|
||||
class TS3FileSystem : public TCustomFileSystem
|
||||
@@ -158,6 +161,11 @@ protected:
|
||||
S3Status GetObjectData(int BufferSize, const char * Buffer, TLibS3GetObjectDataCallbackData & Data);
|
||||
bool ShouldCancelTransfer(TLibS3TransferObjectDataCallbackData & Data);
|
||||
bool IsGoogleCloud();
|
||||
void __fastcall LoadFileProperties(const UnicodeString AFileName, const TRemoteFile * File, void * Param);
|
||||
bool DoLoadFileProperties(const UnicodeString & AFileName, const TRemoteFile * File, TS3FileProperties & Properties);
|
||||
unsigned short AclGrantToPermissions(S3AclGrant & AclGrant, const TS3FileProperties & Properties);
|
||||
bool ParsePathForPropertiesRequests(
|
||||
const UnicodeString & Path, const TRemoteFile * File, UnicodeString & BucketName, UnicodeString & Key);
|
||||
|
||||
static TS3FileSystem * GetFileSystem(void * CallbackData);
|
||||
static void LibS3SessionCallback(ne_session_s * Session, void * CallbackData);
|
||||
|
||||
@@ -447,6 +447,7 @@ bool __fastcall TSCPFileSystem::IsCapable(int Capability) const
|
||||
case fcTextMode:
|
||||
return FTerminal->SessionData->EOLType != FTerminal->Configuration->LocalEOLType;
|
||||
|
||||
case fcAclChangingFiles:
|
||||
case fcNativeTextMode:
|
||||
case fcNewerOnlyUpload:
|
||||
case fcTimestampChanging:
|
||||
|
||||
@@ -32,7 +32,7 @@ struct TSessionInfo
|
||||
bool CertificateVerifiedManually;
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
enum TFSCapability { fcUserGroupListing, fcModeChanging, fcGroupChanging,
|
||||
enum TFSCapability { fcUserGroupListing, fcModeChanging, fcAclChangingFiles, fcGroupChanging,
|
||||
fcOwnerChanging, fcGroupOwnerChangingByID, fcAnyCommand, fcHardLink,
|
||||
fcSymbolicLink,
|
||||
// With WebDAV this is always true, to avoid double-click on
|
||||
|
||||
@@ -491,9 +491,7 @@ public:
|
||||
if (Properties->Valid.Contains(vpRights))
|
||||
{
|
||||
Valid = (TValid)(Valid | valRights);
|
||||
TRights Rights = BaseRights;
|
||||
Rights |= Properties->Rights.NumberSet;
|
||||
Rights &= (unsigned short)~Properties->Rights.NumberUnset;
|
||||
TRights Rights = TRights(BaseRights).Combine(Properties->Rights);
|
||||
if (IsDirectory && Properties->AddXToDirectories)
|
||||
{
|
||||
Rights.AddExecute();
|
||||
@@ -2073,6 +2071,7 @@ bool __fastcall TSFTPFileSystem::IsCapable(int Capability) const
|
||||
case fcAnyCommand:
|
||||
case fcShellAnyCommand:
|
||||
case fcLocking:
|
||||
case fcAclChangingFiles: // pending implementation
|
||||
return false;
|
||||
|
||||
case fcNewerOnlyUpload:
|
||||
|
||||
@@ -582,6 +582,7 @@ bool __fastcall TWebDAVFileSystem::IsCapable(int Capability) const
|
||||
case fcUserGroupListing:
|
||||
case fcModeChanging:
|
||||
case fcModeChangingUpload:
|
||||
case fcAclChangingFiles:
|
||||
case fcGroupChanging:
|
||||
case fcOwnerChanging:
|
||||
case fcAnyCommand:
|
||||
|
||||
@@ -2967,16 +2967,35 @@ bool __fastcall TCustomScpExplorerForm::ExecuteFileOperation(TFileOperation Oper
|
||||
TOperationSide Side, bool OnFocused, bool NoConfirmation, void * Param)
|
||||
{
|
||||
Side = GetSide(Side);
|
||||
bool FullPath = IsSideLocalBrowser(Side);
|
||||
TCustomDirView * ADirView = DirView(Side);
|
||||
std::unique_ptr<TStringList> FileList(new TStringList());
|
||||
ADirView->CreateFileList(OnFocused, FullPath, FileList.get());
|
||||
|
||||
bool Result;
|
||||
TStrings * FileList = DirView(Side)->CreateFileList(OnFocused, IsSideLocalBrowser(Side), NULL);
|
||||
try
|
||||
bool ReloadProperties =
|
||||
(Side == osRemote) && (Operation == foSetProperties) &&
|
||||
DebugAlwaysTrue(HasActiveTerminal()) && Terminal->IsCapable[fcLoadingAdditionalProperties];
|
||||
|
||||
bool Result = ExecuteFileOperation(Operation, Side, FileList.get(), NoConfirmation, Param);
|
||||
|
||||
if (Result && ReloadProperties)
|
||||
{
|
||||
Result = ExecuteFileOperation(Operation, Side, FileList, NoConfirmation, Param);
|
||||
}
|
||||
__finally
|
||||
{
|
||||
delete FileList;
|
||||
std::unique_ptr<TStringList> FileList2(new TStringList());
|
||||
|
||||
FileList->CaseSensitive = true;
|
||||
FileList->Sort();
|
||||
for (int Index = 0; Index < ADirView->Items->Count; Index++)
|
||||
{
|
||||
TListItem * Item = ADirView->Items->Item[Index];
|
||||
UnicodeString FileName = ADirView->ItemFileName(Item);
|
||||
int Index2;
|
||||
if (FileList->Find(FileName, Index2))
|
||||
{
|
||||
FileList2->AddObject(FileName, ADirView->ItemData(Item));
|
||||
}
|
||||
}
|
||||
|
||||
LoadFilesProperties(FileList2.get());
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
@@ -4483,6 +4502,14 @@ void __fastcall TCustomScpExplorerForm::CalculateChecksum(const UnicodeString &
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TCustomScpExplorerForm::LoadFilesProperties(TStrings * FileList)
|
||||
{
|
||||
if (Terminal->LoadFilesProperties(FileList))
|
||||
{
|
||||
RemoteDirView->Invalidate();
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool __fastcall TCustomScpExplorerForm::SetProperties(TOperationSide Side, TStrings * FileList)
|
||||
{
|
||||
bool Result;
|
||||
@@ -4495,10 +4522,7 @@ bool __fastcall TCustomScpExplorerForm::SetProperties(TOperationSide Side, TStri
|
||||
{
|
||||
TRemoteProperties CurrentProperties;
|
||||
|
||||
if (Terminal->LoadFilesProperties(FileList))
|
||||
{
|
||||
RemoteDirView->Invalidate();
|
||||
}
|
||||
LoadFilesProperties(FileList);
|
||||
|
||||
bool CapableGroupChanging = Terminal->IsCapable[fcGroupChanging];
|
||||
bool CapableOwnerChanging = Terminal->IsCapable[fcOwnerChanging];
|
||||
@@ -4553,8 +4577,19 @@ bool __fastcall TCustomScpExplorerForm::SetProperties(TOperationSide Side, TStri
|
||||
|
||||
CurrentProperties = TRemoteProperties::CommonProperties(FileList);
|
||||
|
||||
bool CapableAclChanging = Terminal->IsCapable[fcAclChangingFiles];
|
||||
for (int Index = 0; (Index < FileList->Count) && CapableAclChanging; Index++)
|
||||
{
|
||||
if (dynamic_cast<TRemoteFile *>(FileList->Objects[Index])->IsDirectory)
|
||||
{
|
||||
CapableAclChanging = false;
|
||||
CurrentProperties.Valid = CurrentProperties.Valid >> vpRights;
|
||||
}
|
||||
}
|
||||
|
||||
int Flags = 0;
|
||||
if (Terminal->IsCapable[fcModeChanging]) Flags |= cpMode;
|
||||
if (CapableAclChanging) Flags |= cpAcl;
|
||||
if (CapableOwnerChanging) Flags |= cpOwner;
|
||||
if (CapableGroupChanging) Flags |= cpGroup;
|
||||
|
||||
|
||||
@@ -740,6 +740,7 @@ protected:
|
||||
void __fastcall DirectorySizeCalculated(TOperationSide Side, const UnicodeString & FileName, bool Success);
|
||||
TListItem * VisualiseOperationFinished(TOperationSide Side, const UnicodeString & FileName, bool Unselect);
|
||||
void __fastcall FileDeleted(TOperationSide Side, const UnicodeString & FileName, bool Success);
|
||||
void LoadFilesProperties(TStrings * FileList);
|
||||
|
||||
public:
|
||||
virtual __fastcall ~TCustomScpExplorerForm();
|
||||
|
||||
@@ -118,6 +118,7 @@ void __fastcall TFileSystemInfoDialog::Feed(TFeedFileSystemData AddItem)
|
||||
AddItem(CertificateFingerprintSha1Edit, 0, FSessionInfo.CertificateFingerprintSHA1);
|
||||
|
||||
AddItem(ProtocolView, FSINFO_MODE_CHANGING, CapabilityStr(fcModeChanging));
|
||||
AddItem(ProtocolView, FSINFO_ACL_CHANGING, CapabilityStr(fcAclChangingFiles));
|
||||
AddItem(ProtocolView, FSINFO_OWNER_GROUP_CHANGING, CapabilityStr(fcGroupChanging));
|
||||
UnicodeString AnyCommand;
|
||||
if (!FFileSystemInfo.IsCapable[fcShellAnyCommand] &&
|
||||
|
||||
@@ -55,6 +55,12 @@ __fastcall TPropertiesDialog::TPropertiesDialog(TComponent* AOwner,
|
||||
FFileList = new TStringList();
|
||||
FFileList->Assign(FileList);
|
||||
FAllowedChanges = AllowedChanges;
|
||||
if (FLAGSET(FAllowedChanges, cpAcl))
|
||||
{
|
||||
DebugAssert(FLAGCLEAR(FAllowedChanges, cpMode));
|
||||
RightsLabel->Caption = LoadStr(PROPERTIES_ACL);
|
||||
RightsFrame->DisplayAsAcl();
|
||||
}
|
||||
FUserGroupByID = UserGroupByID;
|
||||
|
||||
FAllowCalculateStats = false;
|
||||
@@ -173,17 +179,14 @@ UnicodeString __fastcall TPropertiesDialog::LoadRemoteToken(
|
||||
void __fastcall TPropertiesDialog::LoadRemoteToken(
|
||||
TComboBox * ComboBox, TEdit * View, TLabel * Label, bool Valid, const TRemoteToken & Token, int Change)
|
||||
{
|
||||
if (Valid)
|
||||
{
|
||||
UnicodeString Value = LoadRemoteToken(Token);
|
||||
ComboBox->Text = Value;
|
||||
View->Text = Value;
|
||||
}
|
||||
UnicodeString Value = Valid ? LoadRemoteToken(Token) : EmptyStr;
|
||||
ComboBox->Text = Value;
|
||||
View->Text = Value;
|
||||
bool AllowedChange = FLAGSET(FAllowedChanges, Change);
|
||||
ComboBox->Visible = Valid && AllowedChange;
|
||||
ComboBox->Visible = AllowedChange;
|
||||
View->Visible = Valid && !AllowedChange;
|
||||
Label->Visible = Valid;
|
||||
Label->FocusControl = AllowedChange ? static_cast<TWinControl *>(ComboBox) : static_cast<TWinControl *>(View);
|
||||
Label->Visible = Label->FocusControl->Visible;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TPropertiesDialog::LoadRemoteTokens(TComboBox * ComboBox,
|
||||
@@ -383,9 +386,18 @@ void __fastcall TPropertiesDialog::LoadStats(__int64 FilesSize,
|
||||
void __fastcall TPropertiesDialog::SetFileProperties(const TRemoteProperties & value)
|
||||
{
|
||||
TValidProperties Valid;
|
||||
if (value.Valid.Contains(vpRights) && FAllowedChanges & cpMode) Valid << vpRights;
|
||||
if (value.Valid.Contains(vpOwner) && FAllowedChanges & cpOwner) Valid << vpOwner;
|
||||
if (value.Valid.Contains(vpGroup) && FAllowedChanges & cpGroup) Valid << vpGroup;
|
||||
if (value.Valid.Contains(vpRights) && (FLAGSET(FAllowedChanges, cpMode) || FLAGSET(FAllowedChanges, cpAcl)))
|
||||
{
|
||||
Valid << vpRights;
|
||||
}
|
||||
if (value.Valid.Contains(vpOwner) && FLAGSET(FAllowedChanges, cpOwner))
|
||||
{
|
||||
Valid << vpOwner;
|
||||
}
|
||||
if (value.Valid.Contains(vpGroup) && FLAGSET(FAllowedChanges, cpGroup))
|
||||
{
|
||||
Valid << vpGroup;
|
||||
}
|
||||
FOrigProperties = value;
|
||||
FOrigProperties.Valid = Valid;
|
||||
FOrigProperties.Recursive = false;
|
||||
@@ -409,14 +421,13 @@ void __fastcall TPropertiesDialog::SetFileProperties(const TRemoteProperties & v
|
||||
LoadRemoteToken(GroupComboBox, GroupView, GroupLabel, value.Valid.Contains(vpGroup), value.Group, cpGroup);
|
||||
LoadRemoteToken(OwnerComboBox, OwnerView, OwnerLabel, value.Valid.Contains(vpOwner), value.Owner, cpOwner);
|
||||
|
||||
bool HasGroupOrOwner = GroupLabel->Visible || OwnerLabel->Visible;
|
||||
bool HasAnything = HasGroupOrOwner || HasRights;
|
||||
bool HasAnything = GroupLabel->Visible || OwnerLabel->Visible || HasRights;
|
||||
// Not necesarily true, let's find the scenario when it is not and then decide how to render that (shift rights up?)
|
||||
DebugAssert(HasGroupOrOwner || !HasRights);
|
||||
DebugAssert((GroupLabel->Visible || OwnerLabel->Visible) || !HasRights);
|
||||
GroupOwnerRightsBevel->Visible = HasAnything;
|
||||
|
||||
RecursiveCheck2->Checked = value.Recursive;
|
||||
RecursiveCheck2->Visible = HasAnything && FAnyDirectories;
|
||||
RecursiveCheck2->Visible = (GroupComboBox->Visible || OwnerComboBox->Visible) && FAnyDirectories;
|
||||
RecursiveBevel->Visible = RecursiveCheck2->Visible || HasRights;
|
||||
|
||||
UpdateControls();
|
||||
@@ -517,7 +528,7 @@ TRemoteProperties __fastcall TPropertiesDialog::GetFileProperties()
|
||||
{
|
||||
TRemoteProperties Result;
|
||||
|
||||
if (FAllowedChanges & cpMode)
|
||||
if (FLAGSET(FAllowedChanges, cpMode) || FLAGSET(FAllowedChanges, cpAcl))
|
||||
{
|
||||
Result.Valid << vpRights;
|
||||
Result.Rights = RightsFrame->Rights;
|
||||
@@ -546,7 +557,10 @@ void __fastcall TPropertiesDialog::UpdateControls()
|
||||
{
|
||||
// No point enabling recursive check if there's no change allowed (supported),
|
||||
// i.e. with WebDAV.
|
||||
EnableControl(RecursiveCheck2, ((FAllowedChanges & (cpGroup | cpOwner | cpMode)) != 0));
|
||||
bool AnyAllowedChanges =
|
||||
FLAGSET(FAllowedChanges, cpGroup) || FLAGSET(FAllowedChanges, cpOwner) ||
|
||||
FLAGSET(FAllowedChanges, cpMode) || FLAGSET(FAllowedChanges, cpAcl);
|
||||
EnableControl(RecursiveCheck2, AnyAllowedChanges);
|
||||
|
||||
bool Allow;
|
||||
try
|
||||
@@ -565,9 +579,9 @@ void __fastcall TPropertiesDialog::UpdateControls()
|
||||
}
|
||||
EnableControl(OkButton, Allow);
|
||||
|
||||
EnableControl(GroupComboBox, FAllowedChanges & cpGroup);
|
||||
EnableControl(OwnerComboBox, FAllowedChanges & cpOwner);
|
||||
EnableControl(RightsFrame, FAllowedChanges & cpMode);
|
||||
EnableControl(GroupComboBox, FLAGSET(FAllowedChanges, cpGroup));
|
||||
EnableControl(OwnerComboBox, FLAGSET(FAllowedChanges, cpOwner));
|
||||
EnableControl(RightsFrame, FLAGSET(FAllowedChanges, cpMode) || FLAGSET(FAllowedChanges, cpAcl));
|
||||
CalculateSizeButton->Visible = FAllowCalculateStats;
|
||||
|
||||
if (!FMultiple)
|
||||
|
||||
@@ -142,6 +142,15 @@ object PropertiesDialog: TPropertiesDialog
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
Shape = bsTopLine
|
||||
end
|
||||
object AclLabel: TLabel
|
||||
Left = 8
|
||||
Top = 203
|
||||
Width = 59
|
||||
Height = 13
|
||||
Caption = 'Permissions:'
|
||||
FocusControl = RightsFrame
|
||||
Visible = False
|
||||
end
|
||||
object LocationLabel: TEdit
|
||||
Left = 85
|
||||
Top = 58
|
||||
|
||||
@@ -58,6 +58,7 @@ __published:
|
||||
TLabel *ChecksumUnknownLabel;
|
||||
TEdit *OwnerView;
|
||||
TEdit *GroupView;
|
||||
TLabel *AclLabel;
|
||||
void __fastcall ControlChange(TObject *Sender);
|
||||
void __fastcall FormCloseQuery(TObject *Sender, bool &CanClose);
|
||||
void __fastcall CalculateSizeButtonClick(TObject *Sender);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <VCLCommon.h>
|
||||
#include <Tools.h>
|
||||
#include <GUITools.h>
|
||||
#include <TextsWin.h>
|
||||
//---------------------------------------------------------------------------
|
||||
#pragma package(smart_init)
|
||||
#pragma link "GrayedCheckBox"
|
||||
@@ -29,6 +29,7 @@ __fastcall TRightsFrame::TRightsFrame(TComponent* Owner)
|
||||
PopupMenu = RightsPopup;
|
||||
FPopingContextMenu = false;
|
||||
FInitialized = false;
|
||||
FAcl = false;
|
||||
|
||||
#define COPY_HINT(R) \
|
||||
Checks[TRights::rrGroup ## R]->Hint = Checks[TRights::rrUser ## R]->Hint; \
|
||||
@@ -192,52 +193,70 @@ void __fastcall TRightsFrame::UpdateControls()
|
||||
DoChange();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TRightsFrame::CycleRights(int Group)
|
||||
void TRightsFrame::CycleRights(TRights::TRightGroup RightGroup)
|
||||
{
|
||||
TRights::TState State;
|
||||
int Last = FAcl ? TRights::rlLastAcl : TRights::rlLastNormal;
|
||||
TRights::TState State = TRights::TState(); // shut up
|
||||
bool Any = false;
|
||||
bool Same = true;
|
||||
for (int Right = 0; Right < 3; Right++)
|
||||
for (int RightLevelI = TRights::rlFirst; RightLevelI <= Last; RightLevelI++)
|
||||
{
|
||||
TRights::TState CState = States[static_cast<TRights::TRight>(
|
||||
TRights::rrUserRead + Right + ((Group - 1) * 3))];
|
||||
TRights::TRightLevel RightLevel = static_cast<TRights::TRightLevel>(RightLevelI);
|
||||
TRights::TRight Right = TRights::CalculateRight(RightGroup, RightLevel);
|
||||
|
||||
if (Right == 0) State = CState;
|
||||
else
|
||||
if (State != CState) Same = False;
|
||||
}
|
||||
|
||||
if (!Same)
|
||||
{
|
||||
State = TRights::rsYes;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (State) {
|
||||
case TRights::rsYes:
|
||||
State = TRights::rsNo;
|
||||
break;
|
||||
|
||||
case TRights::rsNo:
|
||||
State = AllowUndef ? TRights::rsUndef : TRights::rsYes;
|
||||
break;
|
||||
|
||||
case TRights::rsUndef:
|
||||
State = TRights::rsYes;
|
||||
if (Checks[Right]->Visible)
|
||||
{
|
||||
TRights::TState RightState = States[Right];
|
||||
if (!Any)
|
||||
{
|
||||
State = RightState;
|
||||
Any = true;
|
||||
}
|
||||
else if (State != RightState)
|
||||
{
|
||||
Same = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int Right = 0; Right < 3; Right++)
|
||||
if (DebugAlwaysTrue(Any))
|
||||
{
|
||||
States[static_cast<TRights::TRight>(
|
||||
TRights::rrUserRead + Right + ((Group - 1) * 3))] = State;
|
||||
if (!Same)
|
||||
{
|
||||
State = TRights::rsYes;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
case TRights::rsYes:
|
||||
State = TRights::rsNo;
|
||||
break;
|
||||
|
||||
case TRights::rsNo:
|
||||
State = AllowUndef ? TRights::rsUndef : TRights::rsYes;
|
||||
break;
|
||||
|
||||
case TRights::rsUndef:
|
||||
State = TRights::rsYes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int RightLevelI = TRights::rlFirst; RightLevelI <= Last; RightLevelI++)
|
||||
{
|
||||
TRights::TRightLevel RightLevel = static_cast<TRights::TRightLevel>(RightLevelI);
|
||||
TRights::TRight Right = TRights::CalculateRight(RightGroup, RightLevel);
|
||||
States[Right] = State;
|
||||
}
|
||||
UpdateControls();
|
||||
}
|
||||
UpdateControls();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TRightsFrame::RightsButtonsClick(TObject *Sender)
|
||||
void __fastcall TRightsFrame::RightsButtonsClick(TObject * Sender)
|
||||
{
|
||||
CycleRights(((TComponent*)Sender)->Tag);
|
||||
CycleRights(static_cast<TRights::TRightGroup>(dynamic_cast<TComponent *>(Sender)->Tag - 1));
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TRightsFrame::SetAllowAddXToDirectories(bool value)
|
||||
@@ -358,37 +377,37 @@ void __fastcall TRightsFrame::RightsActionsUpdate(TBasicAction *Action,
|
||||
{
|
||||
// explicitly enable as action gets disabled, if its shortcut is pressed,
|
||||
// while the form does not have a focus and OnExecute handler denies the execution
|
||||
NoRightsAction->Enabled = true;
|
||||
NoRightsAction->Enabled = !FAcl;
|
||||
NoRightsAction->Checked = !R.IsUndef && (R.NumberSet == TRights::rfNo);
|
||||
}
|
||||
else if (Action == DefaultRightsAction)
|
||||
{
|
||||
DefaultRightsAction->Enabled = true;
|
||||
DefaultRightsAction->Enabled = !FAcl;
|
||||
DefaultRightsAction->Checked = !R.IsUndef && (R.NumberSet == TRights::rfDefault);
|
||||
}
|
||||
else if (Action == AllRightsAction)
|
||||
{
|
||||
AllRightsAction->Enabled = true;
|
||||
AllRightsAction->Enabled = !FAcl;
|
||||
AllRightsAction->Checked = !R.IsUndef && (R.NumberSet == TRights::rfAll);
|
||||
}
|
||||
else if (Action == LeaveRightsAsIsAction)
|
||||
{
|
||||
LeaveRightsAsIsAction->Enabled = true;
|
||||
LeaveRightsAsIsAction->Enabled = !FAcl;
|
||||
LeaveRightsAsIsAction->Visible = R.AllowUndef;
|
||||
LeaveRightsAsIsAction->Checked = (R.NumberSet == TRights::rfNo) &&
|
||||
(R.NumberUnset == TRights::rfNo);
|
||||
}
|
||||
else if (Action == CopyTextAction)
|
||||
{
|
||||
CopyTextAction->Enabled = !R.IsUndef;
|
||||
CopyTextAction->Enabled = !FAcl && !R.IsUndef;
|
||||
}
|
||||
else if (Action == CopyOctalAction)
|
||||
{
|
||||
CopyOctalAction->Enabled = !R.IsUndef;
|
||||
CopyOctalAction->Enabled = !FAcl && !R.IsUndef;
|
||||
}
|
||||
else if (Action == PasteAction)
|
||||
{
|
||||
PasteAction->Enabled = IsFormatInClipboard(CF_TEXT);
|
||||
PasteAction->Enabled = !FAcl && IsFormatInClipboard(CF_TEXT);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -633,8 +652,15 @@ void __fastcall TRightsFrame::RightsPopupPopup(TObject * /*Sender*/)
|
||||
void __fastcall TRightsFrame::FrameContextPopup(TObject * Sender,
|
||||
TPoint & MousePos, bool & Handled)
|
||||
{
|
||||
SelectScaledImageList(RightsImages);
|
||||
MenuPopup(Sender, MousePos, Handled);
|
||||
if (!FAcl)
|
||||
{
|
||||
SelectScaledImageList(RightsImages);
|
||||
MenuPopup(Sender, MousePos, Handled);
|
||||
}
|
||||
else
|
||||
{
|
||||
Handled = true;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void __fastcall TRightsFrame::UpdateByOctal()
|
||||
@@ -707,3 +733,34 @@ void __fastcall TRightsFrame::CloseButtonClick(TObject *)
|
||||
CloseUp();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TRightsFrame::DisplayAsAcl(TRights::TRight ReadRight, TRights::TRight WriteRight, TRights::TRight ExecRight, TRights::TRight SpecialRight)
|
||||
{
|
||||
TCheckBox * ReadCheck = Checks[ReadRight];
|
||||
TCheckBox * WriteCheck = Checks[WriteRight];
|
||||
TCheckBox * ReadAclCheck = Checks[ExecRight];
|
||||
TCheckBox * WriteAclCheck = Checks[SpecialRight];
|
||||
|
||||
WriteCheck->Visible = false;
|
||||
|
||||
int ReadAclLeft = (3*ReadCheck->Left + 2*WriteAclCheck->Left) / 5;
|
||||
int Shift = ReadAclLeft - ReadAclCheck->Left;
|
||||
ReadAclCheck->Left = ReadAclLeft;
|
||||
ReadAclCheck->Width = ReadAclCheck->Width - Shift;
|
||||
ReadAclCheck->Caption = L"R ACL";
|
||||
|
||||
WriteAclCheck->Caption = L"W ACL";
|
||||
|
||||
GroupLabel->Caption = LoadStr(PROPERTIES_S3_USERS);
|
||||
OthersLabel->Caption = LoadStr(PROPERTIES_S3_EVERYONE);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void TRightsFrame::DisplayAsAcl()
|
||||
{
|
||||
AllowAddXToDirectories = false;
|
||||
OctalLabel->Visible = false;
|
||||
OctalEdit->Visible = false;
|
||||
DisplayAsAcl(TRights::rrUserRead, TRights::rrUserWrite, TRights::rrUserExec, TRights::rrUserIDExec);
|
||||
DisplayAsAcl(TRights::rrGroupRead, TRights::rrGroupWrite, TRights::rrGroupExec, TRights::rrGroupIDExec);
|
||||
DisplayAsAcl(TRights::rrOtherRead, TRights::rrOtherWrite, TRights::rrOtherExec, TRights::rrStickyBit);
|
||||
FAcl = true;
|
||||
}
|
||||
|
||||
@@ -84,8 +84,9 @@ private:
|
||||
bool FPopingContextMenu;
|
||||
UnicodeString FAddXToDirectoriesSuffix;
|
||||
bool FInitialized;
|
||||
bool FAcl;
|
||||
|
||||
void __fastcall CycleRights(int Group);
|
||||
void CycleRights(TRights::TRightGroup RightGroup);
|
||||
bool __fastcall GetAddXToDirectories();
|
||||
bool __fastcall GetAllowUndef();
|
||||
TCheckBox * __fastcall GetChecks(TRights::TRight Right);
|
||||
@@ -104,6 +105,7 @@ public:
|
||||
__fastcall TRightsFrame(TComponent* Owner);
|
||||
void __fastcall DropDown();
|
||||
void __fastcall CloseUp();
|
||||
void DisplayAsAcl();
|
||||
|
||||
__property bool AddXToDirectories = { read = GetAddXToDirectories, write = SetAddXToDirectories };
|
||||
__property bool AllowAddXToDirectories = { read = FAllowAddXToDirectories, write = SetAllowAddXToDirectories };
|
||||
@@ -134,6 +136,7 @@ protected:
|
||||
bool __fastcall DirectoriesXEffective();
|
||||
void __fastcall UpdateOctalEdit();
|
||||
void __fastcall UpdateByOctal();
|
||||
void DisplayAsAcl(TRights::TRight ReadRight, TRights::TRight WriteRight, TRights::TRight ExecRight, TRights::TRight SpecialRight);
|
||||
|
||||
INTERFACE_HOOK_CUSTOM(TFrame);
|
||||
|
||||
|
||||
@@ -653,6 +653,10 @@
|
||||
#define NEW_REMOTE_TAB_HINT 6043
|
||||
#define NEW_REMOTE_TAB_CTRL_HINT 6044
|
||||
#define IMPORT_CONVERTED_KEYS 6045
|
||||
#define FSINFO_ACL_CHANGING 6046
|
||||
#define PROPERTIES_ACL 6047
|
||||
#define PROPERTIES_S3_USERS 6048
|
||||
#define PROPERTIES_S3_EVERYONE 6049
|
||||
|
||||
// 2xxx is reserved for TextsFileZilla.h
|
||||
|
||||
|
||||
@@ -658,6 +658,10 @@ BEGIN
|
||||
NEW_REMOTE_TAB_HINT, "Click to open new session in new remote tab.\nHold down Shift Key to open new session in new window."
|
||||
NEW_REMOTE_TAB_CTRL_HINT, "%s\nHold down Ctrl key to open new local tab."
|
||||
IMPORT_CONVERTED_KEYS, "%d key file(s) in %d imported session(s) were converted or replaced with existing key(s) in supported format."
|
||||
FSINFO_ACL_CHANGING, "Can change ACL"
|
||||
PROPERTIES_ACL, "ACL:"
|
||||
PROPERTIES_S3_USERS, "&Users"
|
||||
PROPERTIES_S3_EVERYONE, "&Everyone"
|
||||
|
||||
WIN_VARIABLE_STRINGS, "WIN_VARIABLE"
|
||||
WINSCP_COPYRIGHT, "Copyright © 2000–2021 Martin Prikryl"
|
||||
|
||||
@@ -307,6 +307,7 @@ struct TCalculateSizeStats;
|
||||
const cpMode = 0x01;
|
||||
const cpOwner = 0x02;
|
||||
const cpGroup = 0x04;
|
||||
const cpAcl = 0x08;
|
||||
typedef void __fastcall (__closure *TCalculateSizeEvent)
|
||||
(TStrings * FileList, __int64 & Size, TCalculateSizeStats & Stats,
|
||||
bool & Close);
|
||||
|
||||
Reference in New Issue
Block a user