UPD: Start to implement a new elevation mechanism

This commit is contained in:
Alexander Koblov 2019-09-12 17:28:10 +00:00
commit 62fd46e72a
4 changed files with 50 additions and 224 deletions

View file

@ -34,7 +34,7 @@ type
procedure DeleteSubDirectory(const aFile: TFile);
protected
function ProcessFile(aFile: TFile): Boolean;
procedure ProcessFile(aFile: TFile);
procedure ProcessList(aFiles: TFiles);
function ShowError(sMessage: String): TFileSourceOperationUIResponse;
procedure LogMessage(sMessage: String; logOptions: TLogOptions; logMsgType: TLogMsgType);
@ -59,7 +59,7 @@ type
implementation
uses
DCOSUtils, DCStrUtils, uLng, uFileSystemUtil, uTrash, uAdministrator, uOSUtils
DCOSUtils, DCStrUtils, uLng, uFileSystemUtil, uTrash
{$IF DEFINED(MSWINDOWS)}
, Windows, uFileUnlock, fFileUnlock
{$ENDIF}
@ -159,10 +159,8 @@ begin
end;
end;
function TFileSystemDeleteOperation.ProcessFile(aFile: TFile): Boolean;
procedure TFileSystemDeleteOperation.ProcessFile(aFile: TFile);
const
ResponsesTrash: array[0..4] of TFileSourceOperationUIResponse
= (fsourYes, fsourAll, fsourSkip, fsourSkipAll, fsourAbort);
ResponsesError: array[0..3] of TFileSourceOperationUIResponse
= (fsourRetry, fsourSkip, fsourSkipAll, fsourAbort);
var
@ -178,7 +176,6 @@ var
ProcessInfo: TProcessInfoArray;
{$ENDIF}
begin
Result := True;
FileName := aFile.FullPath;
if FileIsReadOnly(aFile.Attributes) then
@ -235,15 +232,8 @@ begin
case FDeleteDirectly of
fsoogNone:
begin
if AdministratorPrivileges then
PossibleResponses:= ResponsesTrash
else begin
SetLength(PossibleResponses, Length(ResponsesTrash) + 1);
Move(ResponsesTrash[0], PossibleResponses[0], SizeOf(ResponsesTrash));
PossibleResponses[High(PossibleResponses)]:= fsourRetryAdmin;
end;
case AskQuestion(Format(rsMsgDelToTrashForce, [WrapTextSimple(FileName)]), '',
PossibleResponses,
[fsourYes, fsourAll, fsourSkip, fsourSkipAll, fsourAbort],
fsourYes, fsourAbort) of
fsourYes:
RemoveDirectly:= fsoogYes;
@ -261,8 +251,6 @@ begin
end;
fsourAbort:
RaiseAbortOperation;
fsourRetryAdmin:
Exit(False);
end;
end;
fsoogYes:
@ -344,16 +332,8 @@ begin
sQuestion+= LineEnding + mbSysErrorMessage(LastError);
end;
if AdministratorPrivileges then
begin
SetLength(PossibleResponses, Length(ResponsesError));
Move(ResponsesError[0], PossibleResponses[0], SizeOf(ResponsesError));
end
else begin
SetLength(PossibleResponses, Length(ResponsesError) + 1);
Move(ResponsesError[0], PossibleResponses[0], SizeOf(ResponsesError));
PossibleResponses[High(PossibleResponses)]:= fsourRetryAdmin;
end;
SetLength(PossibleResponses, Length(ResponsesError));
Move(ResponsesError[0], PossibleResponses[0], SizeOf(ResponsesError));
{$IF DEFINED(MSWINDOWS)}
if (Length(ProcessInfo) > 0) or (LastError = ERROR_ACCESS_DENIED) or (LastError = ERROR_SHARING_VIOLATION) then
begin
@ -370,8 +350,6 @@ begin
FSkipErrors := True;
fsourAbort:
RaiseAbortOperation;
fsourRetryAdmin:
Exit(False);
{$IF DEFINED(MSWINDOWS)}
fsourUnlock:
begin
@ -398,11 +376,7 @@ begin
FStatistics.CurrentFile := aFile.FullPath;
UpdateStatistics(FStatistics);
if not ProcessFile(aFile) then
begin
Delete(Self, aFiles, CurrentFileIndex);
Exit;
end;
ProcessFile(aFile);
with FStatistics do
begin

View file

