Make file read-only once assigned to a PropertyFileIncluded instance
This commit is contained in:
parent
ab8a8cd371
commit
9a9510d9e3
|
@ -607,7 +607,7 @@ Document::~Document()
|
||||||
// Remark: The API of Py::Object has been changed to set whether the wrapper owns the passed
|
// Remark: The API of Py::Object has been changed to set whether the wrapper owns the passed
|
||||||
// Python object or not. In the constructor we forced the wrapper to own the object so we need
|
// Python object or not. In the constructor we forced the wrapper to own the object so we need
|
||||||
// not to dec'ref the Python object any more.
|
// not to dec'ref the Python object any more.
|
||||||
// But we must still invalidate the Python object because it need not to be
|
// But we must still invalidate the Python object because it doesn't need to be
|
||||||
// destructed right now because the interpreter can own several references to it.
|
// destructed right now because the interpreter can own several references to it.
|
||||||
Base::PyObjectBase* doc = (Base::PyObjectBase*)DocumentPythonObject.ptr();
|
Base::PyObjectBase* doc = (Base::PyObjectBase*)DocumentPythonObject.ptr();
|
||||||
// Call before decrementing the reference counter, otherwise a heap error can occur
|
// Call before decrementing the reference counter, otherwise a heap error can occur
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
#include "Document.h"
|
#include "Document.h"
|
||||||
#include "PropertyContainer.h"
|
#include "PropertyContainer.h"
|
||||||
#include "DocumentObject.h"
|
#include "DocumentObject.h"
|
||||||
#define new DEBUG_CLIENTBLOCK
|
|
||||||
using namespace App;
|
using namespace App;
|
||||||
using namespace Base;
|
using namespace Base;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -66,10 +66,25 @@ PropertyFileIncluded::~PropertyFileIncluded()
|
||||||
// clean up
|
// clean up
|
||||||
if (!_cValue.empty()) {
|
if (!_cValue.empty()) {
|
||||||
Base::FileInfo file(_cValue.c_str());
|
Base::FileInfo file(_cValue.c_str());
|
||||||
|
file.setPermissions(Base::FileInfo::ReadWrite);
|
||||||
file.deleteFile();
|
file.deleteFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PropertyFileIncluded::aboutToSetValue(void)
|
||||||
|
{
|
||||||
|
// This is a trick to check in Copy() if it is called
|
||||||
|
// directly from outside or by the Undo/Redo mechanism.
|
||||||
|
// In the latter case it is sufficient to rename the file
|
||||||
|
// because another file will be assigned afterwards.
|
||||||
|
// If Copy() is directly called (e.g. to copy the file to
|
||||||
|
// another document) a copy of the file needs to be created.
|
||||||
|
// This copy will be deleted again in the class destructor.
|
||||||
|
this->StatusBits.set(10);
|
||||||
|
Property::aboutToSetValue();
|
||||||
|
this->StatusBits.reset(10);
|
||||||
|
}
|
||||||
|
|
||||||
std::string PropertyFileIncluded::getDocTransientPath(void) const
|
std::string PropertyFileIncluded::getDocTransientPath(void) const
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
|
@ -118,8 +133,10 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName)
|
||||||
// remove old file (if not moved by undo)
|
// remove old file (if not moved by undo)
|
||||||
Base::FileInfo value(_cValue);
|
Base::FileInfo value(_cValue);
|
||||||
std::string pathAct = value.dirPath();
|
std::string pathAct = value.dirPath();
|
||||||
if (value.exists())
|
if (value.exists()) {
|
||||||
|
value.setPermissions(Base::FileInfo::ReadWrite);
|
||||||
value.deleteFile();
|
value.deleteFile();
|
||||||
|
}
|
||||||
|
|
||||||
// if a special name given, use this instead
|
// if a special name given, use this instead
|
||||||
if (sName) {
|
if (sName) {
|
||||||
|
@ -153,25 +170,29 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName)
|
||||||
_BaseFileName = file.fileName();
|
_BaseFileName = file.fileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
// That's wrong and can lead to loss of data!!!
|
// The following applies only on files that are inside the transient
|
||||||
// Just consider the example that two objects with this property
|
// directory:
|
||||||
// exist in the same document and as an initial step the data are
|
// When a file is read-only it is supposed to be assigned to a
|
||||||
// copied from one object to the other. A rename will cause the one
|
// PropertyFileIncluded instance. In this case we must copy the
|
||||||
// object to loose its data.
|
// file because otherwise the above instance looses its data.
|
||||||
#if 0
|
// If the file is writable it is supposed to be of free use and
|
||||||
|
// it can be simply renamed.
|
||||||
|
|
||||||
// if the file is already in transient dir of the document, just use it
|
// if the file is already in transient dir of the document, just use it
|
||||||
if (path == pathTrans) {
|
if (path == pathTrans && file.isWritable()) {
|
||||||
bool done = file.renameFile(_cValue.c_str());
|
bool done = file.renameFile(_cValue.c_str());
|
||||||
if (!done) {
|
if (!done) {
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << "Cannot rename file " << file.filePath() << " to " << _cValue;
|
str << "Cannot rename file " << file.filePath() << " to " << _cValue;
|
||||||
throw Base::Exception(str.str());
|
throw Base::Exception(str.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make the file read-only
|
||||||
|
Base::FileInfo dst(_cValue);
|
||||||
|
dst.setPermissions(Base::FileInfo::ReadOnly);
|
||||||
}
|
}
|
||||||
// otherwise copy from origin location
|
// otherwise copy from origin location
|
||||||
else
|
else {
|
||||||
#endif
|
|
||||||
{
|
|
||||||
// if file already exists in transient dir make a new unique name
|
// if file already exists in transient dir make a new unique name
|
||||||
Base::FileInfo fi(_cValue);
|
Base::FileInfo fi(_cValue);
|
||||||
if (fi.exists()) {
|
if (fi.exists()) {
|
||||||
|
@ -200,6 +221,10 @@ void PropertyFileIncluded::setValue(const char* sFile, const char* sName)
|
||||||
str << "Cannot copy file from " << file.filePath() << " to " << _cValue;
|
str << "Cannot copy file from " << file.filePath() << " to " << _cValue;
|
||||||
throw Base::Exception(str.str());
|
throw Base::Exception(str.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make the file read-only
|
||||||
|
Base::FileInfo dst(_cValue);
|
||||||
|
dst.setPermissions(Base::FileInfo::ReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
hasSetValue();
|
hasSetValue();
|
||||||
|
@ -350,6 +375,9 @@ void PropertyFileIncluded::Restore(Base::XMLReader &reader)
|
||||||
reader.readBinFile(_cValue.c_str());
|
reader.readBinFile(_cValue.c_str());
|
||||||
reader.readEndElement("FileIncluded");
|
reader.readEndElement("FileIncluded");
|
||||||
_BaseFileName = file;
|
_BaseFileName = file;
|
||||||
|
// set read-only after restoring the file
|
||||||
|
Base::FileInfo fi(_cValue.c_str());
|
||||||
|
fi.setPermissions(Base::FileInfo::ReadOnly);
|
||||||
hasSetValue();
|
hasSetValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -375,7 +403,8 @@ void PropertyFileIncluded::SaveDocFile (Base::Writer &writer) const
|
||||||
|
|
||||||
void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
|
void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
|
||||||
{
|
{
|
||||||
Base::ofstream to(Base::FileInfo(_cValue.c_str()));
|
Base::FileInfo fi(_cValue.c_str());
|
||||||
|
Base::ofstream to(fi);
|
||||||
if (!to) {
|
if (!to) {
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << "PropertyFileIncluded::RestoreDocFile(): "
|
str << "PropertyFileIncluded::RestoreDocFile(): "
|
||||||
|
@ -390,6 +419,9 @@ void PropertyFileIncluded::RestoreDocFile(Base::Reader &reader)
|
||||||
to.put((const char)c);
|
to.put((const char)c);
|
||||||
}
|
}
|
||||||
to.close();
|
to.close();
|
||||||
|
|
||||||
|
// set read-only after restoring the file
|
||||||
|
fi.setPermissions(Base::FileInfo::ReadOnly);
|
||||||
hasSetValue();
|
hasSetValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,6 +436,18 @@ Property *PropertyFileIncluded::Copy(void) const
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
// create a new name in the document transient directory
|
// create a new name in the document transient directory
|
||||||
Base::FileInfo newName(getUniqueFileName(file.dirPath(), file.fileName()));
|
Base::FileInfo newName(getUniqueFileName(file.dirPath(), file.fileName()));
|
||||||
|
if (this->StatusBits.test(10)) {
|
||||||
|
// rename the file
|
||||||
|
bool done = file.renameFile(newName.filePath().c_str());
|
||||||
|
if (!done) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << "PropertyFileIncluded::Copy(): "
|
||||||
|
<< "Renaming the file '" << file.filePath() << "' to '"
|
||||||
|
<< newName.filePath() << "' failed.";
|
||||||
|
throw Base::Exception(str.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
// copy the file
|
// copy the file
|
||||||
bool done = file.copyTo(newName.filePath().c_str());
|
bool done = file.copyTo(newName.filePath().c_str());
|
||||||
if (!done) {
|
if (!done) {
|
||||||
|
@ -413,10 +457,14 @@ Property *PropertyFileIncluded::Copy(void) const
|
||||||
<< newName.filePath() << "' failed.";
|
<< newName.filePath() << "' failed.";
|
||||||
throw Base::Exception(str.str());
|
throw Base::Exception(str.str());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// remember the new name for the Undo
|
// remember the new name for the Undo
|
||||||
Base::Console().Log("Copy '%s' to '%s'\n",_cValue.c_str(),newName.filePath().c_str());
|
Base::Console().Log("Copy '%s' to '%s'\n",_cValue.c_str(),newName.filePath().c_str());
|
||||||
prop->_cValue = newName.filePath().c_str();
|
prop->_cValue = newName.filePath().c_str();
|
||||||
|
|
||||||
|
// make backup files writable to avoid copying them again on undo/redo
|
||||||
|
newName.setPermissions(Base::FileInfo::ReadWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
return prop;
|
return prop;
|
||||||
|
@ -429,15 +477,31 @@ void PropertyFileIncluded::Paste(const Property &from)
|
||||||
// make sure that source and destination file are different
|
// make sure that source and destination file are different
|
||||||
if (_cValue != prop._cValue) {
|
if (_cValue != prop._cValue) {
|
||||||
// delete old file (if still there)
|
// delete old file (if still there)
|
||||||
Base::FileInfo(_cValue).deleteFile();
|
Base::FileInfo fi(_cValue);
|
||||||
|
fi.setPermissions(Base::FileInfo::ReadWrite);
|
||||||
|
fi.deleteFile();
|
||||||
|
|
||||||
// get path to destination which can be the transient directory
|
// get path to destination which can be the transient directory
|
||||||
// of another document
|
// of another document
|
||||||
std::string path = getDocTransientPath();
|
std::string pathTrans = getDocTransientPath();
|
||||||
Base::FileInfo fiSrc(prop._cValue);
|
Base::FileInfo fiSrc(prop._cValue);
|
||||||
Base::FileInfo fiDst(path + "/" + prop._BaseFileName);
|
Base::FileInfo fiDst(pathTrans + "/" + prop._BaseFileName);
|
||||||
|
std::string path = fiSrc.dirPath();
|
||||||
|
|
||||||
if (fiSrc.exists()) {
|
if (fiSrc.exists()) {
|
||||||
fiDst.setFile(getUniqueFileName(fiDst.dirPath(), fiDst.fileName()));
|
fiDst.setFile(getUniqueFileName(fiDst.dirPath(), fiDst.fileName()));
|
||||||
|
|
||||||
|
// if the file is already in transient dir of the document, just use it
|
||||||
|
if (path == pathTrans) {
|
||||||
|
if (!fiSrc.renameFile(fiDst.filePath().c_str())) {
|
||||||
|
std::stringstream str;
|
||||||
|
str << "PropertyFileIncluded::Paste(): "
|
||||||
|
<< "Renaming the file '" << fiSrc.filePath() << "' to '"
|
||||||
|
<< fiDst.filePath() << "' failed.";
|
||||||
|
throw Base::Exception(str.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
if (!fiSrc.copyTo(fiDst.filePath().c_str())) {
|
if (!fiSrc.copyTo(fiDst.filePath().c_str())) {
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << "PropertyFileIncluded::Paste(): "
|
str << "PropertyFileIncluded::Paste(): "
|
||||||
|
@ -445,6 +509,10 @@ void PropertyFileIncluded::Paste(const Property &from)
|
||||||
<< fiDst.filePath() << "' failed.";
|
<< fiDst.filePath() << "' failed.";
|
||||||
throw Base::Exception(str.str());
|
throw Base::Exception(str.str());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the file again read-only
|
||||||
|
fiDst.setPermissions(Base::FileInfo::ReadOnly);
|
||||||
_cValue = fiDst.filePath();
|
_cValue = fiDst.filePath();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -108,6 +108,7 @@ protected:
|
||||||
// get the transient path if the property is in a DocumentObject
|
// get the transient path if the property is in a DocumentObject
|
||||||
std::string getDocTransientPath(void) const;
|
std::string getDocTransientPath(void) const;
|
||||||
std::string getUniqueFileName(const std::string&, const std::string&) const;
|
std::string getUniqueFileName(const std::string&, const std::string&) const;
|
||||||
|
void aboutToSetValue(void);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
mutable std::string _cValue;
|
mutable std::string _cValue;
|
||||||
|
|
|
@ -52,10 +52,20 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#define new DEBUG_CLIENTBLOCK
|
|
||||||
|
|
||||||
using namespace Base;
|
using namespace Base;
|
||||||
|
|
||||||
|
#ifndef R_OK
|
||||||
|
#define R_OK 4 /* Test for read permission */
|
||||||
|
#endif
|
||||||
|
#ifndef W_OK
|
||||||
|
#define W_OK 2 /* Test for write permission */
|
||||||
|
#endif
|
||||||
|
#ifndef X_OK
|
||||||
|
#define X_OK 1 /* Test for execute permission */
|
||||||
|
#endif
|
||||||
|
#ifndef F_OK
|
||||||
|
#define F_OK 0 /* Test for existence */
|
||||||
|
#endif
|
||||||
|
|
||||||
//**********************************************************************************
|
//**********************************************************************************
|
||||||
// helper
|
// helper
|
||||||
|
@ -263,9 +273,9 @@ bool FileInfo::exists () const
|
||||||
{
|
{
|
||||||
#if defined (FC_OS_WIN32)
|
#if defined (FC_OS_WIN32)
|
||||||
std::wstring wstr = toStdWString();
|
std::wstring wstr = toStdWString();
|
||||||
return _waccess(wstr.c_str(),0) == 0;
|
return _waccess(wstr.c_str(),F_OK) == 0;
|
||||||
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
||||||
return access(FileName.c_str(),0) == 0;
|
return access(FileName.c_str(),F_OK) == 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,9 +283,9 @@ bool FileInfo::isReadable () const
|
||||||
{
|
{
|
||||||
#if defined (FC_OS_WIN32)
|
#if defined (FC_OS_WIN32)
|
||||||
std::wstring wstr = toStdWString();
|
std::wstring wstr = toStdWString();
|
||||||
return _waccess(wstr.c_str(),4) == 0;
|
return _waccess(wstr.c_str(),R_OK) == 0;
|
||||||
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
||||||
return access(FileName.c_str(),4) == 0;
|
return access(FileName.c_str(),R_OK) == 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,9 +293,29 @@ bool FileInfo::isWritable () const
|
||||||
{
|
{
|
||||||
#if defined (FC_OS_WIN32)
|
#if defined (FC_OS_WIN32)
|
||||||
std::wstring wstr = toStdWString();
|
std::wstring wstr = toStdWString();
|
||||||
return _waccess(wstr.c_str(),2) == 0;
|
return _waccess(wstr.c_str(),W_OK) == 0;
|
||||||
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
||||||
return access(FileName.c_str(),2) == 0;
|
return access(FileName.c_str(),W_OK) == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileInfo::setPermissions (Permissions perms)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
int mode = 0;
|
||||||
|
|
||||||
|
if (perms & FileInfo::ReadOnly)
|
||||||
|
mode |= S_IREAD;
|
||||||
|
if (perms & FileInfo::WriteOnly)
|
||||||
|
mode |= S_IWRITE;
|
||||||
|
|
||||||
|
if (mode == 0) // bad argument
|
||||||
|
return false;
|
||||||
|
#if defined (FC_OS_WIN32)
|
||||||
|
std::wstring wstr = toStdWString();
|
||||||
|
return _wchmod(wstr.c_str(),mode) == 0;
|
||||||
|
#elif defined (FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
||||||
|
return chmod(FileName.c_str(),mode) == 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,13 +503,18 @@ bool FileInfo::deleteDirectoryRecursive(void) const
|
||||||
std::vector<Base::FileInfo> List = getDirectoryContent();
|
std::vector<Base::FileInfo> List = getDirectoryContent();
|
||||||
|
|
||||||
for (std::vector<Base::FileInfo>::iterator It = List.begin();It!=List.end();++It) {
|
for (std::vector<Base::FileInfo>::iterator It = List.begin();It!=List.end();++It) {
|
||||||
if (It->isDir())
|
if (It->isDir()) {
|
||||||
|
It->setPermissions(FileInfo::ReadWrite);
|
||||||
It->deleteDirectoryRecursive();
|
It->deleteDirectoryRecursive();
|
||||||
else if(It->isFile())
|
}
|
||||||
|
else if (It->isFile()) {
|
||||||
|
It->setPermissions(FileInfo::ReadWrite);
|
||||||
It->deleteFile();
|
It->deleteFile();
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
Base::Exception("FileInfo::deleteDirectoryRecursive(): Unknown object Type in directory!");
|
Base::Exception("FileInfo::deleteDirectoryRecursive(): Unknown object Type in directory!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return deleteDirectory();
|
return deleteDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,12 @@ namespace Base
|
||||||
class BaseExport FileInfo
|
class BaseExport FileInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum Permissions {
|
||||||
|
WriteOnly = 0x01,
|
||||||
|
ReadOnly = 0x02,
|
||||||
|
ReadWrite = 0x03,
|
||||||
|
};
|
||||||
|
|
||||||
/// Constrction
|
/// Constrction
|
||||||
FileInfo (const char* _FileName="");
|
FileInfo (const char* _FileName="");
|
||||||
FileInfo (const std::string &_FileName);
|
FileInfo (const std::string &_FileName);
|
||||||
|
@ -89,6 +95,8 @@ public:
|
||||||
bool isReadable () const;
|
bool isReadable () const;
|
||||||
/// Checks if the file exist and is writable
|
/// Checks if the file exist and is writable
|
||||||
bool isWritable () const;
|
bool isWritable () const;
|
||||||
|
/// Tries to set the file permisson
|
||||||
|
bool setPermissions (Permissions);
|
||||||
/// Checks if it is a file (not a direrctory)
|
/// Checks if it is a file (not a direrctory)
|
||||||
bool isFile () const;
|
bool isFile () const;
|
||||||
/// Checks if it is a directory (not a file)
|
/// Checks if it is a directory (not a file)
|
||||||
|
@ -109,7 +117,7 @@ public:
|
||||||
std::vector<Base::FileInfo> getDirectoryContent(void) const;
|
std::vector<Base::FileInfo> getDirectoryContent(void) const;
|
||||||
/// Delete an empty directory
|
/// Delete an empty directory
|
||||||
bool deleteDirectory(void) const;
|
bool deleteDirectory(void) const;
|
||||||
/// Delete a directory and all its content
|
/// Delete a directory and all its content.
|
||||||
bool deleteDirectoryRecursive(void) const;
|
bool deleteDirectoryRecursive(void) const;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user