Implement this function by moving bits from glocalfileinfo.c
2008-02-21 David Zeuthen <davidz@redhat.com>
* glocalfileinfo.c: (_g_local_file_info_get):
* gcontenttype.c:
(g_content_type_get_icon): Implement this function by
moving bits from glocalfileinfo.c
(g_content_type_get_description): Unalias before getting
description (#517687)
* gfile.c: (g_file_class_init),
(g_file_query_filesystem_info_async),
(g_file_query_filesystem_info_finish),
(query_filesystem_info_data_free),
(query_filesystem_info_async_thread),
(g_file_real_query_filesystem_info_async),
(g_file_real_query_filesystem_info_finish):
* gfile.h: Implement async version of
g_file_query_filesystem_info()
* gfileinfo.h: Add new attributes for filesystem::use-preview
* gio.symbols: Update
* gthemedicon.c: (g_themed_icon_append_name):
* gthemedicon.h: Add new new convenience function.
* gunionvolumemonitor.c: (g_union_volume_monitor_dispose),
(get_mounts), (get_volumes), (get_connected_drives),
(get_volume_for_uuid), (get_mount_for_uuid),
(g_union_volume_monitor_init), (populate_union_monitor),
(g_volume_monitor_get), (_g_mount_get_for_mount_path),
(g_volume_monitor_adopt_orphan_mount):
* gvolumemonitor.c:
* gvolumemonitor.h: Use recursive locks so it's safe for volume
monitor implementations to call into the main volume monitor. Also
separate object initialization and volume monitor initialization
such that non-native volume monitors can properly adopt their
mounts away.
svn path=/trunk/; revision=6550
2008-02-21 13:35:05 +01:00
|
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
/* GIO - GLib Input, Output and Streaming Library
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2006-2007 Red Hat, Inc.
|
|
|
|
|
*
|
2022-05-18 10:12:45 +02:00
|
|
|
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
|
*
|
2007-11-26 17:13:05 +01:00
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
* License as published by the Free Software Foundation; either
|
2017-05-27 18:21:30 +02:00
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2007-11-26 17:13:05 +01:00
|
|
|
|
*
|
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Lesser General
|
2014-01-23 12:58:29 +01:00
|
|
|
|
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
2007-11-26 17:13:05 +01:00
|
|
|
|
*
|
|
|
|
|
* Author: Alexander Larsson <alexl@redhat.com>
|
|
|
|
|
*/
|
|
|
|
|
|
2008-06-22 17:10:51 +02:00
|
|
|
|
#include "config.h"
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
Require POSIX.1 (1990) compliance on unix
Assume unix platforms support the original POSIX.1 standard.
Specifically, assume that if G_OS_UNIX, then we have chown(),
getcwd(), getgrgid(), getpwuid(), link(), <grp.h>, <pwd.h>,
<sys/types.h>, <sys/uio.h>, <sys/wait.h>, and <unistd.h>.
Additionally, since all versions of Windows that we care about also
have <sys/types.h>, we can remove HAVE_SYS_TYPES_H checks everywhere.
Also remove one include of <sys/times.h>, and the corresponding
configure check, since the include is not currently needed (and may
always have just been a typo for <sys/time.h>).
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:59 +02:00
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#ifdef HAVE_SYS_TIME_H
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#include <sys/time.h>
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <errno.h>
|
Require POSIX.1 (1990) compliance on unix
Assume unix platforms support the original POSIX.1 standard.
Specifically, assume that if G_OS_UNIX, then we have chown(),
getcwd(), getgrgid(), getpwuid(), link(), <grp.h>, <pwd.h>,
<sys/types.h>, <sys/uio.h>, <sys/wait.h>, and <unistd.h>.
Additionally, since all versions of Windows that we care about also
have <sys/types.h>, we can remove HAVE_SYS_TYPES_H checks everywhere.
Also remove one include of <sys/times.h>, and the corresponding
configure check, since the include is not currently needed (and may
always have just been a typo for <sys/time.h>).
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:59 +02:00
|
|
|
|
#ifdef G_OS_UNIX
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#include <grp.h>
|
|
|
|
|
#include <pwd.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_SELINUX
|
|
|
|
|
#include <selinux/selinux.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_XATTR
|
|
|
|
|
|
|
|
|
|
#if defined HAVE_SYS_XATTR_H
|
|
|
|
|
#include <sys/xattr.h>
|
|
|
|
|
#elif defined HAVE_ATTR_XATTR_H
|
|
|
|
|
#include <attr/xattr.h>
|
|
|
|
|
#else
|
|
|
|
|
#error "Neither <sys/xattr.h> nor <attr/xattr.h> is present but extended attribute support is enabled."
|
|
|
|
|
#endif /* defined HAVE_SYS_XATTR_H || HAVE_ATTR_XATTR_H */
|
|
|
|
|
|
|
|
|
|
#endif /* HAVE_XATTR */
|
|
|
|
|
|
|
|
|
|
#include <glib/gstdio.h>
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#include <glib/gstdioprivate.h>
|
2007-12-14 16:56:56 +01:00
|
|
|
|
#include <gfileattribute-priv.h>
|
2009-06-29 14:13:14 +02:00
|
|
|
|
#include <gfileinfo-priv.h>
|
2009-06-18 09:05:27 +02:00
|
|
|
|
#include <gvfs.h>
|
2007-12-04 17:33:24 +01:00
|
|
|
|
|
Replace #ifdef HAVE_UNISTD_H checks with #ifdef G_OS_UNIX
In Windows development environments that have it, <unistd.h> is mostly
just a wrapper around several other native headers (in particular,
<io.h>, which contains read(), close(), etc, and <process.h>, which
contains getpid()). But given that some Windows dev environments don't
have <unistd.h>, everything that uses those functions on Windows
already needed to include the correct Windows header as well, and so
there is never any point to including <unistd.h> on Windows.
Also, remove some <unistd.h> includes (and a few others) that were
unnecessary even on unix.
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:04:00 +02:00
|
|
|
|
#ifdef G_OS_UNIX
|
|
|
|
|
#include <unistd.h>
|
2013-01-25 18:05:26 +01:00
|
|
|
|
#include "glib-unix.h"
|
2012-11-29 00:50:55 +01:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#include "glib-private.h"
|
|
|
|
|
|
2013-10-11 12:22:31 +02:00
|
|
|
|
#include "thumbnail-verify.h"
|
|
|
|
|
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#include <io.h>
|
|
|
|
|
#ifndef W_OK
|
|
|
|
|
#define W_OK 2
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef R_OK
|
|
|
|
|
#define R_OK 4
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef X_OK
|
|
|
|
|
#define X_OK 0 /* not really */
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef S_ISREG
|
|
|
|
|
#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef S_ISDIR
|
|
|
|
|
#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef S_IXUSR
|
|
|
|
|
#define S_IXUSR _S_IEXEC
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-02-19 16:22:22 +01:00
|
|
|
|
#ifndef O_CLOEXEC
|
|
|
|
|
#define O_CLOEXEC 0
|
|
|
|
|
#endif
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#include "glocalfileinfo.h"
|
|
|
|
|
#include "gioerror.h"
|
|
|
|
|
#include "gthemedicon.h"
|
|
|
|
|
#include "gcontenttypeprivate.h"
|
Replace #ifdef HAVE_UNISTD_H checks with #ifdef G_OS_UNIX
In Windows development environments that have it, <unistd.h> is mostly
just a wrapper around several other native headers (in particular,
<io.h>, which contains read(), close(), etc, and <process.h>, which
contains getpid()). But given that some Windows dev environments don't
have <unistd.h>, everything that uses those functions on Windows
already needed to include the correct Windows header as well, and so
there is never any point to including <unistd.h> on Windows.
Also, remove some <unistd.h> includes (and a few others) that were
unnecessary even on unix.
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:04:00 +02:00
|
|
|
|
#include "glibintl.h"
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2007-11-28 13:39:07 +01:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
struct ThumbMD5Context {
|
|
|
|
|
guint32 buf[4];
|
|
|
|
|
guint32 bits[2];
|
|
|
|
|
unsigned char in[64];
|
|
|
|
|
};
|
2008-03-12 19:33:59 +01:00
|
|
|
|
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#ifndef G_OS_WIN32
|
2008-03-12 19:33:59 +01:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
typedef struct {
|
|
|
|
|
char *user_name;
|
|
|
|
|
char *real_name;
|
|
|
|
|
} UidData;
|
2008-03-12 19:33:59 +01:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
G_LOCK_DEFINE_STATIC (uid_cache);
|
|
|
|
|
static GHashTable *uid_cache = NULL;
|
|
|
|
|
|
|
|
|
|
G_LOCK_DEFINE_STATIC (gid_cache);
|
|
|
|
|
static GHashTable *gid_cache = NULL;
|
|
|
|
|
|
2008-03-12 19:33:59 +01:00
|
|
|
|
#endif /* !G_OS_WIN32 */
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
char *
|
2008-03-12 19:33:59 +01:00
|
|
|
|
_g_local_file_info_create_etag (GLocalFileStat *statbuf)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2021-07-02 15:10:44 +02:00
|
|
|
|
glong sec, usec, nsec;
|
2010-11-01 22:04:31 +01:00
|
|
|
|
|
2020-08-14 16:52:03 +02:00
|
|
|
|
g_return_val_if_fail (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_MTIME), NULL);
|
|
|
|
|
|
2020-08-14 15:46:14 +02:00
|
|
|
|
sec = _g_stat_mtime (statbuf);
|
|
|
|
|
usec = _g_stat_mtim_nsec (statbuf) / 1000;
|
2021-07-02 15:10:44 +02:00
|
|
|
|
nsec = _g_stat_mtim_nsec (statbuf);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2021-07-02 15:10:44 +02:00
|
|
|
|
return g_strdup_printf ("%lu:%lu:%lu", sec, usec, nsec);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
2008-03-12 19:33:59 +01:00
|
|
|
|
_g_local_file_info_create_file_id (GLocalFileStat *statbuf)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
guint64 ino;
|
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
ino = statbuf->file_index;
|
|
|
|
|
#else
|
2020-08-14 15:46:14 +02:00
|
|
|
|
ino = _g_stat_ino (statbuf);
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return g_strdup_printf ("l%" G_GUINT64_FORMAT ":%" G_GUINT64_FORMAT,
|
2020-08-14 15:46:14 +02:00
|
|
|
|
(guint64) _g_stat_dev (statbuf),
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
ino);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
2008-03-12 19:33:59 +01:00
|
|
|
|
_g_local_file_info_create_fs_id (GLocalFileStat *statbuf)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
return g_strdup_printf ("l%" G_GUINT64_FORMAT,
|
2020-08-14 15:46:14 +02:00
|
|
|
|
(guint64) _g_stat_dev (statbuf));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#if defined (S_ISLNK) || defined (G_OS_WIN32)
|
2008-03-12 19:33:59 +01:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
static gchar *
|
|
|
|
|
read_link (const gchar *full_name)
|
|
|
|
|
{
|
W32: significant symlink code changes
Put the core readlink() code into a separate
_g_win32_readlink_handle_raw() function that takes a file handle,
can optionally ensure NUL-terminatedness of its output
(for cases where we need a NUL-terminator and do *not* need
to get the exact contents of the symlink as it is stored in FS)
and can either fill a caller-provided buffer *or* allocate
its own buffer, and can also read the reparse tag.
Put the rest of readlink() code into separate
functions that do UTF-16<->UTF-8, strip inconvenient prefix
and open/close the symlink file handle as needed.
Split _g_win32_stat_utf16_no_trailing_slashes() into
two functions - the one that takes a filename and the one
that takes a file descriptor. The part of these functions
that would have been duplicate is now split into the
_g_win32_fill_privatestat() funcion.
Add more comments explaining what each function does.
Only g_win32_readlink_utf8(), which is callable from outside
via private function interface, gets a real doc-comment,
the rest get normal, non-doc comments.
Change all callers to use the new version of the private
g_win32_readlink_utf8() function, which can now NUL-terminate
and allocate on demand - no need to call it in a loop.
Also, the new code should correctly get reparse tag when the
caller does fstat() on a symlink. Do note that this requires
the caller to get a FD for the symlink, not the target. Figuring
out how to do that is up to the caller.
Since symlink info (target path and reparse tag) are now always
read directly, via DeviceIoControl(), we don't need to use
FindFirstFileW() anymore.
2018-08-24 11:16:46 +02:00
|
|
|
|
#if defined (HAVE_READLINK)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
gchar *buffer;
|
2020-11-17 21:33:48 +01:00
|
|
|
|
gsize size;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
size = 256;
|
|
|
|
|
buffer = g_malloc (size);
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
2020-11-17 21:33:48 +01:00
|
|
|
|
gssize read_size;
|
W32: significant symlink code changes
Put the core readlink() code into a separate
_g_win32_readlink_handle_raw() function that takes a file handle,
can optionally ensure NUL-terminatedness of its output
(for cases where we need a NUL-terminator and do *not* need
to get the exact contents of the symlink as it is stored in FS)
and can either fill a caller-provided buffer *or* allocate
its own buffer, and can also read the reparse tag.
Put the rest of readlink() code into separate
functions that do UTF-16<->UTF-8, strip inconvenient prefix
and open/close the symlink file handle as needed.
Split _g_win32_stat_utf16_no_trailing_slashes() into
two functions - the one that takes a filename and the one
that takes a file descriptor. The part of these functions
that would have been duplicate is now split into the
_g_win32_fill_privatestat() funcion.
Add more comments explaining what each function does.
Only g_win32_readlink_utf8(), which is callable from outside
via private function interface, gets a real doc-comment,
the rest get normal, non-doc comments.
Change all callers to use the new version of the private
g_win32_readlink_utf8() function, which can now NUL-terminate
and allocate on demand - no need to call it in a loop.
Also, the new code should correctly get reparse tag when the
caller does fstat() on a symlink. Do note that this requires
the caller to get a FD for the symlink, not the target. Figuring
out how to do that is up to the caller.
Since symlink info (target path and reparse tag) are now always
read directly, via DeviceIoControl(), we don't need to use
FindFirstFileW() anymore.
2018-08-24 11:16:46 +02:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
read_size = readlink (full_name, buffer, size);
|
|
|
|
|
if (read_size < 0)
|
|
|
|
|
{
|
|
|
|
|
g_free (buffer);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-11-17 21:33:48 +01:00
|
|
|
|
if ((gsize) read_size < size)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
buffer[read_size] = 0;
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
size *= 2;
|
|
|
|
|
buffer = g_realloc (buffer, size);
|
|
|
|
|
}
|
W32: significant symlink code changes
Put the core readlink() code into a separate
_g_win32_readlink_handle_raw() function that takes a file handle,
can optionally ensure NUL-terminatedness of its output
(for cases where we need a NUL-terminator and do *not* need
to get the exact contents of the symlink as it is stored in FS)
and can either fill a caller-provided buffer *or* allocate
its own buffer, and can also read the reparse tag.
Put the rest of readlink() code into separate
functions that do UTF-16<->UTF-8, strip inconvenient prefix
and open/close the symlink file handle as needed.
Split _g_win32_stat_utf16_no_trailing_slashes() into
two functions - the one that takes a filename and the one
that takes a file descriptor. The part of these functions
that would have been duplicate is now split into the
_g_win32_fill_privatestat() funcion.
Add more comments explaining what each function does.
Only g_win32_readlink_utf8(), which is callable from outside
via private function interface, gets a real doc-comment,
the rest get normal, non-doc comments.
Change all callers to use the new version of the private
g_win32_readlink_utf8() function, which can now NUL-terminate
and allocate on demand - no need to call it in a loop.
Also, the new code should correctly get reparse tag when the
caller does fstat() on a symlink. Do note that this requires
the caller to get a FD for the symlink, not the target. Figuring
out how to do that is up to the caller.
Since symlink info (target path and reparse tag) are now always
read directly, via DeviceIoControl(), we don't need to use
FindFirstFileW() anymore.
2018-08-24 11:16:46 +02:00
|
|
|
|
#elif defined (G_OS_WIN32)
|
|
|
|
|
gchar *buffer;
|
|
|
|
|
int read_size;
|
|
|
|
|
|
|
|
|
|
read_size = GLIB_PRIVATE_CALL (g_win32_readlink_utf8) (full_name, NULL, 0, &buffer, TRUE);
|
|
|
|
|
if (read_size < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
else if (read_size == 0)
|
|
|
|
|
return strdup ("");
|
|
|
|
|
else
|
|
|
|
|
return buffer;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#else
|
|
|
|
|
return NULL;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#endif /* S_ISLNK || G_OS_WIN32 */
|
2008-03-12 19:33:59 +01:00
|
|
|
|
|
2008-10-15 05:37:56 +02:00
|
|
|
|
#ifdef HAVE_SELINUX
|
2007-11-26 17:13:05 +01:00
|
|
|
|
/* Get the SELinux security context */
|
|
|
|
|
static void
|
2007-11-30 06:11:25 +01:00
|
|
|
|
get_selinux_context (const char *path,
|
|
|
|
|
GFileInfo *info,
|
2007-11-26 17:13:05 +01:00
|
|
|
|
GFileAttributeMatcher *attribute_matcher,
|
2007-11-30 06:11:25 +01:00
|
|
|
|
gboolean follow_symlinks)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
char *context;
|
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (!_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (is_selinux_enabled ())
|
|
|
|
|
{
|
|
|
|
|
if (follow_symlinks)
|
|
|
|
|
{
|
|
|
|
|
if (lgetfilecon_raw (path, &context) < 0)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (getfilecon_raw (path, &context) < 0)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (context)
|
|
|
|
|
{
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT, context);
|
2008-01-03 10:01:00 +01:00
|
|
|
|
freecon (context);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-10-15 05:37:56 +02:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
#ifdef HAVE_XATTR
|
|
|
|
|
|
2007-12-03 11:23:03 +01:00
|
|
|
|
/* Wrappers to hide away differences between (Linux) getxattr/lgetxattr and
|
|
|
|
|
* (Mac) getxattr(..., XATTR_NOFOLLOW)
|
|
|
|
|
*/
|
|
|
|
|
#ifdef HAVE_XATTR_NOFOLLOW
|
|
|
|
|
#define g_fgetxattr(fd,name,value,size) fgetxattr(fd,name,value,size,0,0)
|
|
|
|
|
#define g_flistxattr(fd,name,size) flistxattr(fd,name,size,0)
|
|
|
|
|
#define g_setxattr(path,name,value,size) setxattr(path,name,value,size,0,0)
|
2022-07-26 09:58:32 +02:00
|
|
|
|
#define g_removexattr(path,name) removexattr(path,name,0)
|
2007-12-03 11:23:03 +01:00
|
|
|
|
#else
|
|
|
|
|
#define g_fgetxattr fgetxattr
|
|
|
|
|
#define g_flistxattr flistxattr
|
|
|
|
|
#define g_setxattr(path,name,value,size) setxattr(path,name,value,size,0)
|
2022-07-26 09:58:32 +02:00
|
|
|
|
#define g_removexattr(path,name) removexattr(path,name)
|
2007-12-03 11:23:03 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2017-10-10 13:59:14 +02:00
|
|
|
|
static gssize
|
2007-12-03 11:23:03 +01:00
|
|
|
|
g_getxattr (const char *path, const char *name, void *value, size_t size,
|
|
|
|
|
gboolean follow_symlinks)
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_XATTR_NOFOLLOW
|
|
|
|
|
return getxattr (path, name, value, size, 0, follow_symlinks ? 0 : XATTR_NOFOLLOW);
|
|
|
|
|
#else
|
|
|
|
|
if (follow_symlinks)
|
|
|
|
|
return getxattr (path, name, value, size);
|
|
|
|
|
else
|
|
|
|
|
return lgetxattr (path, name, value, size);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-10 13:59:14 +02:00
|
|
|
|
static gssize
|
2007-12-03 11:23:03 +01:00
|
|
|
|
g_listxattr(const char *path, char *namebuf, size_t size,
|
|
|
|
|
gboolean follow_symlinks)
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_XATTR_NOFOLLOW
|
|
|
|
|
return listxattr (path, namebuf, size, follow_symlinks ? 0 : XATTR_NOFOLLOW);
|
|
|
|
|
#else
|
|
|
|
|
if (follow_symlinks)
|
|
|
|
|
return listxattr (path, namebuf, size);
|
|
|
|
|
else
|
|
|
|
|
return llistxattr (path, namebuf, size);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
static gboolean
|
|
|
|
|
valid_char (char c)
|
|
|
|
|
{
|
|
|
|
|
return c >= 32 && c <= 126 && c != '\\';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
name_is_valid (const char *str)
|
|
|
|
|
{
|
|
|
|
|
while (*str)
|
|
|
|
|
{
|
|
|
|
|
if (!valid_char (*str++))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
2020-07-08 13:43:55 +02:00
|
|
|
|
hex_escape_buffer (const char *str,
|
|
|
|
|
size_t len,
|
2007-11-30 06:11:25 +01:00
|
|
|
|
gboolean *free_return)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2020-07-08 13:43:55 +02:00
|
|
|
|
size_t num_invalid, i;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
char *escaped_str, *p;
|
|
|
|
|
unsigned char c;
|
|
|
|
|
static char *hex_digits = "0123456789abcdef";
|
|
|
|
|
|
|
|
|
|
num_invalid = 0;
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!valid_char (str[i]))
|
|
|
|
|
num_invalid++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (num_invalid == 0)
|
|
|
|
|
{
|
|
|
|
|
*free_return = FALSE;
|
|
|
|
|
return (char *)str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
escaped_str = g_malloc (len + num_invalid*3 + 1);
|
|
|
|
|
|
|
|
|
|
p = escaped_str;
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
if (valid_char (str[i]))
|
|
|
|
|
*p++ = str[i];
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c = str[i];
|
|
|
|
|
*p++ = '\\';
|
|
|
|
|
*p++ = 'x';
|
|
|
|
|
*p++ = hex_digits[(c >> 4) & 0xf];
|
|
|
|
|
*p++ = hex_digits[c & 0xf];
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-09-07 09:12:06 +02:00
|
|
|
|
*p = 0;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
*free_return = TRUE;
|
|
|
|
|
return escaped_str;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-08 13:43:55 +02:00
|
|
|
|
static char *
|
|
|
|
|
hex_escape_string (const char *str,
|
|
|
|
|
gboolean *free_return)
|
|
|
|
|
{
|
|
|
|
|
return hex_escape_buffer (str, strlen (str), free_return);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
static char *
|
2007-11-30 06:11:25 +01:00
|
|
|
|
hex_unescape_string (const char *str,
|
|
|
|
|
int *out_len,
|
|
|
|
|
gboolean *free_return)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
char *unescaped_str, *p;
|
|
|
|
|
unsigned char c;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
len = strlen (str);
|
|
|
|
|
|
|
|
|
|
if (strchr (str, '\\') == NULL)
|
|
|
|
|
{
|
|
|
|
|
if (out_len)
|
|
|
|
|
*out_len = len;
|
|
|
|
|
*free_return = FALSE;
|
|
|
|
|
return (char *)str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unescaped_str = g_malloc (len + 1);
|
|
|
|
|
|
|
|
|
|
p = unescaped_str;
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
if (str[i] == '\\' &&
|
|
|
|
|
str[i+1] == 'x' &&
|
|
|
|
|
len - i >= 4)
|
|
|
|
|
{
|
|
|
|
|
c =
|
|
|
|
|
(g_ascii_xdigit_value (str[i+2]) << 4) |
|
|
|
|
|
g_ascii_xdigit_value (str[i+3]);
|
|
|
|
|
*p++ = c;
|
|
|
|
|
i += 3;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
*p++ = str[i];
|
|
|
|
|
}
|
|
|
|
|
if (out_len)
|
|
|
|
|
*out_len = p - unescaped_str;
|
2020-07-08 13:45:43 +02:00
|
|
|
|
*p++ = 0;
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
*free_return = TRUE;
|
|
|
|
|
return unescaped_str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2007-11-30 06:11:25 +01:00
|
|
|
|
escape_xattr (GFileInfo *info,
|
2007-11-26 17:13:05 +01:00
|
|
|
|
const char *gio_attr, /* gio attribute name */
|
|
|
|
|
const char *value, /* Is zero terminated */
|
2007-11-30 06:11:25 +01:00
|
|
|
|
size_t len /* not including zero termination */)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
char *escaped_val;
|
|
|
|
|
gboolean free_escaped_val;
|
|
|
|
|
|
2020-07-08 13:43:55 +02:00
|
|
|
|
escaped_val = hex_escape_buffer (value, len, &free_escaped_val);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
g_file_info_set_attribute_string (info, gio_attr, escaped_val);
|
|
|
|
|
|
|
|
|
|
if (free_escaped_val)
|
|
|
|
|
g_free (escaped_val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
get_one_xattr (const char *path,
|
2007-11-30 06:11:25 +01:00
|
|
|
|
GFileInfo *info,
|
2007-11-26 17:13:05 +01:00
|
|
|
|
const char *gio_attr,
|
|
|
|
|
const char *xattr,
|
2007-11-30 06:11:25 +01:00
|
|
|
|
gboolean follow_symlinks)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
char value[64];
|
|
|
|
|
char *value_p;
|
2017-10-10 13:59:14 +02:00
|
|
|
|
gssize len;
|
2017-07-31 12:30:55 +02:00
|
|
|
|
int errsv;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2007-12-03 11:23:03 +01:00
|
|
|
|
len = g_getxattr (path, xattr, value, sizeof (value)-1, follow_symlinks);
|
2017-07-31 12:30:55 +02:00
|
|
|
|
errsv = errno;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
value_p = NULL;
|
|
|
|
|
if (len >= 0)
|
|
|
|
|
value_p = value;
|
2017-07-31 12:30:55 +02:00
|
|
|
|
else if (len == -1 && errsv == ERANGE)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2007-12-03 11:23:03 +01:00
|
|
|
|
len = g_getxattr (path, xattr, NULL, 0, follow_symlinks);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (len < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
value_p = g_malloc (len+1);
|
|
|
|
|
|
2007-12-03 11:23:03 +01:00
|
|
|
|
len = g_getxattr (path, xattr, value_p, len, follow_symlinks);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (len < 0)
|
|
|
|
|
{
|
|
|
|
|
g_free (value_p);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Null terminate */
|
|
|
|
|
value_p[len] = 0;
|
|
|
|
|
|
|
|
|
|
escape_xattr (info, gio_attr, value_p, len);
|
|
|
|
|
|
|
|
|
|
if (value_p != value)
|
|
|
|
|
g_free (value_p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* defined HAVE_XATTR */
|
|
|
|
|
|
|
|
|
|
static void
|
2007-11-30 06:11:25 +01:00
|
|
|
|
get_xattrs (const char *path,
|
|
|
|
|
gboolean user,
|
|
|
|
|
GFileInfo *info,
|
2007-11-26 17:13:05 +01:00
|
|
|
|
GFileAttributeMatcher *matcher,
|
2007-11-30 06:11:25 +01:00
|
|
|
|
gboolean follow_symlinks)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_XATTR
|
|
|
|
|
gboolean all;
|
|
|
|
|
gsize list_size;
|
2017-10-10 13:59:14 +02:00
|
|
|
|
gssize list_res_size;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
size_t len;
|
|
|
|
|
char *list;
|
|
|
|
|
const char *attr, *attr2;
|
|
|
|
|
|
|
|
|
|
if (user)
|
|
|
|
|
all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr");
|
|
|
|
|
else
|
2008-01-03 10:01:00 +01:00
|
|
|
|
all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr-sys");
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (all)
|
|
|
|
|
{
|
2017-07-31 12:30:55 +02:00
|
|
|
|
int errsv;
|
|
|
|
|
|
2007-12-03 11:23:03 +01:00
|
|
|
|
list_res_size = g_listxattr (path, NULL, 0, follow_symlinks);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (list_res_size == -1 ||
|
|
|
|
|
list_res_size == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
list_size = list_res_size;
|
|
|
|
|
list = g_malloc (list_size);
|
|
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
|
2007-12-03 11:23:03 +01:00
|
|
|
|
list_res_size = g_listxattr (path, list, list_size, follow_symlinks);
|
2017-07-31 12:30:55 +02:00
|
|
|
|
errsv = errno;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2017-07-31 12:30:55 +02:00
|
|
|
|
if (list_res_size == -1 && errsv == ERANGE)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
list_size = list_size * 2;
|
|
|
|
|
list = g_realloc (list, list_size);
|
|
|
|
|
goto retry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (list_res_size == -1)
|
2019-10-30 16:35:15 +01:00
|
|
|
|
{
|
|
|
|
|
g_free (list);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
attr = list;
|
|
|
|
|
while (list_res_size > 0)
|
|
|
|
|
{
|
|
|
|
|
if ((user && g_str_has_prefix (attr, "user.")) ||
|
|
|
|
|
(!user && !g_str_has_prefix (attr, "user.")))
|
|
|
|
|
{
|
|
|
|
|
char *escaped_attr, *gio_attr;
|
|
|
|
|
gboolean free_escaped_attr;
|
|
|
|
|
|
|
|
|
|
if (user)
|
|
|
|
|
{
|
|
|
|
|
escaped_attr = hex_escape_string (attr + 5, &free_escaped_attr);
|
2007-12-12 16:50:45 +01:00
|
|
|
|
gio_attr = g_strconcat ("xattr::", escaped_attr, NULL);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
escaped_attr = hex_escape_string (attr, &free_escaped_attr);
|
2007-12-12 16:50:45 +01:00
|
|
|
|
gio_attr = g_strconcat ("xattr-sys::", escaped_attr, NULL);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (free_escaped_attr)
|
|
|
|
|
g_free (escaped_attr);
|
|
|
|
|
|
|
|
|
|
get_one_xattr (path, info, gio_attr, attr, follow_symlinks);
|
2009-01-31 21:06:02 +01:00
|
|
|
|
|
|
|
|
|
g_free (gio_attr);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = strlen (attr) + 1;
|
|
|
|
|
attr += len;
|
|
|
|
|
list_res_size -= len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_free (list);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while ((attr = g_file_attribute_matcher_enumerate_next (matcher)) != NULL)
|
|
|
|
|
{
|
|
|
|
|
char *unescaped_attribute, *a;
|
|
|
|
|
gboolean free_unescaped_attribute;
|
|
|
|
|
|
|
|
|
|
attr2 = strchr (attr, ':');
|
|
|
|
|
if (attr2)
|
|
|
|
|
{
|
2009-04-22 20:09:34 +02:00
|
|
|
|
attr2 += 2; /* Skip '::' */
|
2007-11-26 17:13:05 +01:00
|
|
|
|
unescaped_attribute = hex_unescape_string (attr2, NULL, &free_unescaped_attribute);
|
|
|
|
|
if (user)
|
|
|
|
|
a = g_strconcat ("user.", unescaped_attribute, NULL);
|
|
|
|
|
else
|
|
|
|
|
a = unescaped_attribute;
|
|
|
|
|
|
|
|
|
|
get_one_xattr (path, info, attr, a, follow_symlinks);
|
|
|
|
|
|
|
|
|
|
if (user)
|
|
|
|
|
g_free (a);
|
|
|
|
|
|
|
|
|
|
if (free_unescaped_attribute)
|
|
|
|
|
g_free (unescaped_attribute);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* defined HAVE_XATTR */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_XATTR
|
|
|
|
|
static void
|
2007-11-30 06:11:25 +01:00
|
|
|
|
get_one_xattr_from_fd (int fd,
|
|
|
|
|
GFileInfo *info,
|
2007-11-26 17:13:05 +01:00
|
|
|
|
const char *gio_attr,
|
|
|
|
|
const char *xattr)
|
|
|
|
|
{
|
|
|
|
|
char value[64];
|
|
|
|
|
char *value_p;
|
2017-10-10 13:59:14 +02:00
|
|
|
|
gssize len;
|
2017-07-31 12:30:55 +02:00
|
|
|
|
int errsv;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2008-01-21 15:02:19 +01:00
|
|
|
|
len = g_fgetxattr (fd, xattr, value, sizeof (value) - 1);
|
2017-07-31 12:30:55 +02:00
|
|
|
|
errsv = errno;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
value_p = NULL;
|
|
|
|
|
if (len >= 0)
|
|
|
|
|
value_p = value;
|
2017-07-31 12:30:55 +02:00
|
|
|
|
else if (len == -1 && errsv == ERANGE)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2007-12-03 11:23:03 +01:00
|
|
|
|
len = g_fgetxattr (fd, xattr, NULL, 0);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (len < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2008-01-21 15:02:19 +01:00
|
|
|
|
value_p = g_malloc (len + 1);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2007-12-03 11:23:03 +01:00
|
|
|
|
len = g_fgetxattr (fd, xattr, value_p, len);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (len < 0)
|
|
|
|
|
{
|
|
|
|
|
g_free (value_p);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Null terminate */
|
|
|
|
|
value_p[len] = 0;
|
|
|
|
|
|
|
|
|
|
escape_xattr (info, gio_attr, value_p, len);
|
|
|
|
|
|
|
|
|
|
if (value_p != value)
|
|
|
|
|
g_free (value_p);
|
|
|
|
|
}
|
|
|
|
|
#endif /* defined HAVE_XATTR */
|
|
|
|
|
|
|
|
|
|
static void
|
2007-11-30 06:11:25 +01:00
|
|
|
|
get_xattrs_from_fd (int fd,
|
|
|
|
|
gboolean user,
|
|
|
|
|
GFileInfo *info,
|
2007-11-26 17:13:05 +01:00
|
|
|
|
GFileAttributeMatcher *matcher)
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_XATTR
|
|
|
|
|
gboolean all;
|
|
|
|
|
gsize list_size;
|
2017-10-10 13:59:14 +02:00
|
|
|
|
gssize list_res_size;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
size_t len;
|
|
|
|
|
char *list;
|
|
|
|
|
const char *attr, *attr2;
|
|
|
|
|
|
|
|
|
|
if (user)
|
|
|
|
|
all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr");
|
|
|
|
|
else
|
2007-12-12 16:50:45 +01:00
|
|
|
|
all = g_file_attribute_matcher_enumerate_namespace (matcher, "xattr-sys");
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (all)
|
|
|
|
|
{
|
2017-07-31 12:30:55 +02:00
|
|
|
|
int errsv;
|
|
|
|
|
|
2007-12-03 11:23:03 +01:00
|
|
|
|
list_res_size = g_flistxattr (fd, NULL, 0);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (list_res_size == -1 ||
|
|
|
|
|
list_res_size == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
list_size = list_res_size;
|
|
|
|
|
list = g_malloc (list_size);
|
|
|
|
|
|
|
|
|
|
retry:
|
|
|
|
|
|
2007-12-03 11:23:03 +01:00
|
|
|
|
list_res_size = g_flistxattr (fd, list, list_size);
|
2017-07-31 12:30:55 +02:00
|
|
|
|
errsv = errno;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2017-07-31 12:30:55 +02:00
|
|
|
|
if (list_res_size == -1 && errsv == ERANGE)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
list_size = list_size * 2;
|
|
|
|
|
list = g_realloc (list, list_size);
|
|
|
|
|
goto retry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (list_res_size == -1)
|
2017-11-17 15:39:55 +01:00
|
|
|
|
{
|
|
|
|
|
g_free (list);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
attr = list;
|
|
|
|
|
while (list_res_size > 0)
|
|
|
|
|
{
|
|
|
|
|
if ((user && g_str_has_prefix (attr, "user.")) ||
|
|
|
|
|
(!user && !g_str_has_prefix (attr, "user.")))
|
|
|
|
|
{
|
|
|
|
|
char *escaped_attr, *gio_attr;
|
|
|
|
|
gboolean free_escaped_attr;
|
|
|
|
|
|
|
|
|
|
if (user)
|
|
|
|
|
{
|
|
|
|
|
escaped_attr = hex_escape_string (attr + 5, &free_escaped_attr);
|
2007-12-12 16:50:45 +01:00
|
|
|
|
gio_attr = g_strconcat ("xattr::", escaped_attr, NULL);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
escaped_attr = hex_escape_string (attr, &free_escaped_attr);
|
2007-12-12 16:50:45 +01:00
|
|
|
|
gio_attr = g_strconcat ("xattr-sys::", escaped_attr, NULL);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (free_escaped_attr)
|
|
|
|
|
g_free (escaped_attr);
|
|
|
|
|
|
|
|
|
|
get_one_xattr_from_fd (fd, info, gio_attr, attr);
|
2014-01-16 18:02:18 +01:00
|
|
|
|
g_free (gio_attr);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = strlen (attr) + 1;
|
|
|
|
|
attr += len;
|
|
|
|
|
list_res_size -= len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_free (list);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
while ((attr = g_file_attribute_matcher_enumerate_next (matcher)) != NULL)
|
|
|
|
|
{
|
|
|
|
|
char *unescaped_attribute, *a;
|
|
|
|
|
gboolean free_unescaped_attribute;
|
|
|
|
|
|
|
|
|
|
attr2 = strchr (attr, ':');
|
|
|
|
|
if (attr2)
|
|
|
|
|
{
|
|
|
|
|
attr2++; /* Skip ':' */
|
|
|
|
|
unescaped_attribute = hex_unescape_string (attr2, NULL, &free_unescaped_attribute);
|
|
|
|
|
if (user)
|
|
|
|
|
a = g_strconcat ("user.", unescaped_attribute, NULL);
|
|
|
|
|
else
|
|
|
|
|
a = unescaped_attribute;
|
|
|
|
|
|
|
|
|
|
get_one_xattr_from_fd (fd, info, attr, a);
|
|
|
|
|
|
|
|
|
|
if (user)
|
|
|
|
|
g_free (a);
|
|
|
|
|
|
|
|
|
|
if (free_unescaped_attribute)
|
|
|
|
|
g_free (unescaped_attribute);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* defined HAVE_XATTR */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_XATTR
|
|
|
|
|
static gboolean
|
2007-11-30 06:11:25 +01:00
|
|
|
|
set_xattr (char *filename,
|
|
|
|
|
const char *escaped_attribute,
|
|
|
|
|
const GFileAttributeValue *attr_value,
|
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
char *attribute, *value;
|
|
|
|
|
gboolean free_attribute, free_value;
|
|
|
|
|
int val_len, res, errsv;
|
|
|
|
|
gboolean is_user;
|
|
|
|
|
char *a;
|
|
|
|
|
|
|
|
|
|
if (attr_value == NULL)
|
|
|
|
|
{
|
2008-06-16 18:53:58 +02:00
|
|
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
|
|
|
_("Attribute value must be non-NULL"));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-26 09:58:32 +02:00
|
|
|
|
if (attr_value->type != G_FILE_ATTRIBUTE_TYPE_STRING && attr_value->type != G_FILE_ATTRIBUTE_TYPE_INVALID)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2008-06-16 18:53:58 +02:00
|
|
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
2022-07-26 09:58:32 +02:00
|
|
|
|
_("Invalid attribute type (string or invalid expected)"));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!name_is_valid (escaped_attribute))
|
|
|
|
|
{
|
2008-06-16 18:53:58 +02:00
|
|
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
|
|
|
_("Invalid extended attribute name"));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-12 16:50:45 +01:00
|
|
|
|
if (g_str_has_prefix (escaped_attribute, "xattr::"))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2008-06-10 17:55:31 +02:00
|
|
|
|
escaped_attribute += strlen ("xattr::");
|
2007-11-26 17:13:05 +01:00
|
|
|
|
is_user = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2007-12-12 16:50:45 +01:00
|
|
|
|
g_warn_if_fail (g_str_has_prefix (escaped_attribute, "xattr-sys::"));
|
2008-06-10 17:55:31 +02:00
|
|
|
|
escaped_attribute += strlen ("xattr-sys::");
|
2007-11-26 17:13:05 +01:00
|
|
|
|
is_user = FALSE;
|
|
|
|
|
}
|
2022-07-26 09:58:32 +02:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
attribute = hex_unescape_string (escaped_attribute, NULL, &free_attribute);
|
|
|
|
|
|
|
|
|
|
if (is_user)
|
|
|
|
|
a = g_strconcat ("user.", attribute, NULL);
|
|
|
|
|
else
|
|
|
|
|
a = attribute;
|
2022-07-26 09:58:32 +02:00
|
|
|
|
|
|
|
|
|
if (attr_value->type == G_FILE_ATTRIBUTE_TYPE_STRING)
|
|
|
|
|
{
|
|
|
|
|
value = hex_unescape_string (attr_value->u.string, &val_len, &free_value);
|
|
|
|
|
res = g_setxattr (filename, a, value, val_len);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
value = NULL;
|
|
|
|
|
val_len = 0;
|
|
|
|
|
free_value = FALSE;
|
|
|
|
|
res = g_removexattr (filename, a);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
errsv = errno;
|
|
|
|
|
|
|
|
|
|
if (is_user)
|
|
|
|
|
g_free (a);
|
|
|
|
|
|
|
|
|
|
if (free_attribute)
|
|
|
|
|
g_free (attribute);
|
|
|
|
|
|
|
|
|
|
if (free_value)
|
|
|
|
|
g_free (value);
|
|
|
|
|
|
|
|
|
|
if (res == -1)
|
|
|
|
|
{
|
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
|
g_io_error_from_errno (errsv),
|
2016-09-30 05:47:15 +02:00
|
|
|
|
_("Error setting extended attribute “%s”: %s"),
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
escaped_attribute, g_strerror (errsv));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2007-11-30 06:11:25 +01:00
|
|
|
|
_g_local_file_info_get_parent_info (const char *dir,
|
|
|
|
|
GFileAttributeMatcher *attribute_matcher,
|
|
|
|
|
GLocalParentFileInfo *parent_info)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2010-03-21 19:04:18 +01:00
|
|
|
|
GStatBuf statbuf;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
int res;
|
2009-06-18 09:05:27 +02:00
|
|
|
|
|
|
|
|
|
parent_info->extra_data = NULL;
|
|
|
|
|
parent_info->free_extra_data = NULL;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
parent_info->writable = FALSE;
|
|
|
|
|
parent_info->is_sticky = FALSE;
|
2008-03-11 15:48:28 +01:00
|
|
|
|
parent_info->has_trash_dir = FALSE;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
parent_info->device = 0;
|
2018-06-01 16:43:27 +02:00
|
|
|
|
parent_info->inode = 0;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_UNIX_IS_MOUNTPOINT))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2008-03-12 19:33:59 +01:00
|
|
|
|
/* FIXME: Windows: The underlying _waccess() call in the C
|
|
|
|
|
* library is mostly pointless as it only looks at the READONLY
|
|
|
|
|
* FAT-style attribute of the file, it doesn't check the ACL at
|
|
|
|
|
* all.
|
|
|
|
|
*/
|
2007-11-26 17:13:05 +01:00
|
|
|
|
parent_info->writable = (g_access (dir, W_OK) == 0);
|
|
|
|
|
|
|
|
|
|
res = g_stat (dir, &statbuf);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The sticky bit (S_ISVTX) on a directory means that a file in that directory can be
|
|
|
|
|
* renamed or deleted only by the owner of the file, by the owner of the directory, and
|
|
|
|
|
* by a privileged process.
|
|
|
|
|
*/
|
|
|
|
|
if (res == 0)
|
|
|
|
|
{
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#ifdef S_ISVTX
|
2007-11-26 17:13:05 +01:00
|
|
|
|
parent_info->is_sticky = (statbuf.st_mode & S_ISVTX) != 0;
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#else
|
|
|
|
|
parent_info->is_sticky = FALSE;
|
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
parent_info->owner = statbuf.st_uid;
|
|
|
|
|
parent_info->device = statbuf.st_dev;
|
2018-06-01 16:43:27 +02:00
|
|
|
|
parent_info->inode = statbuf.st_ino;
|
2009-02-23 05:30:06 +01:00
|
|
|
|
/* No need to find trash dir if it's not writable anyway */
|
2008-03-11 15:48:28 +01:00
|
|
|
|
if (parent_info->writable &&
|
2009-06-29 14:13:14 +02:00
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH))
|
2008-03-11 15:48:28 +01:00
|
|
|
|
parent_info->has_trash_dir = _g_local_file_has_trash_dir (dir, statbuf.st_dev);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-18 09:05:27 +02:00
|
|
|
|
void
|
|
|
|
|
_g_local_file_info_free_parent_info (GLocalParentFileInfo *parent_info)
|
|
|
|
|
{
|
|
|
|
|
if (parent_info->extra_data &&
|
|
|
|
|
parent_info->free_extra_data)
|
|
|
|
|
parent_info->free_extra_data (parent_info->extra_data);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
static void
|
|
|
|
|
get_access_rights (GFileAttributeMatcher *attribute_matcher,
|
2007-11-30 06:11:25 +01:00
|
|
|
|
GFileInfo *info,
|
|
|
|
|
const gchar *path,
|
2008-03-12 19:33:59 +01:00
|
|
|
|
GLocalFileStat *statbuf,
|
2007-11-30 06:11:25 +01:00
|
|
|
|
GLocalParentFileInfo *parent_info)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2008-03-12 19:33:59 +01:00
|
|
|
|
/* FIXME: Windows: The underlyin _waccess() is mostly pointless */
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ))
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_READ,
|
|
|
|
|
g_access (path, R_OK) == 0);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE))
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_WRITE,
|
|
|
|
|
g_access (path, W_OK) == 0);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE))
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_EXECUTE,
|
|
|
|
|
g_access (path, X_OK) == 0);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (parent_info)
|
|
|
|
|
{
|
|
|
|
|
gboolean writable;
|
|
|
|
|
|
|
|
|
|
writable = FALSE;
|
|
|
|
|
if (parent_info->writable)
|
|
|
|
|
{
|
2018-04-25 16:07:59 +02:00
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
writable = TRUE;
|
|
|
|
|
#else
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (parent_info->is_sticky)
|
|
|
|
|
{
|
|
|
|
|
uid_t uid = geteuid ();
|
|
|
|
|
|
2020-08-14 15:46:14 +02:00
|
|
|
|
if (uid == _g_stat_uid (statbuf) ||
|
2020-11-17 21:36:09 +01:00
|
|
|
|
uid == (uid_t) parent_info->owner ||
|
2007-11-26 17:13:05 +01:00
|
|
|
|
uid == 0)
|
|
|
|
|
writable = TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
writable = TRUE;
|
2018-04-25 16:07:59 +02:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME))
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME,
|
|
|
|
|
writable);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE))
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE,
|
|
|
|
|
writable);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH))
|
2018-08-13 18:23:10 +02:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH,
|
|
|
|
|
writable && parent_info->has_trash_dir);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2007-11-30 06:11:25 +01:00
|
|
|
|
set_info_from_stat (GFileInfo *info,
|
2008-03-12 19:33:59 +01:00
|
|
|
|
GLocalFileStat *statbuf,
|
2007-11-26 17:13:05 +01:00
|
|
|
|
GFileAttributeMatcher *attribute_matcher)
|
|
|
|
|
{
|
|
|
|
|
GFileType file_type;
|
|
|
|
|
|
|
|
|
|
file_type = G_FILE_TYPE_UNKNOWN;
|
|
|
|
|
|
2020-08-14 15:46:14 +02:00
|
|
|
|
if (S_ISREG (_g_stat_mode (statbuf)))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
file_type = G_FILE_TYPE_REGULAR;
|
2020-08-14 15:46:14 +02:00
|
|
|
|
else if (S_ISDIR (_g_stat_mode (statbuf)))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
file_type = G_FILE_TYPE_DIRECTORY;
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#ifndef G_OS_WIN32
|
2020-08-14 15:46:14 +02:00
|
|
|
|
else if (S_ISCHR (_g_stat_mode (statbuf)) ||
|
|
|
|
|
S_ISBLK (_g_stat_mode (statbuf)) ||
|
|
|
|
|
S_ISFIFO (_g_stat_mode (statbuf))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#ifdef S_ISSOCK
|
2020-08-14 15:46:14 +02:00
|
|
|
|
|| S_ISSOCK (_g_stat_mode (statbuf))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
|
|
|
|
)
|
|
|
|
|
file_type = G_FILE_TYPE_SPECIAL;
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#ifdef S_ISLNK
|
2020-08-14 15:46:14 +02:00
|
|
|
|
else if (S_ISLNK (_g_stat_mode (statbuf)))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
file_type = G_FILE_TYPE_SYMBOLIC_LINK;
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#elif defined (G_OS_WIN32)
|
2018-08-24 10:57:20 +02:00
|
|
|
|
else if (statbuf->reparse_tag == IO_REPARSE_TAG_SYMLINK ||
|
|
|
|
|
statbuf->reparse_tag == IO_REPARSE_TAG_MOUNT_POINT)
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
file_type = G_FILE_TYPE_SYMBOLIC_LINK;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
g_file_info_set_file_type (info, file_type);
|
2020-08-14 15:46:14 +02:00
|
|
|
|
g_file_info_set_size (info, _g_stat_size (statbuf));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2020-08-14 15:46:14 +02:00
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_DEVICE, _g_stat_dev (statbuf));
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_NLINK, _g_stat_nlink (statbuf));
|
2008-03-12 19:33:59 +01:00
|
|
|
|
#ifndef G_OS_WIN32
|
|
|
|
|
/* Pointless setting these on Windows even if they exist in the struct */
|
2020-08-14 15:46:14 +02:00
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_INODE, _g_stat_ino (statbuf));
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_UID, _g_stat_uid (statbuf));
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_GID, _g_stat_gid (statbuf));
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_RDEV, _g_stat_rdev (statbuf));
|
2008-03-12 19:33:59 +01:00
|
|
|
|
#endif
|
2018-08-24 10:43:46 +02:00
|
|
|
|
/* Mostly pointless on Windows.
|
|
|
|
|
* Still, it allows for S_ISREG/S_ISDIR and IWRITE (read-only) checks.
|
|
|
|
|
*/
|
2020-08-14 15:46:14 +02:00
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_MODE, _g_stat_mode (statbuf));
|
2007-12-25 22:21:32 +01:00
|
|
|
|
#if defined (HAVE_STRUCT_STAT_ST_BLKSIZE)
|
2020-08-14 15:46:14 +02:00
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_BLOCK_SIZE, _g_stat_blksize (statbuf));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
2007-12-25 22:21:32 +01:00
|
|
|
|
#if defined (HAVE_STRUCT_STAT_ST_BLOCKS)
|
2020-08-14 15:46:14 +02:00
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_BLOCKS, _g_stat_blocks (statbuf));
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_ALLOCATED_SIZE,
|
2020-08-14 15:46:14 +02:00
|
|
|
|
_g_stat_blocks (statbuf) * G_GUINT64_CONSTANT (512));
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#elif defined (G_OS_WIN32)
|
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_ALLOCATED_SIZE,
|
|
|
|
|
statbuf->allocated_size);
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
2020-01-30 02:56:56 +01:00
|
|
|
|
|
2023-06-28 18:32:25 +02:00
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, _g_stat_mtime (statbuf));
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_USEC, _g_stat_mtim_nsec (statbuf) / 1000);
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED_NSEC, _g_stat_mtim_nsec (statbuf));
|
|
|
|
|
|
2020-08-23 16:41:17 +02:00
|
|
|
|
if (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_ATIME))
|
|
|
|
|
{
|
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS, _g_stat_atime (statbuf));
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, _g_stat_atim_nsec (statbuf) / 1000);
|
2021-07-02 15:10:44 +02:00
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_NSEC, _g_stat_atim_nsec (statbuf));
|
2020-08-23 16:41:17 +02:00
|
|
|
|
}
|
2018-08-08 23:39:43 +02:00
|
|
|
|
|
|
|
|
|
#ifndef G_OS_WIN32
|
|
|
|
|
/* Microsoft uses st_ctime for file creation time,
|
|
|
|
|
* instead of file change time:
|
|
|
|
|
* https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions#generic-text-routine-mappings
|
|
|
|
|
* Thank you, Microsoft!
|
|
|
|
|
*/
|
2020-08-14 15:46:14 +02:00
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED, _g_stat_ctime (statbuf));
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, _g_stat_ctim_nsec (statbuf) / 1000);
|
2021-07-02 15:10:44 +02:00
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_NSEC, _g_stat_ctim_nsec (statbuf));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2020-08-14 17:12:05 +02:00
|
|
|
|
#if defined (HAVE_STATX)
|
|
|
|
|
if (_g_stat_has_field (statbuf, G_LOCAL_FILE_STAT_FIELD_BTIME))
|
|
|
|
|
{
|
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->stx_btime.tv_sec);
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->stx_btime.tv_nsec / 1000);
|
2021-07-02 15:10:44 +02:00
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->stx_btime.tv_nsec);
|
2020-08-14 17:12:05 +02:00
|
|
|
|
}
|
|
|
|
|
#elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIME) && defined (HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC)
|
2015-05-17 10:25:35 +02:00
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtime);
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_birthtimensec / 1000);
|
2021-07-02 15:10:44 +02:00
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->st_birthtimensec);
|
2015-05-17 10:25:35 +02:00
|
|
|
|
#elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIM) && defined (HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC)
|
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtim.tv_sec);
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_birthtim.tv_nsec / 1000);
|
2021-07-02 15:10:44 +02:00
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->st_birthtim.tv_nsec);
|
2015-05-17 10:25:35 +02:00
|
|
|
|
#elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIME)
|
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtime);
|
|
|
|
|
#elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIM)
|
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtim);
|
2018-08-08 23:39:43 +02:00
|
|
|
|
#elif defined (G_OS_WIN32)
|
2020-01-19 15:21:33 +01:00
|
|
|
|
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_ctim.tv_sec);
|
2022-01-23 22:53:49 +01:00
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_USEC, statbuf->st_ctim.tv_nsec / 1000);
|
2021-07-02 15:10:44 +02:00
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED_NSEC, statbuf->st_ctim.tv_nsec);
|
2015-05-17 10:25:35 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_ETAG_VALUE))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
char *etag = _g_local_file_info_create_etag (statbuf);
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_ETAG_VALUE, etag);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_free (etag);
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_ID_FILE))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
char *id = _g_local_file_info_create_file_id (statbuf);
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_ID_FILE, id);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_free (id);
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_ID_FILESYSTEM))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
char *id = _g_local_file_info_create_fs_id (statbuf);
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_ID_FILESYSTEM, id);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_free (id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-12 19:33:59 +01:00
|
|
|
|
#ifndef G_OS_WIN32
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
static char *
|
|
|
|
|
make_valid_utf8 (const char *name)
|
|
|
|
|
{
|
|
|
|
|
GString *string;
|
|
|
|
|
const gchar *remainder, *invalid;
|
2018-10-04 14:22:13 +02:00
|
|
|
|
gsize remaining_bytes, valid_bytes;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
string = NULL;
|
|
|
|
|
remainder = name;
|
|
|
|
|
remaining_bytes = strlen (name);
|
|
|
|
|
|
|
|
|
|
while (remaining_bytes != 0)
|
|
|
|
|
{
|
2018-10-04 14:22:13 +02:00
|
|
|
|
if (g_utf8_validate_len (remainder, remaining_bytes, &invalid))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
break;
|
|
|
|
|
valid_bytes = invalid - remainder;
|
|
|
|
|
|
|
|
|
|
if (string == NULL)
|
|
|
|
|
string = g_string_sized_new (remaining_bytes);
|
|
|
|
|
|
|
|
|
|
g_string_append_len (string, remainder, valid_bytes);
|
|
|
|
|
/* append U+FFFD REPLACEMENT CHARACTER */
|
|
|
|
|
g_string_append (string, "\357\277\275");
|
|
|
|
|
|
|
|
|
|
remaining_bytes -= valid_bytes + 1;
|
|
|
|
|
remainder = invalid + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string == NULL)
|
|
|
|
|
return g_strdup (name);
|
|
|
|
|
|
|
|
|
|
g_string_append (string, remainder);
|
|
|
|
|
|
2007-12-10 15:07:42 +01:00
|
|
|
|
g_warn_if_fail (g_utf8_validate (string->str, -1, NULL));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
return g_string_free (string, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
convert_pwd_string_to_utf8 (char *pwd_str)
|
|
|
|
|
{
|
|
|
|
|
char *utf8_string;
|
|
|
|
|
|
|
|
|
|
if (!g_utf8_validate (pwd_str, -1, NULL))
|
|
|
|
|
{
|
|
|
|
|
utf8_string = g_locale_to_utf8 (pwd_str, -1, NULL, NULL, NULL);
|
|
|
|
|
if (utf8_string == NULL)
|
|
|
|
|
utf8_string = make_valid_utf8 (pwd_str);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
utf8_string = g_strdup (pwd_str);
|
|
|
|
|
|
|
|
|
|
return utf8_string;
|
|
|
|
|
}
|
2008-03-12 19:33:59 +01:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
static void
|
|
|
|
|
uid_data_free (UidData *data)
|
|
|
|
|
{
|
|
|
|
|
g_free (data->user_name);
|
|
|
|
|
g_free (data->real_name);
|
|
|
|
|
g_free (data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* called with lock held */
|
|
|
|
|
static UidData *
|
|
|
|
|
lookup_uid_data (uid_t uid)
|
|
|
|
|
{
|
|
|
|
|
UidData *data;
|
|
|
|
|
char buffer[4096];
|
|
|
|
|
struct passwd pwbuf;
|
|
|
|
|
struct passwd *pwbufp;
|
2018-06-09 01:37:35 +02:00
|
|
|
|
#ifndef __BIONIC__
|
2007-11-26 17:13:05 +01:00
|
|
|
|
char *gecos, *comma;
|
2018-06-09 01:37:35 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (uid_cache == NULL)
|
|
|
|
|
uid_cache = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)uid_data_free);
|
|
|
|
|
|
|
|
|
|
data = g_hash_table_lookup (uid_cache, GINT_TO_POINTER (uid));
|
|
|
|
|
|
|
|
|
|
if (data)
|
|
|
|
|
return data;
|
|
|
|
|
|
|
|
|
|
data = g_new0 (UidData, 1);
|
|
|
|
|
|
2015-10-16 13:36:58 +02:00
|
|
|
|
#if defined(HAVE_GETPWUID_R)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
getpwuid_r (uid, &pwbuf, buffer, sizeof(buffer), &pwbufp);
|
|
|
|
|
#else
|
|
|
|
|
pwbufp = getpwuid (uid);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (pwbufp != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (pwbufp->pw_name != NULL && pwbufp->pw_name[0] != 0)
|
|
|
|
|
data->user_name = convert_pwd_string_to_utf8 (pwbufp->pw_name);
|
|
|
|
|
|
2012-11-28 16:55:54 +01:00
|
|
|
|
#ifndef __BIONIC__
|
2007-11-26 17:13:05 +01:00
|
|
|
|
gecos = pwbufp->pw_gecos;
|
|
|
|
|
|
|
|
|
|
if (gecos)
|
|
|
|
|
{
|
|
|
|
|
comma = strchr (gecos, ',');
|
|
|
|
|
if (comma)
|
|
|
|
|
*comma = 0;
|
|
|
|
|
data->real_name = convert_pwd_string_to_utf8 (gecos);
|
|
|
|
|
}
|
2012-11-28 16:55:54 +01:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Default fallbacks */
|
|
|
|
|
if (data->real_name == NULL)
|
|
|
|
|
{
|
|
|
|
|
if (data->user_name != NULL)
|
|
|
|
|
data->real_name = g_strdup (data->user_name);
|
|
|
|
|
else
|
2008-01-21 15:02:19 +01:00
|
|
|
|
data->real_name = g_strdup_printf ("user #%d", (int)uid);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data->user_name == NULL)
|
2008-01-21 15:02:19 +01:00
|
|
|
|
data->user_name = g_strdup_printf ("%d", (int)uid);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
g_hash_table_replace (uid_cache, GINT_TO_POINTER (uid), data);
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
get_username_from_uid (uid_t uid)
|
|
|
|
|
{
|
|
|
|
|
char *res;
|
|
|
|
|
UidData *data;
|
|
|
|
|
|
|
|
|
|
G_LOCK (uid_cache);
|
|
|
|
|
data = lookup_uid_data (uid);
|
|
|
|
|
res = g_strdup (data->user_name);
|
|
|
|
|
G_UNLOCK (uid_cache);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
get_realname_from_uid (uid_t uid)
|
|
|
|
|
{
|
|
|
|
|
char *res;
|
|
|
|
|
UidData *data;
|
|
|
|
|
|
|
|
|
|
G_LOCK (uid_cache);
|
|
|
|
|
data = lookup_uid_data (uid);
|
|
|
|
|
res = g_strdup (data->real_name);
|
|
|
|
|
G_UNLOCK (uid_cache);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* called with lock held */
|
|
|
|
|
static char *
|
|
|
|
|
lookup_gid_name (gid_t gid)
|
|
|
|
|
{
|
|
|
|
|
char *name;
|
2018-06-09 01:37:35 +02:00
|
|
|
|
#if defined (HAVE_GETGRGID_R)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
char buffer[4096];
|
|
|
|
|
struct group gbuf;
|
2018-06-09 01:37:35 +02:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
struct group *gbufp;
|
2018-06-09 01:37:35 +02:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (gid_cache == NULL)
|
|
|
|
|
gid_cache = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_free);
|
|
|
|
|
|
|
|
|
|
name = g_hash_table_lookup (gid_cache, GINT_TO_POINTER (gid));
|
|
|
|
|
|
|
|
|
|
if (name)
|
|
|
|
|
return name;
|
|
|
|
|
|
2015-10-16 13:36:58 +02:00
|
|
|
|
#if defined (HAVE_GETGRGID_R)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
getgrgid_r (gid, &gbuf, buffer, sizeof(buffer), &gbufp);
|
|
|
|
|
#else
|
|
|
|
|
gbufp = getgrgid (gid);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (gbufp != NULL &&
|
|
|
|
|
gbufp->gr_name != NULL &&
|
|
|
|
|
gbufp->gr_name[0] != 0)
|
|
|
|
|
name = convert_pwd_string_to_utf8 (gbufp->gr_name);
|
|
|
|
|
else
|
|
|
|
|
name = g_strdup_printf("%d", (int)gid);
|
|
|
|
|
|
|
|
|
|
g_hash_table_replace (gid_cache, GINT_TO_POINTER (gid), name);
|
|
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
get_groupname_from_gid (gid_t gid)
|
|
|
|
|
{
|
|
|
|
|
char *res;
|
|
|
|
|
char *name;
|
|
|
|
|
|
|
|
|
|
G_LOCK (gid_cache);
|
|
|
|
|
name = lookup_gid_name (gid);
|
|
|
|
|
res = g_strdup (name);
|
|
|
|
|
G_UNLOCK (gid_cache);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2008-03-12 19:33:59 +01:00
|
|
|
|
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#endif /* !G_OS_WIN32 */
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
static char *
|
2007-11-30 06:11:25 +01:00
|
|
|
|
get_content_type (const char *basename,
|
|
|
|
|
const char *path,
|
2008-03-12 19:33:59 +01:00
|
|
|
|
GLocalFileStat *statbuf,
|
2007-11-30 06:11:25 +01:00
|
|
|
|
gboolean is_symlink,
|
|
|
|
|
gboolean symlink_broken,
|
|
|
|
|
GFileQueryInfoFlags flags,
|
|
|
|
|
gboolean fast)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
if (is_symlink &&
|
|
|
|
|
(symlink_broken || (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS)))
|
2014-08-16 10:47:46 +02:00
|
|
|
|
return g_content_type_from_mime_type ("inode/symlink");
|
2020-08-14 15:46:14 +02:00
|
|
|
|
else if (statbuf != NULL && S_ISDIR(_g_stat_mode (statbuf)))
|
2014-08-16 10:47:46 +02:00
|
|
|
|
return g_content_type_from_mime_type ("inode/directory");
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#ifndef G_OS_WIN32
|
2020-08-14 15:46:14 +02:00
|
|
|
|
else if (statbuf != NULL && S_ISCHR(_g_stat_mode (statbuf)))
|
2014-08-16 10:47:46 +02:00
|
|
|
|
return g_content_type_from_mime_type ("inode/chardevice");
|
2020-08-14 15:46:14 +02:00
|
|
|
|
else if (statbuf != NULL && S_ISBLK(_g_stat_mode (statbuf)))
|
2014-08-16 10:47:46 +02:00
|
|
|
|
return g_content_type_from_mime_type ("inode/blockdevice");
|
2020-08-14 15:46:14 +02:00
|
|
|
|
else if (statbuf != NULL && S_ISFIFO(_g_stat_mode (statbuf)))
|
2014-08-16 10:47:46 +02:00
|
|
|
|
return g_content_type_from_mime_type ("inode/fifo");
|
2020-08-14 15:46:14 +02:00
|
|
|
|
else if (statbuf != NULL && S_ISREG(_g_stat_mode (statbuf)) && _g_stat_size (statbuf) == 0)
|
2015-09-29 17:18:54 +02:00
|
|
|
|
{
|
|
|
|
|
/* Don't sniff zero-length files in order to avoid reading files
|
|
|
|
|
* that appear normal but are not (eg: files in /proc and /sys)
|
|
|
|
|
*/
|
2022-11-03 10:39:53 +01:00
|
|
|
|
return g_content_type_from_mime_type ("application/x-zerosize");
|
2015-09-29 17:18:54 +02:00
|
|
|
|
}
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#ifdef S_ISSOCK
|
2020-08-14 15:46:14 +02:00
|
|
|
|
else if (statbuf != NULL && S_ISSOCK(_g_stat_mode (statbuf)))
|
2014-08-16 10:47:46 +02:00
|
|
|
|
return g_content_type_from_mime_type ("inode/socket");
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *content_type;
|
|
|
|
|
gboolean result_uncertain;
|
2015-09-29 17:18:54 +02:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
content_type = g_content_type_guess (basename, NULL, 0, &result_uncertain);
|
|
|
|
|
|
2022-11-03 19:22:18 +01:00
|
|
|
|
#if !defined(G_OS_WIN32) && !defined(__APPLE__)
|
2015-09-29 17:18:54 +02:00
|
|
|
|
if (!fast && result_uncertain && path != NULL)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2023-11-27 14:14:39 +01:00
|
|
|
|
/* Sniff the first 16KiB of the file (sometimes less, if xdgmime
|
|
|
|
|
* says it doesn’t need so much). Most files need less than 4KiB of
|
|
|
|
|
* sniffing, but some disk images need more (see
|
|
|
|
|
* https://gitlab.gnome.org/GNOME/glib/-/issues/3186). */
|
|
|
|
|
guchar sniff_buffer[16384];
|
2007-11-26 17:13:05 +01:00
|
|
|
|
gsize sniff_length;
|
2022-10-20 00:32:17 +02:00
|
|
|
|
#ifdef O_NOATIME
|
|
|
|
|
int errsv;
|
|
|
|
|
#endif
|
|
|
|
|
int fd;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
sniff_length = _g_unix_content_type_get_sniff_len ();
|
2023-11-27 14:14:39 +01:00
|
|
|
|
if (sniff_length == 0 || sniff_length > sizeof (sniff_buffer))
|
|
|
|
|
sniff_length = sizeof (sniff_buffer);
|
2009-01-05 17:20:40 +01:00
|
|
|
|
|
|
|
|
|
#ifdef O_NOATIME
|
2023-02-19 16:22:22 +01:00
|
|
|
|
fd = g_open (path, O_RDONLY | O_NOATIME | O_CLOEXEC, 0);
|
2017-07-31 12:30:55 +02:00
|
|
|
|
errsv = errno;
|
|
|
|
|
if (fd < 0 && errsv == EPERM)
|
2009-01-05 17:20:40 +01:00
|
|
|
|
#endif
|
2023-02-19 16:22:22 +01:00
|
|
|
|
fd = g_open (path, O_RDONLY | O_CLOEXEC, 0);
|
2009-01-05 17:20:40 +01:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (fd != -1)
|
|
|
|
|
{
|
2017-10-10 13:59:14 +02:00
|
|
|
|
gssize res;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
res = read (fd, sniff_buffer, sniff_length);
|
2013-01-25 18:05:26 +01:00
|
|
|
|
(void) g_close (fd, NULL);
|
2008-02-29 10:49:08 +01:00
|
|
|
|
if (res >= 0)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
g_free (content_type);
|
|
|
|
|
content_type = g_content_type_guess (basename, sniff_buffer, res, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return content_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-22 22:29:41 +02:00
|
|
|
|
typedef enum {
|
|
|
|
|
THUMBNAIL_SIZE_AUTO,
|
|
|
|
|
THUMBNAIL_SIZE_NORMAL,
|
|
|
|
|
THUMBNAIL_SIZE_LARGE,
|
|
|
|
|
THUMBNAIL_SIZE_XLARGE,
|
|
|
|
|
THUMBNAIL_SIZE_XXLARGE,
|
|
|
|
|
THUMBNAIL_SIZE_LAST,
|
|
|
|
|
} ThumbnailSize;
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
get_thumbnail_dirname_from_size (ThumbnailSize size)
|
|
|
|
|
{
|
|
|
|
|
switch (size)
|
|
|
|
|
{
|
|
|
|
|
case THUMBNAIL_SIZE_AUTO:
|
|
|
|
|
return NULL;
|
|
|
|
|
break;
|
|
|
|
|
case THUMBNAIL_SIZE_NORMAL:
|
|
|
|
|
return "normal";
|
|
|
|
|
break;
|
|
|
|
|
case THUMBNAIL_SIZE_LARGE:
|
|
|
|
|
return "large";
|
|
|
|
|
break;
|
|
|
|
|
case THUMBNAIL_SIZE_XLARGE:
|
|
|
|
|
return "x-large";
|
|
|
|
|
break;
|
|
|
|
|
case THUMBNAIL_SIZE_XXLARGE:
|
|
|
|
|
return "xx-large";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_return_val_if_reached (NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-11 12:22:31 +02:00
|
|
|
|
/* @stat_buf is the pre-calculated result of stat(path), or %NULL if that failed. */
|
2007-11-26 17:13:05 +01:00
|
|
|
|
static void
|
2013-10-11 12:22:31 +02:00
|
|
|
|
get_thumbnail_attributes (const char *path,
|
|
|
|
|
GFileInfo *info,
|
2022-09-22 22:29:41 +02:00
|
|
|
|
const GLocalFileStat *stat_buf,
|
|
|
|
|
ThumbnailSize size)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2007-12-04 17:33:24 +01:00
|
|
|
|
GChecksum *checksum;
|
2022-09-22 22:29:41 +02:00
|
|
|
|
const char *dirname;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
char *uri;
|
2022-10-11 16:20:05 +02:00
|
|
|
|
char *filename = NULL;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
char *basename;
|
2022-09-22 22:29:41 +02:00
|
|
|
|
guint32 failed_attr_id;
|
|
|
|
|
guint32 is_valid_attr_id;
|
|
|
|
|
guint32 path_attr_id;
|
|
|
|
|
|
|
|
|
|
switch (size)
|
|
|
|
|
{
|
|
|
|
|
case THUMBNAIL_SIZE_AUTO:
|
|
|
|
|
failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED;
|
|
|
|
|
is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID;
|
|
|
|
|
path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH;
|
|
|
|
|
break;
|
|
|
|
|
case THUMBNAIL_SIZE_NORMAL:
|
|
|
|
|
failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_NORMAL;
|
|
|
|
|
is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_NORMAL;
|
|
|
|
|
path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_NORMAL;
|
|
|
|
|
break;
|
|
|
|
|
case THUMBNAIL_SIZE_LARGE:
|
|
|
|
|
failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_LARGE;
|
|
|
|
|
is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_LARGE;
|
|
|
|
|
path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_LARGE;
|
|
|
|
|
break;
|
|
|
|
|
case THUMBNAIL_SIZE_XLARGE:
|
|
|
|
|
failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XLARGE;
|
|
|
|
|
is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XLARGE;
|
|
|
|
|
path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XLARGE;
|
|
|
|
|
break;
|
|
|
|
|
case THUMBNAIL_SIZE_XXLARGE:
|
|
|
|
|
failed_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XXLARGE;
|
|
|
|
|
is_valid_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XXLARGE;
|
|
|
|
|
path_attr_id = G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XXLARGE;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dirname = get_thumbnail_dirname_from_size (size);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
uri = g_filename_to_uri (path, NULL, NULL);
|
|
|
|
|
|
2007-12-04 17:33:24 +01:00
|
|
|
|
checksum = g_checksum_new (G_CHECKSUM_MD5);
|
2007-12-14 12:07:31 +01:00
|
|
|
|
g_checksum_update (checksum, (const guchar *) uri, strlen (uri));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2007-12-04 17:33:24 +01:00
|
|
|
|
basename = g_strconcat (g_checksum_get_string (checksum), ".png", NULL);
|
|
|
|
|
g_checksum_free (checksum);
|
|
|
|
|
|
2022-09-22 22:29:41 +02:00
|
|
|
|
if (dirname)
|
2022-10-11 16:20:05 +02:00
|
|
|
|
{
|
|
|
|
|
filename = g_build_filename (g_get_user_cache_dir (),
|
2022-09-22 22:29:41 +02:00
|
|
|
|
"thumbnails", dirname, basename,
|
2022-10-11 16:20:05 +02:00
|
|
|
|
NULL);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2022-09-22 22:29:41 +02:00
|
|
|
|
if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
|
|
|
|
|
g_clear_pointer (&filename, g_free);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gssize i;
|
|
|
|
|
|
|
|
|
|
for (i = THUMBNAIL_SIZE_LAST - 1; i >= 0 ; i--)
|
|
|
|
|
{
|
|
|
|
|
filename = g_build_filename (g_get_user_cache_dir (),
|
|
|
|
|
"thumbnails",
|
|
|
|
|
get_thumbnail_dirname_from_size (i),
|
|
|
|
|
basename,
|
|
|
|
|
NULL);
|
|
|
|
|
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
g_clear_pointer (&filename, g_free);
|
|
|
|
|
}
|
2022-10-11 16:20:05 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (filename)
|
2013-10-11 12:22:31 +02:00
|
|
|
|
{
|
2022-09-22 22:29:41 +02:00
|
|
|
|
_g_file_info_set_attribute_byte_string_by_id (info, path_attr_id, filename);
|
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, is_valid_attr_id,
|
2013-10-11 12:22:31 +02:00
|
|
|
|
thumbnail_verify (filename, uri, stat_buf));
|
|
|
|
|
}
|
2007-11-26 17:13:05 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
2012-04-30 18:51:25 +02:00
|
|
|
|
filename = g_build_filename (g_get_user_cache_dir (),
|
2022-10-11 16:20:05 +02:00
|
|
|
|
"thumbnails", "fail",
|
|
|
|
|
"gnome-thumbnail-factory",
|
|
|
|
|
basename,
|
2007-12-04 17:33:24 +01:00
|
|
|
|
NULL);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (g_file_test (filename, G_FILE_TEST_IS_REGULAR))
|
2013-10-11 12:22:31 +02:00
|
|
|
|
{
|
2022-09-22 22:29:41 +02:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, failed_attr_id, TRUE);
|
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, is_valid_attr_id,
|
2013-10-11 12:22:31 +02:00
|
|
|
|
thumbnail_verify (filename, uri, stat_buf));
|
|
|
|
|
}
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
2022-09-22 22:29:41 +02:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_free (basename);
|
|
|
|
|
g_free (filename);
|
2013-10-11 12:22:31 +02:00
|
|
|
|
g_free (uri);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
2007-12-08 15:29:37 +01:00
|
|
|
|
#ifdef G_OS_WIN32
|
2007-12-09 23:10:40 +01:00
|
|
|
|
static void
|
2008-01-21 15:02:19 +01:00
|
|
|
|
win32_get_file_user_info (const gchar *filename,
|
|
|
|
|
gchar **group_name,
|
|
|
|
|
gchar **user_name,
|
|
|
|
|
gchar **real_name)
|
2007-12-08 13:01:06 +01:00
|
|
|
|
{
|
|
|
|
|
PSECURITY_DESCRIPTOR psd = NULL;
|
2007-12-09 23:10:40 +01:00
|
|
|
|
DWORD sd_size = 0; /* first call calculates the size required */
|
2007-12-08 13:01:06 +01:00
|
|
|
|
|
|
|
|
|
wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
|
|
|
|
|
if ((GetFileSecurityW (wfilename,
|
|
|
|
|
GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
|
|
|
|
|
NULL,
|
|
|
|
|
sd_size,
|
|
|
|
|
&sd_size) || (ERROR_INSUFFICIENT_BUFFER == GetLastError())) &&
|
|
|
|
|
(psd = g_try_malloc (sd_size)) != NULL &&
|
|
|
|
|
GetFileSecurityW (wfilename,
|
2007-12-09 23:10:40 +01:00
|
|
|
|
GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
|
|
|
|
|
psd,
|
|
|
|
|
sd_size,
|
|
|
|
|
&sd_size))
|
2007-12-08 13:01:06 +01:00
|
|
|
|
{
|
2007-12-12 13:19:02 +01:00
|
|
|
|
PSID psid = 0;
|
2007-12-09 23:10:40 +01:00
|
|
|
|
BOOL defaulted;
|
|
|
|
|
SID_NAME_USE name_use = 0; /* don't care? */
|
2007-12-12 13:19:02 +01:00
|
|
|
|
wchar_t *name = NULL;
|
|
|
|
|
wchar_t *domain = NULL;
|
|
|
|
|
DWORD name_len = 0;
|
|
|
|
|
DWORD domain_len = 0;
|
|
|
|
|
/* get the user name */
|
|
|
|
|
do {
|
|
|
|
|
if (!user_name)
|
|
|
|
|
break;
|
|
|
|
|
if (!GetSecurityDescriptorOwner (psd, &psid, &defaulted))
|
|
|
|
|
break;
|
|
|
|
|
if (!LookupAccountSidW (NULL, /* local machine */
|
|
|
|
|
psid,
|
|
|
|
|
name, &name_len,
|
|
|
|
|
domain, &domain_len, /* no domain info yet */
|
|
|
|
|
&name_use) && (ERROR_INSUFFICIENT_BUFFER != GetLastError()))
|
|
|
|
|
break;
|
2008-01-21 15:02:19 +01:00
|
|
|
|
name = g_try_malloc (name_len * sizeof (wchar_t));
|
|
|
|
|
domain = g_try_malloc (domain_len * sizeof (wchar_t));
|
2007-12-12 13:19:02 +01:00
|
|
|
|
if (name && domain &&
|
|
|
|
|
LookupAccountSidW (NULL, /* local machine */
|
|
|
|
|
psid,
|
|
|
|
|
name, &name_len,
|
|
|
|
|
domain, &domain_len, /* no domain info yet */
|
|
|
|
|
&name_use))
|
|
|
|
|
{
|
|
|
|
|
*user_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
g_free (name);
|
|
|
|
|
g_free (domain);
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
|
|
/* get the group name */
|
|
|
|
|
do {
|
|
|
|
|
if (!group_name)
|
|
|
|
|
break;
|
|
|
|
|
if (!GetSecurityDescriptorGroup (psd, &psid, &defaulted))
|
|
|
|
|
break;
|
|
|
|
|
if (!LookupAccountSidW (NULL, /* local machine */
|
|
|
|
|
psid,
|
|
|
|
|
name, &name_len,
|
|
|
|
|
domain, &domain_len, /* no domain info yet */
|
|
|
|
|
&name_use) && (ERROR_INSUFFICIENT_BUFFER != GetLastError()))
|
|
|
|
|
break;
|
2008-01-21 15:02:19 +01:00
|
|
|
|
name = g_try_malloc (name_len * sizeof (wchar_t));
|
|
|
|
|
domain = g_try_malloc (domain_len * sizeof (wchar_t));
|
2007-12-12 13:19:02 +01:00
|
|
|
|
if (name && domain &&
|
|
|
|
|
LookupAccountSidW (NULL, /* local machine */
|
|
|
|
|
psid,
|
|
|
|
|
name, &name_len,
|
|
|
|
|
domain, &domain_len, /* no domain info yet */
|
|
|
|
|
&name_use))
|
|
|
|
|
{
|
|
|
|
|
*group_name = g_utf16_to_utf8 (name, -1, NULL, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
g_free (name);
|
|
|
|
|
g_free (domain);
|
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
|
|
|
|
/* TODO: get real name */
|
|
|
|
|
|
|
|
|
|
g_free (psd);
|
2007-12-08 13:01:06 +01:00
|
|
|
|
}
|
|
|
|
|
g_free (wfilename);
|
|
|
|
|
}
|
2007-12-08 15:29:37 +01:00
|
|
|
|
#endif /* G_OS_WIN32 */
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2012-11-29 00:50:55 +01:00
|
|
|
|
#ifndef G_OS_WIN32
|
|
|
|
|
/* support for '.hidden' files */
|
|
|
|
|
G_LOCK_DEFINE_STATIC (hidden_cache);
|
|
|
|
|
static GHashTable *hidden_cache;
|
2020-11-01 20:55:27 +01:00
|
|
|
|
static GSource *hidden_cache_source = NULL; /* Under the hidden_cache lock */
|
|
|
|
|
static guint hidden_cache_ttl_secs = 5;
|
|
|
|
|
static guint hidden_cache_ttl_jitter_secs = 2;
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
GHashTable *hidden_files;
|
|
|
|
|
gint64 timestamp_secs;
|
|
|
|
|
} HiddenCacheData;
|
2012-11-29 00:50:55 +01:00
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
remove_from_hidden_cache (gpointer user_data)
|
|
|
|
|
{
|
2020-11-01 20:55:27 +01:00
|
|
|
|
HiddenCacheData *data;
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
gboolean retval;
|
|
|
|
|
gint64 timestamp_secs;
|
|
|
|
|
|
2012-11-29 00:50:55 +01:00
|
|
|
|
G_LOCK (hidden_cache);
|
2020-11-01 20:55:27 +01:00
|
|
|
|
timestamp_secs = g_source_get_time (hidden_cache_source) / G_USEC_PER_SEC;
|
|
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, hidden_cache);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &data))
|
|
|
|
|
{
|
|
|
|
|
if (timestamp_secs > data->timestamp_secs + hidden_cache_ttl_secs)
|
|
|
|
|
g_hash_table_iter_remove (&iter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_hash_table_size (hidden_cache) == 0)
|
|
|
|
|
{
|
|
|
|
|
g_clear_pointer (&hidden_cache_source, g_source_unref);
|
|
|
|
|
retval = G_SOURCE_REMOVE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
retval = G_SOURCE_CONTINUE;
|
|
|
|
|
|
2012-11-29 00:50:55 +01:00
|
|
|
|
G_UNLOCK (hidden_cache);
|
|
|
|
|
|
2020-11-01 20:55:27 +01:00
|
|
|
|
return retval;
|
2012-11-29 00:50:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GHashTable *
|
|
|
|
|
read_hidden_file (const gchar *dirname)
|
|
|
|
|
{
|
2013-03-12 17:53:42 +01:00
|
|
|
|
gchar *contents = NULL;
|
2012-11-29 00:50:55 +01:00
|
|
|
|
gchar *filename;
|
|
|
|
|
|
|
|
|
|
filename = g_build_path ("/", dirname, ".hidden", NULL);
|
2014-07-22 20:22:23 +02:00
|
|
|
|
(void) g_file_get_contents (filename, &contents, NULL, NULL);
|
2012-11-29 00:50:55 +01:00
|
|
|
|
g_free (filename);
|
|
|
|
|
|
2013-03-12 17:53:42 +01:00
|
|
|
|
if (contents != NULL)
|
2012-11-29 00:50:55 +01:00
|
|
|
|
{
|
|
|
|
|
GHashTable *table;
|
2013-03-12 17:53:42 +01:00
|
|
|
|
gchar **lines;
|
|
|
|
|
gint i;
|
2012-11-29 00:50:55 +01:00
|
|
|
|
|
|
|
|
|
table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
|
|
|
|
2013-03-12 17:53:42 +01:00
|
|
|
|
lines = g_strsplit (contents, "\n", 0);
|
|
|
|
|
g_free (contents);
|
2012-11-29 00:50:55 +01:00
|
|
|
|
|
2013-03-12 17:53:42 +01:00
|
|
|
|
for (i = 0; lines[i]; i++)
|
|
|
|
|
/* hash table takes the individual strings... */
|
|
|
|
|
g_hash_table_add (table, lines[i]);
|
2012-11-29 00:50:55 +01:00
|
|
|
|
|
2013-03-12 17:53:42 +01:00
|
|
|
|
/* ... so we only free the container. */
|
|
|
|
|
g_free (lines);
|
2012-11-29 00:50:55 +01:00
|
|
|
|
|
|
|
|
|
return table;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2020-11-01 20:55:27 +01:00
|
|
|
|
free_hidden_file_data (gpointer user_data)
|
2012-11-29 00:50:55 +01:00
|
|
|
|
{
|
2020-11-01 20:55:27 +01:00
|
|
|
|
HiddenCacheData *data = user_data;
|
|
|
|
|
|
|
|
|
|
g_clear_pointer (&data->hidden_files, g_hash_table_unref);
|
|
|
|
|
g_free (data);
|
2012-11-29 00:50:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
file_is_hidden (const gchar *path,
|
|
|
|
|
const gchar *basename)
|
|
|
|
|
{
|
2020-11-01 20:55:27 +01:00
|
|
|
|
HiddenCacheData *data;
|
2012-11-29 00:50:55 +01:00
|
|
|
|
gboolean result;
|
|
|
|
|
gchar *dirname;
|
|
|
|
|
gpointer table;
|
|
|
|
|
|
|
|
|
|
dirname = g_path_get_dirname (path);
|
|
|
|
|
|
|
|
|
|
G_LOCK (hidden_cache);
|
|
|
|
|
|
|
|
|
|
if G_UNLIKELY (hidden_cache == NULL)
|
|
|
|
|
hidden_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
|
2020-11-01 20:55:27 +01:00
|
|
|
|
g_free, free_hidden_file_data);
|
2012-11-29 00:50:55 +01:00
|
|
|
|
|
|
|
|
|
if (!g_hash_table_lookup_extended (hidden_cache, dirname,
|
2020-11-01 20:55:27 +01:00
|
|
|
|
NULL, (gpointer *) &data))
|
2012-11-29 00:50:55 +01:00
|
|
|
|
{
|
2020-11-01 20:55:27 +01:00
|
|
|
|
data = g_new0 (HiddenCacheData, 1);
|
|
|
|
|
data->hidden_files = table = read_hidden_file (dirname);
|
|
|
|
|
data->timestamp_secs = g_get_monotonic_time () / G_USEC_PER_SEC;
|
2012-11-29 00:50:55 +01:00
|
|
|
|
|
|
|
|
|
g_hash_table_insert (hidden_cache,
|
2022-04-28 12:20:11 +02:00
|
|
|
|
g_strdup (dirname),
|
2020-11-01 20:55:27 +01:00
|
|
|
|
data);
|
|
|
|
|
|
|
|
|
|
if (!hidden_cache_source)
|
|
|
|
|
{
|
|
|
|
|
hidden_cache_source =
|
|
|
|
|
g_timeout_source_new_seconds (hidden_cache_ttl_secs +
|
|
|
|
|
hidden_cache_ttl_jitter_secs);
|
|
|
|
|
g_source_set_priority (hidden_cache_source, G_PRIORITY_DEFAULT);
|
2021-07-26 11:53:02 +02:00
|
|
|
|
g_source_set_static_name (hidden_cache_source,
|
|
|
|
|
"[gio] remove_from_hidden_cache");
|
2020-11-01 20:55:27 +01:00
|
|
|
|
g_source_set_callback (hidden_cache_source,
|
|
|
|
|
remove_from_hidden_cache,
|
|
|
|
|
NULL, NULL);
|
|
|
|
|
g_source_attach (hidden_cache_source,
|
|
|
|
|
GLIB_PRIVATE_CALL (g_get_worker_context) ());
|
|
|
|
|
}
|
2012-11-29 00:50:55 +01:00
|
|
|
|
}
|
2020-11-01 20:55:27 +01:00
|
|
|
|
else
|
|
|
|
|
table = data->hidden_files;
|
2012-11-29 00:50:55 +01:00
|
|
|
|
|
2013-03-12 17:53:42 +01:00
|
|
|
|
result = table != NULL && g_hash_table_contains (table, basename);
|
2012-11-29 00:50:55 +01:00
|
|
|
|
|
|
|
|
|
G_UNLOCK (hidden_cache);
|
|
|
|
|
|
|
|
|
|
g_free (dirname);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
#endif /* !G_OS_WIN32 */
|
|
|
|
|
|
2011-11-01 23:37:35 +01:00
|
|
|
|
void
|
|
|
|
|
_g_local_file_info_get_nostat (GFileInfo *info,
|
|
|
|
|
const char *basename,
|
|
|
|
|
const char *path,
|
|
|
|
|
GFileAttributeMatcher *attribute_matcher)
|
|
|
|
|
{
|
|
|
|
|
g_file_info_set_name (info, basename);
|
|
|
|
|
|
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_DISPLAY_NAME))
|
|
|
|
|
{
|
|
|
|
|
char *display_name = g_filename_display_basename (path);
|
|
|
|
|
|
|
|
|
|
/* look for U+FFFD REPLACEMENT CHARACTER */
|
|
|
|
|
if (strstr (display_name, "\357\277\275") != NULL)
|
|
|
|
|
{
|
|
|
|
|
char *p = display_name;
|
|
|
|
|
display_name = g_strconcat (display_name, _(" (invalid encoding)"), NULL);
|
|
|
|
|
g_free (p);
|
|
|
|
|
}
|
|
|
|
|
g_file_info_set_display_name (info, display_name);
|
|
|
|
|
g_free (display_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_EDIT_NAME))
|
|
|
|
|
{
|
|
|
|
|
char *edit_name = g_filename_display_basename (path);
|
|
|
|
|
g_file_info_set_edit_name (info, edit_name);
|
|
|
|
|
g_free (edit_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_COPY_NAME))
|
|
|
|
|
{
|
|
|
|
|
char *copy_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
|
|
|
|
|
if (copy_name)
|
|
|
|
|
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_COPY_NAME, copy_name);
|
|
|
|
|
g_free (copy_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-29 00:56:53 +02:00
|
|
|
|
static const char *
|
|
|
|
|
get_icon_name (const char *path,
|
|
|
|
|
gboolean use_symbolic,
|
|
|
|
|
gboolean *with_fallbacks_out)
|
|
|
|
|
{
|
|
|
|
|
const char *name = NULL;
|
|
|
|
|
gboolean with_fallbacks = TRUE;
|
|
|
|
|
|
2017-10-05 14:31:10 +02:00
|
|
|
|
if (g_strcmp0 (path, g_get_home_dir ()) == 0)
|
2012-08-29 00:56:53 +02:00
|
|
|
|
{
|
|
|
|
|
name = use_symbolic ? "user-home-symbolic" : "user-home";
|
|
|
|
|
with_fallbacks = FALSE;
|
|
|
|
|
}
|
2017-10-05 14:31:10 +02:00
|
|
|
|
else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)) == 0)
|
2012-08-29 00:56:53 +02:00
|
|
|
|
{
|
|
|
|
|
name = use_symbolic ? "user-desktop-symbolic" : "user-desktop";
|
|
|
|
|
with_fallbacks = FALSE;
|
|
|
|
|
}
|
|
|
|
|
else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)) == 0)
|
|
|
|
|
{
|
|
|
|
|
name = use_symbolic ? "folder-documents-symbolic" : "folder-documents";
|
|
|
|
|
}
|
|
|
|
|
else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD)) == 0)
|
|
|
|
|
{
|
|
|
|
|
name = use_symbolic ? "folder-download-symbolic" : "folder-download";
|
|
|
|
|
}
|
|
|
|
|
else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_MUSIC)) == 0)
|
|
|
|
|
{
|
|
|
|
|
name = use_symbolic ? "folder-music-symbolic" : "folder-music";
|
|
|
|
|
}
|
|
|
|
|
else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_PICTURES)) == 0)
|
|
|
|
|
{
|
|
|
|
|
name = use_symbolic ? "folder-pictures-symbolic" : "folder-pictures";
|
|
|
|
|
}
|
|
|
|
|
else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_PUBLIC_SHARE)) == 0)
|
|
|
|
|
{
|
|
|
|
|
name = use_symbolic ? "folder-publicshare-symbolic" : "folder-publicshare";
|
|
|
|
|
}
|
|
|
|
|
else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_TEMPLATES)) == 0)
|
|
|
|
|
{
|
|
|
|
|
name = use_symbolic ? "folder-templates-symbolic" : "folder-templates";
|
|
|
|
|
}
|
|
|
|
|
else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS)) == 0)
|
|
|
|
|
{
|
|
|
|
|
name = use_symbolic ? "folder-videos-symbolic" : "folder-videos";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
name = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (with_fallbacks_out != NULL)
|
|
|
|
|
*with_fallbacks_out = with_fallbacks;
|
|
|
|
|
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-29 01:22:01 +02:00
|
|
|
|
static GIcon *
|
|
|
|
|
get_icon (const char *path,
|
|
|
|
|
const char *content_type,
|
|
|
|
|
gboolean use_symbolic)
|
|
|
|
|
{
|
|
|
|
|
GIcon *icon = NULL;
|
|
|
|
|
const char *icon_name;
|
|
|
|
|
gboolean with_fallbacks;
|
|
|
|
|
|
2018-05-28 17:19:59 +02:00
|
|
|
|
icon_name = get_icon_name (path, use_symbolic, &with_fallbacks);
|
2012-08-29 01:22:01 +02:00
|
|
|
|
if (icon_name != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (with_fallbacks)
|
|
|
|
|
icon = g_themed_icon_new_with_default_fallbacks (icon_name);
|
|
|
|
|
else
|
|
|
|
|
icon = g_themed_icon_new (icon_name);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (use_symbolic)
|
|
|
|
|
icon = g_content_type_get_symbolic_icon (content_type);
|
|
|
|
|
else
|
|
|
|
|
icon = g_content_type_get_icon (content_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return icon;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
GFileInfo *
|
2007-11-30 06:11:25 +01:00
|
|
|
|
_g_local_file_info_get (const char *basename,
|
|
|
|
|
const char *path,
|
|
|
|
|
GFileAttributeMatcher *attribute_matcher,
|
|
|
|
|
GFileQueryInfoFlags flags,
|
|
|
|
|
GLocalParentFileInfo *parent_info,
|
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
GFileInfo *info;
|
2008-03-12 19:33:59 +01:00
|
|
|
|
GLocalFileStat statbuf;
|
2020-08-14 16:52:03 +02:00
|
|
|
|
GLocalFileStat statbuf2;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
int res;
|
2010-07-08 20:19:08 +02:00
|
|
|
|
gboolean stat_ok;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
gboolean is_symlink, symlink_broken;
|
2009-06-18 09:05:27 +02:00
|
|
|
|
char *symlink_target;
|
|
|
|
|
GVfs *vfs;
|
|
|
|
|
GVfsClass *class;
|
2009-11-26 16:05:07 +01:00
|
|
|
|
guint64 device;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
info = g_file_info_new ();
|
|
|
|
|
|
|
|
|
|
/* Make sure we don't set any unwanted attributes */
|
|
|
|
|
g_file_info_set_attribute_mask (info, attribute_matcher);
|
|
|
|
|
|
2011-11-01 23:37:35 +01:00
|
|
|
|
_g_local_file_info_get_nostat (info, basename, path, attribute_matcher);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (attribute_matcher == NULL)
|
2011-10-16 21:58:29 +02:00
|
|
|
|
{
|
|
|
|
|
g_file_info_unset_attribute_mask (info);
|
|
|
|
|
return info;
|
|
|
|
|
}
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2020-08-14 16:52:03 +02:00
|
|
|
|
res = g_local_file_lstat (path,
|
2020-08-14 17:12:05 +02:00
|
|
|
|
G_LOCAL_FILE_STAT_FIELD_BASIC_STATS | G_LOCAL_FILE_STAT_FIELD_BTIME,
|
2020-08-23 16:41:17 +02:00
|
|
|
|
G_LOCAL_FILE_STAT_FIELD_ALL & (~G_LOCAL_FILE_STAT_FIELD_BTIME) & (~G_LOCAL_FILE_STAT_FIELD_ATIME),
|
2020-08-14 16:52:03 +02:00
|
|
|
|
&statbuf);
|
2008-03-12 19:33:59 +01:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (res == -1)
|
|
|
|
|
{
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
int errsv = errno;
|
2010-07-08 20:19:08 +02:00
|
|
|
|
|
|
|
|
|
/* Don't bail out if we get Permission denied (SELinux?) */
|
|
|
|
|
if (errsv != EACCES)
|
|
|
|
|
{
|
|
|
|
|
char *display_name = g_filename_display_name (path);
|
|
|
|
|
g_object_unref (info);
|
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
|
g_io_error_from_errno (errsv),
|
2016-09-30 05:47:15 +02:00
|
|
|
|
_("Error when getting information for file “%s”: %s"),
|
2010-07-08 20:19:08 +02:00
|
|
|
|
display_name, g_strerror (errsv));
|
|
|
|
|
g_free (display_name);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
2009-11-26 16:05:07 +01:00
|
|
|
|
|
2010-07-08 20:19:08 +02:00
|
|
|
|
/* Even if stat() fails, try to get as much as other attributes possible */
|
|
|
|
|
stat_ok = res != -1;
|
|
|
|
|
|
|
|
|
|
if (stat_ok)
|
2020-08-14 15:46:14 +02:00
|
|
|
|
device = _g_stat_dev (&statbuf);
|
2010-07-08 20:19:08 +02:00
|
|
|
|
else
|
|
|
|
|
device = 0;
|
2009-11-26 16:05:07 +01:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#ifdef S_ISLNK
|
2020-08-14 15:46:14 +02:00
|
|
|
|
is_symlink = stat_ok && S_ISLNK (_g_stat_mode (&statbuf));
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#elif defined (G_OS_WIN32)
|
|
|
|
|
/* glib already checked the FILE_ATTRIBUTE_REPARSE_POINT for us */
|
2018-08-08 23:42:45 +02:00
|
|
|
|
is_symlink = stat_ok &&
|
|
|
|
|
(statbuf.reparse_tag == IO_REPARSE_TAG_SYMLINK ||
|
|
|
|
|
statbuf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#else
|
|
|
|
|
is_symlink = FALSE;
|
|
|
|
|
#endif
|
|
|
|
|
symlink_broken = FALSE;
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (is_symlink)
|
|
|
|
|
{
|
|
|
|
|
g_file_info_set_is_symlink (info, TRUE);
|
|
|
|
|
|
|
|
|
|
/* Unless NOFOLLOW was set we default to following symlinks */
|
|
|
|
|
if (!(flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS))
|
|
|
|
|
{
|
2020-08-14 16:52:03 +02:00
|
|
|
|
res = g_local_file_stat (path,
|
2020-08-14 17:12:05 +02:00
|
|
|
|
G_LOCAL_FILE_STAT_FIELD_BASIC_STATS | G_LOCAL_FILE_STAT_FIELD_BTIME,
|
glocalfile: Never require G_LOCAL_FILE_STAT_FIELD_ATIME
Some filesystems don't have meaningful access times under at least some
circumstances (see #2189, #2205). In this situation the traditional stat()
and related kernel interfaces have to put something meaningless in the
st_atime field, and have no way to signal that it is meaningless.
However, statx() does have a way to signal that the atime is meaningless:
if the filesystem doesn't provide a useful access time, it will unset
the STATX_ATIME bit (as well as filling in the same meaningless value
for the stx_atime field that stat() would have used, for compatibility).
We don't actually *need* the atime, so never include it in the required
mask. This was already done for one code path in commit 6fc143bb
"gio: Allow no atime from statx" to fix #2189, but other callers were
left unchanged in that commit, and receive the same change here.
It is not actually guaranteed that *any* of the flags in the
returned stx_mask will be set (the only guarantee is that items in
STATX_BASIC_STATS have at least a harmless compatibility value, even if
their corresponding flag is cleared), so it might be better to follow
this up by removing the concept of the required mask entirely. However,
as of Linux 5.8 it looks as though STATX_ATIME is the only flag in
STATX_BASIC_STATS that might be cleared in practice, so this simpler
change fixes the immediate regression.
Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/2205
Signed-off-by: Simon McVittie <smcv@collabora.com>
2020-09-15 11:08:14 +02:00
|
|
|
|
G_LOCAL_FILE_STAT_FIELD_ALL & (~G_LOCAL_FILE_STAT_FIELD_BTIME) & (~G_LOCAL_FILE_STAT_FIELD_ATIME),
|
2020-08-14 16:52:03 +02:00
|
|
|
|
&statbuf2);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2010-07-08 20:19:08 +02:00
|
|
|
|
/* Report broken links as symlinks */
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (res != -1)
|
2010-07-08 20:19:08 +02:00
|
|
|
|
{
|
|
|
|
|
statbuf = statbuf2;
|
|
|
|
|
stat_ok = TRUE;
|
|
|
|
|
}
|
2007-11-26 17:13:05 +01:00
|
|
|
|
else
|
|
|
|
|
symlink_broken = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-08 12:13:05 +01:00
|
|
|
|
else
|
|
|
|
|
g_file_info_set_is_symlink (info, FALSE);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2010-07-08 20:19:08 +02:00
|
|
|
|
if (stat_ok)
|
|
|
|
|
set_info_from_stat (info, &statbuf, attribute_matcher);
|
|
|
|
|
|
2008-03-12 19:33:59 +01:00
|
|
|
|
#ifndef G_OS_WIN32
|
2013-01-11 17:10:15 +01:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_IS_HIDDEN))
|
|
|
|
|
{
|
2023-02-08 12:13:05 +01:00
|
|
|
|
g_file_info_set_is_hidden (info,
|
|
|
|
|
(basename != NULL &&
|
|
|
|
|
(basename[0] == '.' ||
|
2023-03-06 13:06:47 +01:00
|
|
|
|
file_is_hidden (path, basename) ||
|
|
|
|
|
(stat_ok &&
|
|
|
|
|
_g_local_file_is_lost_found_dir (path, _g_stat_dev (&statbuf))))));
|
2013-01-11 17:10:15 +01:00
|
|
|
|
}
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2023-03-06 13:38:40 +01:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_IS_BACKUP,
|
|
|
|
|
basename != NULL && basename[strlen (basename) - 1] == '~' &&
|
|
|
|
|
(stat_ok && S_ISREG (_g_stat_mode (&statbuf))));
|
2008-03-12 19:33:59 +01:00
|
|
|
|
#else
|
2023-03-06 15:38:22 +01:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_IS_BACKUP, FALSE);
|
|
|
|
|
|
2023-03-06 15:36:26 +01:00
|
|
|
|
g_file_info_set_is_hidden (info, (statbuf.attributes & FILE_ATTRIBUTE_HIDDEN));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2023-03-06 15:36:26 +01:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_ARCHIVE,
|
|
|
|
|
(statbuf.attributes & FILE_ATTRIBUTE_ARCHIVE));
|
2008-03-12 19:33:59 +01:00
|
|
|
|
|
2023-03-06 15:36:26 +01:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_SYSTEM,
|
|
|
|
|
(statbuf.attributes & FILE_ATTRIBUTE_SYSTEM));
|
2018-08-09 00:26:41 +02:00
|
|
|
|
|
2023-03-06 15:36:26 +01:00
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_MOUNTPOINT,
|
|
|
|
|
(statbuf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT));
|
2018-08-09 00:26:41 +02:00
|
|
|
|
|
|
|
|
|
if (statbuf.reparse_tag != 0)
|
|
|
|
|
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_REPARSE_POINT_TAG, statbuf.reparse_tag);
|
2023-03-06 14:22:05 +01:00
|
|
|
|
|
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_IS_BACKUP, FALSE);
|
2008-03-12 19:33:59 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2009-06-18 09:05:27 +02:00
|
|
|
|
symlink_target = NULL;
|
|
|
|
|
if (is_symlink)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#if defined (S_ISLNK) || defined (G_OS_WIN32)
|
2009-06-18 09:05:27 +02:00
|
|
|
|
symlink_target = read_link (path);
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#endif
|
2009-06-18 09:05:27 +02:00
|
|
|
|
if (symlink_target &&
|
2009-06-29 14:13:14 +02:00
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_SYMLINK_TARGET))
|
2009-06-18 09:05:27 +02:00
|
|
|
|
g_file_info_set_symlink_target (info, symlink_target);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
2012-08-29 00:56:53 +02:00
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_ICON) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_SYMBOLIC_ICON))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2010-07-08 20:19:08 +02:00
|
|
|
|
char *content_type = get_content_type (basename, path, stat_ok ? &statbuf : NULL, is_symlink, symlink_broken, flags, FALSE);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (content_type)
|
|
|
|
|
{
|
|
|
|
|
g_file_info_set_content_type (info, content_type);
|
|
|
|
|
|
2012-08-29 01:22:01 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_ICON)
|
|
|
|
|
|| _g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_SYMBOLIC_ICON))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
GIcon *icon;
|
|
|
|
|
|
2012-08-29 01:22:01 +02:00
|
|
|
|
/* non symbolic icon */
|
2014-03-10 19:46:23 +01:00
|
|
|
|
icon = get_icon (path, content_type, FALSE);
|
2012-08-29 01:22:01 +02:00
|
|
|
|
if (icon != NULL)
|
Implement this function by moving bits from glocalfileinfo.c
2008-02-21 David Zeuthen <davidz@redhat.com>
* glocalfileinfo.c: (_g_local_file_info_get):
* gcontenttype.c:
(g_content_type_get_icon): Implement this function by
moving bits from glocalfileinfo.c
(g_content_type_get_description): Unalias before getting
description (#517687)
* gfile.c: (g_file_class_init),
(g_file_query_filesystem_info_async),
(g_file_query_filesystem_info_finish),
(query_filesystem_info_data_free),
(query_filesystem_info_async_thread),
(g_file_real_query_filesystem_info_async),
(g_file_real_query_filesystem_info_finish):
* gfile.h: Implement async version of
g_file_query_filesystem_info()
* gfileinfo.h: Add new attributes for filesystem::use-preview
* gio.symbols: Update
* gthemedicon.c: (g_themed_icon_append_name):
* gthemedicon.h: Add new new convenience function.
* gunionvolumemonitor.c: (g_union_volume_monitor_dispose),
(get_mounts), (get_volumes), (get_connected_drives),
(get_volume_for_uuid), (get_mount_for_uuid),
(g_union_volume_monitor_init), (populate_union_monitor),
(g_volume_monitor_get), (_g_mount_get_for_mount_path),
(g_volume_monitor_adopt_orphan_mount):
* gvolumemonitor.c:
* gvolumemonitor.h: Use recursive locks so it's safe for volume
monitor implementations to call into the main volume monitor. Also
separate object initialization and volume monitor initialization
such that non-native volume monitors can properly adopt their
mounts away.
svn path=/trunk/; revision=6550
2008-02-21 13:35:05 +01:00
|
|
|
|
{
|
2012-08-29 01:22:01 +02:00
|
|
|
|
g_file_info_set_icon (info, icon);
|
|
|
|
|
g_object_unref (icon);
|
2008-06-19 05:30:17 +02:00
|
|
|
|
}
|
Implement this function by moving bits from glocalfileinfo.c
2008-02-21 David Zeuthen <davidz@redhat.com>
* glocalfileinfo.c: (_g_local_file_info_get):
* gcontenttype.c:
(g_content_type_get_icon): Implement this function by
moving bits from glocalfileinfo.c
(g_content_type_get_description): Unalias before getting
description (#517687)
* gfile.c: (g_file_class_init),
(g_file_query_filesystem_info_async),
(g_file_query_filesystem_info_finish),
(query_filesystem_info_data_free),
(query_filesystem_info_async_thread),
(g_file_real_query_filesystem_info_async),
(g_file_real_query_filesystem_info_finish):
* gfile.h: Implement async version of
g_file_query_filesystem_info()
* gfileinfo.h: Add new attributes for filesystem::use-preview
* gio.symbols: Update
* gthemedicon.c: (g_themed_icon_append_name):
* gthemedicon.h: Add new new convenience function.
* gunionvolumemonitor.c: (g_union_volume_monitor_dispose),
(get_mounts), (get_volumes), (get_connected_drives),
(get_volume_for_uuid), (get_mount_for_uuid),
(g_union_volume_monitor_init), (populate_union_monitor),
(g_volume_monitor_get), (_g_mount_get_for_mount_path),
(g_volume_monitor_adopt_orphan_mount):
* gvolumemonitor.c:
* gvolumemonitor.h: Use recursive locks so it's safe for volume
monitor implementations to call into the main volume monitor. Also
separate object initialization and volume monitor initialization
such that non-native volume monitors can properly adopt their
mounts away.
svn path=/trunk/; revision=6550
2008-02-21 13:35:05 +01:00
|
|
|
|
|
2012-08-29 01:22:01 +02:00
|
|
|
|
/* symbolic icon */
|
2014-03-10 19:46:23 +01:00
|
|
|
|
icon = get_icon (path, content_type, TRUE);
|
2008-06-19 05:30:17 +02:00
|
|
|
|
if (icon != NULL)
|
|
|
|
|
{
|
2012-08-29 01:22:01 +02:00
|
|
|
|
g_file_info_set_symbolic_icon (info, icon);
|
Implement this function by moving bits from glocalfileinfo.c
2008-02-21 David Zeuthen <davidz@redhat.com>
* glocalfileinfo.c: (_g_local_file_info_get):
* gcontenttype.c:
(g_content_type_get_icon): Implement this function by
moving bits from glocalfileinfo.c
(g_content_type_get_description): Unalias before getting
description (#517687)
* gfile.c: (g_file_class_init),
(g_file_query_filesystem_info_async),
(g_file_query_filesystem_info_finish),
(query_filesystem_info_data_free),
(query_filesystem_info_async_thread),
(g_file_real_query_filesystem_info_async),
(g_file_real_query_filesystem_info_finish):
* gfile.h: Implement async version of
g_file_query_filesystem_info()
* gfileinfo.h: Add new attributes for filesystem::use-preview
* gio.symbols: Update
* gthemedicon.c: (g_themed_icon_append_name):
* gthemedicon.h: Add new new convenience function.
* gunionvolumemonitor.c: (g_union_volume_monitor_dispose),
(get_mounts), (get_volumes), (get_connected_drives),
(get_volume_for_uuid), (get_mount_for_uuid),
(g_union_volume_monitor_init), (populate_union_monitor),
(g_volume_monitor_get), (_g_mount_get_for_mount_path),
(g_volume_monitor_adopt_orphan_mount):
* gvolumemonitor.c:
* gvolumemonitor.h: Use recursive locks so it's safe for volume
monitor implementations to call into the main volume monitor. Also
separate object initialization and volume monitor initialization
such that non-native volume monitors can properly adopt their
mounts away.
svn path=/trunk/; revision=6550
2008-02-21 13:35:05 +01:00
|
|
|
|
g_object_unref (icon);
|
|
|
|
|
}
|
2012-08-29 01:22:01 +02:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_free (content_type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2010-07-08 20:19:08 +02:00
|
|
|
|
char *content_type = get_content_type (basename, path, stat_ok ? &statbuf : NULL, is_symlink, symlink_broken, flags, TRUE);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (content_type)
|
|
|
|
|
{
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_FAST_CONTENT_TYPE, content_type);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_free (content_type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_OWNER_USER))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2007-12-08 13:01:06 +01:00
|
|
|
|
char *name = NULL;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
win32_get_file_user_info (path, NULL, &name, NULL);
|
|
|
|
|
#else
|
2010-07-08 20:19:08 +02:00
|
|
|
|
if (stat_ok)
|
2020-08-14 15:46:14 +02:00
|
|
|
|
name = get_username_from_uid (_g_stat_uid (&statbuf));
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (name)
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_OWNER_USER, name);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_free (name);
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_OWNER_USER_REAL))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2007-12-08 13:01:06 +01:00
|
|
|
|
char *name = NULL;
|
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
win32_get_file_user_info (path, NULL, NULL, &name);
|
|
|
|
|
#else
|
2010-07-08 20:19:08 +02:00
|
|
|
|
if (stat_ok)
|
2020-08-14 15:46:14 +02:00
|
|
|
|
name = get_realname_from_uid (_g_stat_uid (&statbuf));
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (name)
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_OWNER_USER_REAL, name);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_free (name);
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_OWNER_GROUP))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2007-12-08 13:01:06 +01:00
|
|
|
|
char *name = NULL;
|
|
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
|
win32_get_file_user_info (path, &name, NULL, NULL);
|
|
|
|
|
#else
|
2010-07-08 20:19:08 +02:00
|
|
|
|
if (stat_ok)
|
2020-08-14 15:46:14 +02:00
|
|
|
|
name = get_groupname_from_gid (_g_stat_gid (&statbuf));
|
2007-12-08 13:01:06 +01:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (name)
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_OWNER_GROUP, name);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_free (name);
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-08 20:19:08 +02:00
|
|
|
|
if (stat_ok && parent_info && parent_info->device != 0 &&
|
2023-03-06 15:36:26 +01:00
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_UNIX_IS_MOUNTPOINT))
|
|
|
|
|
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_IS_MOUNTPOINT,
|
|
|
|
|
(_g_stat_dev (&statbuf) != parent_info->device || _g_stat_ino (&statbuf) == parent_info->inode));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2010-07-08 20:19:08 +02:00
|
|
|
|
if (stat_ok)
|
|
|
|
|
get_access_rights (attribute_matcher, info, path, &statbuf, parent_info);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2008-10-15 05:37:56 +02:00
|
|
|
|
#ifdef HAVE_SELINUX
|
2007-11-26 17:13:05 +01:00
|
|
|
|
get_selinux_context (path, info, attribute_matcher, (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) == 0);
|
2008-10-15 05:37:56 +02:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
get_xattrs (path, TRUE, info, attribute_matcher, (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) == 0);
|
|
|
|
|
get_xattrs (path, FALSE, info, attribute_matcher, (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) == 0);
|
|
|
|
|
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
2017-12-07 11:21:35 +01:00
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED))
|
2013-10-11 12:22:31 +02:00
|
|
|
|
{
|
2022-09-22 22:29:41 +02:00
|
|
|
|
get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_AUTO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_NORMAL) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_NORMAL) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_NORMAL))
|
|
|
|
|
{
|
|
|
|
|
get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_NORMAL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_LARGE) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_LARGE) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_LARGE))
|
|
|
|
|
{
|
|
|
|
|
get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_LARGE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XLARGE) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XLARGE) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XLARGE))
|
|
|
|
|
{
|
|
|
|
|
get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_XLARGE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH_XXLARGE) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID_XXLARGE) ||
|
|
|
|
|
_g_file_attribute_matcher_matches_id (attribute_matcher,
|
|
|
|
|
G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED_XXLARGE))
|
|
|
|
|
{
|
|
|
|
|
get_thumbnail_attributes (path, info, stat_ok ? &statbuf : NULL, THUMBNAIL_SIZE_XXLARGE);
|
2013-10-11 12:22:31 +02:00
|
|
|
|
}
|
2009-06-18 09:05:27 +02:00
|
|
|
|
|
|
|
|
|
vfs = g_vfs_get_default ();
|
|
|
|
|
class = G_VFS_GET_CLASS (vfs);
|
|
|
|
|
if (class->local_file_add_info)
|
|
|
|
|
{
|
|
|
|
|
class->local_file_add_info (vfs,
|
2009-09-28 15:55:44 +02:00
|
|
|
|
path,
|
2009-11-26 16:05:07 +01:00
|
|
|
|
device,
|
2009-06-18 09:05:27 +02:00
|
|
|
|
attribute_matcher,
|
|
|
|
|
info,
|
|
|
|
|
NULL,
|
|
|
|
|
&parent_info->extra_data,
|
|
|
|
|
&parent_info->free_extra_data);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_file_info_unset_attribute_mask (info);
|
|
|
|
|
|
2009-06-18 09:05:27 +02:00
|
|
|
|
g_free (symlink_target);
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GFileInfo *
|
2009-03-03 16:50:13 +01:00
|
|
|
|
_g_local_file_info_get_from_fd (int fd,
|
|
|
|
|
const char *attributes,
|
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2008-03-12 19:33:59 +01:00
|
|
|
|
GLocalFileStat stat_buf;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
GFileAttributeMatcher *matcher;
|
|
|
|
|
GFileInfo *info;
|
2008-03-12 19:33:59 +01:00
|
|
|
|
|
2020-08-14 16:52:03 +02:00
|
|
|
|
if (g_local_file_fstat (fd,
|
2020-08-14 17:12:05 +02:00
|
|
|
|
G_LOCAL_FILE_STAT_FIELD_BASIC_STATS | G_LOCAL_FILE_STAT_FIELD_BTIME,
|
glocalfile: Never require G_LOCAL_FILE_STAT_FIELD_ATIME
Some filesystems don't have meaningful access times under at least some
circumstances (see #2189, #2205). In this situation the traditional stat()
and related kernel interfaces have to put something meaningless in the
st_atime field, and have no way to signal that it is meaningless.
However, statx() does have a way to signal that the atime is meaningless:
if the filesystem doesn't provide a useful access time, it will unset
the STATX_ATIME bit (as well as filling in the same meaningless value
for the stx_atime field that stat() would have used, for compatibility).
We don't actually *need* the atime, so never include it in the required
mask. This was already done for one code path in commit 6fc143bb
"gio: Allow no atime from statx" to fix #2189, but other callers were
left unchanged in that commit, and receive the same change here.
It is not actually guaranteed that *any* of the flags in the
returned stx_mask will be set (the only guarantee is that items in
STATX_BASIC_STATS have at least a harmless compatibility value, even if
their corresponding flag is cleared), so it might be better to follow
this up by removing the concept of the required mask entirely. However,
as of Linux 5.8 it looks as though STATX_ATIME is the only flag in
STATX_BASIC_STATS that might be cleared in practice, so this simpler
change fixes the immediate regression.
Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/2205
Signed-off-by: Simon McVittie <smcv@collabora.com>
2020-09-15 11:08:14 +02:00
|
|
|
|
G_LOCAL_FILE_STAT_FIELD_ALL & (~G_LOCAL_FILE_STAT_FIELD_BTIME) & (~G_LOCAL_FILE_STAT_FIELD_ATIME),
|
2020-08-14 16:52:03 +02:00
|
|
|
|
&stat_buf) == -1)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
int errsv = errno;
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_io_error_from_errno (errsv),
|
2011-09-08 16:11:56 +02:00
|
|
|
|
_("Error when getting information for file descriptor: %s"),
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_strerror (errsv));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info = g_file_info_new ();
|
|
|
|
|
|
|
|
|
|
matcher = g_file_attribute_matcher_new (attributes);
|
|
|
|
|
|
|
|
|
|
/* Make sure we don't set any unwanted attributes */
|
|
|
|
|
g_file_info_set_attribute_mask (info, matcher);
|
|
|
|
|
|
|
|
|
|
set_info_from_stat (info, &stat_buf, matcher);
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_SELINUX
|
2009-06-29 14:13:14 +02:00
|
|
|
|
if (_g_file_attribute_matcher_matches_id (matcher, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT) &&
|
2007-11-26 17:13:05 +01:00
|
|
|
|
is_selinux_enabled ())
|
|
|
|
|
{
|
|
|
|
|
char *context;
|
|
|
|
|
if (fgetfilecon_raw (fd, &context) >= 0)
|
|
|
|
|
{
|
2009-06-29 15:28:08 +02:00
|
|
|
|
_g_file_info_set_attribute_string_by_id (info, G_FILE_ATTRIBUTE_ID_SELINUX_CONTEXT, context);
|
2008-01-03 10:01:00 +01:00
|
|
|
|
freecon (context);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
get_xattrs_from_fd (fd, TRUE, info, matcher);
|
|
|
|
|
get_xattrs_from_fd (fd, FALSE, info, matcher);
|
|
|
|
|
|
|
|
|
|
g_file_attribute_matcher_unref (matcher);
|
|
|
|
|
|
|
|
|
|
g_file_info_unset_attribute_mask (info);
|
|
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2007-11-30 06:11:25 +01:00
|
|
|
|
get_uint32 (const GFileAttributeValue *value,
|
|
|
|
|
guint32 *val_out,
|
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
if (value->type != G_FILE_ATTRIBUTE_TYPE_UINT32)
|
|
|
|
|
{
|
2008-06-16 18:53:58 +02:00
|
|
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
|
|
|
_("Invalid attribute type (uint32 expected)"));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*val_out = value->u.uint32;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-02 15:10:44 +02:00
|
|
|
|
#if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
static gboolean
|
2007-11-30 06:11:25 +01:00
|
|
|
|
get_uint64 (const GFileAttributeValue *value,
|
|
|
|
|
guint64 *val_out,
|
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
if (value->type != G_FILE_ATTRIBUTE_TYPE_UINT64)
|
|
|
|
|
{
|
2008-06-16 18:53:58 +02:00
|
|
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
|
|
|
_("Invalid attribute type (uint64 expected)"));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*val_out = value->u.uint64;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2008-03-12 19:33:59 +01:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
#if defined(HAVE_SYMLINK)
|
|
|
|
|
static gboolean
|
2007-11-30 06:11:25 +01:00
|
|
|
|
get_byte_string (const GFileAttributeValue *value,
|
|
|
|
|
const char **val_out,
|
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
if (value->type != G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
|
|
|
|
|
{
|
2008-06-16 18:53:58 +02:00
|
|
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
|
|
|
_("Invalid attribute type (byte string expected)"));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*val_out = value->u.string;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-10-15 05:37:56 +02:00
|
|
|
|
#ifdef HAVE_SELINUX
|
2008-07-23 06:11:02 +02:00
|
|
|
|
static gboolean
|
|
|
|
|
get_string (const GFileAttributeValue *value,
|
|
|
|
|
const char **val_out,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
if (value->type != G_FILE_ATTRIBUTE_TYPE_STRING)
|
|
|
|
|
{
|
2008-10-10 06:54:51 +02:00
|
|
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
|
|
|
_("Invalid attribute type (byte string expected)"));
|
2008-07-23 06:11:02 +02:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*val_out = value->u.string;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2008-10-15 05:37:56 +02:00
|
|
|
|
#endif
|
2008-07-23 06:11:02 +02:00
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
static gboolean
|
2007-11-30 06:11:25 +01:00
|
|
|
|
set_unix_mode (char *filename,
|
2009-09-01 11:54:48 +02:00
|
|
|
|
GFileQueryInfoFlags flags,
|
2007-11-30 06:11:25 +01:00
|
|
|
|
const GFileAttributeValue *value,
|
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2011-04-26 19:28:17 +02:00
|
|
|
|
guint32 val = 0;
|
2009-09-01 21:26:08 +02:00
|
|
|
|
int res = 0;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (!get_uint32 (value, &val, error))
|
|
|
|
|
return FALSE;
|
2009-09-01 20:36:31 +02:00
|
|
|
|
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#if defined (HAVE_SYMLINK) || defined (G_OS_WIN32)
|
2009-09-01 11:54:48 +02:00
|
|
|
|
if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) {
|
2009-09-01 21:53:35 +02:00
|
|
|
|
#ifdef HAVE_LCHMOD
|
|
|
|
|
res = lchmod (filename, val);
|
|
|
|
|
#else
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
gboolean is_symlink;
|
|
|
|
|
#ifndef G_OS_WIN32
|
2009-09-01 21:26:08 +02:00
|
|
|
|
struct stat statbuf;
|
|
|
|
|
/* Calling chmod on a symlink changes permissions on the symlink.
|
|
|
|
|
* We don't want to do this, so we need to check for a symlink */
|
|
|
|
|
res = g_lstat (filename, &statbuf);
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
is_symlink = (res == 0 && S_ISLNK (statbuf.st_mode));
|
|
|
|
|
#else
|
|
|
|
|
/* FIXME: implement lchmod for W32, should be doable */
|
|
|
|
|
GWin32PrivateStat statbuf;
|
|
|
|
|
|
|
|
|
|
res = GLIB_PRIVATE_CALL (g_win32_lstat_utf8) (filename, &statbuf);
|
2018-08-08 23:42:45 +02:00
|
|
|
|
is_symlink = (res == 0 &&
|
|
|
|
|
(statbuf.reparse_tag == IO_REPARSE_TAG_SYMLINK ||
|
|
|
|
|
statbuf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT));
|
W32: Add a stat() implementation for private use
This commit adds new W32-only functions to gstdio.c,
and a new header file, gstdioprivate.h.
These functions are:
g_win32_stat_utf8()
g_win32_lstat_utf8()
g_win32_fstat()
and they fill a private structure, GWin32PrivateStat,
which has all the fields that normal stat has, as well as some
extras.
These functions are then used throughout glib and gio to get better
data about the system. Specifically:
* Full, 64-bit size, guaranteed (g_stat() is forced to use 32-bit st_size)
* Full, 64-bit file identifier (st_ino is 0 when normal stat() is used, and still is)
* W32 File attributes (which stat() doesn't report); in particular, this allows
symlinks to be correctly identified
* Full, 64-bit time, guaranteed (g_stat() uses 32-bit st_*time on 32-bit Windows)
* Allocated file size (as a W32 replacement for the missing st_blocks)
st_mode remains unchanged (thus, no S_ISLNK), so when these are given back to
glib users (via g_stat(), for example, which is now implemented by calling g_win32_stat_utf8),
this field does not contain anything unexpected.
g_lstat() now calls g_win32_lstat_utf8(), which works on symlinks the way it's supposed to.
Also adds the g_win32_readlink_utf8() function, which behaves like readlink()
(including its inability to return 0-terminated strings and inability to say how large
the output buffer should be; these limitations are purely for compatibility with
existing glib code).
Thus, symlink support should now be much better, although far from being complete.
A new W32-only test in gio/tests/file.c highlights the following features:
* allocated size
* 64-bit time
* unique file IDs
https://bugzilla.gnome.org/show_bug.cgi?id=788180
2017-09-29 12:14:41 +02:00
|
|
|
|
#endif
|
|
|
|
|
if (is_symlink)
|
2009-09-01 21:26:08 +02:00
|
|
|
|
{
|
|
|
|
|
g_set_error_literal (error, G_IO_ERROR,
|
|
|
|
|
G_IO_ERROR_NOT_SUPPORTED,
|
|
|
|
|
_("Cannot set permissions on symlinks"));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2009-09-01 21:53:35 +02:00
|
|
|
|
else if (res == 0)
|
|
|
|
|
res = g_chmod (filename, val);
|
|
|
|
|
#endif
|
|
|
|
|
} else
|
2009-09-01 20:36:31 +02:00
|
|
|
|
#endif
|
2009-09-01 21:26:08 +02:00
|
|
|
|
res = g_chmod (filename, val);
|
|
|
|
|
|
|
|
|
|
if (res == -1)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
int errsv = errno;
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_io_error_from_errno (errsv),
|
2007-11-26 17:13:05 +01:00
|
|
|
|
_("Error setting permissions: %s"),
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_strerror (errsv));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
Require POSIX.1 (1990) compliance on unix
Assume unix platforms support the original POSIX.1 standard.
Specifically, assume that if G_OS_UNIX, then we have chown(),
getcwd(), getgrgid(), getpwuid(), link(), <grp.h>, <pwd.h>,
<sys/types.h>, <sys/uio.h>, <sys/wait.h>, and <unistd.h>.
Additionally, since all versions of Windows that we care about also
have <sys/types.h>, we can remove HAVE_SYS_TYPES_H checks everywhere.
Also remove one include of <sys/times.h>, and the corresponding
configure check, since the include is not currently needed (and may
always have just been a typo for <sys/time.h>).
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:59 +02:00
|
|
|
|
#ifdef G_OS_UNIX
|
2007-11-26 17:13:05 +01:00
|
|
|
|
static gboolean
|
2007-11-30 06:11:25 +01:00
|
|
|
|
set_unix_uid_gid (char *filename,
|
|
|
|
|
const GFileAttributeValue *uid_value,
|
|
|
|
|
const GFileAttributeValue *gid_value,
|
|
|
|
|
GFileQueryInfoFlags flags,
|
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
int res;
|
2011-04-26 19:28:17 +02:00
|
|
|
|
guint32 val = 0;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
uid_t uid;
|
|
|
|
|
gid_t gid;
|
|
|
|
|
|
|
|
|
|
if (uid_value)
|
|
|
|
|
{
|
|
|
|
|
if (!get_uint32 (uid_value, &val, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
uid = val;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
uid = -1;
|
|
|
|
|
|
|
|
|
|
if (gid_value)
|
|
|
|
|
{
|
|
|
|
|
if (!get_uint32 (gid_value, &val, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
gid = val;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
gid = -1;
|
|
|
|
|
|
2008-01-03 10:13:39 +01:00
|
|
|
|
#ifdef HAVE_LCHOWN
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS)
|
|
|
|
|
res = lchown (filename, uid, gid);
|
|
|
|
|
else
|
2008-01-03 10:13:39 +01:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
res = chown (filename, uid, gid);
|
|
|
|
|
|
|
|
|
|
if (res == -1)
|
|
|
|
|
{
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
int errsv = errno;
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_io_error_from_errno (errsv),
|
2007-11-26 17:13:05 +01:00
|
|
|
|
_("Error setting owner: %s"),
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_strerror (errsv));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_SYMLINK
|
|
|
|
|
static gboolean
|
2007-11-30 06:11:25 +01:00
|
|
|
|
set_symlink (char *filename,
|
|
|
|
|
const GFileAttributeValue *value,
|
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
const char *val;
|
|
|
|
|
struct stat statbuf;
|
|
|
|
|
|
|
|
|
|
if (!get_byte_string (value, &val, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (val == NULL)
|
|
|
|
|
{
|
2008-06-16 18:53:58 +02:00
|
|
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
|
|
|
_("symlink must be non-NULL"));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_lstat (filename, &statbuf))
|
|
|
|
|
{
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
int errsv = errno;
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_io_error_from_errno (errsv),
|
2007-11-26 17:13:05 +01:00
|
|
|
|
_("Error setting symlink: %s"),
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_strerror (errsv));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!S_ISLNK (statbuf.st_mode))
|
|
|
|
|
{
|
2008-06-16 18:53:58 +02:00
|
|
|
|
g_set_error_literal (error, G_IO_ERROR,
|
|
|
|
|
G_IO_ERROR_NOT_SYMBOLIC_LINK,
|
|
|
|
|
_("Error setting symlink: file is not a symlink"));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_unlink (filename))
|
|
|
|
|
{
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
int errsv = errno;
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_io_error_from_errno (errsv),
|
2007-11-26 17:13:05 +01:00
|
|
|
|
_("Error setting symlink: %s"),
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_strerror (errsv));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (symlink (filename, val) != 0)
|
|
|
|
|
{
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
int errsv = errno;
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_io_error_from_errno (errsv),
|
2007-11-26 17:13:05 +01:00
|
|
|
|
_("Error setting symlink: %s"),
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
g_strerror (errsv));
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-10-14 14:46:05 +02:00
|
|
|
|
#if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined(G_OS_WIN32)
|
|
|
|
|
static int
|
|
|
|
|
lazy_stat (const char *filename,
|
|
|
|
|
GStatBuf *statbuf,
|
|
|
|
|
gboolean *called_stat)
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
|
|
|
|
|
if (*called_stat)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
res = g_stat (filename, statbuf);
|
|
|
|
|
|
|
|
|
|
if (res == 0)
|
|
|
|
|
*called_stat = TRUE;
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-01-19 20:54:26 +01:00
|
|
|
|
#if defined (G_OS_WIN32)
|
|
|
|
|
/* From
|
|
|
|
|
* https://support.microsoft.com/en-ca/help/167296/how-to-convert-a-unix-time-t-to-a-win32-filetime-or-systemtime
|
|
|
|
|
* FT = UT * 10000000 + 116444736000000000.
|
|
|
|
|
* Converts unix epoch time (a signed 64-bit integer) to FILETIME.
|
|
|
|
|
* Can optionally use a more precise timestamp that has
|
|
|
|
|
* a fraction of a second expressed in nanoseconds.
|
|
|
|
|
* UT must be between January 1st of year 1601 and December 31st of year 30827.
|
|
|
|
|
* nsec must be non-negative and < 1000000000.
|
|
|
|
|
* Returns TRUE if conversion succeeded, FALSE otherwise.
|
|
|
|
|
*
|
|
|
|
|
* The function that does the reverse can be found in
|
|
|
|
|
* glib/gstdio.c.
|
|
|
|
|
*/
|
|
|
|
|
static gboolean
|
|
|
|
|
_g_win32_unix_time_to_filetime (gint64 ut,
|
|
|
|
|
gint32 nsec,
|
|
|
|
|
FILETIME *ft,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
gint64 result;
|
|
|
|
|
/* 1 unit of FILETIME is 100ns */
|
2021-07-09 12:51:41 +02:00
|
|
|
|
const gint64 hundreds_of_nsec_per_sec = 10000000;
|
2020-01-19 20:54:26 +01:00
|
|
|
|
/* The difference between January 1, 1601 UTC (FILETIME epoch) and UNIX epoch
|
|
|
|
|
* in hundreds of nanoseconds.
|
|
|
|
|
*/
|
|
|
|
|
const gint64 filetime_unix_epoch_offset = 116444736000000000;
|
|
|
|
|
/* This is the maximum timestamp that SYSTEMTIME can
|
|
|
|
|
* represent (last millisecond of the year 30827).
|
|
|
|
|
* Since FILETIME and SYSTEMTIME are both used on Windows,
|
|
|
|
|
* we use this as a limit (FILETIME can support slightly
|
|
|
|
|
* larger interval, up to year 30828).
|
|
|
|
|
*/
|
|
|
|
|
const gint64 max_systemtime = 0x7fff35f4f06c58f0;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (ft != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
if (nsec < 0)
|
|
|
|
|
{
|
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
|
G_IO_ERROR_INVALID_DATA,
|
|
|
|
|
_("Extra nanoseconds %d for UNIX timestamp %lld are negative"),
|
|
|
|
|
nsec, ut);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 12:51:41 +02:00
|
|
|
|
if (nsec >= hundreds_of_nsec_per_sec * 100)
|
2020-01-19 20:54:26 +01:00
|
|
|
|
{
|
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
|
G_IO_ERROR_INVALID_DATA,
|
|
|
|
|
_("Extra nanoseconds %d for UNIX timestamp %lld reach 1 second"),
|
|
|
|
|
nsec, ut);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 12:51:41 +02:00
|
|
|
|
if (ut >= (G_MAXINT64 / hundreds_of_nsec_per_sec) ||
|
|
|
|
|
(ut * hundreds_of_nsec_per_sec) >= (G_MAXINT64 - filetime_unix_epoch_offset))
|
2020-01-19 20:54:26 +01:00
|
|
|
|
{
|
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
|
G_IO_ERROR_INVALID_DATA,
|
|
|
|
|
_("UNIX timestamp %lld does not fit into 64 bits"),
|
|
|
|
|
ut);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 12:51:41 +02:00
|
|
|
|
result = ut * hundreds_of_nsec_per_sec + filetime_unix_epoch_offset + nsec / 100;
|
2020-01-19 20:54:26 +01:00
|
|
|
|
|
|
|
|
|
if (result >= max_systemtime || result < 0)
|
|
|
|
|
{
|
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
|
G_IO_ERROR_INVALID_DATA,
|
|
|
|
|
_("UNIX timestamp %lld is outside of the range supported by Windows"),
|
|
|
|
|
ut);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ft->dwLowDateTime = (DWORD) (result);
|
|
|
|
|
ft->dwHighDateTime = (DWORD) (result >> 32);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
set_mtime_atime (const char *filename,
|
|
|
|
|
const GFileAttributeValue *mtime_value,
|
|
|
|
|
const GFileAttributeValue *mtime_usec_value,
|
2021-07-02 15:10:44 +02:00
|
|
|
|
const GFileAttributeValue *mtime_nsec_value,
|
2020-01-19 20:54:26 +01:00
|
|
|
|
const GFileAttributeValue *atime_value,
|
|
|
|
|
const GFileAttributeValue *atime_usec_value,
|
2021-07-02 15:10:44 +02:00
|
|
|
|
const GFileAttributeValue *atime_nsec_value,
|
2020-01-19 20:54:26 +01:00
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
BOOL res;
|
|
|
|
|
guint64 val = 0;
|
|
|
|
|
guint32 val_usec = 0;
|
2021-07-09 13:00:31 +02:00
|
|
|
|
guint32 val_nsec = 0;
|
2020-01-19 20:54:26 +01:00
|
|
|
|
gunichar2 *filename_utf16;
|
|
|
|
|
SECURITY_ATTRIBUTES sec = { sizeof (SECURITY_ATTRIBUTES), NULL, FALSE };
|
|
|
|
|
HANDLE file_handle;
|
|
|
|
|
FILETIME mtime;
|
|
|
|
|
FILETIME atime;
|
|
|
|
|
FILETIME *p_mtime = NULL;
|
|
|
|
|
FILETIME *p_atime = NULL;
|
|
|
|
|
DWORD gle;
|
2022-10-14 14:46:05 +02:00
|
|
|
|
GStatBuf statbuf;
|
|
|
|
|
gboolean got_stat = FALSE;
|
2020-01-19 20:54:26 +01:00
|
|
|
|
|
|
|
|
|
/* ATIME */
|
|
|
|
|
if (atime_value)
|
|
|
|
|
{
|
|
|
|
|
if (!get_uint64 (atime_value, &val, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
val_usec = 0;
|
2021-07-02 15:10:44 +02:00
|
|
|
|
val_nsec = 0;
|
2022-10-14 14:46:05 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (lazy_stat (filename, &statbuf, &got_stat) == 0)
|
|
|
|
|
{
|
|
|
|
|
val = statbuf.st_atime;
|
|
|
|
|
#if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC)
|
|
|
|
|
val_nsec = statbuf.st_atimensec;
|
|
|
|
|
#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
|
|
|
|
|
val_nsec = statbuf.st_atim.tv_nsec;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-09 13:00:31 +02:00
|
|
|
|
|
2022-10-14 14:46:05 +02:00
|
|
|
|
if (atime_usec_value &&
|
|
|
|
|
!get_uint32 (atime_usec_value, &val_usec, error))
|
|
|
|
|
return FALSE;
|
2021-07-09 13:00:31 +02:00
|
|
|
|
|
2022-10-14 14:46:05 +02:00
|
|
|
|
/* Convert to nanoseconds. Clamp the usec value if it’s going to overflow,
|
|
|
|
|
* as %G_MAXINT32 will trigger a ‘too big’ error in
|
|
|
|
|
* _g_win32_unix_time_to_filetime() anyway. */
|
|
|
|
|
val_nsec = (val_usec > G_MAXINT32 / 1000) ? G_MAXINT32 : (val_usec * 1000);
|
|
|
|
|
|
|
|
|
|
if (atime_nsec_value &&
|
|
|
|
|
!get_uint32 (atime_nsec_value, &val_nsec, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (val_nsec > 0)
|
|
|
|
|
{
|
|
|
|
|
if (!_g_win32_unix_time_to_filetime (val, val_nsec, &atime, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!_g_win32_unix_time_to_filetime (val, val_usec, &atime, error))
|
|
|
|
|
return FALSE;
|
2020-01-19 20:54:26 +01:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-14 14:46:05 +02:00
|
|
|
|
p_atime = &atime;
|
|
|
|
|
|
2020-01-19 20:54:26 +01:00
|
|
|
|
/* MTIME */
|
|
|
|
|
if (mtime_value)
|
|
|
|
|
{
|
|
|
|
|
if (!get_uint64 (mtime_value, &val, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
val_usec = 0;
|
2021-07-02 15:10:44 +02:00
|
|
|
|
val_nsec = 0;
|
2022-10-14 14:46:05 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (lazy_stat (filename, &statbuf, &got_stat) == 0)
|
|
|
|
|
{
|
|
|
|
|
val = statbuf.st_mtime;
|
|
|
|
|
#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
|
|
|
|
|
val_nsec = statbuf.st_mtimensec;
|
|
|
|
|
#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
|
|
|
|
|
val_nsec = statbuf.st_mtim.tv_nsec;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-07-09 13:00:31 +02:00
|
|
|
|
|
2022-10-14 14:46:05 +02:00
|
|
|
|
if (mtime_usec_value &&
|
|
|
|
|
!get_uint32 (mtime_usec_value, &val_usec, error))
|
|
|
|
|
return FALSE;
|
2021-07-09 13:00:31 +02:00
|
|
|
|
|
2022-10-14 14:46:05 +02:00
|
|
|
|
/* Convert to nanoseconds. Clamp the usec value if it’s going to overflow,
|
|
|
|
|
* as %G_MAXINT32 will trigger a ‘too big’ error in
|
|
|
|
|
* _g_win32_unix_time_to_filetime() anyway. */
|
|
|
|
|
val_nsec = (val_usec > G_MAXINT32 / 1000) ? G_MAXINT32 : (val_usec * 1000);
|
|
|
|
|
|
|
|
|
|
if (mtime_nsec_value &&
|
|
|
|
|
!get_uint32 (mtime_nsec_value, &val_nsec, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (val_nsec > 0)
|
|
|
|
|
{
|
|
|
|
|
if (!_g_win32_unix_time_to_filetime (val, val_nsec, &mtime, error))
|
|
|
|
|
return FALSE;
|
2020-01-19 20:54:26 +01:00
|
|
|
|
}
|
2022-10-14 14:46:05 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!_g_win32_unix_time_to_filetime (val, val_usec, &mtime, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
p_mtime = &mtime;
|
2020-01-19 20:54:26 +01:00
|
|
|
|
|
|
|
|
|
filename_utf16 = g_utf8_to_utf16 (filename, -1, NULL, NULL, error);
|
|
|
|
|
|
|
|
|
|
if (filename_utf16 == NULL)
|
|
|
|
|
{
|
|
|
|
|
g_prefix_error (error,
|
|
|
|
|
_("File name “%s” cannot be converted to UTF-16"),
|
|
|
|
|
filename);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file_handle = CreateFileW (filename_utf16,
|
|
|
|
|
FILE_WRITE_ATTRIBUTES,
|
|
|
|
|
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
|
|
|
|
|
&sec,
|
|
|
|
|
OPEN_EXISTING,
|
|
|
|
|
FILE_FLAG_BACKUP_SEMANTICS,
|
|
|
|
|
NULL);
|
|
|
|
|
gle = GetLastError ();
|
|
|
|
|
g_clear_pointer (&filename_utf16, g_free);
|
|
|
|
|
|
|
|
|
|
if (file_handle == INVALID_HANDLE_VALUE)
|
|
|
|
|
{
|
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
|
g_io_error_from_errno (gle),
|
|
|
|
|
_("File “%s” cannot be opened: Windows Error %lu"),
|
|
|
|
|
filename, gle);
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = SetFileTime (file_handle, NULL, p_atime, p_mtime);
|
|
|
|
|
gle = GetLastError ();
|
|
|
|
|
CloseHandle (file_handle);
|
|
|
|
|
|
|
|
|
|
if (!res)
|
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
|
g_io_error_from_errno (gle),
|
|
|
|
|
_("Error setting modification or access time for file “%s”: %lu"),
|
|
|
|
|
filename, gle);
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2021-07-02 15:10:44 +02:00
|
|
|
|
#elif defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
static gboolean
|
2007-11-30 06:11:25 +01:00
|
|
|
|
set_mtime_atime (char *filename,
|
|
|
|
|
const GFileAttributeValue *mtime_value,
|
|
|
|
|
const GFileAttributeValue *mtime_usec_value,
|
2021-07-02 15:10:44 +02:00
|
|
|
|
const GFileAttributeValue *mtime_nsec_value,
|
2007-11-30 06:11:25 +01:00
|
|
|
|
const GFileAttributeValue *atime_value,
|
|
|
|
|
const GFileAttributeValue *atime_usec_value,
|
2021-07-02 15:10:44 +02:00
|
|
|
|
const GFileAttributeValue *atime_nsec_value,
|
2007-11-30 06:11:25 +01:00
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
int res;
|
2011-04-26 19:28:17 +02:00
|
|
|
|
guint64 val = 0;
|
2022-10-14 14:46:05 +02:00
|
|
|
|
GStatBuf statbuf;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
gboolean got_stat = FALSE;
|
2021-07-02 15:10:44 +02:00
|
|
|
|
#ifdef HAVE_UTIMENSAT
|
|
|
|
|
struct timespec times_n[2] = { {0, 0}, {0, 0} };
|
2007-11-26 17:13:05 +01:00
|
|
|
|
/* ATIME */
|
|
|
|
|
if (atime_value)
|
|
|
|
|
{
|
|
|
|
|
if (!get_uint64 (atime_value, &val, error))
|
|
|
|
|
return FALSE;
|
2021-07-02 15:10:44 +02:00
|
|
|
|
times_n[0].tv_sec = val;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (lazy_stat (filename, &statbuf, &got_stat) == 0)
|
|
|
|
|
{
|
2022-09-22 15:50:08 +02:00
|
|
|
|
times_n[0].tv_sec = statbuf.st_atime;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC)
|
2021-07-02 15:10:44 +02:00
|
|
|
|
times_n[0].tv_nsec = statbuf.st_atimensec;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
|
2021-07-02 15:10:44 +02:00
|
|
|
|
times_n[0].tv_nsec = statbuf.st_atim.tv_nsec;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-18 14:36:31 +02:00
|
|
|
|
if (atime_usec_value)
|
|
|
|
|
{
|
|
|
|
|
guint32 val_usec = 0;
|
|
|
|
|
|
|
|
|
|
if (!get_uint32 (atime_usec_value, &val_usec, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
times_n[0].tv_nsec = val_usec * 1000;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-02 15:10:44 +02:00
|
|
|
|
if (atime_nsec_value)
|
|
|
|
|
{
|
2022-10-11 14:24:17 +02:00
|
|
|
|
guint32 val_nsec = 0;
|
|
|
|
|
|
2021-07-02 15:10:44 +02:00
|
|
|
|
if (!get_uint32 (atime_nsec_value, &val_nsec, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
times_n[0].tv_nsec = val_nsec;
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
/* MTIME */
|
|
|
|
|
if (mtime_value)
|
|
|
|
|
{
|
|
|
|
|
if (!get_uint64 (mtime_value, &val, error))
|
|
|
|
|
return FALSE;
|
2021-07-02 15:10:44 +02:00
|
|
|
|
times_n[1].tv_sec = val;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (lazy_stat (filename, &statbuf, &got_stat) == 0)
|
|
|
|
|
{
|
2023-01-02 02:55:40 +01:00
|
|
|
|
times_n[1].tv_sec = statbuf.st_mtime;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
|
2021-07-02 15:10:44 +02:00
|
|
|
|
times_n[1].tv_nsec = statbuf.st_mtimensec;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
|
2021-07-02 15:10:44 +02:00
|
|
|
|
times_n[1].tv_nsec = statbuf.st_mtim.tv_nsec;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-11 14:24:17 +02:00
|
|
|
|
|
2023-09-18 14:36:31 +02:00
|
|
|
|
if (mtime_usec_value)
|
|
|
|
|
{
|
|
|
|
|
guint32 val_usec = 0;
|
|
|
|
|
|
|
|
|
|
if (!get_uint32 (mtime_usec_value, &val_usec, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
times_n[1].tv_nsec = val_usec * 1000;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-02 15:10:44 +02:00
|
|
|
|
if (mtime_nsec_value)
|
|
|
|
|
{
|
2022-10-11 14:24:17 +02:00
|
|
|
|
guint32 val_nsec = 0;
|
|
|
|
|
|
2021-07-02 15:10:44 +02:00
|
|
|
|
if (!get_uint32 (mtime_nsec_value, &val_nsec, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
times_n[1].tv_nsec = val_nsec;
|
2022-09-22 15:50:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = utimensat (AT_FDCWD, filename, times_n, 0);
|
|
|
|
|
|
|
|
|
|
#else /* HAVE_UTIMES */
|
|
|
|
|
|
|
|
|
|
struct timeval times[2] = { {0, 0}, {0, 0} };
|
|
|
|
|
|
|
|
|
|
/* ATIME */
|
|
|
|
|
if (atime_value)
|
|
|
|
|
{
|
|
|
|
|
if (!get_uint64 (atime_value, &val, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
times[0].tv_sec = val;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (lazy_stat (filename, &statbuf, &got_stat) == 0)
|
|
|
|
|
{
|
|
|
|
|
times[0].tv_sec = statbuf.st_atime;
|
|
|
|
|
#if defined (HAVE_STRUCT_STAT_ST_ATIMENSEC)
|
|
|
|
|
times[0].tv_usec = statbuf.st_atimensec / 1000;
|
|
|
|
|
#elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC)
|
|
|
|
|
times[0].tv_usec = statbuf.st_atim.tv_nsec / 1000;
|
2021-07-02 15:10:44 +02:00
|
|
|
|
#endif
|
2022-09-22 15:50:08 +02:00
|
|
|
|
}
|
2021-07-02 15:10:44 +02:00
|
|
|
|
}
|
2022-09-22 15:50:08 +02:00
|
|
|
|
|
|
|
|
|
if (atime_usec_value)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2022-10-11 14:24:17 +02:00
|
|
|
|
guint32 val_usec = 0;
|
|
|
|
|
|
2022-09-22 15:50:08 +02:00
|
|
|
|
if (!get_uint32 (atime_usec_value, &val_usec, error))
|
|
|
|
|
return FALSE;
|
Save errno before calling other funcs that potentially alter it. Bug
* gio/gdesktopappinfo.c: (ensure_dir):
* gio/glocalfile.c: (g_local_file_query_filesystem_info),
(g_local_file_read), (g_local_file_delete), (g_local_file_trash),
(g_local_file_move):
* gio/glocalfileinfo.c: (set_xattr), (_g_local_file_info_get),
(_g_local_file_info_get_from_fd), (set_unix_mode),
(set_unix_uid_gid), (set_symlink), (set_mtime_atime):
* gio/glocalfileinputstream.c: (g_local_file_input_stream_read),
(g_local_file_input_stream_skip),
(g_local_file_input_stream_close),
(g_local_file_input_stream_seek):
* gio/glocalfileoutputstream.c:
(g_local_file_output_stream_write),
(g_local_file_output_stream_close),
(g_local_file_output_stream_seek),
(g_local_file_output_stream_truncate), (copy_file_data),
(handle_overwrite_open):
* gio/gunixinputstream.c: (g_unix_input_stream_read),
(g_unix_input_stream_close), (read_async_cb), (close_async_cb):
* gio/gunixoutputstream.c: (g_unix_output_stream_write),
(g_unix_output_stream_close), (write_async_cb), (close_async_cb):
Save
errno before calling other funcs that potentially alter it. Bug
#514766.
svn path=/trunk/; revision=6466
2008-02-06 16:10:08 +01:00
|
|
|
|
|
2022-10-11 14:24:17 +02:00
|
|
|
|
times[0].tv_usec = val_usec;
|
2021-07-02 15:10:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-09-22 15:50:08 +02:00
|
|
|
|
/* MTIME */
|
|
|
|
|
if (mtime_value)
|
|
|
|
|
{
|
|
|
|
|
if (!get_uint64 (mtime_value, &val, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
times[1].tv_sec = val;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (lazy_stat (filename, &statbuf, &got_stat) == 0)
|
|
|
|
|
{
|
|
|
|
|
times[1].tv_sec = statbuf.st_mtime;
|
|
|
|
|
#if defined (HAVE_STRUCT_STAT_ST_MTIMENSEC)
|
|
|
|
|
times[1].tv_usec = statbuf.st_mtimensec / 1000;
|
|
|
|
|
#elif defined (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
|
|
|
|
|
times[1].tv_usec = statbuf.st_mtim.tv_nsec / 1000;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mtime_usec_value)
|
|
|
|
|
{
|
2022-10-11 14:24:17 +02:00
|
|
|
|
guint32 val_usec = 0;
|
|
|
|
|
|
2022-09-22 15:50:08 +02:00
|
|
|
|
if (!get_uint32 (mtime_usec_value, &val_usec, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2022-10-11 14:24:17 +02:00
|
|
|
|
times[1].tv_usec = val_usec;
|
2022-09-22 15:50:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = utimes (filename, times);
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-07-02 15:10:44 +02:00
|
|
|
|
if (res == -1)
|
|
|
|
|
{
|
|
|
|
|
int errsv = errno;
|
|
|
|
|
|
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
|
g_io_error_from_errno (errsv),
|
|
|
|
|
_("Error setting modification or access time: %s"),
|
|
|
|
|
g_strerror (errsv));
|
|
|
|
|
return FALSE;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-07-23 06:11:02 +02:00
|
|
|
|
|
2008-10-15 05:37:56 +02:00
|
|
|
|
#ifdef HAVE_SELINUX
|
2008-07-23 06:11:02 +02:00
|
|
|
|
static gboolean
|
|
|
|
|
set_selinux_context (char *filename,
|
2020-12-01 10:20:11 +01:00
|
|
|
|
const GFileAttributeValue *value,
|
|
|
|
|
GError **error)
|
2008-07-23 06:11:02 +02:00
|
|
|
|
{
|
|
|
|
|
const char *val;
|
|
|
|
|
|
|
|
|
|
if (!get_string (value, &val, error))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (val == NULL)
|
2020-12-01 10:20:11 +01:00
|
|
|
|
{
|
|
|
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
|
|
|
_("SELinux context must be non-NULL"));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2008-07-23 06:11:02 +02:00
|
|
|
|
|
2020-12-01 10:20:11 +01:00
|
|
|
|
if (!is_selinux_enabled ())
|
|
|
|
|
{
|
|
|
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
|
|
|
_("SELinux is not enabled on this system"));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (setfilecon_raw (filename, val) < 0)
|
|
|
|
|
{
|
|
|
|
|
int errsv = errno;
|
2008-07-23 06:11:02 +02:00
|
|
|
|
|
2020-12-01 10:20:11 +01:00
|
|
|
|
g_set_error (error, G_IO_ERROR,
|
|
|
|
|
g_io_error_from_errno (errsv),
|
|
|
|
|
_("Error setting SELinux context: %s"),
|
|
|
|
|
g_strerror (errsv));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-23 06:11:02 +02:00
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
2008-10-15 05:37:56 +02:00
|
|
|
|
#endif
|
2008-07-23 06:11:02 +02:00
|
|
|
|
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
gboolean
|
2008-01-21 15:02:19 +01:00
|
|
|
|
_g_local_file_info_set_attribute (char *filename,
|
|
|
|
|
const char *attribute,
|
|
|
|
|
GFileAttributeType type,
|
|
|
|
|
gpointer value_p,
|
|
|
|
|
GFileQueryInfoFlags flags,
|
|
|
|
|
GCancellable *cancellable,
|
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2007-12-14 16:56:56 +01:00
|
|
|
|
GFileAttributeValue value = { 0 };
|
2009-06-18 09:05:27 +02:00
|
|
|
|
GVfsClass *class;
|
|
|
|
|
GVfs *vfs;
|
2007-12-14 16:56:56 +01:00
|
|
|
|
|
|
|
|
|
_g_file_attribute_value_set_from_pointer (&value, type, value_p, FALSE);
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0)
|
2009-09-01 11:54:48 +02:00
|
|
|
|
return set_unix_mode (filename, flags, &value, error);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
Require POSIX.1 (1990) compliance on unix
Assume unix platforms support the original POSIX.1 standard.
Specifically, assume that if G_OS_UNIX, then we have chown(),
getcwd(), getgrgid(), getpwuid(), link(), <grp.h>, <pwd.h>,
<sys/types.h>, <sys/uio.h>, <sys/wait.h>, and <unistd.h>.
Additionally, since all versions of Windows that we care about also
have <sys/types.h>, we can remove HAVE_SYS_TYPES_H checks everywhere.
Also remove one include of <sys/times.h>, and the corresponding
configure check, since the include is not currently needed (and may
always have just been a typo for <sys/time.h>).
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:59 +02:00
|
|
|
|
#ifdef G_OS_UNIX
|
2007-11-26 17:13:05 +01:00
|
|
|
|
else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_UID) == 0)
|
2007-12-14 16:56:56 +01:00
|
|
|
|
return set_unix_uid_gid (filename, &value, NULL, flags, error);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_GID) == 0)
|
2007-12-14 16:56:56 +01:00
|
|
|
|
return set_unix_uid_gid (filename, NULL, &value, flags, error);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_SYMLINK
|
2007-12-20 14:30:47 +01:00
|
|
|
|
else if (strcmp (attribute, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET) == 0)
|
2007-12-14 16:56:56 +01:00
|
|
|
|
return set_symlink (filename, &value, error);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2021-07-02 15:10:44 +02:00
|
|
|
|
#if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED) == 0)
|
2021-07-02 15:10:44 +02:00
|
|
|
|
return set_mtime_atime (filename, &value, NULL, NULL, NULL, NULL, NULL, error);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC) == 0)
|
2021-07-02 15:10:44 +02:00
|
|
|
|
return set_mtime_atime (filename, NULL, &value, NULL, NULL, NULL, NULL, error);
|
|
|
|
|
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC) == 0)
|
|
|
|
|
return set_mtime_atime (filename, NULL, NULL, &value, NULL, NULL, NULL, error);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS) == 0)
|
2021-07-02 15:10:44 +02:00
|
|
|
|
return set_mtime_atime (filename, NULL, NULL, NULL, &value, NULL, NULL, error);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC) == 0)
|
2021-07-02 15:10:44 +02:00
|
|
|
|
return set_mtime_atime (filename, NULL, NULL, NULL, NULL, &value, NULL, error);
|
|
|
|
|
else if (strcmp (attribute, G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC) == 0)
|
|
|
|
|
return set_mtime_atime (filename, NULL, NULL, NULL, NULL, NULL, &value, error);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_XATTR
|
2007-12-12 16:50:45 +01:00
|
|
|
|
else if (g_str_has_prefix (attribute, "xattr::"))
|
2007-12-14 16:56:56 +01:00
|
|
|
|
return set_xattr (filename, attribute, &value, error);
|
2007-12-12 16:50:45 +01:00
|
|
|
|
else if (g_str_has_prefix (attribute, "xattr-sys::"))
|
2007-12-14 16:56:56 +01:00
|
|
|
|
return set_xattr (filename, attribute, &value, error);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
#endif
|
2008-07-23 06:11:02 +02:00
|
|
|
|
|
|
|
|
|
#ifdef HAVE_SELINUX
|
|
|
|
|
else if (strcmp (attribute, G_FILE_ATTRIBUTE_SELINUX_CONTEXT) == 0)
|
|
|
|
|
return set_selinux_context (filename, &value, error);
|
|
|
|
|
#endif
|
2009-06-18 09:05:27 +02:00
|
|
|
|
|
|
|
|
|
vfs = g_vfs_get_default ();
|
|
|
|
|
class = G_VFS_GET_CLASS (vfs);
|
|
|
|
|
if (class->local_file_set_attributes)
|
|
|
|
|
{
|
|
|
|
|
GFileInfo *info;
|
|
|
|
|
|
|
|
|
|
info = g_file_info_new ();
|
|
|
|
|
g_file_info_set_attribute (info,
|
|
|
|
|
attribute,
|
|
|
|
|
type,
|
|
|
|
|
value_p);
|
|
|
|
|
if (!class->local_file_set_attributes (vfs, filename,
|
|
|
|
|
info,
|
|
|
|
|
flags, cancellable,
|
|
|
|
|
error))
|
|
|
|
|
{
|
|
|
|
|
g_object_unref (info);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_file_info_get_attribute_status (info, attribute) == G_FILE_ATTRIBUTE_STATUS_SET)
|
|
|
|
|
{
|
|
|
|
|
g_object_unref (info);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_object_unref (info);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
|
|
|
_("Setting attribute %s not supported"), attribute);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
2007-11-30 06:11:25 +01:00
|
|
|
|
_g_local_file_info_set_attributes (char *filename,
|
|
|
|
|
GFileInfo *info,
|
|
|
|
|
GFileQueryInfoFlags flags,
|
|
|
|
|
GCancellable *cancellable,
|
|
|
|
|
GError **error)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2008-03-12 19:33:59 +01:00
|
|
|
|
GFileAttributeValue *value;
|
Require POSIX.1 (1990) compliance on unix
Assume unix platforms support the original POSIX.1 standard.
Specifically, assume that if G_OS_UNIX, then we have chown(),
getcwd(), getgrgid(), getpwuid(), link(), <grp.h>, <pwd.h>,
<sys/types.h>, <sys/uio.h>, <sys/wait.h>, and <unistd.h>.
Additionally, since all versions of Windows that we care about also
have <sys/types.h>, we can remove HAVE_SYS_TYPES_H checks everywhere.
Also remove one include of <sys/times.h>, and the corresponding
configure check, since the include is not currently needed (and may
always have just been a typo for <sys/time.h>).
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:59 +02:00
|
|
|
|
#ifdef G_OS_UNIX
|
2008-03-12 19:33:59 +01:00
|
|
|
|
GFileAttributeValue *uid, *gid;
|
2020-01-19 20:54:26 +01:00
|
|
|
|
#endif
|
2021-07-02 15:10:44 +02:00
|
|
|
|
#if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
|
|
|
|
|
GFileAttributeValue *mtime, *mtime_usec, *mtime_nsec, *atime, *atime_usec, *atime_nsec;
|
2008-03-12 19:33:59 +01:00
|
|
|
|
#endif
|
2020-01-19 20:54:26 +01:00
|
|
|
|
#if defined (G_OS_UNIX) || defined (G_OS_WIN32)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
GFileAttributeStatus status;
|
2008-03-12 19:33:59 +01:00
|
|
|
|
#endif
|
2007-11-26 17:13:05 +01:00
|
|
|
|
gboolean res;
|
2009-06-18 09:05:27 +02:00
|
|
|
|
GVfsClass *class;
|
|
|
|
|
GVfs *vfs;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
/* Handles setting multiple specified data in a single set, and takes care
|
|
|
|
|
of ordering restrictions when setting attributes */
|
|
|
|
|
|
|
|
|
|
res = TRUE;
|
|
|
|
|
|
|
|
|
|
/* Set symlink first, since this recreates the file */
|
|
|
|
|
#ifdef HAVE_SYMLINK
|
2007-12-20 14:30:47 +01:00
|
|
|
|
value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (value)
|
|
|
|
|
{
|
|
|
|
|
if (!set_symlink (filename, value, error))
|
|
|
|
|
{
|
|
|
|
|
value->status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING;
|
|
|
|
|
res = FALSE;
|
|
|
|
|
/* Don't set error multiple times */
|
|
|
|
|
error = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
value->status = G_FILE_ATTRIBUTE_STATUS_SET;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
Require POSIX.1 (1990) compliance on unix
Assume unix platforms support the original POSIX.1 standard.
Specifically, assume that if G_OS_UNIX, then we have chown(),
getcwd(), getgrgid(), getpwuid(), link(), <grp.h>, <pwd.h>,
<sys/types.h>, <sys/uio.h>, <sys/wait.h>, and <unistd.h>.
Additionally, since all versions of Windows that we care about also
have <sys/types.h>, we can remove HAVE_SYS_TYPES_H checks everywhere.
Also remove one include of <sys/times.h>, and the corresponding
configure check, since the include is not currently needed (and may
always have just been a typo for <sys/time.h>).
https://bugzilla.gnome.org/show_bug.cgi?id=710519
2013-10-19 19:03:59 +02:00
|
|
|
|
#ifdef G_OS_UNIX
|
2007-11-26 17:13:05 +01:00
|
|
|
|
/* Group uid and gid setting into one call
|
|
|
|
|
* Change ownership before permissions, since ownership changes can
|
|
|
|
|
change permissions (e.g. setuid)
|
|
|
|
|
*/
|
2007-12-14 16:56:56 +01:00
|
|
|
|
uid = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_UID);
|
|
|
|
|
gid = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_GID);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
|
|
|
|
if (uid || gid)
|
|
|
|
|
{
|
|
|
|
|
if (!set_unix_uid_gid (filename, uid, gid, flags, error))
|
|
|
|
|
{
|
|
|
|
|
status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING;
|
|
|
|
|
res = FALSE;
|
|
|
|
|
/* Don't set error multiple times */
|
|
|
|
|
error = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
status = G_FILE_ATTRIBUTE_STATUS_SET;
|
|
|
|
|
if (uid)
|
|
|
|
|
uid->status = status;
|
|
|
|
|
if (gid)
|
|
|
|
|
gid->status = status;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2007-12-14 16:56:56 +01:00
|
|
|
|
value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_MODE);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (value)
|
|
|
|
|
{
|
2009-09-01 11:54:48 +02:00
|
|
|
|
if (!set_unix_mode (filename, flags, value, error))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
value->status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING;
|
|
|
|
|
res = FALSE;
|
|
|
|
|
/* Don't set error multiple times */
|
|
|
|
|
error = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
value->status = G_FILE_ATTRIBUTE_STATUS_SET;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-02 15:10:44 +02:00
|
|
|
|
#if defined (HAVE_UTIMES) || defined (HAVE_UTIMENSAT) || defined (G_OS_WIN32)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
/* Group all time settings into one call
|
|
|
|
|
* Change times as the last thing to avoid it changing due to metadata changes
|
|
|
|
|
*/
|
|
|
|
|
|
2007-12-14 16:56:56 +01:00
|
|
|
|
mtime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
|
|
|
|
|
mtime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC);
|
2021-07-02 15:10:44 +02:00
|
|
|
|
mtime_nsec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC);
|
2007-12-14 16:56:56 +01:00
|
|
|
|
atime = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
|
|
|
|
|
atime_usec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS_USEC);
|
2021-07-02 15:10:44 +02:00
|
|
|
|
atime_nsec = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC);
|
2007-11-26 17:13:05 +01:00
|
|
|
|
|
2021-07-02 15:10:44 +02:00
|
|
|
|
if (mtime || mtime_usec || mtime_nsec || atime || atime_usec || atime_nsec)
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
2021-07-02 15:10:44 +02:00
|
|
|
|
if (!set_mtime_atime (filename, mtime, mtime_usec, mtime_nsec, atime, atime_usec, atime_nsec, error))
|
2007-11-26 17:13:05 +01:00
|
|
|
|
{
|
|
|
|
|
status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING;
|
|
|
|
|
res = FALSE;
|
|
|
|
|
/* Don't set error multiple times */
|
|
|
|
|
error = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
status = G_FILE_ATTRIBUTE_STATUS_SET;
|
|
|
|
|
|
|
|
|
|
if (mtime)
|
|
|
|
|
mtime->status = status;
|
|
|
|
|
if (mtime_usec)
|
|
|
|
|
mtime_usec->status = status;
|
2021-07-02 15:10:44 +02:00
|
|
|
|
if (mtime_nsec)
|
|
|
|
|
mtime_nsec->status = status;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
if (atime)
|
|
|
|
|
atime->status = status;
|
|
|
|
|
if (atime_usec)
|
|
|
|
|
atime_usec->status = status;
|
2021-07-02 15:10:44 +02:00
|
|
|
|
if (atime_nsec)
|
|
|
|
|
atime_nsec->status = status;
|
2007-11-26 17:13:05 +01:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* xattrs are handled by default callback */
|
|
|
|
|
|
2008-07-23 06:11:02 +02:00
|
|
|
|
|
|
|
|
|
/* SELinux context */
|
|
|
|
|
#ifdef HAVE_SELINUX
|
|
|
|
|
if (is_selinux_enabled ()) {
|
|
|
|
|
value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_SELINUX_CONTEXT);
|
|
|
|
|
if (value)
|
|
|
|
|
{
|
|
|
|
|
if (!set_selinux_context (filename, value, error))
|
|
|
|
|
{
|
|
|
|
|
value->status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING;
|
|
|
|
|
res = FALSE;
|
|
|
|
|
/* Don't set error multiple times */
|
|
|
|
|
error = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
value->status = G_FILE_ATTRIBUTE_STATUS_SET;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-06-18 09:05:27 +02:00
|
|
|
|
vfs = g_vfs_get_default ();
|
|
|
|
|
class = G_VFS_GET_CLASS (vfs);
|
|
|
|
|
if (class->local_file_set_attributes)
|
|
|
|
|
{
|
|
|
|
|
if (!class->local_file_set_attributes (vfs, filename,
|
|
|
|
|
info,
|
|
|
|
|
flags, cancellable,
|
|
|
|
|
error))
|
|
|
|
|
{
|
|
|
|
|
res = FALSE;
|
|
|
|
|
/* Don't set error multiple times */
|
|
|
|
|
error = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-26 17:13:05 +01:00
|
|
|
|
return res;
|
|
|
|
|
}
|