xaizek / vifm (License: GPLv2+) (since 2018-12-07)
Vifm is a file manager with curses interface, which provides Vi[m]-like environment for managing objects within file systems, extended with some useful ideas from mutt.
Commit 5782270ada10ec2d93ab773cae4ab4e9b31a40f3

Fallback to fast content type in glib mime type detection
to determine content type glib checks xdg mime info database for entries
matching file extension. in simplest case there is a single match which
becomes file's content type. there are cases however when multiple
matches are found ie `*.png` files match both `PNG image (image/png)` as
well as `Animated PNG image (image/apng)`:

https://gitlab.freedesktop.org/xdg/shared-mime-info/-/blob/2.4/data/freedesktop.org.xml.in#L5513-5535

in order to decide between multple choices glib tries to match magic
bytes if file data is available. for local files (implementation
provided by glib) data is usually readily available and selection
mechanism works fine. even if for some reason data cannot be obtained
(no real path to file is provided) one of the multiple choices is
picked. however remote files (implementation provided by gvfs) end up
without `standard::content-type` leading to vfim crash:

https://gitlab.gnome.org/GNOME/gvfs/-/blob/1.58.0/daemon/gvfsbackendsmb.c#L1542-1543

Mismatch between glib and gvfs behavior was already raised upstream:

https://gitlab.gnome.org/GNOME/gvfs/-/issues/822

in the meantime however let's introduce two improvements:

1. don't crash if for whatever reason content type is missing
2. fallback to `standard::fast-content-type` if `standard::content-type`
is missing as both glib and gvfs provide it

Fixes #1114
Author: Jan Palus
Author date (UTC): 2025-11-20 23:44
Committer name: Jan Palus
Committer date (UTC): 2025-11-20 23:44
Parent(s): 8cbeba4398374abc0182676e76ee843c82a56a79
Signing key: AF176E5122D88062
Tree: 41a02fcc2e6566ba9d88a15f45c547c6e5e4979c
File Lines added Lines deleted
configure.ac 2 1
src/int/file_magic.c 19 2
File configure.ac changed (mode: 100644) (index 227d9eead..5128bc77f)
... ... if test "$use_glib" = "yes"; then
680 680 LIBS="$LIBS $(pkg-config --libs glib-2.0 gio-2.0)" LIBS="$LIBS $(pkg-config --libs glib-2.0 gio-2.0)"
681 681 AC_CHECK_HEADER([gio/gio.h], [], [AC_MSG_ERROR([gio/gio.h header not found.])], [[#include <gio/gio.h>]]) AC_CHECK_HEADER([gio/gio.h], [], [AC_MSG_ERROR([gio/gio.h header not found.])], [[#include <gio/gio.h>]])
682 682 AC_CHECK_HEADER([glib.h], [], [AC_MSG_ERROR([glib.h header not found.])], [[#include <glib.h>]]) AC_CHECK_HEADER([glib.h], [], [AC_MSG_ERROR([glib.h header not found.])], [[#include <glib.h>]])
683 AC_CHECK_FUNC([g_file_info_get_content_type], [], [AC_MSG_ERROR([g_file_info_get_content_type() function not found.])])
683 AC_CHECK_FUNC([g_file_info_has_attribute], [], [AC_MSG_ERROR([g_file_info_has_attribute() function not found.])])
684 AC_CHECK_FUNC([g_file_info_get_attribute_string], [], [AC_MSG_ERROR([g_file_info_get_attribute_string() function not found.])])
684 685 AC_CHECK_FUNC([g_file_new_for_path], [], [AC_MSG_ERROR([g_file_new_for_path() function not found.])]) AC_CHECK_FUNC([g_file_new_for_path], [], [AC_MSG_ERROR([g_file_new_for_path() function not found.])])
685 686 AC_CHECK_FUNC([g_file_query_info], [], [AC_MSG_ERROR([g_file_query_info() function not found.])]) AC_CHECK_FUNC([g_file_query_info], [], [AC_MSG_ERROR([g_file_query_info() function not found.])])
686 687 AC_CHECK_FUNC([g_object_unref], [], [AC_MSG_ERROR([g_object_unref() function not found.])]) AC_CHECK_FUNC([g_object_unref], [], [AC_MSG_ERROR([g_object_unref() function not found.])])
File src/int/file_magic.c changed (mode: 100644) (index 5aff3ac36..37e7b8738)
... ... get_gtk_mimetype(const char filename[], char buf[], size_t buf_sz)
180 180 #ifdef HAVE_GLIB #ifdef HAVE_GLIB
181 181 GFile *file; GFile *file;
182 182 GFileInfo *info; GFileInfo *info;
183 int result;
184 static const char *attrs[] = {
185 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
186 G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE,
187 NULL
188 };
189 const char **attr;
183 190
184 191 file = g_file_new_for_path(filename); file = g_file_new_for_path(filename);
185 192 info = g_file_query_info(file, "standard::", G_FILE_QUERY_INFO_NONE, NULL, info = g_file_query_info(file, "standard::", G_FILE_QUERY_INFO_NONE, NULL,
 
... ... get_gtk_mimetype(const char filename[], char buf[], size_t buf_sz)
190 197 return -1; return -1;
191 198 } }
192 199
193 copy_str(buf, buf_sz, g_file_info_get_content_type(info));
200 result = -1;
201 for(attr = attrs; *attr != NULL; ++attr)
202 {
203 if(g_file_info_has_attribute(info, *attr))
204 {
205 copy_str(buf, buf_sz, g_file_info_get_attribute_string(info, *attr));
206 result = 0;
207 break;
208 }
209 }
210
194 211 g_object_unref(info); g_object_unref(info);
195 212 g_object_unref(file); g_object_unref(file);
196 return 0;
213 return result;
197 214 #else /* #ifdef HAVE_GLIB */ #else /* #ifdef HAVE_GLIB */
198 215 return -1; return -1;
199 216 #endif /* #ifdef HAVE_GLIB */ #endif /* #ifdef HAVE_GLIB */
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/vifm

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/vifm

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master