1/* GLib testing framework examples and tests
2 * Copyright (C) 2008 Red Hat, Inc.
3 * Authors: Tomas Bzatek <tbzatek@redhat.com>
4 *
5 * This work is provided "as is"; redistribution and modification
6 * in whole or in part, in any medium, physical or electronic is
7 * permitted without restriction.
8 *
9 * This work is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * In no event shall the authors or contributors be liable for any
14 * direct, indirect, incidental, special, exemplary, or consequential
15 * damages (including, but not limited to, procurement of substitute
16 * goods or services; loss of use, data, or profits; or business
17 * interruption) however caused and on any theory of liability, whether
18 * in contract, strict liability, or tort (including negligence or
19 * otherwise) arising in any way out of the use of this software, even
20 * if advised of the possibility of such damage.
21 */
22
23#include "config.h"
24
25#include <glib/glib.h>
26#include <gio/gio.h>
27#include <stdlib.h>
28#include <string.h>
29#ifdef G_OS_WIN32
30#include <stdio.h>
31#include <glib/gstdio.h>
32#include <windows.h>
33#include <shlobj.h>
34#include <io.h> /* for _get_osfhandle */
35#endif
36
37#define TEST_NAME "Prilis zlutoucky kun"
38#define TEST_DISPLAY_NAME "UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88"
39#define TEST_SIZE 0xFFFFFFF0
40
41static void
42test_assigned_values (GFileInfo *info)
43{
44 const char *name, *display_name, *mistake;
45 guint64 size;
46 GFileType type;
47
48 /* Test for attributes presence */
49 g_assert_true (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_NAME));
50 g_assert_true (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME));
51 g_assert_true (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE));
52 g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_COPY_NAME));
53
54 /* Retrieve data back and compare */
55
56 name = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_STANDARD_NAME);
57 display_name = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
58 mistake = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_COPY_NAME);
59 size = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE);
60 type = g_file_info_get_file_type (info);
61
62 g_assert_cmpstr (name, ==, TEST_NAME);
63 g_assert_cmpstr (display_name, ==, TEST_DISPLAY_NAME);
64 g_assert_null (mistake);
65 g_assert_cmpint (size, ==, TEST_SIZE);
66 g_assert_cmpstr (name, ==, g_file_info_get_name (info));
67 g_assert_cmpstr (display_name, ==, g_file_info_get_display_name (info));
68 g_assert_cmpint (size, ==, g_file_info_get_size (info) );
69 g_assert_cmpint (type, ==, G_FILE_TYPE_DIRECTORY);
70}
71
72
73
74static void
75test_g_file_info (void)
76{
77 GFileInfo *info;
78 GFileInfo *info_dup;
79 GFileInfo *info_copy;
80 char **attr_list;
81 GFileAttributeMatcher *matcher;
82
83 info = g_file_info_new ();
84
85 /* Test for empty instance */
86 attr_list = g_file_info_list_attributes (info, NULL);
87 g_assert_nonnull (attr_list);
88 g_assert_null (*attr_list);
89 g_strfreev (str_array: attr_list);
90
91 g_file_info_set_attribute_byte_string (info, G_FILE_ATTRIBUTE_STANDARD_NAME, TEST_NAME);
92 g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, TEST_DISPLAY_NAME);
93 g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE, TEST_SIZE);
94 g_file_info_set_file_type (info, type: G_FILE_TYPE_DIRECTORY);
95
96 /* The attr list should not be empty now */
97 attr_list = g_file_info_list_attributes (info, NULL);
98 g_assert_nonnull (attr_list);
99 g_assert_nonnull (*attr_list);
100 g_strfreev (str_array: attr_list);
101
102 test_assigned_values (info);
103
104 /* Test dups */
105 info_dup = g_file_info_dup (other: info);
106 g_assert_nonnull (info_dup);
107 test_assigned_values (info: info_dup);
108
109 info_copy = g_file_info_new ();
110 g_file_info_copy_into (src_info: info_dup, dest_info: info_copy);
111 g_assert_nonnull (info_copy);
112 test_assigned_values (info: info_copy);
113
114 /* Test remove attribute */
115 g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER));
116 g_file_info_set_attribute_int32 (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER, attr_value: 10);
117 g_assert_true (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER));
118
119 g_assert_cmpint (g_file_info_get_attribute_type (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER), ==, G_FILE_ATTRIBUTE_TYPE_INT32);
120 g_assert_cmpint (g_file_info_get_attribute_status (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER), !=, G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING);
121
122 g_file_info_remove_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER);
123 g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER));
124 g_assert_cmpint (g_file_info_get_attribute_type (info, G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER), ==, G_FILE_ATTRIBUTE_TYPE_INVALID);
125
126 matcher = g_file_attribute_matcher_new (G_FILE_ATTRIBUTE_STANDARD_NAME ","
127 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
128
129 g_assert_true (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_NAME));
130 g_assert_false (g_file_attribute_matcher_matches_only (matcher, G_FILE_ATTRIBUTE_STANDARD_NAME));
131 g_assert_false (g_file_attribute_matcher_matches (matcher, G_FILE_ATTRIBUTE_STANDARD_SIZE));
132
133 g_file_info_set_attribute_mask (info, mask: matcher);
134 g_file_attribute_matcher_unref (matcher);
135
136 g_assert_false (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE));
137 g_assert_true (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_NAME));
138
139 g_object_unref (object: info);
140 g_object_unref (object: info_dup);
141 g_object_unref (object: info_copy);
142}
143
144static void
145test_g_file_info_modification_time (void)
146{
147 GFile *file = NULL;
148 GFileIOStream *io_stream = NULL;
149 GFileInfo *info = NULL;
150 GDateTime *dt = NULL, *dt_usecs = NULL, *dt_new = NULL, *dt_new_usecs = NULL;
151 GTimeSpan ts;
152 GError *error = NULL;
153
154 g_test_summary (summary: "Test that getting the modification time of a file works.");
155
156 file = g_file_new_tmp (tmpl: "g-file-info-test-XXXXXX", iostream: &io_stream, error: &error);
157 g_assert_no_error (error);
158
159 info = g_file_query_info (file,
160 G_FILE_ATTRIBUTE_TIME_MODIFIED,
161 flags: G_FILE_QUERY_INFO_NONE,
162 NULL, error: &error);
163 g_assert_no_error (error);
164
165 /* Check the modification time is retrievable. */
166 dt = g_file_info_get_modification_date_time (info);
167 g_assert_nonnull (dt);
168
169 /* Try again with microsecond precision. */
170 g_clear_object (&info);
171 info = g_file_query_info (file,
172 G_FILE_ATTRIBUTE_TIME_MODIFIED "," G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
173 flags: G_FILE_QUERY_INFO_NONE,
174 NULL, error: &error);
175 g_assert_no_error (error);
176
177 dt_usecs = g_file_info_get_modification_date_time (info);
178 g_assert_nonnull (dt_usecs);
179
180 ts = g_date_time_difference (end: dt_usecs, begin: dt);
181 g_assert_cmpint (ts, >, 0);
182 g_assert_cmpint (ts, <, G_USEC_PER_SEC);
183
184 /* Try round-tripping the modification time. */
185 dt_new = g_date_time_add (datetime: dt_usecs, G_USEC_PER_SEC + 50);
186 g_file_info_set_modification_date_time (info, mtime: dt_new);
187
188 dt_new_usecs = g_file_info_get_modification_date_time (info);
189 ts = g_date_time_difference (end: dt_new_usecs, begin: dt_new);
190 g_assert_cmpint (ts, ==, 0);
191
192 /* Clean up. */
193 g_clear_object (&io_stream);
194 g_file_delete (file, NULL, NULL);
195 g_clear_object (&file);
196
197 g_clear_object (&info);
198 g_date_time_unref (datetime: dt);
199 g_date_time_unref (datetime: dt_usecs);
200 g_date_time_unref (datetime: dt_new);
201 g_date_time_unref (datetime: dt_new_usecs);
202}
203
204#ifdef G_OS_WIN32
205static void
206test_internal_enhanced_stdio (void)
207{
208 char *p0, *p1, *ps;
209 gboolean try_sparse;
210 gchar *tmp_dir_root;
211 wchar_t *tmp_dir_root_w;
212 gchar *c;
213 DWORD fsflags;
214 FILE *f;
215 SYSTEMTIME st;
216 FILETIME ft;
217 HANDLE h;
218 GStatBuf statbuf_p0, statbuf_p1, statbuf_ps;
219 GFile *gf_p0, *gf_p1, *gf_ps;
220 GFileInfo *fi_p0, *fi_p1, *fi_ps;
221 guint64 size_p0, alsize_p0, size_ps, alsize_ps;
222 const gchar *id_p0;
223 const gchar *id_p1;
224 guint64 time_p0;
225 gchar *tmp_dir;
226 wchar_t *programdata_dir_w;
227 wchar_t *users_dir_w;
228 static const GUID folder_id_programdata =
229 { 0x62AB5D82, 0xFDC1, 0x4DC3, { 0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97 } };
230 static const GUID folder_id_users =
231 { 0x0762D272, 0xC50A, 0x4BB0, { 0xA3, 0x82, 0x69, 0x7D, 0xCD, 0x72, 0x9B, 0x80 } };
232 GDateTime *dt = NULL, *dt2 = NULL;
233 GTimeSpan ts;
234 /* Just before SYSTEMTIME limit (Jan 1 30827) */
235 const gint64 one_sec_before_systemtime_limit = 910670515199;
236 gboolean retval;
237 GError *local_error = NULL;
238
239
240 programdata_dir_w = NULL;
241 SHGetKnownFolderPath (&folder_id_programdata, 0, NULL, &programdata_dir_w);
242
243 users_dir_w = NULL;
244 SHGetKnownFolderPath (&folder_id_users, 0, NULL, &users_dir_w);
245
246 if (programdata_dir_w != NULL && users_dir_w != NULL)
247 {
248 gchar *programdata;
249 gchar *users_dir;
250 gchar *allusers;
251 gchar *commondata;
252 GFile *gf_programdata, *gf_allusers, *gf_commondata;
253 GFileInfo *fi_programdata, *fi_allusers, *fi_allusers_target, *fi_commondata, *fi_commondata_target;
254 GFileType ft_allusers;
255 GFileType ft_allusers_target;
256 GFileType ft_programdata;
257 GFileType ft_commondata;
258 gboolean allusers_is_symlink;
259 gboolean commondata_is_symlink;
260 gboolean commondata_is_mount_point;
261 guint32 allusers_reparse_tag;
262 guint32 commondata_reparse_tag;
263 const gchar *id_allusers;
264 const gchar *id_allusers_target;
265 const gchar *id_commondata_target;
266 const gchar *id_programdata;
267 const gchar *allusers_target;
268 const gchar *commondata_target;
269
270 /* C:/ProgramData */
271 programdata = g_utf16_to_utf8 (programdata_dir_w, -1, NULL, NULL, NULL);
272 g_assert_nonnull (programdata);
273 /* C:/Users */
274 users_dir = g_utf16_to_utf8 (users_dir_w, -1, NULL, NULL, NULL);
275 g_assert_nonnull (users_dir);
276 /* "C:/Users/All Users" is a known directory symlink
277 * for "C:/ProgramData".
278 */
279 allusers = g_build_filename (users_dir, "All Users", NULL);
280
281 /* "C:/Users/All Users/Application Data" is a known
282 * junction for "C:/ProgramData"
283 */
284 commondata = g_build_filename (allusers, "Application Data", NULL);
285
286 /* We don't test g_stat() and g_lstat() on these directories,
287 * because it is pointless - there's no way to tell that these
288 * functions behave correctly in this case
289 * (st_ino is useless, so we can't tell apart g_stat() and g_lstat()
290 * results; st_mode is also useless as it does not support S_ISLNK;
291 * and these directories have no interesting properties other
292 * than [not] being symlinks).
293 */
294 gf_programdata = g_file_new_for_path (programdata);
295 gf_allusers = g_file_new_for_path (allusers);
296 gf_commondata = g_file_new_for_path (commondata);
297
298 fi_programdata = g_file_query_info (gf_programdata,
299 G_FILE_ATTRIBUTE_ID_FILE ","
300 G_FILE_ATTRIBUTE_STANDARD_TYPE,
301 G_FILE_QUERY_INFO_NONE,
302 NULL, NULL);
303
304 fi_allusers_target = g_file_query_info (gf_allusers,
305 G_FILE_ATTRIBUTE_ID_FILE ","
306 G_FILE_ATTRIBUTE_STANDARD_TYPE,
307 G_FILE_QUERY_INFO_NONE,
308 NULL, NULL);
309
310 fi_allusers = g_file_query_info (gf_allusers,
311 G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET ","
312 G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
313 G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG ","
314 G_FILE_ATTRIBUTE_ID_FILE ","
315 G_FILE_ATTRIBUTE_STANDARD_TYPE,
316 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
317 NULL, NULL);
318
319 fi_commondata = g_file_query_info (gf_commondata,
320 G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET ","
321 G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
322 G_FILE_ATTRIBUTE_DOS_IS_MOUNTPOINT ","
323 G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG ","
324 G_FILE_ATTRIBUTE_ID_FILE ","
325 G_FILE_ATTRIBUTE_STANDARD_TYPE,
326 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
327 NULL, NULL);
328
329 fi_commondata_target = g_file_query_info (gf_commondata,
330 G_FILE_ATTRIBUTE_ID_FILE ","
331 G_FILE_ATTRIBUTE_STANDARD_TYPE,
332 G_FILE_QUERY_INFO_NONE,
333 NULL, NULL);
334
335 g_assert_true (g_file_info_has_attribute (fi_programdata, G_FILE_ATTRIBUTE_ID_FILE));
336 g_assert_true (g_file_info_has_attribute (fi_programdata, G_FILE_ATTRIBUTE_STANDARD_TYPE));
337
338 g_assert_true (g_file_info_has_attribute (fi_allusers_target, G_FILE_ATTRIBUTE_ID_FILE));
339 g_assert_true (g_file_info_has_attribute (fi_allusers_target, G_FILE_ATTRIBUTE_STANDARD_TYPE));
340 g_assert_true (g_file_info_has_attribute (fi_commondata_target, G_FILE_ATTRIBUTE_ID_FILE));
341 g_assert_true (g_file_info_has_attribute (fi_commondata_target, G_FILE_ATTRIBUTE_STANDARD_TYPE));
342
343 g_assert_true (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_ID_FILE));
344 g_assert_true (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_TYPE));
345 g_assert_true (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK));
346 g_assert_true (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG));
347 g_assert_true (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET));
348
349 g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_ID_FILE));
350 g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_STANDARD_TYPE));
351 g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK));
352 g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_DOS_IS_MOUNTPOINT));
353 g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG));
354 g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET));
355
356 ft_allusers = g_file_info_get_file_type (fi_allusers);
357 ft_allusers_target = g_file_info_get_file_type (fi_allusers_target);
358 ft_programdata = g_file_info_get_file_type (fi_programdata);
359 ft_commondata = g_file_info_get_file_type (fi_commondata);
360
361 g_assert_cmpint (ft_allusers, ==, G_FILE_TYPE_DIRECTORY);
362 g_assert_cmpint (ft_allusers_target, ==, G_FILE_TYPE_DIRECTORY);
363 g_assert_cmpint (ft_programdata, ==, G_FILE_TYPE_DIRECTORY);
364 g_assert_cmpint (ft_commondata, ==, G_FILE_TYPE_DIRECTORY);
365
366 allusers_is_symlink = g_file_info_get_attribute_boolean (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
367 allusers_reparse_tag = g_file_info_get_attribute_uint32 (fi_allusers, G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG);
368 commondata_is_symlink = g_file_info_get_attribute_boolean (fi_commondata, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
369 commondata_is_mount_point = g_file_info_get_attribute_boolean (fi_commondata, G_FILE_ATTRIBUTE_DOS_IS_MOUNTPOINT);
370 commondata_reparse_tag = g_file_info_get_attribute_uint32 (fi_commondata, G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG);
371
372 g_assert_true (allusers_is_symlink);
373 g_assert_cmpuint (allusers_reparse_tag, ==, IO_REPARSE_TAG_SYMLINK);
374 g_assert_true (commondata_is_symlink);
375 g_assert_true (commondata_is_mount_point);
376 g_assert_cmpuint (commondata_reparse_tag, ==, IO_REPARSE_TAG_MOUNT_POINT);
377
378 id_allusers = g_file_info_get_attribute_string (fi_allusers, G_FILE_ATTRIBUTE_ID_FILE);
379 id_allusers_target = g_file_info_get_attribute_string (fi_allusers_target, G_FILE_ATTRIBUTE_ID_FILE);
380 id_commondata_target = g_file_info_get_attribute_string (fi_commondata_target, G_FILE_ATTRIBUTE_ID_FILE);
381 id_programdata = g_file_info_get_attribute_string (fi_programdata, G_FILE_ATTRIBUTE_ID_FILE);
382
383 g_assert_cmpstr (id_allusers_target, ==, id_programdata);
384 g_assert_cmpstr (id_commondata_target, ==, id_programdata);
385 g_assert_cmpstr (id_allusers, !=, id_programdata);
386
387 allusers_target = g_file_info_get_symlink_target (fi_allusers);
388
389 g_assert_true (g_str_has_suffix (allusers_target, "ProgramData"));
390
391 commondata_target = g_file_info_get_symlink_target (fi_commondata);
392
393 g_assert_true (g_str_has_suffix (commondata_target, "ProgramData"));
394
395 g_object_unref (fi_allusers);
396 g_object_unref (fi_allusers_target);
397 g_object_unref (fi_commondata);
398 g_object_unref (fi_commondata_target);
399 g_object_unref (fi_programdata);
400 g_object_unref (gf_allusers);
401 g_object_unref (gf_commondata);
402 g_object_unref (gf_programdata);
403
404 g_free (allusers);
405 g_free (commondata);
406 g_free (users_dir);
407 g_free (programdata);
408 }
409
410 if (programdata_dir_w)
411 CoTaskMemFree (programdata_dir_w);
412
413 if (users_dir_w)
414 CoTaskMemFree (users_dir_w);
415
416 tmp_dir = g_dir_make_tmp ("glib_stdio_testXXXXXX", NULL);
417 g_assert_nonnull (tmp_dir);
418
419 /* Technically, this isn't necessary - we already assume NTFS, because of
420 * symlink support, and NTFS also supports sparse files. Still, given
421 * the amount of unusual I/O APIs called in this test, checking for
422 * sparse file support of the filesystem where temp directory is
423 * doesn't seem to be out of place.
424 */
425 try_sparse = FALSE;
426 tmp_dir_root = g_strdup (tmp_dir);
427 /* We need "C:\\" or "C:/", with a trailing [back]slash */
428 for (c = tmp_dir_root; c && c[0] && c[1]; c++)
429 if (c[0] == ':')
430 {
431 c[2] = '\0';
432 break;
433 }
434 tmp_dir_root_w = g_utf8_to_utf16 (tmp_dir_root, -1, NULL, NULL, NULL);
435 g_assert_nonnull (tmp_dir_root_w);
436 g_free (tmp_dir_root);
437 g_assert_true (GetVolumeInformationW (tmp_dir_root_w, NULL, 0, NULL, NULL, &fsflags, NULL, 0));
438 g_free (tmp_dir_root_w);
439 try_sparse = (fsflags & FILE_SUPPORTS_SPARSE_FILES) == FILE_SUPPORTS_SPARSE_FILES;
440
441 p0 = g_build_filename (tmp_dir, "zool", NULL);
442 p1 = g_build_filename (tmp_dir, "looz", NULL);
443 ps = g_build_filename (tmp_dir, "sparse", NULL);
444
445 if (try_sparse)
446 {
447 FILE_SET_SPARSE_BUFFER ssb;
448 FILE_ZERO_DATA_INFORMATION zdi;
449
450 g_remove (ps);
451
452 f = g_fopen (ps, "wb");
453 g_assert_nonnull (f);
454
455 h = (HANDLE) _get_osfhandle (fileno (f));
456 g_assert_cmpuint ((guintptr) h, !=, (guintptr) INVALID_HANDLE_VALUE);
457
458 ssb.SetSparse = TRUE;
459 g_assert_true (DeviceIoControl (h,
460 FSCTL_SET_SPARSE,
461 &ssb, sizeof (ssb),
462 NULL, 0, NULL, NULL));
463
464 /* Make it a sparse file that starts with 4GBs of zeros */
465 zdi.FileOffset.QuadPart = 0;
466 zdi.BeyondFinalZero.QuadPart = 0xFFFFFFFFULL + 1;
467 g_assert_true (DeviceIoControl (h,
468 FSCTL_SET_ZERO_DATA,
469 &zdi, sizeof (zdi),
470 NULL, 0, NULL, NULL));
471
472 /* Let's not keep this seemingly 4GB monster around
473 * longer than we absolutely need to. Do all operations
474 * without assertions, then remove the file immediately.
475 */
476 _fseeki64 (f, 0xFFFFFFFFULL, SEEK_SET);
477 fprintf (f, "Hello 4GB World!");
478 fflush (f);
479 fclose (f);
480
481 memset (&statbuf_ps, 0, sizeof (statbuf_ps));
482
483 g_stat (ps, &statbuf_ps);
484
485 gf_ps = g_file_new_for_path (ps);
486
487 fi_ps = g_file_query_info (gf_ps,
488 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
489 G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE,
490 G_FILE_QUERY_INFO_NONE,
491 NULL, NULL);
492
493 g_remove (ps);
494
495 g_assert_true (g_file_info_has_attribute (fi_ps, G_FILE_ATTRIBUTE_STANDARD_SIZE));
496 g_assert_true (g_file_info_has_attribute (fi_ps, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
497
498 size_ps = g_file_info_get_attribute_uint64 (fi_ps, G_FILE_ATTRIBUTE_STANDARD_SIZE);
499 alsize_ps = g_file_info_get_attribute_uint64 (fi_ps, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE);
500
501 /* allocated size should small (usually - size of the FS cluster,
502 * let's assume it's less than 1 gigabyte),
503 * size should be more than 4 gigabytes,
504 * st_size should not exceed its 0xFFFFFFFF 32-bit limit,
505 * and should be nonzero (this also detects a failed g_stat() earlier).
506 */
507 g_assert_cmpuint (alsize_ps, <, 0x40000000);
508 g_assert_cmpuint (size_ps, >, G_GUINT64_CONSTANT (0xFFFFFFFF));
509 g_assert_cmpuint (statbuf_ps.st_size, >, 0);
510 g_assert_cmpuint (statbuf_ps.st_size, <=, 0xFFFFFFFF);
511
512 g_object_unref (fi_ps);
513 g_object_unref (gf_ps);
514 }
515
516 /* Wa-a-ay past 02/07/2106 @ 6:28am (UTC),
517 * which is the date corresponding to 0xFFFFFFFF + 1.
518 * This is easier to check than Y2038 (0x80000000 + 1),
519 * since there's no need to worry about signedness this way.
520 */
521 st.wYear = 2106;
522 st.wMonth = 2;
523 st.wDay = 9;
524 st.wHour = 0;
525 st.wMinute = 0;
526 st.wSecond = 0;
527 st.wMilliseconds = 0;
528
529 g_assert_true (SystemTimeToFileTime (&st, &ft));
530
531 f = g_fopen (p0, "w");
532 g_assert_nonnull (f);
533
534 h = (HANDLE) _get_osfhandle (fileno (f));
535 g_assert_cmpuint ((guintptr) h, !=, (guintptr) INVALID_HANDLE_VALUE);
536
537 fprintf (f, "1");
538 fflush (f);
539
540 g_assert_true (SetFileTime (h, &ft, &ft, &ft));
541
542 fclose (f);
543
544 f = g_fopen (p1, "w");
545 g_assert_nonnull (f);
546
547 fclose (f);
548
549 memset (&statbuf_p0, 0, sizeof (statbuf_p0));
550 memset (&statbuf_p1, 0, sizeof (statbuf_p1));
551
552 g_assert_cmpint (g_stat (p0, &statbuf_p0), ==, 0);
553 g_assert_cmpint (g_stat (p1, &statbuf_p1), ==, 0);
554
555 gf_p0 = g_file_new_for_path (p0);
556 gf_p1 = g_file_new_for_path (p1);
557
558 fi_p0 = g_file_query_info (gf_p0,
559 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
560 G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE ","
561 G_FILE_ATTRIBUTE_ID_FILE ","
562 G_FILE_ATTRIBUTE_TIME_MODIFIED ","
563 G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
564 G_FILE_QUERY_INFO_NONE,
565 NULL, NULL);
566
567 fi_p1 = g_file_query_info (gf_p1,
568 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
569 G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE ","
570 G_FILE_ATTRIBUTE_ID_FILE ","
571 G_FILE_ATTRIBUTE_TIME_MODIFIED ","
572 G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
573 G_FILE_QUERY_INFO_NONE,
574 NULL, NULL);
575
576 g_assert_true (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_STANDARD_SIZE));
577 g_assert_true (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
578 g_assert_true (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_ID_FILE));
579 g_assert_true (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_TIME_MODIFIED));
580 g_assert_true (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC));
581
582 g_assert_true (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_STANDARD_SIZE));
583 g_assert_true (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
584 g_assert_true (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_ID_FILE));
585 g_assert_true (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_TIME_MODIFIED));
586 g_assert_true (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC));
587
588 size_p0 = g_file_info_get_attribute_uint64 (fi_p0, G_FILE_ATTRIBUTE_STANDARD_SIZE);
589 alsize_p0 = g_file_info_get_attribute_uint64 (fi_p0, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE);
590
591 /* size should be 1, allocated size should be something else
592 * (could be 0 or the size of the FS cluster, but never 1).
593 */
594 g_assert_cmpuint (size_p0, ==, statbuf_p0.st_size);
595 g_assert_cmpuint (size_p0, ==, 1);
596 g_assert_cmpuint (alsize_p0, !=, size_p0);
597
598 id_p0 = g_file_info_get_attribute_string (fi_p0, G_FILE_ATTRIBUTE_ID_FILE);
599 id_p1 = g_file_info_get_attribute_string (fi_p1, G_FILE_ATTRIBUTE_ID_FILE);
600
601 /* st_ino from W32 stat() is useless for file identification.
602 * It will be either 0, or it will be the same for both files.
603 */
604 g_assert_cmpint (statbuf_p0.st_ino, ==, statbuf_p1.st_ino);
605 g_assert_cmpstr (id_p0, !=, id_p1);
606
607 time_p0 = g_file_info_get_attribute_uint64 (fi_p0, G_FILE_ATTRIBUTE_TIME_MODIFIED);
608
609 /* Check that GFileInfo doesn't suffer from Y2106 problem.
610 * Don't check stat(), as its contents may vary depending on
611 * the host platform architecture
612 * (time fields are 32-bit on 32-bit Windows,
613 * and 64-bit on 64-bit Windows, usually),
614 * so it *can* pass this test in some cases.
615 */
616 g_assert_cmpuint (time_p0, >, G_GUINT64_CONSTANT (0xFFFFFFFF));
617
618 dt = g_file_info_get_modification_date_time (fi_p0);
619 g_assert_nonnull (dt);
620 dt2 = g_date_time_add (dt, G_USEC_PER_SEC / 100 * 200);
621 g_object_unref (fi_p0);
622 fi_p0 = g_file_info_new ();
623 g_file_info_set_modification_date_time (fi_p0, dt2);
624
625 g_assert_true (g_file_set_attributes_from_info (gf_p0,
626 fi_p0,
627 G_FILE_QUERY_INFO_NONE,
628 NULL,
629 NULL));
630 g_date_time_unref (dt2);
631 g_object_unref (fi_p0);
632 fi_p0 = g_file_query_info (gf_p0,
633 G_FILE_ATTRIBUTE_TIME_MODIFIED ","
634 G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
635 G_FILE_QUERY_INFO_NONE,
636 NULL, NULL);
637 dt2 = g_file_info_get_modification_date_time (fi_p0);
638 ts = g_date_time_difference (dt2, dt);
639 g_assert_cmpint (ts, >, 0);
640 g_assert_cmpint (ts, <, G_USEC_PER_SEC / 100 * 300);
641
642 g_date_time_unref (dt);
643 g_date_time_unref (dt2);
644
645 g_file_info_set_attribute_uint64 (fi_p0,
646 G_FILE_ATTRIBUTE_TIME_MODIFIED,
647 one_sec_before_systemtime_limit);
648 g_file_info_set_attribute_uint32 (fi_p0, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, 0);
649 g_assert_true (g_file_set_attributes_from_info (gf_p0,
650 fi_p0,
651 G_FILE_QUERY_INFO_NONE,
652 NULL,
653 NULL));
654
655 g_file_info_set_attribute_uint64 (fi_p0,
656 G_FILE_ATTRIBUTE_TIME_MODIFIED,
657 one_sec_before_systemtime_limit + G_USEC_PER_SEC * 2);
658 g_file_info_set_attribute_uint32 (fi_p0, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, 0);
659 retval = g_file_set_attributes_from_info (gf_p0,
660 fi_p0,
661 G_FILE_QUERY_INFO_NONE,
662 NULL,
663 &local_error);
664 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
665 g_assert_false (retval);
666 g_clear_error (&local_error);
667
668 g_object_unref (fi_p0);
669 g_object_unref (fi_p1);
670 g_object_unref (gf_p0);
671 g_object_unref (gf_p1);
672 g_remove (p0);
673 g_remove (p1);
674 g_free (p0);
675 g_free (p1);
676 g_rmdir (tmp_dir);
677}
678#endif
679
680static void
681test_xattrs (void)
682{
683 GFile *file = NULL;
684 GFileIOStream *stream = NULL;
685 GFileInfo *file_info0 = NULL, *file_info1 = NULL;
686 GError *local_error = NULL;
687
688 g_test_summary (summary: "Test setting and getting escaped xattrs");
689
690 /* Create a temporary file; no need to write anything to it. */
691 file = g_file_new_tmp (tmpl: "g-file-info-test-xattrs-XXXXXX", iostream: &stream, error: &local_error);
692 g_assert_no_error (local_error);
693 g_assert_nonnull (file);
694
695 g_io_stream_close (G_IO_STREAM (stream), NULL, NULL);
696 g_object_unref (object: stream);
697
698 /* Check the existing xattrs. */
699 file_info0 = g_file_query_info (file, attributes: "xattr::*", flags: G_FILE_QUERY_INFO_NONE, NULL, error: &local_error);
700 g_assert_no_error (local_error);
701 g_assert_nonnull (file_info0);
702
703 /* Set some new xattrs, with escaping and some embedded nuls. */
704 g_file_info_set_attribute_string (info: file_info0, attribute: "xattr::escaped", attr_value: "hello\\x82\\x80\\xbd");
705 g_file_info_set_attribute_string (info: file_info0, attribute: "xattr::string", attr_value: "hi there");
706 g_file_info_set_attribute_string (info: file_info0, attribute: "xattr::embedded-nul", attr_value: "hi\\x00there");
707
708 g_file_set_attributes_from_info (file, info: file_info0, flags: G_FILE_QUERY_INFO_NONE, NULL, error: &local_error);
709
710 g_object_unref (object: file_info0);
711
712 if (g_error_matches (error: local_error, G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED))
713 {
714 g_test_skip (msg: "xattrs not supported on this file system");
715 g_clear_error (err: &local_error);
716 }
717 else
718 {
719 g_assert_no_error (local_error);
720
721 /* Check they were set properly. */
722 file_info1 = g_file_query_info (file, attributes: "xattr::*", flags: G_FILE_QUERY_INFO_NONE, NULL, error: &local_error);
723 g_assert_no_error (local_error);
724 g_assert_nonnull (file_info1);
725
726 g_assert_true (g_file_info_has_namespace (file_info1, "xattr"));
727
728 g_assert_cmpstr (g_file_info_get_attribute_string (file_info1, "xattr::escaped"), ==, "hello\\x82\\x80\\xbd");
729 g_assert_cmpstr (g_file_info_get_attribute_string (file_info1, "xattr::string"), ==, "hi there");
730 g_assert_cmpstr (g_file_info_get_attribute_string (file_info1, "xattr::embedded-nul"), ==, "hi\\x00there");
731
732 g_object_unref (object: file_info1);
733 }
734
735 /* Tidy up. */
736 g_file_delete (file, NULL, NULL);
737
738 g_object_unref (object: file);
739}
740
741int
742main (int argc,
743 char *argv[])
744{
745 g_test_init (argc: &argc, argv: &argv, NULL);
746
747 g_test_add_func (testpath: "/g-file-info/test_g_file_info", test_func: test_g_file_info);
748 g_test_add_func (testpath: "/g-file-info/test_g_file_info/modification-time", test_func: test_g_file_info_modification_time);
749#ifdef G_OS_WIN32
750 g_test_add_func ("/g-file-info/internal-enhanced-stdio", test_internal_enhanced_stdio);
751#endif
752 g_test_add_func (testpath: "/g-file-info/xattrs", test_func: test_xattrs);
753
754 return g_test_run();
755}
756

source code of gtk/subprojects/glib/gio/tests/g-file-info.c