After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 737302 - Rename files twice when renaming files to avoid case-insensitive filesystem issues
Rename files twice when renaming files to avoid case-insensitive filesystem i...
Status: RESOLVED FIXED
Product: easytag
Classification: Other
Component: general
2.2.x
Other All
: Normal enhancement
: 2.2
Assigned To: EasyTAG maintainer(s)
EasyTAG maintainer(s)
Depends on:
Blocks:
 
 
Reported: 2014-09-24 23:02 UTC by J.B. Nicholson
Modified: 2015-05-09 08:02 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description J.B. Nicholson 2014-09-24 23:02:37 UTC
Files are sometimes stored on case-insensitive filesystems where files like "01 - Foobar.flac" and "01 - foobar.flac" are considered to be the same file (for example, network filesystems mounted as if they were local). On case-insensitive filesystems a rename from one filename to the other (where only the case changes) will fail.

To avoid this problem EasyTag could rename the file twice: first, rename the source file to a temporary filename, and then rename the temporary filename to the final destination name. An example would be: "01 - Foobar.flac" becomes "temporaryfilename" which then becomes "01 - foobar.flac". It would work best if the temporary filename were conservatively chosen from US English alphanumeric characters.
Comment 1 David King 2014-09-25 17:23:29 UTC
Thanks for the bug report. EasyTAG used to rename with an intermediate temporary file, but this changed in 2.1.9. I just added a workaround which uses a temporary file as a rename target if the rename operation fails because the destination already exists. I pushed the workaround to the master and easytag-2-2 branches, as b86a305e841d4ee1dd5bc61d15ac5dcdb88e192c and 656946c80805acc39c3102c1dff480658064bb8c.
Comment 2 J.B. Nicholson 2014-12-05 03:32:35 UTC
Was this fix supposed to be in the 2.3.2 release? I'm not seeing the fix for this in the 2.3.2 release (I'm seeing the same behavior I described in comment 0) but it's entirely possible I just need to be more patient to see the workaround you pushed in a later version.
Comment 3 David King 2014-12-05 11:45:03 UTC
The fix was in the 2.3.1 (and 2.2.4) release. After testing again, it works for me on a VFAT device (and I verified that the file-already-exists code was executed). If it does not work for you, I can probably split the code out into a test, which should make it easier to run.
Comment 4 J.B. Nicholson 2014-12-27 07:13:16 UTC
Thanks for this (and all your other work on EasyTAG!), I appreciate the effort. It might be helpful for me to see the test.

In case this matters: Here's what I'm doing with 2.3.2 on a GNU/Linux system connected via SMB to a case-insensitive shared folder. I've soft-linked the mounted folder to /home/jbn/music-admin. On the remote system there is "Various/The Disco Box/" which has a number of FLAC files:

1. Open EasyTAG on "/home/jbn/music-admin/Various/The Disco Box/" and select "13 - Kool & The Gang - Get Down On It.flac".
2. Change the artist field to "Kool & the Gang" (note the case change on "the") and set the change. The artist name changes in the artist column.
3. Open the Tag and Filename Scan panel and pick the "%n - %a - %t" pattern. Click "Scan Files" which sets the new filename as "13 - Kool & the Gang - Get Down On It.flac".
4. Click save in the toolbar to commit the changes.

I get the following "Rename File Error":
======begin========
Cannot rename file ‘/home/jbn/music-admin/Various/The Disco Box/13 - Kool & The Gang - Get Down On It.flac’ to ‘/home/jbn/music-admin/Various/The Disco Box/13 - Kool & the Gang - Get Down On It.flac’

Target file exists
======end==========

To work around this I append an "x" to the pattern in the Tag and Filename Scan panel (my pattern is now "%n - %a - %tx"), click "Scan Files" as in step 3, then resave the file. Then the new filename works without error. Then I can remove the trailing "x", redo steps 3 and 4 as listed above and I end up with the filename I want.
Comment 5 David King 2014-12-27 19:09:25 UTC
This case should be handled by et_rename_file(), which catches the error of a file existing by renaming to a temporary file and then renaming to the new filename. The code relies on a move operation being atomic (this should be the case on POSIX systems, and with the ReplaceFile() call on Windows, but I do not know if the local GFile implementation calls that function), but should be relatively robust, and only returns an error that the target file exists after first attempting to move the file to an intermediate temporary file.

Are you sure that the destination file does not exist? Is the SMB share backed by a Windows or Linux machine? Do you know how it is mounted, such as using the kernel CIFS driver, or an alternative userspace implementation (the easiest way to check is probably if it shows up in "mount or "gvfs-mount --list" output)?

I split out the code and wrote a test, which should work fine on both case-sensitive and case-insensitive filesystems:

https://git.gnome.org/browse/easytag/log/?h=wip/case-insensitive-rename

I can run this test successfully on both a case-sensitive filesystem (ext4) and a case-insensitive filesystem (VFAT). I do not have a SMB share to test with, unfortunately. You can run the test yourself by checking out the branch (clone the repository and then "git checkout wip/case-insensitive-rename", followed by the usual "./autogen.sh" and "make"), then running the tests with "make check". To run the test on a filesystem of your choice, set the TMPDIR environment variable when running it, such as with:

TMPDIR=/home/jbn/music-admin tests/test-misc

Bear in mind that you may get some temporary files left behind if the test fails (named "EasyTAG-test*").
Comment 6 David King 2015-05-09 08:02:45 UTC
The test was included with the recent 2.3.6 release, so it should be easy to verify the results if you build EasyTAG manually (with the "make check" instructions as above, once you have run "./configure").