ADD: Support for owner file property on Windows.

This commit is contained in:
cobines 2010-04-14 19:36:35 +00:00
commit 0561bf130e
3 changed files with 177 additions and 5 deletions

View file

@ -105,6 +105,9 @@ implementation
uses
uOSUtils, uFindEx, uDateTimeUtils,
{$IFDEF MSWINDOWS}
uMyWindows,
{$ENDIF}
{$IFDEF UNIX}
BaseUnix, uUsersGroups, FileUtil,
{$ENDIF}
@ -146,6 +149,10 @@ var
StatInfo: BaseUnix.Stat; //buffer for stat info
sFullPath: String;
{$ENDIF}
{$IF DEFINED(MSWINDOWS)}
var
sUser, sGroup: String;
{$ENDIF}
begin
Result := TFile.Create(APath);
@ -171,6 +178,15 @@ begin
LinkProperty.IsValid := mbFileSystemEntryExists(LinkProperty.LinkTo);
end;
OwnerProperty := TFileOwnerProperty.Create;
OwnerProperty.Owner := 0;
OwnerProperty.Group := 0;
if GetFileOwner(Path + SearchRecord.Name, sUser, sGroup) then
begin
OwnerProperty.OwnerStr := sUser;
OwnerProperty.GroupStr := sGroup;
end;
{$ELSEIF DEFINED(UNIX)}
StatInfo := PUnixFindData(SearchRecord.FindHandle)^.StatRec;
@ -345,10 +361,8 @@ begin
fpModificationTime,
fpCreationTime,
fpLastAccessTime,
uFileProperty.fpLink
{$IFDEF UNIX}
, fpOwner
{$ENDIF}
uFileProperty.fpLink,
fpOwner
];
end;

View file

