Bug 363599

Summary: Media File ctime Changes Even When Only Writing To XMP Sidecar File
Product: [Applications] digikam Reporter: C Doe <cfdoe1>
Component: Metadata-SidecarAssignee: Digikam Developers <digikam-bugs-null>
Status: RESOLVED FIXED    
Severity: normal CC: caulier.gilles, metzpinguin, paul_krause_1980
Priority: NOR    
Version: 3.5.0   
Target Milestone: ---   
Platform: Ubuntu   
OS: Linux   
Latest Commit: Version Fixed In: 7.1.0
Sentry Crash Report:

Description C Doe 2016-05-27 19:20:24 UTC
When writing metadata "to XMP sidecar only", digikam also updates the ctime of the media file, even though nothing is (supposed to be) written to the media file, and even though "Update file timestamp when metadata is saved" is NOT selected.

This causes backup programs to make unnecessary backups of unmodified media files, and defeats the purpose of the "Write to XMP sidecar only" feature.  And it seems it would be inconsistent with the expected behavior for the checkbox "Update file timestamp when metadata is saved" even if one is not using the XMP sidecar feature.

Reproducible: Always
Comment 1 caulier.gilles 2016-07-06 19:56:15 UTC
This file still valid using last digiKam 5.0.0 ?

Gilles Caulier
Comment 2 caulier.gilles 2016-11-25 14:39:39 UTC
What's about this file using digiKam AppImage bundle 5.4.0 pre release given at this url :

https://drive.google.com/drive/folders/0BzeiVr-byqt5Y0tIRWVWelRJenM

Gilles Caulier
Comment 3 Paul Krause 2020-07-15 17:18:54 UTC
I can confirm it still appears with "digikam-7.0.0-rc-x86-64.appimage" and various other versions.

Checking the source code, output of digikam, and system calls, it seems to me that core/libs/metadataengine/engine/metaengine_p.cpp copies and restores the mtime even when "Write to XMP sidecar only" is selected.
Replacing the line 454
if (!updateFileTimeStamp)
with
if (!updateFileTimeStamp && (metadataWritingMode != WRITE_TO_SIDECAR_ONLY))
would fix this.
This would not cover the case of WRITE_TO_SIDECAR_ONLY_FOR_READ_ONLY_FILES!
Comment 4 Maik Qualmann 2020-07-15 18:28:26 UTC
I cannot confirm the problem. If I start from the original bug report, the metadata is only written in XMP sidecars. In this case, the original file is never changed. I tested that. Note that the feature you patch is used when writing metadata to files and sidecars. So the original bug report is definitely not reproducible.

Maik
Comment 5 Maik Qualmann 2020-07-16 05:44:49 UTC
Note: The modification date in the digiKam view for files with sidecars not only comes from the image, but also from the sidecar. So always the latest change date. We use this trick to detect external changes to the sidecar. So you have to use a file manager to look at the file's modification date to see if it has changed when writing metadata.

Maik
Comment 6 Paul Krause 2020-07-16 08:26:12 UTC
Dear Maik,

What you say is (nearly completely) right.
But, it seems there is a misunderstanding between the modification time (mtime in Linux terms) and the ctime mentioned in the original report.
I provide additional info, including STEPS TO REPRODUCE below. If you are not on Linux, the call to "stat" might be impossible or needless.





STEPS TO REPRODUCE
1. Run: export QT_LOGGING_RULES="digikam*=true"; digikam 
2. Settings -> uncheck "Update file modification timestamp when files are modified"
3. Settings -> check "Write to sidecar files" and select "Write to XMP sidecar only"
4. Note ctime and mtime. On Linux, I use: stat --format="mtime:%y     ctime:%z" image.jpg
5. Add tag to a file, e.g. "Tag" to "image.jpg".
6. Perform a synchronization if "lazy synchronization" is activated.
7. Note the new file times.


OBSERVED RESULT
mtime of the file is the same as before.
The ctime is changed.
Output:
digikam.general: Writing tags
digikam.general: -------------------------- New Keywords ("Tag")
digikam.metaengine: MetaEngine::metadataWritingMode 1
digikam.metaengine: Will write XMP sidecar for file "image.jpg.xmp"
digikam.metaengine: wroteComment:  false
digikam.metaengine: wroteEXIF:  true
digikam.metaengine: wroteIPTC:  true
digikam.metaengine: wroteXMP:  true
digikam.metaengine: File time stamp restored
digikam.metaengine: Metadata for file "image.jpg" written to XMP sidecar.


EXPECTED RESULT
"digikam.metaengine: File time stamp restored" is not performed.
Both mtime and ctime, and the inode as whole, are completely untouched.


ADDITIONAL INFORMATION
The ctime might only exist on Linux (or Unix) filesystems, or have a different meaning on Windows.
It is updated, e.g., whenever the modification time is changed.
The function "saveOperations" does this, as a side effect, in line 498 by writing the old value of the modification time to the filesystem.
I'm not an expert on these times, please refer to, e.g., https://www.quora.com/What-is-the-difference-between-mtime-atime-and-ctime, if you are neither and do not believe me.

I admit, I neither ran a debugger nor looked at the source code too serious, except core/libs/metadataengine/engine/metaengine_p*.
Please correct me if I'm wrong, the string "File time stamp restored" appears nowhere in the source code, except in the function "saveOperations", specifically on line 503 and non-reusable. It is outputted for me, thus I conclude this function is called, even if "Write to XMP sidecar only" is selected.

If this helps, I can provide further output of
export QT_LOGGING_RULES="digikam*=true"; strace -f -e "trace=%file" digikam
Comment 7 Maik Qualmann 2020-07-16 09:44:29 UTC
I'll take a closer look at ctime tonight. The fact is, when writing only in sidecars, there are no attempts to write to the original file. It is clear that you will see the message to restore the timestamp because this function also writes the sidecar. It is the same process for Exiv2. If the ctime should change, would Exiv2 theoretically have to do this, perhaps to synchronize the access rights between the sidecar and the original file?

Maik
Comment 8 Paul Krause 2020-07-16 18:01:24 UTC
Thanks.
Please have a look at the "if (!updateFileTimeStamp)" block of the "saveOperations" function.
image->writeMetadata() modifies the sidecar file. The original file, including its mtime (modification time), are thus never changed.
However, the variable filePath points to the original file. The call to utime (or Windows equivalent) unnecessarily sets the mtime (modification time) and atime (access time) of the original file, and automatically the ctime too.



Regarding the access rights and exiv2, I think, yes the ctime would change, but Exiv2 would not "have to do this".
However, I cannot see a change of access rights in the strace output nor on the files. Does a synchronization should happen?

The technical precise answer is that access rights can be equal, and can be compared, independently from the ctimes of the files.
The ctime (time of last status change) cannot be manipulated directly.
But, setting the access rights on a file, the Linux kernel automatically updates the ctime of the file too.
Synchronizing, unequal, access rights thus does not has to, but also cannot avoid, modifying the ctime of at least one of the files.
Comment 9 Maik Qualmann 2020-07-16 18:57:45 UTC
Git commit e49682c67be4e8a68603d6876a4a7b67023975fa by Maik Qualmann.
Committed on 16/07/2020 at 18:54.
Pushed by mqualmann into branch 'master'.

fix ctime change when write to sidecar only
FIXED-IN: 7.1.0

M  +1    -0    NEWS
M  +20   -12   core/libs/metadataengine/engine/metaengine_p.cpp

https://invent.kde.org/graphics/digikam/commit/e49682c67be4e8a68603d6876a4a7b67023975fa