Maintain file permissions when renaming

Temporary and autosave files do not neccessarily have the correct
permissions set to replace existing project files.  This updates the
permissions to match the existing values where possible

Fixes https://gitlab.com/kicad/code/kicad/-/issues/13574
This commit is contained in:
Seth Hillbrand 2023-05-24 17:07:46 -07:00
parent 122be418bb
commit 48ecd742eb
12 changed files with 147 additions and 6 deletions

View File

@ -63,6 +63,7 @@
#include <wx/stdpaths.h> #include <wx/stdpaths.h>
#include <wx/string.h> #include <wx/string.h>
#include <kiplatform/app.h> #include <kiplatform/app.h>
#include <kiplatform/io.h>
#include <kiplatform/ui.h> #include <kiplatform/ui.h>
#include <functional> #include <functional>
@ -1295,6 +1296,9 @@ void EDA_BASE_FRAME::CheckForAutoSaveFile( const wxFileName& aFileName )
// the file name. // the file name.
if( response == wxYES ) if( response == wxYES )
{ {
// Preserve the permissions of the current file
KIPLATFORM::IO::DuplicatePermissions( aFileName.GetFullPath(), autoSaveFileName.GetFullPath() );
if( !wxRenameFile( autoSaveFileName.GetFullPath(), aFileName.GetFullPath() ) ) if( !wxRenameFile( autoSaveFileName.GetFullPath(), aFileName.GetFullPath() ) )
{ {
wxMessageBox( _( "The auto save file could not be renamed to the board file name." ), wxMessageBox( _( "The auto save file could not be renamed to the board file name." ),

View File

@ -71,6 +71,8 @@
#include <widgets/wx_progress_reporters.h> #include <widgets/wx_progress_reporters.h>
#include <widgets/wx_html_report_box.h> #include <widgets/wx_html_report_box.h>
#include <kiplatform/io.h>
#if wxCHECK_VERSION( 3, 1, 7 ) #if wxCHECK_VERSION( 3, 1, 7 )
#include "widgets/filedlg_hook_save_project.h" #include "widgets/filedlg_hook_save_project.h"
#else #else
@ -741,6 +743,8 @@ bool SCH_EDIT_FRAME::saveSchematicFile( SCH_SHEET* aSheet, const wxString& aSave
if( success ) if( success )
{ {
// Preserve the permissions of the current file
KIPLATFORM::IO::DuplicatePermissions( schematicFileName.GetFullPath(), tempFile );
// Replace the original with the temporary file we just wrote // Replace the original with the temporary file we just wrote
success = wxRenameFile( tempFile, schematicFileName.GetFullPath() ); success = wxRenameFile( tempFile, schematicFileName.GetFullPath() );

View File

@ -32,6 +32,7 @@
#include <confirm.h> #include <confirm.h>
#include <gestfich.h> #include <gestfich.h>
#include <kiplatform/environment.h> #include <kiplatform/environment.h>
#include <kiplatform/io.h>
#include <kiway.h> #include <kiway.h>
#include <tool/tool_manager.h> #include <tool/tool_manager.h>
#include <tools/kicad_manager_actions.h> #include <tools/kicad_manager_actions.h>

View File

@ -23,6 +23,8 @@
#include <wx/string.h> #include <wx/string.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
FILE* KIPLATFORM::IO::SeqFOpen( const wxString& aPath, const wxString& aMode ) FILE* KIPLATFORM::IO::SeqFOpen( const wxString& aPath, const wxString& aMode )
{ {
@ -32,3 +34,26 @@ FILE* KIPLATFORM::IO::SeqFOpen( const wxString& aPath, const wxString& aMode )
return fp; return fp;
} }
bool KIPLATFORM::IO::DuplicatePermissions( const wxString &aSrc, const wxString &aDest )
{
struct stat sourceStat;
if( stat( aSrc.fn_str(), &sourceStat ) == 0 )
{
mode_t permissions = sourceStat.st_mode & ( S_IRWXU | S_IRWXG | S_IRWXO );
if( chmod( aDest.fn_str(), permissions ) == 0 )
{
return true;
}
else
{
// Handle error
return false;
}
}
else
{
// Handle error
return false;
}
}

View File

@ -37,6 +37,13 @@ namespace IO
* to say linux and it's posix_fadvise * to say linux and it's posix_fadvise
*/ */
FILE* SeqFOpen( const wxString& aPath, const wxString& mode ); FILE* SeqFOpen( const wxString& aPath, const wxString& mode );
/**
* Duplicates the file security data from one file to another ensuring that they are
* the same between both. This assumes that the user has permission to set #aDest
* @return true if the process was successful
*/
bool DuplicatePermissions( const wxString& aSrc, const wxString& aDest );
} // namespace IO } // namespace IO
} // namespace KIPLATFORM } // namespace KIPLATFORM

View File

@ -69,3 +69,41 @@ FILE* KIPLATFORM::IO::SeqFOpen( const wxString& aPath, const wxString& aMode )
return wxFopen( aPath, aMode ); return wxFopen( aPath, aMode );
#endif #endif
} }
bool KIPLATFORM::IO::DuplicatePermissions( const wxString &aSrc, const wxString &aDest )
{
bool retval = false;
PSECURITY_DESCRIPTOR pSD = nullptr;
DWORD dwSize = 0;
// Retrieve the security descriptor from the source file
if( GetFileSecurity( sourceFilePath.wc_str(),
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
NULL, 0, &dwSize ) )
{
pSD = static_cast<PSECURITY_DESCRIPTOR>( new BYTE[dwSize] );
if( !pSD )
return false;
if( !GetFileSecurity( sourceFilePath.wc_str(),
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION, pSD, dwSize, &dwSize ) )
{
delete[] pSD;
return false;
}
// Assign the retrieved security descriptor to the destination file
if( !SetFileSecurity( destFilePath.wc_str(),
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION, pSD ) )
{
retval = false;
}
delete[] pSD;
}
return retval;
}

View File

@ -19,6 +19,8 @@
#include <kiplatform/io.h> #include <kiplatform/io.h>
#import <Foundation/Foundation.h>
#include <wx/crt.h> #include <wx/crt.h>
#include <wx/string.h> #include <wx/string.h>
@ -26,3 +28,37 @@ FILE* KIPLATFORM::IO::SeqFOpen( const wxString& aPath, const wxString& aMode )
{ {
return wxFopen( aPath, aMode ); return wxFopen( aPath, aMode );
} }
bool AssignPermissions(const wxString& sourceFilePath, const wxString& destFilePath)
{
NSString *sourcePath = [NSString stringWithUTF8String:sourceFilePath.utf8_str()];
NSString *destPath = [NSString stringWithUTF8String:destFilePath.utf8_str()];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSDictionary *sourceAttributes = [fileManager attributesOfItemAtPath:sourcePath error:&error];
if( !sourceAttributes )
{
NSLog(@"Error retrieving source file attributes: %@", error);
return false;
}
NSNumber *permissions = sourceAttributes[NSFilePosixPermissions];
if (permissions == nil)
{
return false;
}
if ([fileManager setAttributes:@{NSFilePosixPermissions: permissions} ofItemAtPath:destPath error:&error])
{
return true;
}
else
{
NSLog(@"Error assigning permissions: %@", error);
return false;
}
}

View File

@ -32,6 +32,8 @@
#include <widgets/wx_infobar.h> #include <widgets/wx_infobar.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <kiplatform/io.h>
#include "pl_editor_frame.h" #include "pl_editor_frame.h"
#include "pl_editor_id.h" #include "pl_editor_id.h"
#include "properties_frame.h" #include "properties_frame.h"
@ -307,6 +309,9 @@ bool PL_EDITOR_FRAME::SaveDrawingSheetFile( const wxString& aFullFileName )
return false; return false;
} }
// Preserve the permissions of the current file
KIPLATFORM::IO::DuplicatePermissions( aFullFileName, tempFile );
if( !wxRenameFile( tempFile, aFullFileName ) ) if( !wxRenameFile( tempFile, aFullFileName ) )
return false; return false;

View File

@ -38,6 +38,7 @@
#include <footprint.h> #include <footprint.h>
#include <pad.h> #include <pad.h>
#include <kiplatform/io.h>
#include "step_pcb_model.h" #include "step_pcb_model.h"
#include "streamwrapper.h" #include "streamwrapper.h"
@ -831,6 +832,10 @@ bool STEP_PCB_MODEL::WriteSTEP( const wxString& aFileName )
if( success ) if( success )
{ {
// Preserve the permissions of the current file
KIPLATFORM::IO::DuplicatePermissions( fn.GetFullPath(), tmpfname );
if( !wxRenameFile( tmpfname, fn.GetFullName(), true ) ) if( !wxRenameFile( tmpfname, fn.GetFullName(), true ) )
{ {
ReportMessage( wxString::Format( wxT( "Cannot rename temporary file '%s' to '%s'.\n" ), ReportMessage( wxString::Format( wxT( "Cannot rename temporary file '%s' to '%s'.\n" ),

View File

@ -23,6 +23,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#include <string>
#include <confirm.h> #include <confirm.h>
#include <core/arraydim.h> #include <core/arraydim.h>
#include <gestfich.h> #include <gestfich.h>
@ -57,13 +59,14 @@
#include <plugins/cadstar/cadstar_pcb_archive_plugin.h> #include <plugins/cadstar/cadstar_pcb_archive_plugin.h>
#include <plugins/kicad/pcb_plugin.h> #include <plugins/kicad/pcb_plugin.h>
#include <dialogs/dialog_imported_layers.h> #include <dialogs/dialog_imported_layers.h>
#include <string>
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
#include "footprint_info_impl.h" #include "footprint_info_impl.h"
#include "board_commit.h" #include "board_commit.h"
#include "zone_filler.h" #include "zone_filler.h"
#include <wx_filename.h> // For ::ResolvePossibleSymlinks() #include <wx_filename.h> // For ::ResolvePossibleSymlinks()
#include <kiplatform/io.h>
#include <wx/wupdlock.h> #include <wx/wupdlock.h>
#include <wx/filedlg.h> #include <wx/filedlg.h>
#include <wx/wfstream.h> #include <wx/wfstream.h>
@ -1093,6 +1096,9 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool addToHistory,
return false; return false;
} }
// Preserve the permissions of the current file
KIPLATFORM::IO::DuplicatePermissions( pcbFileName.GetFullPath(), tempFile );
// If save succeeded, replace the original with what we just wrote // If save succeeded, replace the original with what we just wrote
if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) ) if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) )
{ {

View File

@ -34,6 +34,8 @@
#include <thread_pool.h> #include <thread_pool.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <kiplatform/io.h>
#include <wx/textfile.h> #include <wx/textfile.h>
#include <wx/txtstrm.h> #include <wx/txtstrm.h>
#include <wx/wfstream.h> #include <wx/wfstream.h>
@ -331,6 +333,9 @@ void FOOTPRINT_LIST_IMPL::WriteCacheToFile( const wxString& aFilePath )
txtStream.Flush(); txtStream.Flush();
outStream.Close(); outStream.Close();
// Preserve the permissions of the current file
KIPLATFORM::IO::DuplicatePermissions( aFilePath, tmpFileName.GetFullPath() );
if( !wxRenameFile( tmpFileName.GetFullPath(), aFilePath, true ) ) if( !wxRenameFile( tmpFileName.GetFullPath(), aFilePath, true ) )
{ {
// cleanup in case rename failed // cleanup in case rename failed

View File

@ -55,6 +55,8 @@
#include <zone.h> #include <zone.h>
#include <zones.h> #include <zones.h>
#include <kiplatform/io.h>
// For some reason wxWidgets is built with wxUSE_BASE64 unset so expose the wxWidgets // For some reason wxWidgets is built with wxUSE_BASE64 unset so expose the wxWidgets
// base64 code. Needed for PCB_BITMAP // base64 code. Needed for PCB_BITMAP
#define wxUSE_BASE64 1 #define wxUSE_BASE64 1
@ -129,6 +131,9 @@ void FP_CACHE::Save( FOOTPRINT* aFootprint )
// and it is fully inexplicable. See if this dodges the error. // and it is fully inexplicable. See if this dodges the error.
wxMilliSleep( 250L ); wxMilliSleep( 250L );
// Preserve the permissions of the current file
KIPLATFORM::IO::DuplicatePermissions( fn.GetFullPath(), tempFileName );
if( !wxRenameFile( tempFileName, fn.GetFullPath() ) ) if( !wxRenameFile( tempFileName, fn.GetFullPath() ) )
{ {
wxString msg = wxString::Format( _( "Cannot rename temporary file '%s' to '%s'" ), wxString msg = wxString::Format( _( "Cannot rename temporary file '%s' to '%s'" ),