@ -114,7 +114,7 @@ function ExecCmdFork(sCmd: String): Boolean;
function ExecCmdFork(sCmd: String; sParams: String; sStartPath: String = ''; bShowCommandLinePriorToExecute: Boolean = False;
bTerm: Boolean = False; bKeepTerminalOpen: tTerminalEndindMode = termStayOpen): Boolean;
function ExecCmdAdmin(sCmd: String; sParams: String; sStartPath: String = ''): Boolean;
function ExecCmdAdmin(const Exe: String; Args: array of String; sStartPath: String = ''): Boolean;
{en
Opens a file or URL in the user's preferred application
@param(URL File name or URL)
@ -408,23 +408,55 @@ begin
end;
{$ENDIF}
function ExecCmdAdmin(sCmd: String; sParams: String; sStartPath: String): Boolean;
function ExecCmdAdmin(const Exe: String; Args: array of String; sStartPath: String): Boolean;
{$IF DEFINED(MSWINDOWS)}
var
Index: Integer;
AParams: String;
begin
sStartPath:= RemoveQuotation(sStartPath);
AParams := EmptyStr;
for Index := Low(Args) to High(Args) do
AParams += QuoteDouble(Args[Index]) + ' ';
if sStartPath = '' then
if sStartPath = EmptyStr then
sStartPath:= mbGetCurrentDir;
sCmd:= NormalizePathDelimiters(sCmd);
Result:= ShellExecuteW(0, 'runas', PWideChar(UTF8Decode(sCmd)),
PWideChar(UTF8Decode(sParams)),
Result:= ShellExecuteW(0, 'runas', PWideChar(UTF8Decode(Exe)),
PWideChar(UTF8Decode(AParams)),
PWideChar(UTF8Decode(sStartPath)), SW_SHOW) > 32;
end;
{$ELSE}
{$ELSEIF DEFINED(DARWIN)}
var
Index: Integer;
ACommand: String;
AParams: TStringArray;
begin
Result:= False;
ACommand:= EscapeNoQuotes(Exe);
for Index := Low(Args) to High(Args) do
ACommand += ' ' + EscapeNoQuotes(Args[Index]);
SetLength(AParams, 7);
AParams[0]:= '-e';
AParams[1]:= 'on run argv';
AParams[2]:= '-e';
AParams[3]:= 'do shell script (item 1 of argv) with administrator privileges';
AParams[4]:= '-e';
AParams[5]:='end run';
AParams[6]:= ACommand;
Result:= ExecuteCommand('/usr/bin/osascript', AParams, sStartPath);
end;
{$ELSE}
var
Index: Integer;
AParams: TStringArray;
begin
SetLength(AParams, Length(Args) + 1);
for Index := Low(Args) to High(Args) do
AParams[Index + 1]:= Args[Index];
AParams[0] := Exe;
Result:= ExecuteCommand('/usr/bin/pkexec', AParams, sStartPath);
end;
{$ENDIF}

View file

@ -1,171 +0,0 @@
{
Double commander
-------------------------------------------------------------------------
Executes file operations with administrator privileges
Copyright (C) 2016-2019 Alexander Koblov (alexx2000@mail.ru)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
}
unit uAdministrator;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Dialogs, uFileSystemFileSource, uFile,
uFileSystemDeleteOperation;
type
EAccessDenied = class(Exception);
procedure ExecuteOperation(const FileList: String);
procedure Delete(Helper: TFileSystemDeleteOperation; Files: TFiles; Index: Integer);
implementation
uses
uFileSource, uFileSourceOperationMessageBoxesUI, dmCommonData, uOSUtils,
uGlobs, uGlobsPaths, uOperationsManager, uFileSourceOperation, DCXmlConfig,
uFileSourceOperationOptions, uSpecialDir, DCOSUtils,
uDCUtils;
type
{ TDummy }
TDummy = class
procedure Finish(Operation: TFileSourceOperation; State: TFileSourceOperationState);
end;
var
Dummy: TDummy;
FFileSourceOperationMessageBoxesUI: TFileSourceOperationMessageBoxesUI;
procedure Initialize;
begin
LoadPaths;
LoadWindowsSpecialDir;
InitGlobs;
Dummy:= TDummy.Create;
Application.CreateForm(TdmComData, dmComData); // common data
FFileSourceOperationMessageBoxesUI := TFileSourceOperationMessageBoxesUI.Create;
end;
procedure Delete(Xml: TXmlConfig);
var
Files: TFiles;
ANode: TXmlNode;
FileSource: IFileSource;
Operation: TFileSystemDeleteOperation;
begin
ANode:= Xml.FindNode(Xml.RootNode, 'FileList');
if Assigned(ANode) then
begin
Files:= TFiles.Create(Xml.GetAttr(aNode, 'Path', EmptyStr));
ANode:= ANode.FirstChild;
while Assigned(ANode) do
begin
if ANode.CompareName('Item') = 0 then
begin
Files.Add(TFileSystemFileSource.CreateFileFromFile(Xml.GetAttr(aNode, 'Name', EmptyStr)));
end;
ANode:= ANode.NextSibling;
end;
FileSource:= TFileSystemFileSource.GetFileSource;
Operation:= FileSource.CreateDeleteOperation(Files) as TFileSystemDeleteOperation;
Operation.SkipErrors:= False;
Operation.Recycle:= Xml.GetValue(Xml.RootNode, 'Recycle', False);
Operation.SymLinkOption:= TFileSourceOperationOptionSymLink(Xml.GetValue(Xml.RootNode, 'SymLinkOption', Integer(fsooslNone)));
Operation.DeleteReadOnly:= TFileSourceOperationOptionGeneral(Xml.GetValue(Xml.RootNode, 'DeleteReadOnly', Integer(fsoogNone)));
Operation.AddUserInterface(FFileSourceOperationMessageBoxesUI);
Operation.AddStateChangedListener([fsosStopped], @Dummy.Finish);
OperationsManager.AddOperation(Operation, True);
end;
end;
procedure Delete(Helper: TFileSystemDeleteOperation; Files: TFiles; Index: Integer);
var
I: Integer;
Xml: TXmlConfig;
ANode: TXmlNode;
SubNode: TXmlNode;
FileName: String;
begin
FileName:= GetTempFileName;
Xml:= TXmlConfig.Create(FileName);
Xml.SetValue(Xml.RootNode, 'Operation', 0);
Xml.SetValue(Xml.RootNode, 'Recycle', Helper.Recycle);
Xml.SetValue(Xml.RootNode, 'DeleteReadOnly', Integer(Helper.DeleteReadOnly));
Xml.SetValue(Xml.RootNode, 'SymLinkOption', Integer(Helper.SymLinkOption));
ANode := Xml.AddNode(Xml.RootNode, 'FileList');
Xml.SetAttr(ANode, 'Path', Files.Path);
for I:= 0 to Index do
begin
SubNode := Xml.AddNode(ANode, 'Item');
Xml.SetAttr(SubNode, 'Name', Files[I].FullPath);
end;
Xml.Save;
Xml.Free;
ExecCmdAdmin(ParamStrU(0), '--config-dir=' + QuoteStr(gpCfgDir) +
' ' +
'--operation=' + QuoteStr(FileName));
end;
procedure ExecuteOperation(const FileList: String);
var
Xml: TXmlConfig;
begin
try
Initialize;
Xml:= TXmlConfig.Create(FileList, True);
try
case Xml.GetValue(Xml.RootNode, 'Operation', -1) of
0: Delete(Xml);
end;
finally
Xml.Free;
mbDeleteFile(FileList);
end;
Application.Run;
Halt(0);
except
on E: Exception do
begin
ShowMessage(E.Message);
Halt(1);
end;
end;
end;
{ TDummy }
procedure TDummy.Finish(Operation: TFileSourceOperation; State: TFileSourceOperationState);
begin
Application.Terminate;
end;
end.

View file

@ -26,7 +26,7 @@ implementation
uses
Forms, Dialogs, SysUtils, uOSUtils, uDCUtils, uGlobsPaths, getopts, uDebug,
uLng, uClipboard, uAdministrator, DCStrUtils;
uLng, uClipboard, DCStrUtils;
function DecodePath(const Path: String): String;
begin
@ -42,7 +42,7 @@ procedure ProcessCommandLineParams;
var
Option: AnsiChar = #0;
OptionIndex: LongInt = 0;
Options: array[1..6] of TOption;
Options: array[1..5] of TOption;
OptionUnknown: String;
begin
FillChar(Options, SizeOf(Options), #0);
@ -68,11 +68,6 @@ begin
begin
Name:= 'no-splash';
end;
with Options[6] do
begin
Name:= 'operation';
Has_arg:= 1;
end;
FillChar(CommandLineParams, SizeOf(TCommandLineParams), #0);
repeat
try
@ -108,10 +103,6 @@ begin
begin
CommandLineParams.NoSplash:= True;
end;
6:
begin
ExecuteOperation(ParamStrU(TrimQuotes(OptArg)));
end;
end;
end;
'L', 'l': CommandLineParams.LeftPath:= DecodePath(ParamStrU(OptArg));