GNOME Bugzilla – Bug 606497
Eog handles symbolic links as if they are files
Last modified: 2021-06-19 08:48:00 UTC
Starting situation: /path/link.jpg --symbolic link to--> /path/subpath/001.jpg The link is opened in eog. The image is edited in some way (flipped for example). The image is saved. Result: /path/link.jpg is now the edited image. /path/subpath/001.jpg hasn't changed. What happens when saving: 1) A file with a unique name is created in the directory containing the link: /path/.goutputstream-7FHH3U 2) The new file is renamed to the name of the link: /path/.goutputstream-7FHH3U --> /path/link.jpg. Behavior I expected: 1) Create a new file with a unique name in the directory where the actual file exists. 2) Unlinking the actual file and renaming the new file to the name of the actual file.
This happens because eog uses g_file_move() instead of g_file_replace() + g_output_stream_write(). The latter is the method used by applications like gedit, and it follows symlinks recursively. The least-change fix for this is to keep following symlinks till we get to the regular file, and move on top of that file, specifically: tmp_file_move_to_uri() in src/eog-image.c .
g_file_replace() appears to be not exactly unproblematic in its current form (see bug 602412).
It seems a problem with glib. Test this code: #include <glib.h> #include <gio/gio.h> #include <stdio.h> int main(int argc, char **argv) { GFile *file = g_file_new_for_path(argv[1]); GFileType type = g_file_query_file_type(file, G_FILE_QUERY_INFO_NONE, NULL); switch (type) { case G_FILE_TYPE_UNKNOWN: printf("Type unknown: %d\n", type); break; case G_FILE_TYPE_REGULAR: printf("Type regular: %d\n", type); break; case G_FILE_TYPE_DIRECTORY: printf("Type directory: %d\n", type); break; case G_FILE_TYPE_SYMBOLIC_LINK: printf("Type link: %d\n", type); break; case G_FILE_TYPE_SPECIAL: printf("Type special: %d\n", type); break; case G_FILE_TYPE_SHORTCUT: printf("Type shortcut: %d\n", type); break; case G_FILE_TYPE_MOUNTABLE: printf("Type mountable: %d\n", type); break; } g_object_unref(file); return 0; } For links the output is always "Type regular: 1" Any ideas?
No, it works correctly. The trick is that g_file_query_file_type uses g_file_query_info() and thus follows symlinks by default (and so will return G_FILE_TYPE_REGULAR). If you want info on the symlink you need to add the G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS flag. However, it seems if you're using g_file_query_info() without the NOFOLLOW flag you can query the is-symlink attribute and will still get the information that you're looking at a symlink.
Sorry, my bad. Would it be really bad if we test the file type before save? We can use g_file_query_file_type to check type and realpath to get the path if file is a link
Created attachment 276436 [details] [review] Patch using g_file_query_file_type and realpath This patch use realpath and check file type using g_file_query_file_type. It is only an idea, I want to know your opinion
I am not sure whether it is save to assume that a file being a G_FILE_TYPE_SYMBOLIC_LINK is a local symlink which is resolvable by realpath. Some gvfs module might have an idea of a remote symlink. Checking the output of g_file_get_path should fix that. You should not replace priv->file with the resolved symlink. This would also display the resolved file name and path in the UI which could be a bit irritating to the user. Also do the detection in the tmp_file_move_to_uri function as proposed by Nirbeek Chauhan to keep things together. There'll be also some error handling necessary. It might be a good idea to wrap this realpath usage in an #ifdef block that verifies that the called implementation should be based on the POSIX-2008 definition, as only that one behaves correctly with NULL for the second parameter. And at this point it might just be easier to use g_file_replace with the workaround implemented by gedit than trying to use realpath safely.
Created attachment 289932 [details] [review] Patch using g_file_query_info Maybe this could be a good approach
GNOME is going to shut down bugzilla.gnome.org in favor of gitlab.gnome.org. As part of that, we are mass-closing older open tickets in bugzilla.gnome.org which have not seen updates for a longer time (resources are unfortunately quite limited so not every ticket can get handled). If you can still reproduce the situation described in this ticket in a recent and supported software version, then please follow https://wiki.gnome.org/GettingInTouch/BugReportingGuidelines and create a new ticket at https://gitlab.gnome.org/GNOME/eog/-/issues/ Thank you for your understanding and your help.