@ -98,11 +98,19 @@ function mbGetRemoteFileName(const sLocalName: UTF8String): UTF8String;
@returns(The function returns @true if successful, @false otherwise)
}
function mbGetShortPathName(const sLongPath: UTF8String; out sShortPath: AnsiString): Boolean;
{en
Retrieves owner of the file (user and group).
Both user and group contain computer name.
@param(sPath Absolute path to the file. May be UNC path.)
@param(sUser Returns user name of the file.)
@param(sGroup Returns primary group of the file.)
}
function GetFileOwner(const sPath: String; out sUser, sGroup: String): Boolean;
implementation
uses
LCLProc, ShellAPI, MMSystem, JwaWinNetWk;
LCLProc, ShellAPI, MMSystem, JwaWinNetWk, uShlObjAdditional;
function mciSendCommand(IDDevice: MCIDEVICEID; uMsg: UINT; fdwCommand: DWORD; dwParam: DWORD_PTR): MCIERROR; stdcall; external 'winmm.dll' name 'mciSendCommandA';
@ -244,5 +252,149 @@ begin
end;
end;
function GetFileOwner(const sPath: String; out sUser, sGroup: String): Boolean;
var
wsMachineName: WideString;
function SidToDisplayString(sid: PSID; sidType: SID_NAME_USE): String;
var
pName: PWideChar = nil;
pDomain: PWideChar = nil;
NameLen: DWORD = 0;
DomainLen: DWORD = 0;
begin
// We're expecting insufficient buffer error here.
if (LookupAccountSidW(PWideChar(wsMachineName), sid,
nil, @NameLen,
nil, @DomainLen,
@SidType) = False) and
(GetLastError = ERROR_INSUFFICIENT_BUFFER) then
begin
pName := Getmem(NameLen * SizeOf(WideChar));
pDomain := Getmem(DomainLen * SizeOf(WideChar));
if Assigned(pName) and Assigned(pDomain) and
LookupAccountSidW(PWideChar(wsMachineName), sid,
pName, @NameLen,
pDomain, @DomainLen,
@SidType) then
begin
if pDomain[0] <> #0 then
Result := UTF8Encode(WideString(pDomain) + PathDelim + WideString(pName))
else
Result := UTF8Encode(WideString(pName));
end
else
Result := EmptyStr;
Freemem(pName);
Freemem(pDomain);
end
else
Result := EmptyStr;
end;
// From UNC name extracts computer name.
function GetMachineName(wPathName: LPCWSTR): WideString;
var
lpMachineName,
lpMachineNameNext: PWideChar;
begin
lpMachineName := PathFindNextComponentW(wPathName);
if Assigned(lpMachineName) then
begin
lpMachineNameNext := PathFindNextComponentW(lpMachineName);
if Assigned(lpMachineNameNext) then
SetString(Result, lpMachineName, lpMachineNameNext - lpMachineName - 1)
else
Result := lpMachineName;
end
else
Result := EmptyWideStr;
end;
var
wszUNCPathName: array[0..32767] of WideChar;
wsPathName: WideString;
pSecurityDescriptor: PSECURITY_DESCRIPTOR = nil;
pOwnerSid: PSID = nil;
pUNI: UNIVERSAL_NAME_INFOW;
bDefault: Boolean;
dwPathSize: DWORD = 32767;
dwSizeNeeded: DWORD = 0;
begin
Result := False;
if Length(sPath) = 0 then
Exit;
try
wsPathName := UTF8Decode(sPath);
// Check if the path is to remote share and get remote machine name.
if PathIsUNCW(PWideChar(wsPathName)) then
begin
// Path is in full UNC format.
wsMachineName := GetMachineName(PWideChar(wsPathName));
end
else
begin
// Check if local path is mapped to network share.
pUNI.lpUniversalName := PWideChar(@wszUNCPathName[0]);
if WNetGetUniversalNameW(PWideChar(wsPathName),
UNIVERSAL_NAME_INFO_LEVEL, @pUNI, dwPathSize) = NO_ERROR then
begin
wsMachineName := GetMachineName(PWideChar(@wszUNCPathName[0]));
end;
// else not a network share, no network connection, etc.
end;
{ Get security descriptor. }
// We're expecting insufficient buffer error here.
if (GetFileSecurityW(PWideChar(wsPathName),
OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION,
nil, 0, @dwSizeNeeded) <> False) or
(GetLastError <> ERROR_INSUFFICIENT_BUFFER) or
(dwSizeNeeded = 0) then
begin
Exit;
end;
pSecurityDescriptor := GetMem(dwSizeNeeded);
if not Assigned(pSecurityDescriptor) then
Exit;
if not GetFileSecurityW(PWideChar(wsPathName),
OWNER_SECURITY_INFORMATION or GROUP_SECURITY_INFORMATION,
pSecurityDescriptor,
dwSizeNeeded, @dwSizeNeeded) then
begin
Exit;
end;
{ Get Owner and Group. }
if GetSecurityDescriptorOwner(pSecurityDescriptor, pOwnerSid, @bDefault) then
sUser := SidToDisplayString(pOwnerSid, SidTypeUser)
else
sUser := EmptyStr;
if GetSecurityDescriptorGroup(pSecurityDescriptor, pOwnerSid, @bDefault) then
sGroup := SidToDisplayString(pOwnerSid, SidTypeGroup)
else
sGroup := EmptyStr;
Result := True;
finally
if Assigned(pSecurityDescriptor) then
Freemem(pSecurityDescriptor);
end;
end;
end.

View file

@ -1803,6 +1803,12 @@ function SHChangeIconDialog(hOwner: THandle; var FileName: UTF8String; var IconI
function SHGetOverlayIconIndex(const sFilePath, sFileName: UTF8String): Integer;
function SHGetInfoTip(const sFilePath, sFileName: UTF8String): UTF8String;
function PathIsUNCA(pszPath: LPCSTR): WINBOOL; stdcall; external 'shlwapi' name 'PathIsUNCA';
function PathIsUNCW(pwszPath: LPCWSTR): WINBOOL; stdcall; external 'shlwapi' name 'PathIsUNCW';
function PathFindNextComponentA(pszPath: LPCSTR): LPSTR; stdcall; external 'shlwapi' name 'PathFindNextComponentA';
function PathFindNextComponentW(pwszPath: LPCWSTR): LPWSTR; stdcall; external 'shlwapi' name 'PathFindNextComponentW';
procedure OleErrorUTF8(ErrorCode: HResult);
procedure OleCheckUTF8(Result: HResult);