My physical path include symbolic links and on some PCs also a NFS mount, that's probably that cause the problem along the way.
In the following thread the offered solution is to replace QFileInfo::canonicalFilePath() with QFileInfo::absoluteFilePath().
However, it has never become really clear why exactly the current implementation fails. So, to examine the issues I did the following steps:
- Create the directory /tmp/test/real_dir/asm
- In /tmp/test create a soft link called link_dir to real_dir
- Copy the assembly project from here to /tmp/test/real_dir/asm
Now if I open the file
test asm4.FCStd via /tmp/test/real_dir/asm everything works as expected. If I open it instead via /tmp/test/link_dir/asm the problems start. The error message is:
11:58:17 8.7e-08 <App> Document.cpp(2842): test_asm4#_x25mm_round_shaft.LinkedObject: Link not restored
Linked object: Model
Linked file: 6x25mm round shaft.FCStd
11:58:17 0.000474066 <App> Document.cpp(2842): test_asm4#_mm_lighweight_hub.LinkedObject: Link not restored
Linked object: Model
Linked file: 6mm lighweight hub.FCStd
And the loaded
test asm4 document is marked as touched.
What happened is:
When loading a project then inside App::DocInfo::get() an entry to a map is added with information about the document. As key the absolute file path with the soft link is used.
When trying to search for the further assembly files while loading the project the function App::DocInfo::restoreDocument() is used. In this function the path was created with QFileInfo::canonicalFilePath() and thus the soft link has been resolved to the real path.
This path is used to search in the map but because it has no matching key the second file won't be loaded.
This explains why the whole assembly project cannot be loaded completely.
I don't understand how the file location is handled by freecad and ASM4, but it looks like the path is not saved as "/home/alex/FreeCAD/test/filename.FCStd" as the user sees is when saving the file, but something like "../../../../../mnt/storage/FreeCAD/test/filename.FCStd"
The reason for this mess is caused by computing a relative path from two absolute paths with a different directory hierarchy. You can easily test it with:
Code: Select all
from PySide2 import QtCore
docDir = QtCore.QDir("/home/alex/FreeCAD/test")
docDir.relativeFilePath("/mnt/storage/FreeCAD/test")
# gives: '../../../../mnt/storage/FreeCAD/test'
The function call QDir::relativeFilePath() is used in App::DocInfo::getDocPath() and it will we assigned to the filePath member of the PropertyXLink.
You will break your model as soon as you save the document because it then writes this broken path into the Document.xml
Btw:
Uncompressed the file, in Document.xml I can see the problematic paths, such as:
<XLink file="../../../../../media/storage/home/alex/Workspace/FreeCAD/Mahsanatron/v-wheel set 13mm.FCStd"
Since it's guaranteed that the very first file of a valid FCStd project is Document.xml you can directly read its content with
zless test\ asm4.FCStd
Thinking about it while writing...
Even with the physical location check as it was implemented now (before the fix), someone could symlink the file itself in the working directory, so there will be 2 different file names pointing to the same file and those will still be overridden without any warning.
Yes and no. It's mainly an issue when you create symlinks to directories. However, when you create soft links or hard links to the actual file the situation is different:
The default behaviour of FreeCAD when overwriting an existing file is that it creates a separate file with a GUID as suffix and if the write process was successful it renames or removes (depends on the number of backup files) the original file and removes the GUID from the new file.
This means you can load the actual file, a soft-linked file or a hard-linked file without worrying that you overwrite files each other. What will happen is that you will end up with three independent files.
Now you can switch off this behaviour by adding the boolean parameter
User parameter:BaseApp/Preferences/Document/BackupPolicy and set it to false. In this case when saving a document the existing file will be used directly to write the content to.
And with the PR applied there is still a certain risk that you overwrite a file by accident:
it happens when you create a hard link to the original project and if BackupPolicy is set to false. With the Qt API there is no way to see that both files are identical in the file system and thus the check to warn the user will fail.