1 | /* GIO - GLib Input, Output and Streaming Library |
2 | * |
3 | * Copyright (C) 2006-2007 Red Hat, Inc. |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2.1 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General |
16 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
17 | * |
18 | * Author: Alexander Larsson <alexl@redhat.com> |
19 | */ |
20 | |
21 | #ifndef __G_LOCAL_FILE_INFO_H__ |
22 | #define __G_LOCAL_FILE_INFO_H__ |
23 | |
24 | /* Needed for statx() */ |
25 | #ifndef _GNU_SOURCE |
26 | #define _GNU_SOURCE |
27 | #endif |
28 | |
29 | #include <fcntl.h> |
30 | #include <gio/gfileinfo.h> |
31 | #include <gio/gfile.h> |
32 | #include <glib/glib-private.h> |
33 | #include <glib/gstdio.h> |
34 | #include <glib/gstdioprivate.h> |
35 | #include <sys/stat.h> |
36 | #include <sys/types.h> |
37 | |
38 | #ifdef HAVE_STATX |
39 | #include <sys/sysmacros.h> |
40 | #endif |
41 | |
42 | G_BEGIN_DECLS |
43 | |
44 | typedef struct |
45 | { |
46 | gboolean writable; |
47 | gboolean is_sticky; |
48 | gboolean has_trash_dir; |
49 | /* owner should be uid_t but it breaks compliance with MS-Windows */ |
50 | int owner; |
51 | dev_t device; |
52 | ino_t inode; |
53 | gpointer ; |
54 | GDestroyNotify ; |
55 | } GLocalParentFileInfo; |
56 | |
57 | #ifdef HAVE_STATX |
58 | #define GLocalFileStat struct statx |
59 | |
60 | typedef enum |
61 | { |
62 | G_LOCAL_FILE_STAT_FIELD_TYPE = STATX_TYPE, |
63 | G_LOCAL_FILE_STAT_FIELD_MODE = STATX_MODE, |
64 | G_LOCAL_FILE_STAT_FIELD_NLINK = STATX_NLINK, |
65 | G_LOCAL_FILE_STAT_FIELD_UID = STATX_UID, |
66 | G_LOCAL_FILE_STAT_FIELD_GID = STATX_GID, |
67 | G_LOCAL_FILE_STAT_FIELD_ATIME = STATX_ATIME, |
68 | G_LOCAL_FILE_STAT_FIELD_MTIME = STATX_MTIME, |
69 | G_LOCAL_FILE_STAT_FIELD_CTIME = STATX_CTIME, |
70 | G_LOCAL_FILE_STAT_FIELD_INO = STATX_INO, |
71 | G_LOCAL_FILE_STAT_FIELD_SIZE = STATX_SIZE, |
72 | G_LOCAL_FILE_STAT_FIELD_BLOCKS = STATX_BLOCKS, |
73 | G_LOCAL_FILE_STAT_FIELD_BTIME = STATX_BTIME, |
74 | } GLocalFileStatField; |
75 | |
76 | #define G_LOCAL_FILE_STAT_FIELD_BASIC_STATS STATX_BASIC_STATS |
77 | #define G_LOCAL_FILE_STAT_FIELD_ALL STATX_ALL |
78 | |
79 | static inline int |
80 | g_local_file_statx (int dirfd, |
81 | const char *pathname, |
82 | int flags, |
83 | GLocalFileStatField mask, |
84 | GLocalFileStatField mask_required, |
85 | GLocalFileStat *stat_buf) |
86 | { |
87 | int retval; |
88 | |
89 | /* Allow the caller to set mask_required==G_LOCAL_FILE_STAT_FIELD_ALL as a |
90 | * shortcut for saying it’s equal to @mask. */ |
91 | mask_required &= mask; |
92 | |
93 | retval = statx (dirfd: dirfd, path: pathname, flags: flags, mask: mask, buf: stat_buf); |
94 | if (retval == 0 && (stat_buf->stx_mask & mask_required) != mask_required) |
95 | { |
96 | /* Not all required fields could be returned. */ |
97 | errno = ERANGE; |
98 | return -1; |
99 | } |
100 | |
101 | return retval; |
102 | } |
103 | |
104 | static inline int |
105 | g_local_file_fstat (int fd, |
106 | GLocalFileStatField mask, |
107 | GLocalFileStatField mask_required, |
108 | GLocalFileStat *stat_buf) |
109 | { |
110 | return g_local_file_statx (dirfd: fd, pathname: "" , AT_EMPTY_PATH, mask, mask_required, stat_buf); |
111 | } |
112 | |
113 | static inline int |
114 | g_local_file_fstatat (int fd, |
115 | const char *path, |
116 | int flags, |
117 | GLocalFileStatField mask, |
118 | GLocalFileStatField mask_required, |
119 | GLocalFileStat *stat_buf) |
120 | { |
121 | return g_local_file_statx (dirfd: fd, pathname: path, flags, mask, mask_required, stat_buf); |
122 | } |
123 | |
124 | static inline int |
125 | g_local_file_lstat (const char *path, |
126 | GLocalFileStatField mask, |
127 | GLocalFileStatField mask_required, |
128 | GLocalFileStat *stat_buf) |
129 | { |
130 | return g_local_file_statx (AT_FDCWD, pathname: path, |
131 | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | AT_STATX_SYNC_AS_STAT, |
132 | mask, mask_required, stat_buf); |
133 | } |
134 | |
135 | static inline int |
136 | g_local_file_stat (const char *path, |
137 | GLocalFileStatField mask, |
138 | GLocalFileStatField mask_required, |
139 | GLocalFileStat *stat_buf) |
140 | { |
141 | return g_local_file_statx (AT_FDCWD, pathname: path, |
142 | AT_NO_AUTOMOUNT | AT_STATX_SYNC_AS_STAT, |
143 | mask, mask_required, stat_buf); |
144 | } |
145 | |
146 | inline static gboolean _g_stat_has_field (const GLocalFileStat *buf, GLocalFileStatField field) { return buf->stx_mask & field; } |
147 | |
148 | inline static guint16 _g_stat_mode (const GLocalFileStat *buf) { return buf->stx_mode; } |
149 | inline static guint32 _g_stat_nlink (const GLocalFileStat *buf) { return buf->stx_nlink; } |
150 | inline static dev_t _g_stat_dev (const GLocalFileStat *buf) { return makedev (buf->stx_dev_major, buf->stx_dev_minor); } |
151 | inline static guint64 _g_stat_ino (const GLocalFileStat *buf) { return buf->stx_ino; } |
152 | inline static guint64 _g_stat_size (const GLocalFileStat *buf) { return buf->stx_size; } |
153 | |
154 | inline static guint32 _g_stat_uid (const GLocalFileStat *buf) { return buf->stx_uid; } |
155 | inline static guint32 _g_stat_gid (const GLocalFileStat *buf) { return buf->stx_gid; } |
156 | inline static dev_t _g_stat_rdev (const GLocalFileStat *buf) { return makedev (buf->stx_rdev_major, buf->stx_rdev_minor); } |
157 | inline static guint32 _g_stat_blksize (const GLocalFileStat *buf) { return buf->stx_blksize; } |
158 | |
159 | inline static guint64 _g_stat_blocks (const GLocalFileStat *buf) { return buf->stx_blocks; } |
160 | |
161 | inline static gint64 _g_stat_atime (const GLocalFileStat *buf) { return buf->stx_atime.tv_sec; } |
162 | inline static gint64 _g_stat_ctime (const GLocalFileStat *buf) { return buf->stx_ctime.tv_sec; } |
163 | inline static gint64 _g_stat_mtime (const GLocalFileStat *buf) { return buf->stx_mtime.tv_sec; } |
164 | inline static guint32 _g_stat_atim_nsec (const GLocalFileStat *buf) { return buf->stx_atime.tv_nsec; } |
165 | inline static guint32 _g_stat_ctim_nsec (const GLocalFileStat *buf) { return buf->stx_ctime.tv_nsec; } |
166 | inline static guint32 _g_stat_mtim_nsec (const GLocalFileStat *buf) { return buf->stx_mtime.tv_nsec; } |
167 | |
168 | #else /* if !HAVE_STATX */ |
169 | |
170 | #ifdef G_OS_WIN32 |
171 | /* We want 64-bit file size, file ID and symlink support */ |
172 | #define GLocalFileStat GWin32PrivateStat |
173 | #else |
174 | #define GLocalFileStat struct stat |
175 | #endif |
176 | |
177 | /* If the system doesn’t have statx() support, emulate it using traditional |
178 | * stat(). It supports fields %G_LOCAL_FILE_STAT_FIELD_BASIC_STATS only, and |
179 | * always returns all of them. */ |
180 | typedef enum |
181 | { |
182 | G_LOCAL_FILE_STAT_FIELD_TYPE = (1 << 0), |
183 | G_LOCAL_FILE_STAT_FIELD_MODE = (1 << 1), |
184 | G_LOCAL_FILE_STAT_FIELD_NLINK = (1 << 2), |
185 | G_LOCAL_FILE_STAT_FIELD_UID = (1 << 3), |
186 | G_LOCAL_FILE_STAT_FIELD_GID = (1 << 4), |
187 | G_LOCAL_FILE_STAT_FIELD_ATIME = (1 << 5), |
188 | G_LOCAL_FILE_STAT_FIELD_MTIME = (1 << 6), |
189 | G_LOCAL_FILE_STAT_FIELD_CTIME = (1 << 7), |
190 | G_LOCAL_FILE_STAT_FIELD_INO = (1 << 8), |
191 | G_LOCAL_FILE_STAT_FIELD_SIZE = (1 << 9), |
192 | G_LOCAL_FILE_STAT_FIELD_BLOCKS = (1 << 10), |
193 | G_LOCAL_FILE_STAT_FIELD_BTIME = (1 << 11), |
194 | } GLocalFileStatField; |
195 | |
196 | #define G_LOCAL_FILE_STAT_FIELD_BASIC_STATS \ |
197 | (G_LOCAL_FILE_STAT_FIELD_TYPE | G_LOCAL_FILE_STAT_FIELD_MODE | \ |
198 | G_LOCAL_FILE_STAT_FIELD_NLINK | G_LOCAL_FILE_STAT_FIELD_UID | \ |
199 | G_LOCAL_FILE_STAT_FIELD_GID | G_LOCAL_FILE_STAT_FIELD_ATIME | \ |
200 | G_LOCAL_FILE_STAT_FIELD_MTIME | G_LOCAL_FILE_STAT_FIELD_CTIME | \ |
201 | G_LOCAL_FILE_STAT_FIELD_INO | G_LOCAL_FILE_STAT_FIELD_SIZE | \ |
202 | G_LOCAL_FILE_STAT_FIELD_BLOCKS) |
203 | #define G_LOCAL_FILE_STAT_FIELD_ALL (G_LOCAL_FILE_STAT_FIELD_BASIC_STATS | G_LOCAL_FILE_STAT_FIELD_BTIME) |
204 | |
205 | static inline int |
206 | g_local_file_fstat (int fd, |
207 | GLocalFileStatField mask, |
208 | GLocalFileStatField mask_required, |
209 | GLocalFileStat *stat_buf) |
210 | { |
211 | if ((G_LOCAL_FILE_STAT_FIELD_BASIC_STATS & (mask_required & mask)) != (mask_required & mask)) |
212 | { |
213 | /* Only G_LOCAL_FILE_STAT_FIELD_BASIC_STATS are supported. */ |
214 | errno = ERANGE; |
215 | return -1; |
216 | } |
217 | |
218 | #ifdef G_OS_WIN32 |
219 | return GLIB_PRIVATE_CALL (g_win32_fstat) (fd, stat_buf); |
220 | #else |
221 | return fstat (fd, stat_buf); |
222 | #endif |
223 | } |
224 | |
225 | static inline int |
226 | g_local_file_fstatat (int fd, |
227 | const char *path, |
228 | int flags, |
229 | GLocalFileStatField mask, |
230 | GLocalFileStatField mask_required, |
231 | GLocalFileStat *stat_buf) |
232 | { |
233 | if ((G_LOCAL_FILE_STAT_FIELD_BASIC_STATS & (mask_required & mask)) != (mask_required & mask)) |
234 | { |
235 | /* Only G_LOCAL_FILE_STAT_FIELD_BASIC_STATS are supported. */ |
236 | errno = ERANGE; |
237 | return -1; |
238 | } |
239 | |
240 | #if !defined(G_OS_WIN32) && defined(AT_FDCWD) |
241 | return fstatat (fd, path, stat_buf, flags); |
242 | #else |
243 | /* Currently not supported on Windows or macOS < 10.10 */ |
244 | errno = ENOSYS; |
245 | return -1; |
246 | #endif |
247 | } |
248 | |
249 | static inline int |
250 | g_local_file_lstat (const char *path, |
251 | GLocalFileStatField mask, |
252 | GLocalFileStatField mask_required, |
253 | GLocalFileStat *stat_buf) |
254 | { |
255 | if ((G_LOCAL_FILE_STAT_FIELD_BASIC_STATS & (mask_required & mask)) != (mask_required & mask)) |
256 | { |
257 | /* Only G_LOCAL_FILE_STAT_FIELD_BASIC_STATS are supported. */ |
258 | errno = ERANGE; |
259 | return -1; |
260 | } |
261 | |
262 | #ifdef G_OS_WIN32 |
263 | return GLIB_PRIVATE_CALL (g_win32_lstat_utf8) (path, stat_buf); |
264 | #else |
265 | return g_lstat (path, stat_buf); |
266 | #endif |
267 | } |
268 | |
269 | static inline int |
270 | g_local_file_stat (const char *path, |
271 | GLocalFileStatField mask, |
272 | GLocalFileStatField mask_required, |
273 | GLocalFileStat *stat_buf) |
274 | { |
275 | if ((G_LOCAL_FILE_STAT_FIELD_BASIC_STATS & (mask_required & mask)) != (mask_required & mask)) |
276 | { |
277 | /* Only G_LOCAL_FILE_STAT_FIELD_BASIC_STATS are supported. */ |
278 | errno = ERANGE; |
279 | return -1; |
280 | } |
281 | |
282 | #ifdef G_OS_WIN32 |
283 | return GLIB_PRIVATE_CALL (g_win32_stat_utf8) (path, stat_buf); |
284 | #else |
285 | return stat (path, stat_buf); |
286 | #endif |
287 | } |
288 | |
289 | inline static gboolean _g_stat_has_field (const GLocalFileStat *buf, GLocalFileStatField field) { return (G_LOCAL_FILE_STAT_FIELD_BASIC_STATS & field) == field; } |
290 | |
291 | #ifndef G_OS_WIN32 |
292 | inline static mode_t _g_stat_mode (const GLocalFileStat *buf) { return buf->st_mode; } |
293 | inline static nlink_t _g_stat_nlink (const GLocalFileStat *buf) { return buf->st_nlink; } |
294 | #else |
295 | inline static guint16 _g_stat_mode (const GLocalFileStat *buf) { return buf->st_mode; } |
296 | inline static guint32 _g_stat_nlink (const GLocalFileStat *buf) { return buf->st_nlink; } |
297 | #endif |
298 | inline static dev_t _g_stat_dev (const GLocalFileStat *buf) { return buf->st_dev; } |
299 | inline static ino_t _g_stat_ino (const GLocalFileStat *buf) { return buf->st_ino; } |
300 | inline static off_t _g_stat_size (const GLocalFileStat *buf) { return buf->st_size; } |
301 | |
302 | #ifndef G_OS_WIN32 |
303 | inline static uid_t _g_stat_uid (const GLocalFileStat *buf) { return buf->st_uid; } |
304 | inline static gid_t _g_stat_gid (const GLocalFileStat *buf) { return buf->st_gid; } |
305 | inline static dev_t _g_stat_rdev (const GLocalFileStat *buf) { return buf->st_rdev; } |
306 | inline static blksize_t _g_stat_blksize (const GLocalFileStat *buf) { return buf->st_blksize; } |
307 | #else |
308 | inline static guint16 _g_stat_uid (const GLocalFileStat *buf) { return buf->st_uid; } |
309 | inline static guint16 _g_stat_gid (const GLocalFileStat *buf) { return buf->st_gid; } |
310 | #endif |
311 | |
312 | #ifdef HAVE_STRUCT_STAT_ST_BLOCKS |
313 | inline static blkcnt_t _g_stat_blocks (const GLocalFileStat *buf) { return buf->st_blocks; } |
314 | #endif |
315 | |
316 | #ifndef G_OS_WIN32 |
317 | inline static time_t _g_stat_atime (const GLocalFileStat *buf) { return buf->st_atime; } |
318 | inline static time_t _g_stat_ctime (const GLocalFileStat *buf) { return buf->st_ctime; } |
319 | inline static time_t _g_stat_mtime (const GLocalFileStat *buf) { return buf->st_mtime; } |
320 | #endif |
321 | #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC |
322 | inline static guint32 _g_stat_atim_nsec (const GLocalFileStat *buf) { return buf->st_atim.tv_nsec; } |
323 | inline static guint32 _g_stat_ctim_nsec (const GLocalFileStat *buf) { return buf->st_ctim.tv_nsec; } |
324 | inline static guint32 _g_stat_mtim_nsec (const GLocalFileStat *buf) { return buf->st_mtim.tv_nsec; } |
325 | #endif |
326 | |
327 | #endif /* !HAVE_STATX */ |
328 | |
329 | #define G_LOCAL_FILE_INFO_NOSTAT_ATTRIBUTES \ |
330 | G_FILE_ATTRIBUTE_STANDARD_NAME "," \ |
331 | G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," \ |
332 | G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME "," \ |
333 | G_FILE_ATTRIBUTE_STANDARD_COPY_NAME |
334 | |
335 | gboolean _g_local_file_has_trash_dir (const char *dirname, |
336 | dev_t dir_dev); |
337 | #ifdef G_OS_UNIX |
338 | gboolean _g_local_file_is_lost_found_dir (const char *path, |
339 | dev_t path_dev); |
340 | #endif |
341 | void _g_local_file_info_get_parent_info (const char *dir, |
342 | GFileAttributeMatcher *attribute_matcher, |
343 | GLocalParentFileInfo *parent_info); |
344 | void _g_local_file_info_free_parent_info (GLocalParentFileInfo *parent_info); |
345 | void _g_local_file_info_get_nostat (GFileInfo *info, |
346 | const char *basename, |
347 | const char *path, |
348 | GFileAttributeMatcher *attribute_matcher); |
349 | GFileInfo *_g_local_file_info_get (const char *basename, |
350 | const char *path, |
351 | GFileAttributeMatcher *attribute_matcher, |
352 | GFileQueryInfoFlags flags, |
353 | GLocalParentFileInfo *parent_info, |
354 | GError **error); |
355 | GFileInfo *_g_local_file_info_get_from_fd (int fd, |
356 | const char *attributes, |
357 | GError **error); |
358 | char * _g_local_file_info_create_etag (GLocalFileStat *statbuf); |
359 | gboolean _g_local_file_info_set_attribute (char *filename, |
360 | const char *attribute, |
361 | GFileAttributeType type, |
362 | gpointer value_p, |
363 | GFileQueryInfoFlags flags, |
364 | GCancellable *cancellable, |
365 | GError **error); |
366 | gboolean _g_local_file_info_set_attributes (char *filename, |
367 | GFileInfo *info, |
368 | GFileQueryInfoFlags flags, |
369 | GCancellable *cancellable, |
370 | GError **error); |
371 | |
372 | G_END_DECLS |
373 | |
374 | #endif /* __G_FILE_LOCAL_FILE_INFO_H__ */ |
375 | |