I didn't find an easy way to get and set the permissions of a file with wxWidgets.
So I created a short patch that copies and renames the original file, instead of creating a new (empty) one.
It might not be the most elegant way, I think, but it works and it does not change any other function.
--- codeblocks-1.0svn.orig/src/sdk/filemanager.cpp 2008-03-01 09:23:55.000000000 +0100
+++ codeblocks-1.0svn.work/src/sdk/filemanager.cpp 2008-03-30 19:18:01.000000000 +0200
@@ -309,6 +309,10 @@
wxString tempName(name + _T(".cbTemp"));
do
{
+ if(wxRenameFile(name, tempName) == false)
+ return false;
+ if(wxCopyFile(tempName, name) ==false)
+ return false;
wxFile f(tempName, wxFile::write);
if(!f.IsOpened())
return false;
I didn't find an easy way to get and set the permissions of a file with wxWidgets.
So I created a short patch that copies and renames the original file, instead of creating a new (empty) one.
It might not be the most elegant way, I think, but it works and it does not change any other function.
Have you checked if wxCopyFile copies the attributes?
If it does, this tweak of your patch would work.
(I'm not changing your patch just for the sake of changing it. I'm concerned that the added code in the patch above could succeed with wxFileRename and fail with wxCopyFile and then your file is mysteriously missing. See what I'm saying?)
--- codeblocks-1.0svn.orig/src/sdk/filemanager.cpp 2008-03-01 09:23:55.000000000 +0100
+++ codeblocks-1.0svn.work/src/sdk/filemanager.cpp 2008-03-30 19:18:01.000000000 +0200
@@ -309,6 +309,8 @@
wxString tempName(name + _T(".cbTemp"));
do
{
+ if(wxCopyFile(name, tempName) ==false)
+ return false;
wxFile f(tempName, wxFile::write);
if(!f.IsOpened())
return false;
What about this simple code to query the file permissions of the original file and assign them to the file-after-safe-saving?
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
...
struct stat fileStats;
stat("file.cpp", &fileStats);
// vodoo magic to do safe file saving
chmod("file.cpp", fileStats.st_mode);
That should do the trick, and it could even work on Mac OS.
Hi Ceniza,
it's simple, but it works.
At least on my Laptop with debian sid (64-bit) with utf-8 as standard-encoding (in C::B and filesystem).
Not tested with other combinations.
On windows the same bug exists and persists.
If I have special rights for some users, they all are set to default (everyone can do everything, all added users get removed) on my w2k-box.
Nevertheless here is your idea as working patch.
Compiles on linux and w2k.
It should not break the "ultra-paranoid custom file save function that Code::Blocks uses".
--- codeblocks-1.0svn.orig/src/sdk/filemanager.cpp 2008-04-02 23:11:44.000000000 +0200
+++ codeblocks-1.0svn.work/src/sdk/filemanager.cpp 2008-04-06 23:22:29.000000000 +0200
@@ -278,6 +278,12 @@
if(!f.IsOpened())
return false;
+ // take file permissions from original file ...
+ struct stat fileStats;
+ stat(name.mb_str(), &fileStats);
+ // ... and give them to the new one
+ chmod(tempName.mb_str(), fileStats.st_mode);
+
if(f.Write(data, len) != len)
{
f.Close();
@@ -313,6 +319,12 @@
if(!f.IsOpened())
return false;
+ // take file permissions from original file ...
+ struct stat fileStats;
+ stat(name.mb_str(), &fileStats);
+ // ... and give them to the new one
+ chmod(tempName.mb_str(), fileStats.st_mode);
+
if(WriteWxStringToFile(f, data, encoding, bom) == false)
{
f.Close();
This patch should solve the issue. I've tested this on Windows. :)
Index: src/sdk/filemanager.cpp
===================================================================
--- src/sdk/filemanager.cpp (revision 4999)
+++ src/sdk/filemanager.cpp (working copy)
@@ -299,29 +299,35 @@
return WriteWxStringToFile(f, data, encoding, bom);
}
- if(platform::windows)
- {
- wxFile f;
- if(!f.Open(name, wxFile::read_write))
- return false;
- }
+ wxFile f;
+ if (!f.Open(name, wxFile::read_write))
+ return false;
wxString tempName(name + _T(".cbTemp"));
do
{
- wxFile f(tempName, wxFile::write);
- if(!f.IsOpened())
+ if (!wxCopyFile(name, tempName))
+ {
+ f.Close();
return false;
+ }
if(WriteWxStringToFile(f, data, encoding, bom) == false)
{
f.Close();
- wxRemoveFile(tempName);
+ // Keep the backup file as the original file has been destroyed
return false;
}
+ else
+ {
+ wxRemoveFile(tempName);
+ }
+
+ f.Close();
+
}while(false);
- return ReplaceFile(name, tempName);
+ return true;
}
bool FileManager::ReplaceFile(const wxString& old_file, const wxString& new_file)
@Thomas,
If you know the exact version of wx which has the buggy wxCopyFile() implementation, then we can specify the exact version users should avoid. :)
Here is the patch I actually use for the binaries in my repo:
--- codeblocks-1.0svn.orig/src/sdk/filemanager.cpp 2008-05-04 14:14:54.000000000 +0200
+++ codeblocks-1.0svn.work/src/sdk/filemanager.cpp 2008-05-10 12:46:55.000000000 +0200
@@ -264,29 +264,48 @@
return f.Write(data, len);
}
+ wxString tempName(name + _T(".cbTemp"));
+
+ wxFile f_tmp(tempName, wxFile::write);
+ if(!f_tmp.IsOpened())
+ return false;
+
+ if(f_tmp.Write(data, len) != len)
+ {
+ f_tmp.Close();
+ wxRemoveFile(tempName);
+ return false;
+ }
+
if(platform::windows) // work around broken Windows readonly flag
{
- wxFile f;
- if(!f.Open(name, wxFile::read_write))
+ wxFile f(name, wxFile::read_write);
+ if(!f.IsOpened())
return false;
}
-
- wxString tempName(name + _T(".cbTemp"));
do
{
- wxFile f(tempName, wxFile::write);
+ wxFile f(name, wxFile::write);
if(!f.IsOpened())
return false;
-
if(f.Write(data, len) != len)
{
f.Close();
- wxRemoveFile(tempName);
return false;
}
}while(false);
- return ReplaceFile(name, tempName);
+ if (Manager::IsAppShuttingDown())
+ {
+ // app shut down, forget delayed deletion
+ wxRemoveFile(tempName);
+ }
+ else
+ {
+ // issue a delayed deletion of the back'd up (old) file
+ delayedDeleteThread.Queue(new DelayedDelete(tempName));
+ }
+ return true;
}
bool FileManager::Save(const wxString& name, const wxString& data, wxFontEncoding encoding, bool bom)
@@ -296,32 +315,53 @@
wxFile f(name, wxFile::write);
if(!f.IsOpened())
return false;
+
return WriteWxStringToFile(f, data, encoding, bom);
}
- if(platform::windows)
+ wxString tempName(name + _T(".cbTemp"));
+
+ wxFile f_tmp(tempName, wxFile::write);
+ if(!f_tmp.IsOpened())
+ return false;
+
+ if(WriteWxStringToFile(f_tmp, data, encoding, bom) == false)
+ {
+ f_tmp.Close();
+ wxRemoveFile(tempName);
+ return false;
+ }
+
+ if(platform::windows) // work around broken Windows readonly flag
{
- wxFile f;
- if(!f.Open(name, wxFile::read_write))
+ wxFile f(name, wxFile::read_write);
+ if(!f.IsOpened())
return false;
}
-
- wxString tempName(name + _T(".cbTemp"));
do
{
- wxFile f(tempName, wxFile::write);
+ wxFile f(name, wxFile::write);
if(!f.IsOpened())
return false;
if(WriteWxStringToFile(f, data, encoding, bom) == false)
{
f.Close();
- wxRemoveFile(tempName);
return false;
}
}while(false);
- return ReplaceFile(name, tempName);
+ if (Manager::IsAppShuttingDown())
+ {
+ // app shut down, forget delayed deletion
+ wxRemoveFile(tempName);
+ }
+ else
+ {
+ // issue a delayed deletion of the back'd up (old) file
+ delayedDeleteThread.Queue(new DelayedDelete(tempName));
+ }
+ return true;
}
bool FileManager::ReplaceFile(const wxString& old_file, const wxString& new_file)
That leads to the following functions (I only post the function with BOM, but it's identically to the other one except the way the string is written to the files):
bool FileManager::Save(const wxString& name, const wxString& data, wxFontEncoding encoding, bool bom)
{
if(wxFileExists(name) == false) // why bother if we don't need to
{
wxFile f(name, wxFile::write);
if(!f.IsOpened())
return false;
return WriteWxStringToFile(f, data, encoding, bom);
}
wxString tempName(name + _T(".cbTemp"));
wxFile f_tmp(tempName, wxFile::write);
if(!f_tmp.IsOpened())
return false;
if(WriteWxStringToFile(f_tmp, data, encoding, bom) == false)
{
f_tmp.Close();
wxRemoveFile(tempName);
return false;
}
if(platform::windows) // work around broken Windows readonly flag
{
wxFile f(name, wxFile::read_write);
if(!f.IsOpened())
return false;
}
do
{
wxFile f(name, wxFile::write);
if(!f.IsOpened())
return false;
if(WriteWxStringToFile(f, data, encoding, bom) == false)
{
f.Close();
return false;
}
}while(false);
if (Manager::IsAppShuttingDown())
{
// app shut down, forget delayed deletion
wxRemoveFile(tempName);
}
else
{
// issue a delayed deletion of the back'd up (old) file
delayedDeleteThread.Queue(new DelayedDelete(tempName));
}
return true;
}
It's absolutely necessary not to open the file we want to write into in readwrite-mode !!
See my post here (http://forums.codeblocks.org/index.php/topic,8388.msg61925.html#msg61925)
@Jens,
IMO, there is a problem with your patch.
The workflow of your patch is-
1) Write the new contents to a temporary file.
2) Write the new contents to the original file.
3) Delete the file created in step 1.
The problem is, once step 2 is started, the original file is lost. In case of any error, there is no way of recovering the original file.
I've added your modification of delayed delete to my original patch and planning to commit it later this week. This is what my patch looks right now. I need to apply it to the other Save function.
Index: src/sdk/filemanager.cpp
===================================================================
--- src/sdk/filemanager.cpp (revision 5083)
+++ src/sdk/filemanager.cpp (working copy)
@@ -309,19 +309,42 @@
wxString tempName(name + _T(".cbTemp"));
do
{
- wxFile f(tempName, wxFile::write);
- if(!f.IsOpened())
+ if (!wxCopyFile(name, tempName))
+ {
return false;
+ }
+ wxFile f(name, wxFile::write);
+ if (!f.IsOpened())
+ {
+ return false;
+ }
if(WriteWxStringToFile(f, data, encoding, bom) == false)
{
f.Close();
- wxRemoveFile(tempName);
+ // Keep the backup file as the original file has been destroyed
return false;
}
+ else
+ {
+ wxRemoveFile(tempName);
+ }
+
+ f.Close();
+
}while(false);
- return ReplaceFile(name, tempName);
+ if (Manager::IsAppShuttingDown())
+ {
+ // app shut down, forget delayed deletion
+ wxRemoveFile(tempName);
+ }
+ else
+ {
+ // issue a delayed deletion of the back'd up (old) file
+ delayedDeleteThread.Queue(new DelayedDelete(tempName));
+ }
+ return true;
}
bool FileManager::ReplaceFile(const wxString& old_file, const wxString& new_file)
Regards,
Biplab