master
c 3,800 lines 109 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 lxtfs.c
8
9 Abstract:
10
11 This file contains common test functions for file system tests.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "lxtfs.h"
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/uio.h>
20 #include <sys/epoll.h>
21 #include <sys/inotify.h>
22 #include <sys/mount.h>
23 #include <sys/xattr.h>
24 #include <sys/wait.h>
25 #include <sys/mman.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <limits.h>
29 #include <dirent.h>
30 #include <stdlib.h>
31 #include <libmount/libmount.h>
32 #include "lxtmount.h"
33
34 #define FS_RENAMEAT_TEST_FILE "file"
35 #define FS_RENAMEAT_TEST_FILE2 "file2"
36 #define FS_UTIME_TESTFILE "testfile"
37 #define FS_UTIME_TESTLINK "testlink"
38 #define FS_NS_PER_SEC (1000000000ull)
39 #define FS_NS_PER_NT_UNIT (100ull)
40 #define FS_UNIX_TIME_2000 (946684800)
41 #define FS_SECONDS_PER_DAY (86400)
42 #define FS_FAT_MODIFIED_TIME_PRECISION (2)
43 #define FS_CURRENT_TIME_ALLOWED_VARIANCE (2)
44
45 //
46 // The following macros are used by LxtFsDeleteCurrentWorkingDirectoryCommon
47 // and LxtFsDeleteOpenFileCommon.
48 //
49
50 #define FS_DELETE_TEST_DIR_NAME "delete_test"
51 #define FS_DELETE_TEST_DIR FS_TEST_DIR_PARENT "/" FS_DELETE_TEST_DIR_NAME
52 #define FS_DELETE_TEST_RENAME_FILE_NAME "/delete_test_file"
53 #define FS_DELETE_TEST_RENAME_FILE FS_TEST_DIR_PARENT FS_DELETE_TEST_RENAME_FILE_NAME
54 #define FS_DELETE_TEST_DIR_AT "../" FS_DELETE_TEST_DIR_NAME
55 #define FS_DELETE_TEST_CHILD "child"
56 #define FS_DELETE_LINK_SUFFIX " (deleted)"
57 #define FS_CHILD_PATH_FORMAT "%s/%s"
58 #define FS_FD_PATH_FORMAT "/proc/self/fd/%d"
59 #define FS_PROC_SELF_CWD "/proc/self/cwd"
60
61 //
62 // The following macros are used by LxtFsRenameDirCommon.
63 //
64
65 #define FS_RENAME_TEST_DIR "/rename_test"
66 #define FS_RENAME_TEST_DIR2 "/rename_test2"
67 #define FS_RENAME_TEST_DIR3 "/rename_test3"
68 #define FS_RENAME_TEST_FILE "/rename_test_file"
69 #define FS_RENAME_TEST_DIR_CHILD FS_RENAME_TEST_DIR "/child"
70 #define FS_RENAME_TEST_DIR_CHILD2 FS_RENAME_TEST_DIR "/child2"
71 #define FS_RENAME_TEST_DIR2_CHILD FS_RENAME_TEST_DIR2 "/child"
72 #define FS_RENAME_TEST_DIR2_CHILD2 FS_RENAME_TEST_DIR2 "/child2"
73 #define FS_RENAME_TEST_DIR_GRANDCHILD FS_RENAME_TEST_DIR_CHILD "/child2"
74 #define FS_RENAME_TEST_DIR_SLASH "/rename_test_slash/"
75 #define FS_RENAME_TEST_DIR_SLASH2 "/rename_test_slash2"
76 #define FS_RENAME_TEST_DIR_SLASH_LINK "/rename_test_slash_link"
77 #define FS_RENAME_TEST_DIR_SLASH_LINK2 "/rename_test_slash_link2"
78
79 //
80 // Flags for LxtFsTimestampCheckUpdate
81 //
82
83 #define FS_TIMESTAMP_ACCESS (0x1)
84 #define FS_TIMESTAMP_MODIFY (0x2)
85 #define FS_TIMESTAMP_CHANGE (0x4)
86
87 #define FS_TIMESTAMP_SLEEP_TIME (100000)
88
89 #define FS_MOUNT_DRVFS_COMMAND_FORMAT "mount -t drvfs %s %s -o rw,noatime"
90 #define FS_MOUNT_DRVFS_OPTIONS_COMMAND_FORMAT FS_MOUNT_DRVFS_COMMAND_FORMAT ",%s"
91 #define FS_PLAN9_UNC_PREFIX "UNC\\"
92 #define FS_PLAN9_UNC_PREFIX_LENGTH (sizeof(FS_PLAN9_UNC_PREFIX) - 1)
93 #define FS_UNC_PATH_PREFIX_LENGTH (2)
94
95 typedef struct _BASIC_TEST_CASE
96 {
97 struct timespec SetTime[2];
98 struct timespec ExpectTime[2];
99 } BASIC_TEST_CASE, *PBASIC_TEST_CASE;
100
101 enum
102 {
103 NameVariationFullName,
104 NameVariationCwdRelative,
105 NameVariationRelative,
106 NameVariationDescriptor,
107 NameVariationFullFileViaLink,
108 NameVariationCwdRelativeViaLink,
109 NameVariationRelativeViaLink,
110 NameVariationDescriptorViaLink,
111 NameVariationFullFileOnLink,
112 NameVariationCwdRelativeOnLink,
113 NameVariationRelativeOnLink,
114 NameVariationMax = NameVariationRelativeOnLink,
115 NameVariationFatMax = NameVariationDescriptor
116 };
117
118 struct linux_dirent
119 {
120 unsigned long d_ino;
121 unsigned long d_off;
122 unsigned short d_reclen;
123 char d_name[];
124 // char pad;
125 // char d_type;
126 };
127
128 int LxtFsDeleteCurrentWorkingDirectoryHelper(char* BaseDir, char* DeleteTestDir, int Flags);
129
130 int LxtFsDeleteOpenFileHelper(int Fd, char* BaseDir, char* DeleteTestDir, int Flags);
131
132 int LxtFsTimestampCheckCurrent(const struct timespec* Timestamp);
133
134 int LxtFsTimestampCheckEqual(const struct timespec* Timestamp1, const struct timespec* Timestamp2);
135
136 int LxtFsTimestampCheckGreater(const struct timespec* Timestamp1, const struct timespec* Timestamp2);
137
138 int LxtFsTimestampCheckUpdate(const char* Path, struct stat* PreviousStat, int Flags);
139
140 long long LxtFsTimestampDiff(const struct timespec* Timestamp1, const struct timespec* Timestamp2);
141
142 bool LxtFsUtimeDoTimesMatch(const struct timespec* Actual, const struct timespec* Expected, int AllowedVarianceSeconds);
143
144 void LxtFsUtimeRoundToFatAccessTime(struct timespec* Timespec);
145
146 void LxtFsUtimeRoundToFatModifiedTime(struct timespec* Timespec);
147
148 void LxtFsUtimeRoundToNt(struct timespec* Timespec);
149
150 //
151 // All real timestamps are offset from the year 2000 because FAT can only
152 // accept timestamps after 1980.
153
154 BASIC_TEST_CASE BasicTestCases[] = {
155 {{{FS_UNIX_TIME_2000 + 1111111, 2222222}, {FS_UNIX_TIME_2000 + 3333333, 4444444}},
156 {{FS_UNIX_TIME_2000 + 1111111, 2222222}, {FS_UNIX_TIME_2000 + 3333333, 4444444}}},
157
158 {{{5555555, UTIME_OMIT}, {FS_UNIX_TIME_2000 + 6666666, 7777777}},
159 {{FS_UNIX_TIME_2000 + 1111111, 2222222}, {FS_UNIX_TIME_2000 + 6666666, 7777777}}},
160
161 {{{FS_UNIX_TIME_2000 + 5555555, 8888888}, {9999999, UTIME_OMIT}},
162 {{FS_UNIX_TIME_2000 + 5555555, 8888888}, {FS_UNIX_TIME_2000 + 6666666, 7777777}}},
163
164 {{{1111111, UTIME_NOW}, {FS_UNIX_TIME_2000 + 2222222, 3333333}}, {{5555555, UTIME_NOW}, {FS_UNIX_TIME_2000 + 2222222, 3333333}}},
165
166 {{{FS_UNIX_TIME_2000 + 1111111, 22222222}, {3333333, UTIME_NOW}}, {{FS_UNIX_TIME_2000 + 1111111, 22222222}, {4444444, UTIME_NOW}}},
167
168 {{{1111111, UTIME_NOW}, {3333333, UTIME_NOW}}, {{2222222, UTIME_NOW}, {4444444, UTIME_NOW}}},
169
170 {{{0, UTIME_NOW}, {3333333, UTIME_NOW}}, {{0, UTIME_NOW}, {4444444, UTIME_NOW}}},
171
172 //
173 // This time is at 1am UTC, which is likely to be in the previous day local
174 // time (if the test is run on a system in the US). Having this value here
175 // ensures the test handles that correctly for FAT timestamp rounding in
176 // case it occurs for the current time.
177 //
178
179 {{{1498440508, 22222222}, {3333333, UTIME_NOW}}, {{1498440508, 22222222}, {4444444, UTIME_NOW}}},
180 };
181
182 LXT_FS_INFO g_LxtFsInfo;
183
184 int LxtFsCheckDrvFsMount(const char* Source, const char* Target, const char* Options, int ParentId, const char* MountRoot)
185
186 /*++
187
188 Description:
189
190 This routine verifies the mount options for a drvfs mount.
191
192 N.B. On WSL 2 this uses 9p mount options.
193
194 Arguments:
195
196 Source - Supplies the mount source.
197
198 Target - Supplies the mount target.
199
200 Options - Supplies optional mount options.
201
202 ParentId - Supplies the expected parent ID of the mount.
203
204 MountRoot - Supplies the expected mount root.
205
206 Return Value:
207
208 Returns 0 on success, -1 on failure.
209
210 --*/
211
212 {
213
214 char ExpectedOptions[1024];
215 char ExpectedCombinedOptions[1024];
216 LXT_FS_INFO FsInfo;
217 size_t Index;
218 size_t Length;
219 char Plan9Options[1024];
220 const char* Plan9Source;
221 int Result;
222 char Temp[1024];
223 char* UncSource = NULL;
224
225 LxtCheckResult(LxtFsGetFsInfo(Target, &FsInfo));
226 if (FsInfo.FsType == LxtFsTypeDrvFs)
227 {
228 if (Options == NULL)
229 {
230 Options = "case=off";
231 }
232
233 snprintf(ExpectedOptions, sizeof(ExpectedOptions), "rw,%s", Options);
234 snprintf(ExpectedCombinedOptions, sizeof(ExpectedCombinedOptions), "rw,noatime,%s", Options);
235
236 LxtCheckResult(MountCheckIsMount(Target, ParentId, Source, "drvfs", MountRoot, "rw,noatime", ExpectedOptions, ExpectedCombinedOptions, 0));
237 }
238 else if (FsInfo.FsType == LxtFsTypePlan9)
239 {
240 if (Options == NULL)
241 {
242 Temp[0] = '\0';
243 }
244 else
245 {
246 Temp[0] = ';';
247 strncpy(Temp + 1, Options, sizeof(Temp) - 1);
248 for (Index = 0; Index < strlen(Temp); Index += 1)
249 {
250 if (Temp[Index] == ',')
251 {
252 Temp[Index] = ';';
253 }
254 }
255 }
256
257 Length = strlen(Source);
258 if ((Length >= FS_UNC_PATH_PREFIX_LENGTH) && ((Source[0] == '/') || (Source[0] == '\\')) &&
259 ((Source[1] == '/') || (Source[1] == '\\')))
260 {
261
262 Length -= FS_UNC_PATH_PREFIX_LENGTH;
263 UncSource = malloc(Length + FS_PLAN9_UNC_PREFIX_LENGTH + 1);
264 if (UncSource == NULL)
265 {
266 LxtLogError("malloc");
267 Result = -1;
268 goto ErrorExit;
269 }
270
271 memcpy(UncSource, FS_PLAN9_UNC_PREFIX, FS_PLAN9_UNC_PREFIX_LENGTH);
272 memcpy(&UncSource[FS_PLAN9_UNC_PREFIX_LENGTH], &Source[FS_UNC_PATH_PREFIX_LENGTH], Length);
273
274 UncSource[Length + FS_PLAN9_UNC_PREFIX_LENGTH] = '\0';
275 Plan9Source = UncSource;
276 }
277 else
278 {
279 Plan9Source = Source;
280 }
281
282 if (FsInfo.Flags.VirtIo != 0)
283 {
284 Source = "drvfsa";
285 snprintf(
286 Plan9Options,
287 sizeof(Plan9Options),
288 "aname=drvfs;path=%s%s;symlinkroot=/mnt/,cache=0x5,access=client,msize=262144,trans=virtio",
289 Plan9Source,
290 Temp);
291 }
292 else
293 {
294 snprintf(
295 Plan9Options,
296 sizeof(Plan9Options),
297 "aname=drvfs;path=%s%s;symlinkroot=/mnt/,cache=0x5,access=client,msize=65536,trans=fd,rfd=*,wfd=*",
298 Plan9Source,
299 Temp);
300 }
301
302 //
303 // The combined options aren't checked for 9p because the placement of
304 // noatime by libmount is inconsistent.
305 //
306
307 snprintf(ExpectedOptions, sizeof(ExpectedOptions), "rw,%s", Plan9Options);
308 LxtCheckResult(MountCheckIsMount(Target, ParentId, Source, "9p", MountRoot, "rw,noatime", ExpectedOptions, NULL, 0));
309 }
310 else if (FsInfo.FsType == LxtFsTypeVirtioFs)
311 {
312 snprintf(ExpectedOptions, sizeof(ExpectedOptions), "rw");
313 LxtCheckResult(MountCheckIsMount(Target, ParentId, NULL, "virtiofs", MountRoot, "rw,noatime", ExpectedOptions, NULL, 0));
314 }
315
316 ErrorExit:
317 free(UncSource);
318 return Result;
319 }
320
321 int LxtFsCreateTestDir(char* Directory)
322
323 /*++
324
325 Description:
326
327 This routine creates a test directory, succeeding if it already exists.
328
329 Arguments:
330
331 Directory - Supplies the directory name.
332
333 Return Value:
334
335 Returns 0 on success, -1 on failure.
336
337 --*/
338
339 {
340
341 int Result;
342
343 Result = mkdir(Directory, 0777);
344 if ((Result < 0) && (errno != EEXIST))
345 {
346 LxtLogError("Failed to create directory %s", Directory);
347 goto ErrorExit;
348 }
349
350 Result = 0;
351
352 ErrorExit:
353 return Result;
354 }
355
356 int LxtFsDeleteCurrentWorkingDirectoryCommon(char* BaseDir, int Flags)
357
358 /*++
359
360 Description:
361
362 This routine tests the behavior if the current working directory is
363 unlinked.
364
365 Arguments:
366
367 BaseDir - Supplies the top directory to use for the test.
368
369 Flags - Supplies various flags.
370
371 Return Value:
372
373 Returns 0 on success, -1 on failure.
374
375 --*/
376
377 {
378
379 char DeleteTestDir[PATH_MAX];
380 char DeleteTestRenameFile[PATH_MAX];
381 int Fd;
382 char Path[PATH_MAX];
383 char* PointerResult;
384 int Result;
385
386 sprintf(DeleteTestDir, "%s/%s", BaseDir, FS_DELETE_TEST_DIR_NAME);
387 sprintf(DeleteTestRenameFile, "%s/%s", BaseDir, FS_DELETE_TEST_RENAME_FILE_NAME);
388
389 //
390 // Create the directory, change to it, and do a sanity check on the normal
391 // return values of these functions.
392 //
393
394 Fd = -1;
395 memset(Path, 0, sizeof(Path));
396 LxtCheckErrno(Fd = creat(DeleteTestRenameFile, 0666));
397 LxtCheckErrno(close(Fd));
398 LxtCheckErrnoZeroSuccess(mkdir(DeleteTestDir, 0777));
399 LxtCheckErrnoZeroSuccess(chdir(DeleteTestDir));
400 LxtCheckErrno(LxtGetcwd(Path, sizeof(Path)));
401 LxtCheckStringEqual(Path, DeleteTestDir);
402 memset(Path, 0, sizeof(Path));
403 LxtCheckErrno(readlink(FS_PROC_SELF_CWD, Path, sizeof(Path)));
404 LxtCheckStringEqual(Path, DeleteTestDir);
405
406 //
407 // Unlinking the directory with "." should fail.
408 //
409
410 LxtCheckErrnoFailure(rmdir("."), EINVAL);
411
412 //
413 // Unlink the directory.
414 //
415
416 LxtCheckErrnoZeroSuccess(rmdir(DeleteTestDir));
417
418 //
419 // Check the behavior.
420 //
421
422 LxtCheckResult(LxtFsDeleteCurrentWorkingDirectoryHelper(BaseDir, DeleteTestDir, Flags));
423
424 //
425 // Nothing should change if a new directory is created with the same name.
426 //
427
428 LxtCheckErrnoZeroSuccess(mkdir(DeleteTestDir, 0777));
429 LxtCheckResult(LxtFsDeleteCurrentWorkingDirectoryHelper(BaseDir, DeleteTestDir, Flags));
430 rmdir(DeleteTestDir);
431
432 //
433 // Opening the deleted directory should succeed.
434 //
435 // N.B. This currently doesn't work on Plan 9 or virtiofs.
436 //
437
438 if (g_LxtFsInfo.FsType != LxtFsTypePlan9 && g_LxtFsInfo.FsType != LxtFsTypeVirtioFs)
439 {
440 LxtCheckErrno(Fd = open(".", O_DIRECTORY | O_RDONLY));
441 LxtCheckResult(LxtFsDeleteOpenFileHelper(Fd, BaseDir, DeleteTestDir, Flags));
442 }
443
444 //
445 // Try to chdir to the parent.
446 //
447 // N.B. This currently doesn't work on virtiofs.
448 //
449
450 if (g_LxtFsInfo.FsType != LxtFsTypeVirtioFs)
451 {
452 LxtCheckErrnoZeroSuccess(chdir(".."));
453 LxtCheckErrno(LxtGetcwd(Path, sizeof(Path)));
454 LxtCheckStringEqual(Path, BaseDir);
455 memset(Path, 0, sizeof(Path));
456 LxtCheckErrno(readlink(FS_PROC_SELF_CWD, Path, sizeof(Path)));
457 LxtCheckStringEqual(Path, BaseDir);
458 }
459
460 //
461 // Try to chdir back to the deleted directory.
462 //
463 // N.B. This currently does not work on Plan 9 or virtiofs.
464 //
465
466 if (g_LxtFsInfo.FsType != LxtFsTypePlan9 && g_LxtFsInfo.FsType != LxtFsTypeVirtioFs)
467 {
468 LxtCheckErrnoZeroSuccess(fchdir(Fd));
469 LxtCheckResult(LxtFsDeleteCurrentWorkingDirectoryHelper(BaseDir, DeleteTestDir, Flags));
470 }
471
472 ErrorExit:
473 if (Fd >= 0)
474 {
475 close(Fd);
476 }
477
478 rmdir(DeleteTestDir);
479 unlink(DeleteTestRenameFile);
480
481 return Result;
482 }
483
484 int LxtFsDeleteCurrentWorkingDirectoryHelper(char* BaseDir, char* DeleteTestDir, int Flags)
485
486 /*++
487
488 Description:
489
490 This routine checks if a deleted working directory behaves as expected.
491
492 Arguments:
493
494 BaseDir - Supplies the top directory to use for the test.
495
496 DeleteTestDir - Supplies the path to the delete test root directory.
497
498 Flags - Supplies various flags.
499
500 Return Value:
501
502 Returns 0 on success, -1 on failure.
503
504 --*/
505
506 {
507
508 char DeleteTestDirDeleteSuffix[PATH_MAX];
509 char DeleteTestRenameFile[PATH_MAX];
510 char Path[PATH_MAX];
511 int ParentFd;
512 char* PointerResult;
513 int Result;
514
515 sprintf(DeleteTestDirDeleteSuffix, "%s%s", DeleteTestDir, FS_DELETE_LINK_SUFFIX);
516 sprintf(DeleteTestRenameFile, "%s/%s", BaseDir, FS_DELETE_TEST_RENAME_FILE_NAME);
517 ParentFd = -1;
518
519 //
520 // Check the result of getcwd and /proc/self/cwd
521 //
522
523 memset(Path, 0, sizeof(Path));
524 LxtCheckErrnoFailure(LxtGetcwd(Path, sizeof(Path)), ENOENT);
525 memset(Path, 0, sizeof(Path));
526 LxtCheckErrno(readlink(FS_PROC_SELF_CWD, Path, sizeof(Path)));
527 LxtCheckStringEqual(Path, DeleteTestDirDeleteSuffix);
528
529 //
530 // Creating a new item in the current working directory should fail.
531 //
532
533 LxtCheckErrnoFailure(open(FS_DELETE_TEST_CHILD, O_CREAT | O_WRONLY, 0777), ENOENT);
534
535 LxtCheckErrnoFailure(mkdir(FS_DELETE_TEST_CHILD, 0777), ENOENT);
536 LxtCheckErrnoFailure(link(BaseDir, FS_DELETE_TEST_CHILD), ENOENT);
537 LxtCheckErrnoFailure(symlink("/proc", FS_DELETE_TEST_CHILD), ENOENT);
538 LxtCheckErrnoFailure(rename(DeleteTestRenameFile, "./" FS_DELETE_TEST_CHILD), ENOENT);
539
540 if ((Flags & FS_DELETE_DRVFS) == 0)
541 {
542 LxtCheckErrnoFailure(mknod(FS_DELETE_TEST_CHILD, S_IFIFO | 0777, 0), ENOENT);
543 }
544
545 //
546 // Opening the parent should succeed.
547 //
548
549 LxtCheckErrno(ParentFd = open("..", O_DIRECTORY | O_RDONLY));
550 LxtCheckResult(LxtCheckFdPath(ParentFd, BaseDir));
551
552 ErrorExit:
553 if (ParentFd >= 0)
554 {
555 close(ParentFd);
556 }
557
558 return Result;
559 }
560
561 int LxtFsDeleteOpenFileCommon(char* BaseDir, int Flags)
562
563 /*++
564
565 Description:
566
567 This routine tests using unlink and rmdir on a file/directory that's open.
568
569 Arguments:
570
571 BaseDir - Supplies the top directory to use for the test.
572
573 Flags - Supplies various flags.
574
575 Return Value:
576
577 Returns 0 on success, -1 on failure.
578
579 --*/
580
581 {
582
583 int ChildFd;
584 char ChildPath[PATH_MAX];
585 char ChildPathDeleteSuffix[PATH_MAX];
586 char ChildPathSubpath[PATH_MAX];
587 char DeleteTestDir[PATH_MAX];
588 char DeleteTestDirAt[PATH_MAX];
589 char DeleteTestRenameFile[PATH_MAX];
590 int Fd;
591 char Path[PATH_MAX];
592 int ReopenFd;
593 int Result;
594 struct stat Stat;
595
596 sprintf(DeleteTestDir, "%s/%s", BaseDir, FS_DELETE_TEST_DIR_NAME);
597 sprintf(DeleteTestDirAt, "../%s", FS_DELETE_TEST_DIR_NAME);
598 sprintf(DeleteTestRenameFile, "%s/%s", BaseDir, FS_DELETE_TEST_RENAME_FILE_NAME);
599 sprintf(ChildPath, "%s/%s", DeleteTestDir, FS_DELETE_TEST_CHILD);
600 sprintf(ChildPathDeleteSuffix, "%s%s", ChildPath, FS_DELETE_LINK_SUFFIX);
601 Fd = -1;
602 ChildFd = -1;
603 ReopenFd = -1;
604 LxtCheckErrno(Fd = creat(DeleteTestRenameFile, 0666));
605 LxtCheckErrno(close(Fd));
606 LxtCheckErrnoZeroSuccess(mkdir(DeleteTestDir, 0777));
607 LxtCheckErrno(Fd = open(DeleteTestDir, O_DIRECTORY | O_RDONLY));
608
609 //
610 // It should be possible to create a child in the directory.
611 //
612
613 LxtCheckErrno(ChildFd = openat(Fd, FS_DELETE_TEST_CHILD, O_CREAT | O_WRONLY, 0777));
614
615 LxtCheckResult(LxtCheckFdPath(ChildFd, ChildPath));
616
617 //
618 // Unlink the file and check the path indicates it's deleted.
619 //
620
621 LxtCheckErrnoZeroSuccess(unlinkat(Fd, FS_DELETE_TEST_CHILD, 0));
622 LxtCheckResult(LxtCheckFdPath(ChildFd, ChildPathDeleteSuffix));
623
624 //
625 // Reopening through the file descriptor should work.
626 //
627 // N.B Reopening currently doesn't work on Plan 9 or virtiofs.
628 //
629
630 if (g_LxtFsInfo.FsType != LxtFsTypePlan9 && g_LxtFsInfo.FsType != LxtFsTypeVirtioFs)
631 {
632 sprintf(Path, FS_FD_PATH_FORMAT, ChildFd);
633
634 LxtCheckErrno(ReopenFd = open(Path, O_RDONLY));
635 LxtCheckResult(LxtCheckFdPath(ReopenFd, ChildPathDeleteSuffix));
636
637 //
638 // Check that fstat on the deleted file returns 0 link count.
639 //
640 // N.B. Plan 9 will return ENOENT instead for all the below.
641 //
642
643 LxtCheckErrnoZeroSuccess(fstat(ChildFd, &Stat));
644 LxtCheckEqual(Stat.st_nlink, 0, "%d");
645
646 //
647 // The target is a file so subpaths don't work.
648 //
649
650 sprintf(ChildPathSubpath, FS_CHILD_PATH_FORMAT, Path, ".");
651 LxtCheckErrnoFailure(open(ChildPathSubpath, O_RDONLY), ENOTDIR);
652 sprintf(ChildPathSubpath, FS_CHILD_PATH_FORMAT, Path, "..");
653 LxtCheckErrnoFailure(open(ChildPathSubpath, O_RDONLY), ENOTDIR);
654 sprintf(ChildPathSubpath, FS_CHILD_PATH_FORMAT, Path, "foo");
655 LxtCheckErrnoFailure(open(ChildPathSubpath, O_RDONLY), ENOTDIR);
656 LxtCheckErrnoZeroSuccess(close(ReopenFd));
657 ReopenFd = -1;
658 }
659
660 LxtCheckErrnoZeroSuccess(close(ChildFd));
661 ChildFd = -1;
662
663 //
664 // Unlinking the directory through "." should fail.
665 //
666
667 LxtCheckErrnoFailure(unlinkat(Fd, ".", AT_REMOVEDIR), EINVAL);
668
669 //
670 // Unlink the directory.
671 //
672
673 LxtCheckErrnoZeroSuccess(rmdir(DeleteTestDir));
674
675 //
676 // Trying to re-open the deleted directory should fail.
677 //
678
679 LxtCheckErrnoFailure(ChildFd = openat(Fd, DeleteTestDirAt, O_DIRECTORY | O_RDONLY), ENOENT);
680
681 //
682 // Check behavior is correct after deleting.
683 //
684
685 LxtCheckResult(LxtFsDeleteOpenFileHelper(Fd, BaseDir, DeleteTestDir, Flags));
686
687 //
688 // Even if a directory with the same name is created.
689 //
690
691 LxtCheckErrnoZeroSuccess(mkdir(DeleteTestDir, 0777));
692 LxtCheckResult(LxtFsDeleteOpenFileHelper(Fd, BaseDir, DeleteTestDir, Flags));
693
694 ErrorExit:
695 if (ReopenFd >= 0)
696 {
697 close(ReopenFd);
698 }
699
700 if (ChildFd >= 0)
701 {
702 close(ChildFd);
703 }
704
705 if (Fd >= 0)
706 {
707 close(Fd);
708 }
709
710 unlink(DeleteTestRenameFile);
711 unlink(ChildPath);
712 rmdir(DeleteTestDir);
713
714 return Result;
715 }
716
717 int LxtFsDeleteOpenFileHelper(int Fd, char* BaseDir, char* DeleteTestDir, int Flags)
718
719 /*++
720
721 Description:
722
723 This routine checks if a file descriptor pointing to a deleted directory
724 behaves as expected.
725
726 Arguments:
727
728 Fd - Supplies the file descriptor.
729
730 BaseDir - Supplies the top directory to use for the test.
731
732 DeleteTestDir - Supplies the path to the delete test root directory.
733
734 Flags - Supplies various flags.
735
736 Return Value:
737
738 Returns 0 on success, -1 on failure.
739
740 --*/
741
742 {
743
744 char ChildPathSubpath[PATH_MAX];
745 char DeleteTestDirDeleteSuffix[PATH_MAX];
746 char DeleteTestRenameFile[PATH_MAX];
747 int ParentFd;
748 char Path[PATH_MAX];
749 int ReopenFd;
750 int Result;
751
752 sprintf(DeleteTestDirDeleteSuffix, "%s%s", DeleteTestDir, FS_DELETE_LINK_SUFFIX);
753 sprintf(DeleteTestRenameFile, "%s/%s", BaseDir, FS_DELETE_TEST_RENAME_FILE_NAME);
754 ParentFd = -1;
755 ReopenFd = -1;
756
757 //
758 // Check the path indicates it's deleted.
759 //
760
761 LxtCheckResult(LxtCheckFdPath(Fd, DeleteTestDirDeleteSuffix));
762
763 //
764 // Check that creating new items fails as expected.
765 //
766
767 LxtCheckErrnoFailure(openat(Fd, FS_DELETE_TEST_CHILD, O_CREAT | O_WRONLY, 0666), ENOENT);
768
769 LxtCheckErrnoFailure(mkdirat(Fd, FS_DELETE_TEST_CHILD, 0777), ENOENT);
770 LxtCheckErrnoFailure(linkat(AT_FDCWD, BaseDir, Fd, FS_DELETE_TEST_CHILD, 0), ENOENT);
771
772 LxtCheckErrnoFailure(symlinkat("/proc", Fd, FS_DELETE_TEST_CHILD), ENOENT);
773 LxtCheckErrnoFailure(renameat(AT_FDCWD, DeleteTestRenameFile, Fd, FS_DELETE_TEST_CHILD), ENOENT);
774
775 //
776 // Drvfs doesn't support mknod.
777 //
778
779 if ((Flags & FS_DELETE_DRVFS) == 0)
780 {
781 LxtCheckErrnoFailure(mknodat(Fd, FS_DELETE_TEST_CHILD, S_IFIFO | 0777, 0), ENOENT);
782 }
783
784 //
785 // Navigating to the parent from the deleted directory should succeed.
786 //
787
788 LxtCheckErrno(ParentFd = openat(Fd, "..", O_DIRECTORY | O_RDONLY));
789 LxtCheckResult(LxtCheckFdPath(ParentFd, BaseDir));
790
791 //
792 // Reopening through the file descriptor should work.
793 //
794
795 sprintf(ChildPathSubpath, FS_CHILD_PATH_FORMAT, Path, "foo");
796 LxtCheckErrnoFailure(open(ChildPathSubpath, O_RDONLY), ENOENT);
797
798 ErrorExit:
799 if (ParentFd >= 0)
800 {
801 close(ParentFd);
802 }
803
804 if (ReopenFd >= 0)
805 {
806 close(ReopenFd);
807 }
808
809 return Result;
810 }
811
812 int LxtFsDeleteLoopCommon(const char* BaseDir)
813
814 /*++
815
816 Description:
817
818 This routine tests deleting files in a loop with multiple getdents calls.
819
820 Arguments:
821
822 BaseDir - Supplies the base directory.
823
824 Return Value:
825
826 Returns 0 on success, -1 on failure.
827
828 --*/
829
830 {
831
832 char Buffer[512];
833 int BytesRead;
834 int Calls;
835 int Count;
836 struct dirent64* Entry;
837 int Fd;
838 const int FileCount = 500;
839 int Index;
840 char Path[PATH_MAX];
841 int Result;
842
843 Fd = -1;
844
845 //
846 // Create the directory and the test files.
847 //
848
849 LxtCheckErrnoZeroSuccess(mkdir(BaseDir, 0777));
850 for (Index = 0; Index < FileCount; Index += 1)
851 {
852 snprintf(Path, sizeof(Path), "%s/file%d", BaseDir, Index);
853 LxtCheckErrno(Fd = creat(Path, 0666));
854 LxtCheckClose(Fd);
855 }
856
857 //
858 // List the directory, and delete the files in between calls.
859 //
860
861 Calls = 0;
862 Count = 0;
863 LxtCheckErrno(Fd = open(BaseDir, O_RDONLY | O_DIRECTORY));
864 LxtCheckErrno(BytesRead = LxtGetdents64(Fd, Buffer, sizeof(Buffer)));
865
866 while (BytesRead != 0)
867 {
868 Calls += 1;
869 Index = 0;
870 while (Index < BytesRead)
871 {
872 Entry = (struct dirent64*)&Buffer[Index];
873 if ((strcmp(Entry->d_name, ".") != 0) && (strcmp(Entry->d_name, "..") != 0))
874 {
875
876 snprintf(Path, sizeof(Path), "%s/%s", BaseDir, Entry->d_name);
877 LxtCheckErrnoZeroSuccess(unlink(Path));
878 Count += 1;
879 }
880
881 Index += Entry->d_reclen;
882 }
883
884 LxtCheckErrno(BytesRead = LxtGetdents64(Fd, Buffer, sizeof(Buffer)));
885 }
886
887 //
888 // Make sure all files were deleted, and that more than one getdents call
889 // was used (otherwise the test is meaningless).
890 //
891
892 LxtCheckEqual(Count, FileCount, "%d");
893 LxtCheckGreater(Calls, 1, "%d");
894 LxtLogInfo("Calls: %d", Calls);
895 LxtCheckClose(Fd);
896
897 //
898 // The directory is now empty so it can be removed.
899 //
900
901 LxtCheckErrnoZeroSuccess(rmdir(BaseDir));
902
903 ErrorExit:
904 if (Fd >= 0)
905 {
906 close(Fd);
907 }
908
909 rmdir(BaseDir);
910 return Result;
911 }
912
913 int LxtFsGetDentsAlignmentCommon(const char* BaseDir, int Flags)
914
915 /*++
916
917 Description:
918
919 This routine tests the alignment and padding of the entries returned by
920 getdents.
921
922 Arguments:
923
924 BaseDir - Supplies the directory to use.
925
926 Flags - Supplies the flags.
927
928 Return Value:
929
930 Returns 0 on success, -1 on failure.
931
932 --*/
933
934 {
935
936 char Buffer[4096];
937 int Count;
938 struct linux_dirent* Entry;
939 struct dirent64* Entry64;
940 int Fd;
941 int Fd2;
942 int Index;
943 int Length;
944 const int MaxChildLength = 16;
945 char Name[MaxChildLength + 1];
946 int Offset;
947 int Result;
948 int Size;
949
950 Fd = -1;
951 Fd2 = -1;
952
953 LxtCheckErrnoZeroSuccess(mkdir(BaseDir, 0777));
954 LxtCheckErrno(Fd = open(BaseDir, O_RDONLY | O_DIRECTORY));
955
956 //
957 // No need to create entries with length 1 and 2 since the . and .. entries
958 // already take care of that.
959 //
960
961 for (Length = 3; Length <= MaxChildLength; Length += 1)
962 {
963 for (Index = 0; Index < Length; Index += 1)
964 {
965 Name[Index] = 'a' + Index;
966 }
967
968 Name[Length] = '\0';
969 LxtCheckErrnoZeroSuccess(mkdirat(Fd, Name, 0777));
970 }
971
972 if ((Flags & FS_TEST_GETDENTS64) == 0)
973 {
974 #ifdef __NR_getdents
975 LxtCheckErrno(Size = LxtGetdents(Fd, Buffer, sizeof(Buffer)));
976 #else
977 LxtLogError("Test not supported on this architecture.");
978 Result = LXT_RESULT_FAILURE;
979 goto ErrorExit;
980 #endif
981 }
982 else
983 {
984 LxtCheckErrno(Size = LxtGetdents64(Fd, Buffer, sizeof(Buffer)));
985 }
986
987 LxtCheckGreater(Size, 0, "%d");
988 LxtCheckEqual(Size % sizeof(long), 0, "%d");
989 Offset = 0;
990 Count = 0;
991 while (Offset < Size)
992 {
993
994 //
995 // Verify the record length of each entry.
996 //
997 // N.B. These sizes are precalculated for amd64; they may need to be
998 // adjusted on different architectures.
999 //
1000
1001 if ((Flags & FS_TEST_GETDENTS64) == 0)
1002 {
1003 Entry = (struct linux_dirent*)&Buffer[Offset];
1004 Length = strlen(Entry->d_name);
1005 LxtLogInfo("getdents %s: %d", Entry->d_name, Entry->d_reclen);
1006 if (Length <= 4)
1007 {
1008 LxtCheckEqual(Entry->d_reclen, 24, "%d");
1009 }
1010 else if (Length <= 12)
1011 {
1012 LxtCheckEqual(Entry->d_reclen, 32, "%d");
1013 }
1014 else
1015 {
1016 LxtCheckEqual(Entry->d_reclen, 40, "%d");
1017 }
1018
1019 //
1020 // Make sure the file type is in the last entry.
1021 //
1022
1023 LxtCheckEqual(Buffer[Offset + Entry->d_reclen - 1], DT_DIR, "%d");
1024 Offset += Entry->d_reclen;
1025 }
1026 else
1027 {
1028 Entry64 = (struct dirent64*)&Buffer[Offset];
1029 Length = strlen(Entry64->d_name);
1030 LxtLogInfo("getdents64 %s: %d", Entry64->d_name, Entry64->d_reclen);
1031 if (Length <= 4)
1032 {
1033 LxtCheckEqual(Entry64->d_reclen, 24, "%d");
1034 }
1035 else if (Length <= 12)
1036 {
1037 LxtCheckEqual(Entry64->d_reclen, 32, "%d");
1038 }
1039 else
1040 {
1041 LxtCheckEqual(Entry64->d_reclen, 40, "%d");
1042 }
1043
1044 LxtCheckEqual(Entry64->d_type, DT_DIR, "%d");
1045 Offset += Entry64->d_reclen;
1046 }
1047
1048 Count += 1;
1049 }
1050
1051 LxtCheckEqual(Count, MaxChildLength, "%d");
1052
1053 //
1054 // Open a child for the buffer size tests; on real Linux, the entries are
1055 // not in any specific order so the minimum entry size may not fit the
1056 // actual first item returned. The child directory is empty so the entries
1057 // will fit in the minimum size.
1058 //
1059
1060 LxtCheckErrno(Fd2 = openat(Fd, "abc", O_RDONLY | O_DIRECTORY));
1061 if ((Flags & FS_TEST_GETDENTS64) == 0)
1062 {
1063
1064 //
1065 // getdents variation (and not getdents64) won't run when
1066 // __NR_getdents is not defined. So, commenting out the
1067 // below is just for compilation safety.
1068 //
1069
1070 #ifdef __NR_getdents
1071 LxtCheckErrnoFailure(LxtGetdents(Fd2, Buffer, 23), EINVAL);
1072 LxtCheckErrno(Size = LxtGetdents(Fd2, Buffer, 24));
1073 LxtCheckEqual(Size, 24, "%d");
1074 #endif
1075 }
1076 else
1077 {
1078 LxtCheckErrnoFailure(LxtGetdents64(Fd2, Buffer, 23), EINVAL);
1079 LxtCheckErrno(Size = LxtGetdents64(Fd2, Buffer, 24));
1080 LxtCheckEqual(Size, 24, "%d");
1081 }
1082
1083 ErrorExit:
1084 if (Fd2 >= 0)
1085 {
1086 close(Fd2);
1087 }
1088
1089 if (Fd >= 0)
1090 {
1091 for (Length = 3; Length <= MaxChildLength; Length += 1)
1092 {
1093 for (Index = 0; Index < Length; Index += 1)
1094 {
1095 Name[Index] = 'a' + Index;
1096 }
1097
1098 Name[Length] = '\0';
1099 unlinkat(Fd, Name, AT_REMOVEDIR);
1100 }
1101
1102 close(Fd);
1103 }
1104
1105 rmdir(BaseDir);
1106 return Result;
1107 }
1108
1109 int LxtFsGetFsInfo(const char* Path, PLXT_FS_INFO Info)
1110
1111 /*++
1112
1113 Description:
1114
1115 This routine gets file system information.
1116
1117 Arguments:
1118
1119 Path - Supplies the test root path.
1120
1121 Info - Supplies a buffer which receives file system information.
1122
1123 Return Value:
1124
1125 Returns 0 on success, -1 on failure.
1126
1127 --*/
1128
1129 {
1130
1131 char FsType[10];
1132 LXT_FS_INFO LocalInfo;
1133 char Options[1024];
1134 int Result;
1135
1136 memset(&LocalInfo, 0, sizeof(LocalInfo));
1137
1138 LxtCheckResult(MountGetFileSystem(Path, FsType, sizeof(FsType), Options, sizeof(Options)));
1139
1140 if (strcmp(FsType, FS_DRVFS_NAME) == 0)
1141 {
1142 LocalInfo.FsType = LxtFsTypeDrvFs;
1143 LocalInfo.Flags.DrvFsBehavior = 1;
1144 }
1145 else if (strcmp(FsType, FS_WSLFS_NAME) == 0)
1146 {
1147 LocalInfo.FsType = LxtFsTypeWslFs;
1148 LocalInfo.Flags.DrvFsBehavior = 1;
1149 LocalInfo.Flags.Cached = 1;
1150 }
1151 else if (strcmp(FsType, FS_9P_NAME) == 0)
1152 {
1153 LocalInfo.FsType = LxtFsTypePlan9;
1154 LocalInfo.Flags.DrvFsBehavior = 1;
1155 if (strstr(Options, "loose") != NULL)
1156 {
1157 LocalInfo.Flags.Cached = 1;
1158 }
1159
1160 if (strstr(Options, "trans=virtio") != NULL)
1161 {
1162 LocalInfo.Flags.VirtIo = 1;
1163 }
1164 }
1165 else if (strcmp(FsType, FS_VIRTIOFS_NAME) == 0)
1166 {
1167 LocalInfo.FsType = LxtFsTypeVirtioFs;
1168 LocalInfo.Flags.DrvFsBehavior = 1;
1169 if (strstr(Options, "dax") != NULL)
1170 {
1171 LocalInfo.Flags.Dax = 1;
1172 }
1173 }
1174 else
1175 {
1176 LocalInfo.FsType = LxtFsTypeLxFs;
1177 }
1178
1179 *Info = LocalInfo;
1180 Result = LXT_RESULT_SUCCESS;
1181
1182 ErrorExit:
1183 return Result;
1184 }
1185
1186 int LxtFsInotifyEpollCommon(char* BaseDir)
1187
1188 /*++
1189
1190 Description:
1191
1192 This routine contains common inotify epoll tests that are shared between
1193 lxfs and drvfs tests.
1194
1195 Arguments:
1196
1197 BaseDir - Supplies the base directory for the test.
1198
1199 Return Value:
1200
1201 Returns 0 on success, -1 on failure.
1202
1203 --*/
1204
1205 {
1206
1207 int Ed;
1208 int Fd;
1209 int Id;
1210 int Wd;
1211 int Result;
1212 char Buf[10];
1213 char InotifyBuf[500];
1214 struct inotify_event* Events[INOTIFY_TEST_EVENTS_BUF_SIZE];
1215 int NumEvents;
1216 struct epoll_event EpollControlEvent;
1217 struct epoll_event EpollWaitEvent[2];
1218 char TestFile1[PATH_MAX];
1219 char TestFile2[PATH_MAX];
1220 char TestFile1Hlink[PATH_MAX];
1221 char TestFile1Slink[PATH_MAX];
1222
1223 //
1224 // Initialize and also do cleanup if the files have not been removed.
1225 //
1226
1227 sprintf(TestFile1, "%s%s", BaseDir, INOTIFY_TEST_FILE1_NAME_ONLY);
1228 sprintf(TestFile2, "%s%s", BaseDir, INOTIFY_TEST_FILE2_NAME_ONLY);
1229 sprintf(TestFile1Hlink, "%s%s", BaseDir, INOTIFY_TEST_FILE1_HLINK_NAME_ONLY);
1230 sprintf(TestFile1Slink, "%s%s", BaseDir, INOTIFY_TEST_FILE1_SLINK_NAME_ONLY);
1231 unlink(TestFile1);
1232 unlink(TestFile2);
1233 unlink(TestFile1Hlink);
1234 unlink(TestFile1Slink);
1235 rmdir(BaseDir);
1236 LxtCheckErrnoZeroSuccess(mkdir(BaseDir, 0777));
1237 LxtCheckErrno(Fd = creat(TestFile1, 0777));
1238 LxtCheckErrnoZeroSuccess(close(Fd));
1239
1240 LxtCheckErrno(Id = inotify_init());
1241 LxtCheckErrno(Result = inotify_add_watch(Id, TestFile1, IN_ALL_EVENTS));
1242
1243 //
1244 // Create an epoll container and add the inotify file descriptor to it.
1245 //
1246
1247 LxtCheckErrno(Ed = epoll_create(1));
1248 EpollControlEvent.events = EPOLLIN;
1249 EpollControlEvent.data.fd = Id;
1250 Result = epoll_ctl(Ed, EPOLL_CTL_ADD, Id, &EpollControlEvent);
1251 LxtCheckErrno(Result);
1252
1253 //
1254 // Wait for data to be available with a timeout. This should timeout since
1255 // there is no data.
1256 //
1257
1258 Result = epoll_wait(Ed, EpollWaitEvent, 2, 80);
1259 LxtCheckEqual(Result, 0, "%d");
1260
1261 //
1262 // Generate some inotify events.
1263 //
1264
1265 LxtCheckErrno(Fd = open(TestFile1, O_WRONLY));
1266 LxtCheckErrno(Result = write(Fd, Buf, 10));
1267 LxtCheckEqual(Result, 10, "%d");
1268 LxtCheckErrnoZeroSuccess(close(Fd));
1269
1270 //
1271 // Now epoll should return 1 ready file descriptor.
1272 //
1273
1274 Result = epoll_wait(Ed, EpollWaitEvent, 2, 1000);
1275 LxtCheckEqual(Result, 1, "%d");
1276
1277 //
1278 // Drain the inotify events.
1279 //
1280
1281 usleep(1000 * 80);
1282 LxtCheckErrno(LxtFsInotifyReadAndProcess(Id, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
1283
1284 LxtCheckTrue(NumEvents > 0);
1285
1286 //
1287 // Epoll should timeout again, since there are no events to be read.
1288 //
1289
1290 Result = epoll_wait(Ed, EpollWaitEvent, 2, 80);
1291 LxtCheckEqual(Result, 0, "%d");
1292
1293 Result = LXT_RESULT_SUCCESS;
1294
1295 ErrorExit:
1296 close(Id);
1297 close(Ed);
1298 unlink(TestFile1);
1299 rmdir(BaseDir);
1300 return Result;
1301 }
1302
1303 int LxtFsInotifyPosixUnlinkRenameCommon(char* BaseDir)
1304
1305 /*++
1306
1307 Description:
1308
1309 This routine contains common inotify POSIX unlink/rename tests that are
1310 shared between lxfs and drvfs tests.
1311
1312 Arguments:
1313
1314 BaseDir - Supplies the base directory for the test.
1315
1316 Return Value:
1317
1318 Returns 0 on success, -1 on failure.
1319
1320 --*/
1321
1322 {
1323
1324 int Fd;
1325 int Id;
1326 int Result;
1327 char TestFile1[PATH_MAX];
1328 char TestFile2[PATH_MAX];
1329 char TestFile3[PATH_MAX];
1330
1331 //
1332 // Initialize and also do cleanup if the files have not been removed.
1333 //
1334
1335 sprintf(TestFile1, "%s%s", BaseDir, INOTIFY_TEST_FILE1_NAME_ONLY);
1336 sprintf(TestFile2, "%s%s", BaseDir, INOTIFY_TEST_FILE2_NAME_ONLY);
1337 sprintf(TestFile3, "%s%s", BaseDir, INOTIFY_TEST_FILE3_NAME_ONLY);
1338 unlink(TestFile1);
1339 unlink(TestFile2);
1340 unlink(TestFile3);
1341 rmdir(BaseDir);
1342 LxtCheckErrnoZeroSuccess(mkdir(BaseDir, 0777));
1343 LxtCheckErrno(Fd = creat(TestFile1, 0777));
1344 LxtCheckErrnoZeroSuccess(close(Fd));
1345 LxtCheckErrno(Fd = creat(TestFile2, 0777));
1346 LxtCheckErrnoZeroSuccess(close(Fd));
1347 LxtCheckErrno(Fd = creat(TestFile3, 0777));
1348 LxtCheckErrnoZeroSuccess(close(Fd));
1349
1350 //
1351 // Setup inotify.
1352 //
1353
1354 LxtCheckErrno(Id = inotify_init());
1355 LxtCheckErrno(Result = inotify_add_watch(Id, TestFile1, IN_ALL_EVENTS));
1356 LxtCheckErrno(Result = inotify_add_watch(Id, TestFile2, IN_ALL_EVENTS));
1357 LxtCheckErrno(Result = inotify_add_watch(Id, TestFile3, IN_ALL_EVENTS));
1358
1359 //
1360 // Test that POSIX unlinking a file watched by inotify succeeds. Verify that
1361 // a new file with the same name can be created.
1362 //
1363
1364 LxtCheckErrnoZeroSuccess(unlink(TestFile1));
1365 LxtCheckErrnoFailure(Fd = open(TestFile1, O_RDONLY), ENOENT);
1366 LxtCheckErrno(Fd = creat(TestFile1, 0777));
1367 LxtCheckErrnoZeroSuccess(close(Fd));
1368
1369 //
1370 // Test that renaming a file with overwrite succeeds when both files are
1371 // being watched by inotify.
1372 //
1373
1374 LxtCheckErrnoZeroSuccess(rename(TestFile2, TestFile3));
1375 LxtCheckErrnoFailure(Fd = open(TestFile2, O_RDONLY), ENOENT);
1376 LxtCheckErrno(Fd = creat(TestFile2, 0777));
1377 LxtCheckErrnoZeroSuccess(close(Fd));
1378 LxtCheckErrnoFailure(Fd = open(TestFile3, O_CREAT | O_EXCL), EEXIST);
1379 LxtCheckErrno(Fd = open(TestFile3, O_RDONLY));
1380 LxtCheckErrnoZeroSuccess(close(Fd));
1381
1382 Result = LXT_RESULT_SUCCESS;
1383
1384 ErrorExit:
1385 close(Id);
1386 close(Fd);
1387 unlink(TestFile1);
1388 unlink(TestFile2);
1389 unlink(TestFile3);
1390 rmdir(BaseDir);
1391 return Result;
1392 }
1393
1394 int LxtFsInotifyReadAndProcess(int Id, char* ReadBuf, int ReadBufSize, struct inotify_event** Events, int NumEventsIn, int* NumEventsOut, int IgnoreAttribModify)
1395
1396 /*++
1397
1398 Description:
1399
1400 This routine reads from the supplied inotify fd and returns a list
1401 of pointers to all the inotify events read.
1402
1403 Arguments:
1404
1405 Id - Inotify file descriptor.
1406
1407 ReadBuf - Buffer to read the inotify events into.
1408
1409 ReadBufSize - Size of ReadBuf in bytes.
1410
1411 Events - An array of pointers to events to fill in.
1412
1413 NumEventsIn - Max number of event pointers that Events can hold.
1414
1415 NumEventsOut - Number of event pointers filled into Events.
1416
1417 IgnoreAttribModify - Whether to ignore IN_ATTRIB and IN_MODIFY for
1418 directories (used for DrvFs only).
1419
1420 Return Value:
1421
1422 Returns the number of bytes read, -1 on failure.
1423
1424 --*/
1425
1426 {
1427
1428 char* Ptr;
1429 struct inotify_event* Event;
1430 int Result;
1431 int NumEvents;
1432
1433 NumEvents = 0;
1434 Result = read(Id, ReadBuf, ReadBufSize);
1435 if (Result < 0)
1436 {
1437 goto ErrorExit;
1438 }
1439
1440 for (Ptr = ReadBuf; Ptr < ReadBuf + Result; Ptr += sizeof(struct inotify_event) + Event->len)
1441 {
1442
1443 if (NumEvents >= NumEventsIn)
1444 {
1445 Result = -1;
1446 goto ErrorExit;
1447 }
1448
1449 Event = (struct inotify_event*)Ptr;
1450
1451 //
1452 // Ignore IN_ATTRIB and IN_MODIFY for DrvFs directories, since Windows
1453 // generates lots of irrelevant such notifications for DrvFs directories.
1454 //
1455
1456 if ((IgnoreAttribModify != FALSE) && ((Event->mask & IN_ISDIR) != 0) && ((Event->mask & (IN_ATTRIB | IN_MODIFY)) != 0))
1457 {
1458
1459 continue;
1460 }
1461
1462 Events[NumEvents] = Event;
1463 NumEvents += 1;
1464 }
1465
1466 ErrorExit:
1467 *NumEventsOut = NumEvents;
1468 return Result;
1469 }
1470
1471 int LxtFsInotifyUnmountBindCommon(char* BaseDir)
1472
1473 /*++
1474
1475 Description:
1476
1477 This routine contains common inotify unmount tests that are shared between
1478 lxfs and drvfs.
1479
1480 Arguments:
1481
1482 BaseDir - Supplies the base directory for the test.
1483
1484 Return Value:
1485
1486 Returns 0 on success, -1 on failure.
1487
1488 --*/
1489
1490 {
1491
1492 int Fd;
1493 int Id1;
1494 int Wd[10];
1495 char Buf[10];
1496 char InotifyBuf[500];
1497 struct inotify_event* Events[INOTIFY_TEST_EVENTS_BUF_SIZE];
1498 int NumEvents;
1499 int Bytes;
1500 int Result;
1501 char TestFile1[PATH_MAX];
1502 char TestFile2[PATH_MAX];
1503 char TestFile1Hlink[PATH_MAX];
1504 char TestFile1Slink[PATH_MAX];
1505 char TestDir1[PATH_MAX];
1506 char TestDir2[PATH_MAX];
1507 char TestDir11[PATH_MAX];
1508 char TestFile111[PATH_MAX];
1509
1510 //
1511 // Initialize and also do cleanup if the files have not been removed.
1512 //
1513
1514 sprintf(TestFile1, "%s%s", BaseDir, INOTIFY_TEST_FILE1_NAME_ONLY);
1515 sprintf(TestFile2, "%s%s", BaseDir, INOTIFY_TEST_FILE2_NAME_ONLY);
1516 sprintf(TestFile1Hlink, "%s%s", BaseDir, INOTIFY_TEST_FILE1_HLINK_NAME_ONLY);
1517 sprintf(TestFile1Slink, "%s%s", BaseDir, INOTIFY_TEST_FILE1_SLINK_NAME_ONLY);
1518 sprintf(TestDir1, "%s%s", BaseDir, "bind_mount_tmp/");
1519 sprintf(TestDir2, "%s%s", BaseDir, "bind_mount_tmp_2/");
1520 sprintf(TestDir11, "%s%s", TestDir1, "subdir11/");
1521 sprintf(TestFile111, "%s%s", TestDir11, "file111");
1522 unlink(TestFile1);
1523 unlink(TestFile2);
1524 unlink(TestFile1Hlink);
1525 unlink(TestFile1Slink);
1526 rmdir(TestDir11);
1527 umount(TestDir2);
1528 rmdir(TestDir2);
1529 umount(TestDir1);
1530 rmdir(TestDir1);
1531 rmdir(BaseDir);
1532
1533 LxtCheckErrnoZeroSuccess(mkdir(BaseDir, 0777));
1534 LxtCheckErrno(Fd = creat(TestFile1, 0777));
1535 LxtCheckErrnoZeroSuccess(close(Fd));
1536
1537 //
1538 // Create a tmpfs (TestDir1) and create some files inside it.
1539 //
1540
1541 LxtCheckErrnoZeroSuccess(mkdir(TestDir1, 0777));
1542 LxtCheckErrnoZeroSuccess(mount("tmpfs", TestDir1, "tmpfs", 0, NULL));
1543 LxtCheckErrnoZeroSuccess(mkdir(TestDir11, 0777));
1544 LxtCheckErrno(Fd = creat(TestFile111, 0777));
1545 LxtCheckErrnoZeroSuccess(close(Fd));
1546
1547 //
1548 // Create a bind mount (TestDir2) to the tmpfs (TestDir1).
1549 //
1550
1551 LxtCheckErrnoZeroSuccess(mkdir(TestDir2, 0777));
1552 LxtCheckErrnoZeroSuccess(mount(TestDir1, TestDir2, NULL, MS_BIND, NULL));
1553
1554 //
1555 // Setup inotify and verify. Note that TestDir1 and TestDir2 point to the
1556 // same inode (directory).
1557 //
1558
1559 LxtCheckErrno(Id1 = inotify_init1(IN_NONBLOCK));
1560
1561 LxtCheckErrno(
1562 Wd[0] = // wd: 1
1563 inotify_add_watch(Id1, TestDir1, IN_ALL_EVENTS));
1564
1565 LxtCheckErrno(
1566 Wd[1] = // wd: 2
1567 inotify_add_watch(Id1, TestDir11, IN_ALL_EVENTS));
1568
1569 LxtCheckErrno(
1570 Wd[2] = // wd: 3
1571 inotify_add_watch(Id1, TestFile111, IN_ALL_EVENTS));
1572
1573 LxtCheckErrno(
1574 Wd[3] = // wd: 1
1575 inotify_add_watch(Id1, TestDir2, IN_ALL_EVENTS));
1576
1577 LxtCheckEqual(Wd[0], 1, "%d");
1578 LxtCheckEqual(Wd[1], 2, "%d");
1579 LxtCheckEqual(Wd[2], 3, "%d");
1580 LxtCheckEqual(Wd[0], Wd[3], "%d");
1581
1582 //
1583 // Umount TestDir1. Verify that nothing happens in inotify since the inodes
1584 // are not really unmounted (TestDir2 is still mounted).
1585 //
1586
1587 LxtCheckErrnoZeroSuccess(umount(TestDir1));
1588
1589 LxtCheckErrnoFailure(
1590 LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE), EAGAIN);
1591
1592 LxtCheckEqual(NumEvents, 0, "%d");
1593
1594 //
1595 // Unmount TestDir2. Now, each file and directory inside TestDir2 should
1596 // generate 2 inotify events (IN_UNMOUNT, then IN_IGNORED).
1597 //
1598
1599 LxtCheckErrnoZeroSuccess(umount(TestDir2));
1600
1601 LxtCheckErrno(LxtFsInotifyReadAndProcess(Id1, InotifyBuf, sizeof(InotifyBuf), Events, INOTIFY_TEST_EVENTS_BUF_SIZE, &NumEvents, FALSE));
1602
1603 LxtCheckEqual(NumEvents, 6, "%d");
1604 LxtCheckEqual(Events[0]->mask, IN_UNMOUNT, "%d");
1605 LxtCheckEqual(Events[1]->mask, IN_IGNORED, "%d");
1606
1607 //
1608 // In Linux kernel 5.10 the IN_ISDIR flag is also returned.
1609 // Ignore the presence of this flag so this test can be run on multiple
1610 // versions of the kernel.
1611 //
1612
1613 Events[2]->mask &= ~IN_ISDIR;
1614 Events[4]->mask &= ~IN_ISDIR;
1615 LxtCheckEqual(Events[2]->mask, IN_UNMOUNT, "%d");
1616 LxtCheckEqual(Events[3]->mask, IN_IGNORED, "%d");
1617 LxtCheckEqual(Events[4]->mask, IN_UNMOUNT, "%d");
1618 LxtCheckEqual(Events[5]->mask, IN_IGNORED, "%d");
1619 LxtCheckEqual(Events[0]->wd, Events[1]->wd, "%d");
1620 LxtCheckEqual(Events[2]->wd, Events[3]->wd, "%d");
1621 LxtCheckEqual(Events[4]->wd, Events[5]->wd, "%d");
1622 LxtCheckNotEqual(Events[0]->wd, Events[2]->wd, "%d");
1623 LxtCheckNotEqual(Events[2]->wd, Events[4]->wd, "%d");
1624
1625 Result = LXT_RESULT_SUCCESS;
1626
1627 ErrorExit:
1628 close(Id1);
1629 close(Fd);
1630 unlink(TestFile1);
1631 rmdir(TestDir11);
1632 umount(TestDir2);
1633 rmdir(TestDir2);
1634 umount(TestDir1);
1635 rmdir(TestDir1);
1636 rmdir(BaseDir);
1637 return Result;
1638 }
1639
1640 int LxtFsMountDrvFs(const char* Source, const char* Target, const char* Options)
1641
1642 /*++
1643
1644 Description:
1645
1646 This routine mounts drvfs through the mount binary.
1647
1648 N.B. This allows drvfs to be mounted using 9p for WSL 2.
1649
1650 Arguments:
1651
1652 Source - Supplies the mount source.
1653
1654 Target - Supplies the mount target.
1655
1656 Options - Supplies optional mount options.
1657
1658 Return Value:
1659
1660 Returns 0 on success, -1 on failure.
1661
1662 --*/
1663
1664 {
1665
1666 char Command[4096];
1667 size_t Index;
1668 int Result;
1669
1670 if (Options == NULL)
1671 {
1672 snprintf(Command, sizeof(Command), FS_MOUNT_DRVFS_COMMAND_FORMAT, Source, Target);
1673 }
1674 else
1675 {
1676 snprintf(Command, sizeof(Command), FS_MOUNT_DRVFS_OPTIONS_COMMAND_FORMAT, Source, Target, Options);
1677 }
1678
1679 LxtCheckErrnoZeroSuccess(system(Command));
1680
1681 ErrorExit:
1682 return Result;
1683 }
1684
1685 int LxtFsRenameAtCommon(int DirFd1, int DirFd2)
1686
1687 /*++
1688
1689 Description:
1690
1691 This routine tests the renameat system call on volfs.
1692
1693 Arguments:
1694
1695 DirFd1 - Supplies a file descriptor for the first directory to use for the test.
1696
1697 DirFd2 - Supplies a file descriptor for the second directory to use for the test.
1698
1699 Return Value:
1700
1701 Returns 0 on success, -1 on failure.
1702
1703 --*/
1704
1705 {
1706
1707 int Fd1;
1708 int Result;
1709
1710 Fd1 = -1;
1711
1712 //
1713 // Create a file and rename it using AT_FDCWD.
1714 //
1715
1716 LxtCheckErrno(Fd1 = open(FS_RENAMEAT_TEST_FILE, O_RDWR | O_CREAT, S_IRWXU));
1717 LxtClose(Fd1);
1718 Fd1 = -1;
1719
1720 LxtCheckErrno(renameat(AT_FDCWD, FS_RENAMEAT_TEST_FILE, AT_FDCWD, FS_RENAMEAT_TEST_FILE2));
1721
1722 LxtCheckErrno(Fd1 = open(FS_RENAMEAT_TEST_FILE, O_RDWR | O_CREAT, S_IRWXU));
1723 LxtClose(Fd1);
1724 Fd1 = -1;
1725
1726 LxtCheckErrno(renameat(AT_FDCWD, FS_RENAMEAT_TEST_FILE, DirFd2, FS_RENAMEAT_TEST_FILE));
1727
1728 LxtCheckErrno(Fd1 = openat(DirFd1, FS_RENAMEAT_TEST_FILE, O_RDWR | O_CREAT, S_IRWXU));
1729 LxtClose(Fd1);
1730 Fd1 = -1;
1731
1732 //
1733 // Rename a file over an existing file, but add a trailing slash to the target filename, error.
1734 //
1735
1736 LxtCheckErrnoFailure(renameat(DirFd1, FS_RENAMEAT_TEST_FILE, DirFd2, FS_RENAMEAT_TEST_FILE "/"), ENOTDIR);
1737
1738 LxtCheckErrno(renameat(DirFd1, FS_RENAMEAT_TEST_FILE, AT_FDCWD, FS_RENAMEAT_TEST_FILE2));
1739
1740 //
1741 // Create a file and rename it into a subdirectory.
1742 //
1743
1744 LxtCheckErrno(Fd1 = openat(DirFd1, FS_RENAMEAT_TEST_FILE, O_RDWR | O_CREAT, S_IRWXU));
1745 LxtClose(Fd1);
1746 Fd1 = -1;
1747
1748 LxtCheckErrno(renameat(DirFd1, FS_RENAMEAT_TEST_FILE, DirFd2, FS_RENAMEAT_TEST_FILE));
1749
1750 //
1751 // Create a new file and rename it into a deeper subdirectory.
1752 // The rename originally renamed the file into a/b/c/d/e/f/, but due to Bug 8405643, the file
1753 // is now renamed into a/b/c, so that the directory rename further below will not fail (It
1754 // sometimes fails if the source directory contains a file).
1755 //
1756
1757 LxtCheckErrno(Fd1 = openat(DirFd1, FS_RENAMEAT_TEST_FILE, O_RDWR | O_CREAT, S_IRWXU));
1758 LxtClose(Fd1);
1759 Fd1 = -1;
1760
1761 LxtCheckErrno(renameat(DirFd1, FS_RENAMEAT_TEST_FILE, DirFd2, FS_RENAMEAT_TEST_FILE));
1762
1763 //
1764 // Attempt to rename a folder into a descendent of itself.
1765 //
1766
1767 LxtCheckErrnoFailure(renameat(DirFd1, "b", DirFd2, "d/e/f/b"), EINVAL);
1768
1769 //
1770 // Rename folders that have trailing slashes.
1771 //
1772
1773 LxtCheckErrnoZeroSuccess(renameat(DirFd1, "b/c/d/", DirFd1, "b/d"));
1774 LxtCheckErrnoZeroSuccess(renameat(DirFd1, "b/d/", DirFd1, "b/c/d"));
1775 LxtCheckErrnoZeroSuccess(renameat(DirFd1, "b/c/d/", DirFd1, "b/d/"));
1776 LxtCheckErrnoZeroSuccess(renameat(DirFd1, "b/d/", DirFd1, "b/c/d/"));
1777
1778 //
1779 // Invalid parameter variations.
1780 //
1781
1782 LxtCheckErrnoFailure(renameat(-1, "b", DirFd2, "d/e/f/b"), EBADF);
1783 LxtCheckErrnoFailure(renameat(DirFd1, NULL, DirFd2, "d/e/f/b"), EFAULT);
1784 LxtCheckErrnoFailure(renameat(DirFd1, "b", -1, "d/e/f/b"), EBADF);
1785 LxtCheckErrnoFailure(renameat(DirFd1, "b", DirFd2, NULL), EFAULT);
1786
1787 ErrorExit:
1788 if (Fd1 >= 0)
1789 {
1790 LxtClose(Fd1);
1791 }
1792
1793 unlinkat(DirFd2, "d/e/f/" FS_RENAMEAT_TEST_FILE, 0);
1794 unlinkat(DirFd2, FS_RENAMEAT_TEST_FILE, 0);
1795 unlinkat(AT_FDCWD, FS_RENAMEAT_TEST_FILE2, 0);
1796
1797 return Result;
1798 }
1799
1800 int LxtFsRenameDirCommon(char* BaseDir)
1801
1802 /*++
1803
1804 Description:
1805
1806 This routine tests the rename system call for directories.
1807
1808 Arguments:
1809
1810 BaseDir - Supplies the top directory to use for the test.
1811
1812 Return Value:
1813
1814 Returns 0 on success, -1 on failure.
1815
1816 --*/
1817
1818 {
1819
1820 int Attempts;
1821 int Attempts2;
1822 pid_t ChildPid;
1823 int Fd;
1824 char RenameTestDir[PATH_MAX];
1825 char RenameTestDirChild[PATH_MAX];
1826 char RenameTestDirGrandchild[PATH_MAX];
1827 char RenameTestDirSlash[PATH_MAX];
1828 char RenameTestDirSlash2[PATH_MAX];
1829 char RenameTestDirSlashLink[PATH_MAX];
1830 char RenameTestDirSlashLinkSlash[PATH_MAX];
1831 char RenameTestDirSlashLink2[PATH_MAX];
1832 char RenameTestDir2[PATH_MAX];
1833 char RenameTestDir2Child[PATH_MAX];
1834 char RenameTestDir2Child2[PATH_MAX];
1835 char RenameTestDir2Slash[PATH_MAX];
1836 char RenameTestDir3[PATH_MAX];
1837 char RenameTestDir3Slash[PATH_MAX];
1838 char RenameTestFile[PATH_MAX];
1839 int Result;
1840 int Status;
1841
1842 ChildPid = -1;
1843 Fd = -1;
1844 sprintf(RenameTestDir, "%s%s", BaseDir, FS_RENAME_TEST_DIR);
1845 sprintf(RenameTestDirChild, "%s%s", BaseDir, FS_RENAME_TEST_DIR_CHILD);
1846 sprintf(RenameTestDirGrandchild, "%s%s", BaseDir, FS_RENAME_TEST_DIR_GRANDCHILD);
1847 sprintf(RenameTestDirSlash, "%s%s", BaseDir, FS_RENAME_TEST_DIR_SLASH);
1848 sprintf(RenameTestDirSlash2, "%s%s", BaseDir, FS_RENAME_TEST_DIR_SLASH2);
1849 sprintf(RenameTestDirSlashLink, "%s%s", BaseDir, FS_RENAME_TEST_DIR_SLASH_LINK);
1850 sprintf(RenameTestDirSlashLinkSlash, "%s%s/", BaseDir, FS_RENAME_TEST_DIR_SLASH_LINK);
1851 sprintf(RenameTestDirSlashLink2, "%s%s", BaseDir, FS_RENAME_TEST_DIR_SLASH_LINK2);
1852 sprintf(RenameTestDir2, "%s%s", BaseDir, FS_RENAME_TEST_DIR2);
1853 sprintf(RenameTestDir2Child, "%s%s", BaseDir, FS_RENAME_TEST_DIR2_CHILD);
1854 sprintf(RenameTestDir2Child2, "%s%s", BaseDir, FS_RENAME_TEST_DIR2_CHILD2);
1855 sprintf(RenameTestDir2Slash, "%s%s////", BaseDir, FS_RENAME_TEST_DIR2);
1856 sprintf(RenameTestDir3, "%s%s", BaseDir, FS_RENAME_TEST_DIR3);
1857 sprintf(RenameTestDir3Slash, "%s%s/", BaseDir, FS_RENAME_TEST_DIR3);
1858 sprintf(RenameTestFile, "%s%s", BaseDir, FS_RENAME_TEST_FILE);
1859
1860 //
1861 // Renaming a directory to be its own parent should fail with ENOTEMPTY.
1862 //
1863
1864 LxtCheckResult(LxtFsCreateTestDir(RenameTestDir));
1865 LxtCheckErrnoZeroSuccess(mkdir(RenameTestDirChild, 0777));
1866 LxtCheckErrnoFailure(rename(RenameTestDirChild, RenameTestDir), ENOTEMPTY);
1867
1868 //
1869 // Or ancestor.
1870 //
1871
1872 LxtCheckErrnoZeroSuccess(mkdir(RenameTestDirGrandchild, 0777));
1873 LxtCheckErrnoFailure(rename(RenameTestDirGrandchild, RenameTestDir), ENOTEMPTY);
1874
1875 //
1876 // Renaming it over an existing directory should succeed.
1877 //
1878
1879 LxtCheckErrnoZeroSuccess(mkdir(RenameTestDir2, 0777));
1880 LxtCheckErrnoZeroSuccess(rename(RenameTestDirChild, RenameTestDir2));
1881
1882 //
1883 // Renaming to a non-existent directory where the target directory
1884 // contains trailing slash(es).
1885 //
1886
1887 LxtCheckErrnoZeroSuccess(rename(RenameTestDir2, RenameTestDir3Slash));
1888 LxtCheckErrnoZeroSuccess(rename(RenameTestDir3, RenameTestDir2Slash));
1889
1890 //
1891 // Renaming a file to its parent should also fail.
1892 //
1893
1894 LxtCheckErrno(Fd = creat(RenameTestDirChild, 0666));
1895 LxtCheckErrnoZeroSuccess(close(Fd));
1896 Fd = -1;
1897 LxtCheckErrnoFailure(rename(RenameTestDirChild, RenameTestDir), ENOTEMPTY);
1898
1899 //
1900 // Renaming a file over a directory should fail with EISDIR.
1901 //
1902
1903 LxtCheckErrnoFailure(rename(RenameTestDirChild, RenameTestDir2), EISDIR);
1904
1905 //
1906 // And directory over file should fail with ENOTDIR.
1907 //
1908
1909 LxtCheckErrnoFailure(rename(RenameTestDir2, RenameTestDirChild), ENOTDIR);
1910
1911 //
1912 // The following test cases deal with the old name containing a trailing slash.
1913 //
1914 // Renaming a directory to a nonexistent directory should succeed.
1915 //
1916
1917 LxtCheckErrnoZeroSuccess(mkdir(RenameTestDirSlash, 0777));
1918 LxtCheckErrnoZeroSuccess(rename(RenameTestDirSlash, RenameTestDirSlash2));
1919
1920 //
1921 // Renaming a symlink with a trailing slash should fail with ENOTDIR.
1922 //
1923
1924 LxtCheckErrnoZeroSuccess(symlink(RenameTestDirSlash2, RenameTestDirSlashLink));
1925 LxtCheckErrnoFailure(rename(RenameTestDirSlashLinkSlash, RenameTestDirSlashLink2), ENOTDIR);
1926
1927 //
1928 // The following tests reproduce a bug in lxcore when renaming a directory
1929 // fails due to open handles to a descendant of that directory. Since this
1930 // scenario would not fail on real Linux in the first place, this test
1931 // will not pass on real Linux.
1932 //
1933 // Once lxcore is able to rename directories with open handles to a
1934 // descendant, this test will need to be updated.
1935 //
1936
1937 LxtCheckErrnoZeroSuccess(rmdir(RenameTestDir2Child2));
1938 LxtCheckErrnoZeroSuccess(rmdir(RenameTestDir2));
1939 LxtLogInfo("This test will not pass on real Linux.");
1940
1941 //
1942 // Keep the child open so renaming the directory will fail on lxcore.
1943 //
1944
1945 LxtCheckErrno(Fd = open(RenameTestDirChild, O_RDONLY));
1946 LxtCheckErrnoFailure(rename(RenameTestDir, RenameTestDir2), EACCES);
1947
1948 //
1949 // Attempt to unlink the child while it is still open.
1950 //
1951
1952 LxtCheckErrnoZeroSuccess(unlink(RenameTestDirChild));
1953 LxtCheckErrnoZeroSuccess(close(Fd));
1954 Fd = -1;
1955
1956 //
1957 // Repeat, but this time use the file as a rename target.
1958 //
1959
1960 LxtCheckErrno(Fd = creat(RenameTestDirChild, 0666));
1961 LxtCheckErrnoZeroSuccess(close(Fd));
1962 Fd = -1;
1963 LxtCheckErrno(Fd = creat(RenameTestFile, 0666));
1964 LxtCheckErrnoZeroSuccess(close(Fd));
1965 Fd = -1;
1966 LxtCheckErrno(Fd = open(RenameTestDirChild, O_RDONLY));
1967 LxtCheckErrnoFailure(rename(RenameTestDir, RenameTestDir2), EACCES);
1968 LxtCheckErrnoZeroSuccess(rename(RenameTestFile, RenameTestDirChild));
1969 LxtCheckClose(Fd);
1970
1971 ErrorExit:
1972 LXT_SYNCHRONIZATION_POINT_END();
1973
1974 if (Fd >= 0)
1975 {
1976 close(Fd);
1977 }
1978
1979 unlink(RenameTestDirSlashLink);
1980 rmdir(RenameTestDirSlash);
1981 rmdir(RenameTestDirSlash2);
1982 rmdir(RenameTestDirGrandchild);
1983 unlink(RenameTestDirChild);
1984 unlink(RenameTestDir2Child);
1985 unlink(RenameTestFile);
1986 rmdir(RenameTestDirChild);
1987 rmdir(RenameTestDir);
1988 rmdir(RenameTestDir2Child2);
1989 rmdir(RenameTestDir2);
1990
1991 return Result;
1992 }
1993
1994 void LxtFsTestCleanup(const char* TestDir, const char* DrvFsDir, bool UseDrvFs)
1995
1996 /*++
1997
1998 Description:
1999
2000 This routine cleans up directories and mounts created by LxtFsTestSetup.
2001
2002 Arguments:
2003
2004 TestDir - Supplies the test parent directory.
2005
2006 DrvFsDir - Supplies the DrvFs test directory.
2007
2008 UseDrvFs - Supplies a value which indicates whether DrvFs was used for the
2009 test.
2010
2011 Return Value:
2012
2013 None.
2014
2015 --*/
2016
2017 {
2018
2019 char DrvFsPath[PATH_MAX];
2020
2021 //
2022 // Clean up DrvFs if needed, and remount with default options.
2023 //
2024 // N.B. Make sure the cwd isn't in the dir, as this prevents unmounting.
2025 //
2026
2027 if (UseDrvFs != false)
2028 {
2029 chdir("/");
2030 umount(TestDir);
2031 snprintf(DrvFsPath, sizeof(DrvFsPath), "%s%s", FS_DRVFS_PREFIX, DrvFsDir);
2032 rmdir(DrvFsPath);
2033 umount(FS_DRVFS_PREFIX);
2034 LxtFsMountDrvFs(FS_DRVFS_DRIVE, FS_DRVFS_PREFIX, NULL);
2035 }
2036
2037 rmdir(TestDir);
2038 return;
2039 }
2040
2041 int LxtFsTestSetup(PLXT_ARGS Args, const char* TestDir, const char* DrvFsDir, bool UseDrvFs)
2042
2043 /*++
2044
2045 Description:
2046
2047 This routine sets up the test environment for tests that can run on either
2048 lxfs or drvfs. It also populates the global FS info structure.
2049
2050 Arguments:
2051
2052 Args - Supplies the arguments.
2053
2054 TestDir - Supplies the root directory for the tests.
2055
2056 DrvFsDir - Supplies the DrvFs directory to use for testing. This must
2057 start with a slash, and be relative from the root of the DrvFs mount.
2058
2059 UseDrvFs - Supplies a value indicating whether DrvFs is being used.
2060
2061 Return Value:
2062
2063 Returns 0 on success, -1 on failure.
2064
2065 --*/
2066
2067 {
2068
2069 char DrvFsPath[PATH_MAX];
2070 int Index;
2071 int ParentId;
2072 int Result;
2073
2074 //
2075 // Do nothing if the caller just wants to show help.
2076 //
2077
2078 if (Args->HelpRequested != false)
2079 {
2080 Result = 0;
2081 goto ErrorExit;
2082 }
2083
2084 //
2085 // Create the test dir.
2086 //
2087
2088 LxtCheckErrnoZeroSuccess(mkdir(TestDir, 0777));
2089 if (UseDrvFs == FALSE)
2090 {
2091 LxtCheckResult(LxtFsGetFsInfo(TestDir, &g_LxtFsInfo));
2092 Result = 0;
2093 goto ErrorExit;
2094 }
2095
2096 //
2097 // If drvfs is used, metadata support is required. Unmount and remount
2098 // drvfs with metadata support.
2099 //
2100 // N.B. Make sure the cwd isn't inside DrvFs as this prevents unmounting.
2101 //
2102
2103 LxtCheckErrnoZeroSuccess(chdir("/"));
2104 LxtCheckErrnoZeroSuccess(umount(FS_DRVFS_PREFIX));
2105 LxtCheckResult(ParentId = MountGetMountId(FS_DRVFS_PREFIX));
2106 LxtCheckResult(LxtFsMountDrvFs(FS_DRVFS_DRIVE, FS_DRVFS_PREFIX, "metadata,case=dir"));
2107
2108 LxtCheckResult(LxtFsCheckDrvFsMount(FS_DRVFS_DRIVE, FS_DRVFS_PREFIX, "metadata,case=dir", ParentId, "/"));
2109
2110 //
2111 // The tests can't be run on the root directory of the volume. Therefore,
2112 // create a directory to run the tests in and bind mount it to the test
2113 // root.
2114 //
2115
2116 snprintf(DrvFsPath, sizeof(DrvFsPath), "%s%s", FS_DRVFS_PREFIX, DrvFsDir);
2117 LxtLogInfo("mkdir(%s, 0777)", DrvFsPath);
2118 LxtCheckErrnoZeroSuccess(mkdir(DrvFsPath, 0777));
2119 LxtCheckResult(ParentId = MountGetMountId(TestDir));
2120 LxtCheckErrnoZeroSuccess(mount(DrvFsPath, TestDir, NULL, MS_BIND, NULL));
2121
2122 LxtCheckResult(LxtFsCheckDrvFsMount(FS_DRVFS_DRIVE, TestDir, "metadata,case=dir", ParentId, DrvFsDir));
2123
2124 LxtCheckResult(LxtFsGetFsInfo(TestDir, &g_LxtFsInfo));
2125
2126 ErrorExit:
2127 return Result;
2128 }
2129
2130 int LxtFsTimestampCheckCurrent(const struct timespec* Timestamp)
2131
2132 /*++
2133
2134 Description:
2135
2136 This routine checks if a timestamp is close to the current time.
2137
2138 Arguments:
2139
2140 Timestamp - Supplies the timestamp to check.
2141
2142 Return Value:
2143
2144 Returns 0 on success, -1 on failure.
2145
2146 --*/
2147
2148 {
2149
2150 struct timespec CurrentTime;
2151 int Result;
2152
2153 //
2154 // File system timestamp updates use the coarse clock.
2155 //
2156
2157 LxtCheckErrnoZeroSuccess(clock_gettime(CLOCK_REALTIME_COARSE, &CurrentTime));
2158
2159 if (LxtFsUtimeDoTimesMatch(Timestamp, &CurrentTime, FS_FAT_MODIFIED_TIME_PRECISION) == false)
2160 {
2161
2162 Result = LXT_RESULT_FAILURE;
2163 goto ErrorExit;
2164 }
2165
2166 Result = LXT_RESULT_SUCCESS;
2167
2168 ErrorExit:
2169 return Result;
2170 }
2171
2172 int LxtFsTimestampCheckEqual(const struct timespec* Timestamp1, const struct timespec* Timestamp2)
2173
2174 /*++
2175
2176 Description:
2177
2178 This routine checks whether two timestamps are equal.
2179
2180 Arguments:
2181
2182 Timestamp1 - Supplies the first timestamp.
2183
2184 Timestamp2 - Supplies the second timestamp.
2185
2186 Return Value:
2187
2188 Returns 0 on success, -1 on failure.
2189
2190 --*/
2191
2192 {
2193
2194 int Result;
2195
2196 if (LxtFsUtimeDoTimesMatch(Timestamp1, Timestamp2, 0) == false)
2197 {
2198 Result = LXT_RESULT_FAILURE;
2199 goto ErrorExit;
2200 }
2201
2202 Result = LXT_RESULT_SUCCESS;
2203
2204 ErrorExit:
2205 return Result;
2206 }
2207
2208 int LxtFsTimestampCheckGreater(const struct timespec* Timestamp1, const struct timespec* Timestamp2)
2209
2210 /*++
2211
2212 Description:
2213
2214 This routine checks if timestamp 1 is larger than timestamp 2.
2215
2216 Arguments:
2217
2218 Timestamp1 - Supplies the first timestamp.
2219
2220 Timestamp2 - Supplies the second timestamp.
2221
2222 Return Value:
2223
2224 Returns 0 on success, -1 on failure.
2225
2226 --*/
2227
2228 {
2229
2230 int Result;
2231
2232 if (LxtFsTimestampDiff(Timestamp1, Timestamp2) <= 0)
2233 {
2234 LxtLogError(
2235 "Time %lld.%.9ld not greater than time %lld.%.9ld",
2236 (long long)Timestamp1->tv_sec,
2237 (long)Timestamp1->tv_nsec,
2238 (long long)Timestamp2->tv_sec,
2239 (long)Timestamp2->tv_nsec);
2240
2241 Result = LXT_RESULT_FAILURE;
2242 goto ErrorExit;
2243 }
2244
2245 Result = LXT_RESULT_SUCCESS;
2246
2247 ErrorExit:
2248 return Result;
2249 }
2250
2251 int LxtFsTimestampCheckUpdate(const char* Path, struct stat* PreviousStat, int Flags)
2252
2253 /*++
2254
2255 Description:
2256
2257 This routine checks if the specified timestamps have been updated.
2258
2259 Arguments:
2260
2261 Path - Supplies the path of the file to check.
2262
2263 PreviousStat - Supplies the previous timestamps, and gets updated with the
2264 current timestamp on success.
2265
2266 Flags - Supplies the flags.
2267
2268 Return Value:
2269
2270 Returns 0 on success, -1 on failure.
2271
2272 --*/
2273
2274 {
2275
2276 int Result;
2277 struct stat Stat;
2278
2279 LxtCheckErrnoZeroSuccess(lstat(Path, &Stat));
2280 if ((Flags & FS_TIMESTAMP_ACCESS) != 0)
2281 {
2282 LxtCheckResult(LxtFsTimestampCheckGreater(&Stat.st_atim, &PreviousStat->st_atim));
2283
2284 LxtCheckResult(LxtFsTimestampCheckCurrent(&Stat.st_atim));
2285 }
2286 else
2287 {
2288 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat.st_atim, &PreviousStat->st_atim));
2289 }
2290
2291 if ((Flags & FS_TIMESTAMP_MODIFY) != 0)
2292 {
2293 LxtCheckResult(LxtFsTimestampCheckGreater(&Stat.st_mtim, &PreviousStat->st_mtim));
2294
2295 LxtCheckResult(LxtFsTimestampCheckCurrent(&Stat.st_mtim));
2296 }
2297 else
2298 {
2299 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat.st_mtim, &PreviousStat->st_mtim));
2300 }
2301
2302 if ((Flags & FS_TIMESTAMP_CHANGE) != 0)
2303 {
2304 LxtCheckResult(LxtFsTimestampCheckGreater(&Stat.st_ctim, &PreviousStat->st_ctim));
2305
2306 LxtCheckResult(LxtFsTimestampCheckCurrent(&Stat.st_ctim));
2307 }
2308 else
2309 {
2310 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat.st_ctim, &PreviousStat->st_ctim));
2311 }
2312
2313 *PreviousStat = Stat;
2314
2315 ErrorExit:
2316 return Result;
2317 }
2318
2319 int LxtFsTimestampCommon(const char* BaseDir, int Flags)
2320
2321 /*++
2322
2323 Description:
2324
2325 This routine tests timestamp updates made by various file operations.
2326
2327 N.B. These timestamp updates were verified on Linux with the "strictatime"
2328 mount flag, so they include all the correct access time updates. WSL
2329 does not currently implement access time updates.
2330
2331 Arguments:
2332
2333 Args - Supplies the command line arguments.
2334
2335 Flags - Supplies the flags.
2336
2337 Return Value:
2338
2339 Returns 0 on success, -1 on failure.
2340
2341 --*/
2342
2343 {
2344
2345 int AccessTime;
2346 int Fd;
2347 char LinkPath[PATH_MAX];
2348 char* Map;
2349 char Path[PATH_MAX];
2350 void* PointerResult;
2351 int Result;
2352 struct stat Stat;
2353 struct stat Stat2;
2354 struct stat Stat3;
2355 struct stat Stat4;
2356 char Temp[PATH_MAX];
2357
2358 //
2359 // Since WSL doesn't update access time, only include the access time
2360 // checks when requested.
2361 //
2362
2363 AccessTime = 0;
2364 if ((Flags & FS_TIMESTAMP_NOATIME) == 0)
2365 {
2366 AccessTime = FS_TIMESTAMP_ACCESS;
2367 }
2368
2369 snprintf(Path, sizeof(Path), "%s/%s", BaseDir, "test");
2370 snprintf(LinkPath, sizeof(LinkPath), "%s/%s", BaseDir, "testlink");
2371 Fd = -1;
2372 LxtCheckErrnoZeroSuccess(stat(BaseDir, &Stat));
2373
2374 //
2375 // Creating and removing items in a directory should update the time of
2376 // the directory. The items themselves should initialize to all times set
2377 // to the current time.
2378 //
2379 // First create a directory.
2380 //
2381
2382 usleep(FS_TIMESTAMP_SLEEP_TIME);
2383 LxtLogInfo("Create directory...");
2384 LxtCheckErrnoZeroSuccess(mkdir(Path, 0777));
2385 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2386
2387 LxtCheckErrnoZeroSuccess(lstat(Path, &Stat2));
2388 LxtCheckResult(LxtFsTimestampCheckCurrent(&Stat2.st_atim));
2389 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_mtim));
2390 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_ctim));
2391
2392 usleep(FS_TIMESTAMP_SLEEP_TIME);
2393 LxtLogInfo("Remove directory...");
2394 LxtCheckErrnoZeroSuccess(rmdir(Path));
2395 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2396
2397 //
2398 // Create a socket file.
2399 //
2400
2401 usleep(FS_TIMESTAMP_SLEEP_TIME);
2402 LxtLogInfo("Create socket...");
2403 LxtCheckErrnoZeroSuccess(mknod(Path, S_IFSOCK | 0666, 0));
2404 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2405
2406 LxtCheckErrnoZeroSuccess(lstat(Path, &Stat2));
2407 LxtCheckResult(LxtFsTimestampCheckCurrent(&Stat2.st_atim));
2408 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_mtim));
2409 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_ctim));
2410
2411 usleep(FS_TIMESTAMP_SLEEP_TIME);
2412 LxtLogInfo("Remove socket...");
2413 LxtCheckErrnoZeroSuccess(unlink(Path));
2414 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2415
2416 //
2417 // Create a fifo file.
2418 //
2419
2420 usleep(FS_TIMESTAMP_SLEEP_TIME);
2421 LxtLogInfo("Create fifo...");
2422 LxtCheckErrnoZeroSuccess(mknod(Path, S_IFIFO | 0666, 0));
2423 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2424
2425 LxtCheckErrnoZeroSuccess(lstat(Path, &Stat2));
2426 LxtCheckResult(LxtFsTimestampCheckCurrent(&Stat2.st_atim));
2427 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_mtim));
2428 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_ctim));
2429
2430 usleep(FS_TIMESTAMP_SLEEP_TIME);
2431 LxtLogInfo("Remove fifo...");
2432 LxtCheckErrnoZeroSuccess(unlink(Path));
2433 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2434 //
2435 // Create a character device file.
2436 //
2437
2438 usleep(FS_TIMESTAMP_SLEEP_TIME);
2439 LxtLogInfo("Create character device...");
2440 LxtCheckErrnoZeroSuccess(mknod(Path, S_IFCHR | 0666, 0));
2441 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2442
2443 LxtCheckErrnoZeroSuccess(lstat(Path, &Stat2));
2444 LxtCheckResult(LxtFsTimestampCheckCurrent(&Stat2.st_atim));
2445 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_mtim));
2446 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_ctim));
2447
2448 usleep(FS_TIMESTAMP_SLEEP_TIME);
2449 LxtLogInfo("Remove character device...");
2450 LxtCheckErrnoZeroSuccess(unlink(Path));
2451 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2452
2453 //
2454 // Create a file.
2455 //
2456
2457 usleep(FS_TIMESTAMP_SLEEP_TIME);
2458 LxtLogInfo("Create file...");
2459 LxtCheckErrno(Fd = creat(Path, 0666));
2460 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2461
2462 LxtCheckErrnoZeroSuccess(lstat(Path, &Stat2));
2463 LxtCheckResult(LxtFsTimestampCheckCurrent(&Stat2.st_atim));
2464 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_mtim));
2465 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_ctim));
2466 LxtCheckClose(Fd);
2467 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2468 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2469
2470 //
2471 // Create a hard link.
2472 //
2473 // N.B. The hard link has the same time stamps as the original file, and
2474 // ctime gets updated both when the link is created and unlinked.
2475 //
2476
2477 usleep(FS_TIMESTAMP_SLEEP_TIME);
2478 LxtLogInfo("Create hard link...");
2479 LxtCheckErrnoZeroSuccess(link(Path, LinkPath));
2480 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2481
2482 LxtCheckResult(LxtFsTimestampCheckUpdate(LinkPath, &Stat2, FS_TIMESTAMP_CHANGE));
2483
2484 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2485 usleep(FS_TIMESTAMP_SLEEP_TIME);
2486 LxtLogInfo("Remove hard link...");
2487 LxtCheckErrnoZeroSuccess(unlink(LinkPath));
2488 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2489
2490 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, FS_TIMESTAMP_CHANGE));
2491
2492 //
2493 // Create a symbolic link.
2494 //
2495
2496 usleep(FS_TIMESTAMP_SLEEP_TIME);
2497 LxtLogInfo("Create symlink...");
2498 LxtCheckErrnoZeroSuccess(symlink(Path, LinkPath));
2499 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2500
2501 LxtCheckErrnoZeroSuccess(lstat(LinkPath, &Stat2));
2502 LxtCheckResult(LxtFsTimestampCheckCurrent(&Stat2.st_atim));
2503 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_mtim));
2504 LxtCheckResult(LxtFsTimestampCheckEqual(&Stat2.st_atim, &Stat2.st_ctim));
2505
2506 //
2507 // Readlink updates the access time.
2508 //
2509
2510 usleep(FS_TIMESTAMP_SLEEP_TIME);
2511 LxtLogInfo("Readlink...");
2512 LxtCheckErrno(readlink(LinkPath, Temp, sizeof(Temp)));
2513 LxtCheckResult(LxtFsTimestampCheckUpdate(LinkPath, &Stat2, AccessTime));
2514 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2515
2516 //
2517 // Remove the link.
2518 //
2519
2520 usleep(FS_TIMESTAMP_SLEEP_TIME);
2521 LxtLogInfo("Remove symlink...");
2522 LxtCheckErrnoZeroSuccess(unlink(LinkPath));
2523 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2524
2525 //
2526 // Chmod updates the change time.
2527 //
2528 // N.B. For every operation, also check that the timestamp of the parent
2529 // directory is not updated.
2530 //
2531 // N.B. Timestamps are updated even if the values aren't actually changed.
2532 //
2533
2534 LxtCheckErrnoZeroSuccess(lstat(Path, &Stat2));
2535 usleep(FS_TIMESTAMP_SLEEP_TIME);
2536 LxtLogInfo("Chmod...");
2537 LxtCheckErrnoZeroSuccess(chmod(Path, 0600));
2538 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, FS_TIMESTAMP_CHANGE));
2539 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2540 usleep(FS_TIMESTAMP_SLEEP_TIME);
2541 LxtCheckErrnoZeroSuccess(chmod(Path, 0600));
2542 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, FS_TIMESTAMP_CHANGE));
2543 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2544
2545 //
2546 // Chown updates the change time.
2547 //
2548
2549 usleep(FS_TIMESTAMP_SLEEP_TIME);
2550 LxtLogInfo("Chown...");
2551 LxtCheckErrnoZeroSuccess(chown(Path, 1000, 1001));
2552 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, FS_TIMESTAMP_CHANGE));
2553 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2554 usleep(FS_TIMESTAMP_SLEEP_TIME);
2555 LxtCheckErrnoZeroSuccess(chown(Path, 1000, 1001));
2556 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, FS_TIMESTAMP_CHANGE));
2557 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2558
2559 //
2560 // Stat does not change any timestamps (not even atime).
2561 //
2562 // N.B. The check function uses stat so just doing that twice is sufficient
2563 // to test this.
2564 //
2565
2566 usleep(FS_TIMESTAMP_SLEEP_TIME);
2567 LxtLogInfo("Stat...");
2568 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2569 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2570 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2571
2572 //
2573 // Setxattr updates the change time.
2574 //
2575
2576 usleep(FS_TIMESTAMP_SLEEP_TIME);
2577 LxtLogInfo("Setxattr...");
2578 LxtCheckErrnoZeroSuccess(setxattr(Path, "user.test", "value", 5, XATTR_CREATE));
2579
2580 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, FS_TIMESTAMP_CHANGE));
2581 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2582 usleep(FS_TIMESTAMP_SLEEP_TIME);
2583 LxtCheckErrnoZeroSuccess(setxattr(Path, "user.test", "value2", 6, XATTR_REPLACE));
2584
2585 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, FS_TIMESTAMP_CHANGE));
2586 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2587
2588 //
2589 // Getxattr does not change any timestamps (not even atime).
2590 //
2591
2592 usleep(FS_TIMESTAMP_SLEEP_TIME);
2593 LxtLogInfo("Getxattr...");
2594 LxtCheckErrno(getxattr(Path, "user.test", Temp, sizeof(Temp)));
2595 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2596 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2597
2598 //
2599 // listxattr does not change any timestamps (not even atime).
2600 //
2601
2602 usleep(FS_TIMESTAMP_SLEEP_TIME);
2603 LxtLogInfo("Listxattr...");
2604 LxtCheckErrno(listxattr(Path, Temp, sizeof(Temp)));
2605 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2606 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2607
2608 //
2609 // Removexattr updates the change time.
2610 //
2611
2612 usleep(FS_TIMESTAMP_SLEEP_TIME);
2613 LxtLogInfo("Removexattr...");
2614 LxtCheckErrno(removexattr(Path, "user.test"));
2615 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, FS_TIMESTAMP_CHANGE));
2616 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2617
2618 //
2619 // Rename to the same directory (reusing LinkPath for this since it doesn't
2620 // exist at this point). This change the parent and target timestamps.
2621 //
2622
2623 usleep(FS_TIMESTAMP_SLEEP_TIME);
2624 LxtLogInfo("Rename (same directory)...");
2625 LxtCheckErrnoZeroSuccess(rename(Path, LinkPath));
2626 LxtCheckResult(LxtFsTimestampCheckUpdate(LinkPath, &Stat2, FS_TIMESTAMP_CHANGE));
2627 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2628
2629 //
2630 // Rename to a different directory.
2631 //
2632
2633 snprintf(Temp, sizeof(Temp), "%s/%s", BaseDir, "targetdir");
2634 LxtCheckErrnoZeroSuccess(mkdir(Temp, 0777));
2635 LxtCheckErrnoZeroSuccess(lstat(Temp, &Stat3));
2636 usleep(FS_TIMESTAMP_SLEEP_TIME);
2637 LxtLogInfo("Rename (different directory)...");
2638 snprintf(Temp, sizeof(Temp), "%s/%s", BaseDir, "targetdir/target");
2639 LxtCheckErrnoZeroSuccess(rename(LinkPath, Temp));
2640 LxtCheckResult(LxtFsTimestampCheckUpdate(Temp, &Stat2, FS_TIMESTAMP_CHANGE));
2641 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2642
2643 snprintf(Temp, sizeof(Temp), "%s/%s", BaseDir, "targetdir");
2644 LxtCheckResult(LxtFsTimestampCheckUpdate(Temp, &Stat3, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2645
2646 //
2647 // Create a file to overwrite with a rename, and create a link to that
2648 // file. The overwrite should count as an unlink, and therefore update the
2649 // change time.
2650 //
2651
2652 LxtCheckErrno(Fd = creat(Path, 0666));
2653 LxtCheckClose(Fd);
2654 LxtCheckErrnoZeroSuccess(link(Path, LinkPath));
2655 LxtCheckErrnoZeroSuccess(lstat(Path, &Stat4));
2656 LxtCheckEqual(Stat4.st_nlink, 2, "%d");
2657 usleep(FS_TIMESTAMP_SLEEP_TIME);
2658 LxtLogInfo("Rename (overwrite target)...");
2659 snprintf(Temp, sizeof(Temp), "%s/%s", BaseDir, "targetdir/target");
2660 LxtCheckErrnoZeroSuccess(rename(Temp, Path));
2661 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, FS_TIMESTAMP_CHANGE));
2662 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2663
2664 snprintf(Temp, sizeof(Temp), "%s/%s", BaseDir, "targetdir");
2665 LxtCheckResult(LxtFsTimestampCheckUpdate(Temp, &Stat3, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2666
2667 LxtCheckResult(LxtFsTimestampCheckUpdate(LinkPath, &Stat4, FS_TIMESTAMP_CHANGE));
2668
2669 LxtCheckEqual(Stat4.st_nlink, 1, "%d");
2670
2671 //
2672 // Open this file (which by itself doesn't update any timestamps).
2673 //
2674
2675 usleep(FS_TIMESTAMP_SLEEP_TIME);
2676 LxtLogInfo("Open...");
2677 LxtCheckErrno(Fd = open(Path, O_RDWR));
2678 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2679 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2680
2681 //
2682 // Write updates the mtime and ctime (unless no data is written).
2683 //
2684 // N.B. This happens regardless of whether the write extends the file or
2685 // not.
2686 //
2687
2688 usleep(FS_TIMESTAMP_SLEEP_TIME);
2689 LxtLogInfo("Write...");
2690 LxtCheckErrno(write(Fd, "test\0", 5));
2691 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2692
2693 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2694 usleep(FS_TIMESTAMP_SLEEP_TIME);
2695 LxtCheckErrno(write(Fd, "", 0));
2696 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2697 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2698
2699 //
2700 // Sync doesn't update any timestamps.
2701 //
2702
2703 usleep(FS_TIMESTAMP_SLEEP_TIME);
2704 LxtLogInfo("Sync...");
2705 LxtCheckErrnoZeroSuccess(fsync(Fd));
2706 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2707 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2708
2709 //
2710 // Seek doesn't update any timestamps.
2711 //
2712
2713 usleep(FS_TIMESTAMP_SLEEP_TIME);
2714 LxtLogInfo("Seek...");
2715 LxtCheckErrno(lseek(Fd, 0, SEEK_SET));
2716 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2717 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2718
2719 //
2720 // Read updates the atime (even if no data is read, even with a zero size
2721 // buffer).
2722 //
2723
2724 usleep(FS_TIMESTAMP_SLEEP_TIME);
2725 LxtLogInfo("Read...");
2726 LxtCheckErrno(read(Fd, Temp, 2));
2727 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, AccessTime));
2728 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2729 usleep(FS_TIMESTAMP_SLEEP_TIME);
2730 LxtCheckErrno(read(Fd, Temp, sizeof(Temp)));
2731 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, AccessTime));
2732 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2733 usleep(FS_TIMESTAMP_SLEEP_TIME);
2734 LxtCheckErrnoZeroSuccess(read(Fd, Temp, sizeof(Temp)));
2735 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, AccessTime));
2736 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2737 usleep(FS_TIMESTAMP_SLEEP_TIME);
2738 LxtCheckErrno(lseek(Fd, 0, SEEK_SET));
2739 LxtCheckErrnoZeroSuccess(read(Fd, Temp, 0));
2740 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, AccessTime));
2741 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2742
2743 //
2744 // This is the only ioctl supported by LxFs; it doesn't update any
2745 // timestamps.
2746 //
2747
2748 LxtCheckErrno(lseek(Fd, 0, SEEK_SET));
2749 usleep(FS_TIMESTAMP_SLEEP_TIME);
2750 LxtLogInfo("Ioctl (FIONREAD)...");
2751 LxtCheckErrnoZeroSuccess(ioctl(Fd, FIONREAD, Temp));
2752 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2753 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2754
2755 //
2756 // Mmap updates the access time immediately regardless of protection or
2757 // other flags. The write/modify time is updated when the mapping is first
2758 // written to, which WSL currently does not do correctly.
2759 //
2760
2761 usleep(FS_TIMESTAMP_SLEEP_TIME);
2762 LxtLogInfo("Mmap...");
2763 LxtCheckNullErrno(Map = mmap(NULL, 5, PROT_NONE, MAP_PRIVATE, Fd, 0));
2764
2765 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, AccessTime));
2766 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2767 usleep(FS_TIMESTAMP_SLEEP_TIME);
2768 LxtCheckErrnoZeroSuccess(munmap(Map, 5));
2769 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2770 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2771 usleep(FS_TIMESTAMP_SLEEP_TIME);
2772 LxtCheckNullErrno(Map = mmap(NULL, 5, PROT_READ | PROT_WRITE, MAP_SHARED, Fd, 0));
2773
2774 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, AccessTime));
2775 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2776
2777 usleep(FS_TIMESTAMP_SLEEP_TIME);
2778 LxtLogInfo("Value = %s", Map);
2779 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2780 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2781 usleep(FS_TIMESTAMP_SLEEP_TIME);
2782 memcpy(Map, "1234", 4);
2783
2784 //
2785 // TODO_LX: Enable this check one WSL correctly does write timestamps for
2786 // mapped files.
2787 //
2788
2789 // LxtCheckResult(LxtFsTimestampCheckUpdate(Path,
2790 // &Stat2,
2791 // (FS_TIMESTAMP_CHANGE |
2792 // FS_TIMESTAMP_MODIFY)));
2793
2794 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2795 usleep(FS_TIMESTAMP_SLEEP_TIME);
2796 memcpy(Map, "abcd", 4);
2797 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2798 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2799 usleep(FS_TIMESTAMP_SLEEP_TIME);
2800 LxtCheckErrnoZeroSuccess(msync(Map, 5, MS_SYNC));
2801 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2802 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2803 usleep(FS_TIMESTAMP_SLEEP_TIME);
2804 LxtCheckErrnoZeroSuccess(munmap(Map, 5));
2805 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, 0));
2806 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2807
2808 //
2809 // Fallocate updates change time, and write time only if the file's length
2810 // is changed.
2811 //
2812
2813 usleep(FS_TIMESTAMP_SLEEP_TIME);
2814 LxtLogInfo("Fallocate...");
2815 LxtCheckErrnoZeroSuccess(fallocate(Fd, 0, 0, 1024));
2816 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2817
2818 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2819 usleep(FS_TIMESTAMP_SLEEP_TIME);
2820 LxtCheckErrnoZeroSuccess(fallocate(Fd, 0, 0, 1024));
2821 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, FS_TIMESTAMP_CHANGE));
2822 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2823 usleep(FS_TIMESTAMP_SLEEP_TIME);
2824 LxtCheckErrnoZeroSuccess(fallocate(Fd, FALLOC_FL_KEEP_SIZE, 0, 2048));
2825 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, FS_TIMESTAMP_CHANGE));
2826 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2827 LxtCheckClose(Fd);
2828
2829 //
2830 // Truncate updates modify time and change time, even if the size did
2831 // not change.
2832 //
2833
2834 usleep(FS_TIMESTAMP_SLEEP_TIME);
2835 LxtLogInfo("Truncate...");
2836 LxtCheckErrnoZeroSuccess(truncate(Path, 2));
2837 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2838
2839 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2840 usleep(FS_TIMESTAMP_SLEEP_TIME);
2841 LxtCheckErrnoZeroSuccess(truncate(Path, 2));
2842 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2843
2844 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2845
2846 //
2847 // Opening with O_TRUNC updates modify time and change time, even if the
2848 // size does not change.
2849 //
2850
2851 usleep(FS_TIMESTAMP_SLEEP_TIME);
2852 LxtLogInfo("Open (O_TRUNC)...");
2853 LxtCheckErrno(Fd = open(Path, O_RDWR | O_TRUNC));
2854 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2855
2856 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2857 LxtCheckClose(Fd);
2858 usleep(FS_TIMESTAMP_SLEEP_TIME);
2859 LxtCheckErrno(Fd = open(Path, O_RDWR | O_TRUNC));
2860 LxtCheckResult(LxtFsTimestampCheckUpdate(Path, &Stat2, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2861
2862 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, 0));
2863 LxtCheckClose(Fd);
2864
2865 //
2866 // Unlink the file.
2867 //
2868
2869 usleep(FS_TIMESTAMP_SLEEP_TIME);
2870 LxtLogInfo("Remove file...");
2871 LxtCheckErrnoZeroSuccess(unlink(LinkPath));
2872 LxtCheckResult(LxtFsTimestampCheckUpdate(BaseDir, &Stat, (FS_TIMESTAMP_MODIFY | FS_TIMESTAMP_CHANGE)));
2873
2874 //
2875 // Note that:
2876 // - utimensat updates the change time to the current time; this is test
2877 // by the utime test.
2878 //
2879
2880 ErrorExit:
2881 if (Fd >= 0)
2882 {
2883 close(Fd);
2884 }
2885
2886 snprintf(Temp, sizeof(Temp), "%s/%s", BaseDir, "targetdir/target");
2887 unlink(Temp);
2888 snprintf(Temp, sizeof(Temp), "%s/%s", BaseDir, "targetdir");
2889 rmdir(Temp);
2890 rmdir(Path);
2891 unlink(Path);
2892 unlink(LinkPath);
2893 return Result;
2894 }
2895
2896 long long LxtFsTimestampDiff(const struct timespec* Timestamp1, const struct timespec* Timestamp2)
2897
2898 /*++
2899
2900 Description:
2901
2902 This routine gets the difference between two timestamps, in nanoseconds.
2903
2904 Arguments:
2905
2906 Timestamp1 - Supplies the first timestamp.
2907
2908 Timestamp2 - Supplies the second timestamp.
2909
2910 Return Value:
2911
2912 The value of Timestamp1 - Timestamp2, in nanoseconds
2913
2914 --*/
2915
2916 {
2917
2918 int Result;
2919 long long TimestampNs1;
2920 long long TimestampNs2;
2921
2922 TimestampNs1 = (Timestamp1->tv_sec * FS_NS_PER_SEC) + Timestamp1->tv_nsec;
2923 TimestampNs2 = (Timestamp2->tv_sec * FS_NS_PER_SEC) + Timestamp2->tv_nsec;
2924 return TimestampNs1 - TimestampNs2;
2925 }
2926
2927 int LxtFsUtimeBasicCommon(const char* BaseDir, int Flags)
2928
2929 /*++
2930
2931 Routine Description:
2932
2933 This routine executes basic test functions, including setting timestamps
2934 to a range of values including UTIME_NOW or UTIME_OMIT, on a range of
2935 different ways to specify the target file, including relative, absolute,
2936 descriptor, via symbolic link, on a symbolic link, and validating that
2937 the expected outcome occurs.
2938
2939 Arguments:
2940
2941 BaseDir - Supplies the directory containing the test files.
2942
2943 Flags - Supplies the flags.
2944
2945 Return Value:
2946
2947 0 if all variations complete successfully, -1 if they do not.
2948
2949 --*/
2950
2951 {
2952
2953 int AllowedAccessVariance;
2954 int AllowedChangeVariance;
2955 int AllowedModifiedVariance;
2956 char ChildFileFullPath[100];
2957 PBASIC_TEST_CASE CurrentTest;
2958 struct timespec CurrentTime;
2959 int DirFd;
2960 struct timespec ExpectedAccessTime;
2961 struct timespec ExpectedChangeTime;
2962 struct timespec ExpectedModifiedTime;
2963 char LinkFullPath[100];
2964 int NameVariation;
2965 int NameVariationLast;
2966 struct stat NoChangeStatBufferOld;
2967 struct stat NoChangeStatBufferNew;
2968 int Result;
2969 const char* SetFilename;
2970 int SetFlags;
2971 struct timespec* SetTime;
2972 struct stat StatBuffer;
2973 unsigned int TestCase;
2974 const char* ValidateFilename;
2975 const char* ValidateNoChangeFilename;
2976
2977 //
2978 // Initialize locals.
2979 //
2980
2981 DirFd = -1;
2982 Result = 0;
2983 SetFlags = 0;
2984 ValidateNoChangeFilename = NULL;
2985 snprintf(ChildFileFullPath, sizeof(ChildFileFullPath), "%s/%s", BaseDir, FS_UTIME_TESTFILE);
2986
2987 snprintf(LinkFullPath, sizeof(LinkFullPath), "%s/%s", BaseDir, FS_UTIME_TESTLINK);
2988
2989 //
2990 // Sleep for 2 seconds to make sure that the initial ctime of the test file
2991 // wouldn't pass the current time test if utimensat doesn't update it.
2992 //
2993
2994 LxtLogInfo("Sleeping...");
2995 sleep(3);
2996
2997 //
2998 // Try different combinations of specifying file names.
2999 //
3000
3001 NameVariationLast = NameVariationMax;
3002 if ((Flags & FS_UTIME_NO_SYMLINKS) != 0)
3003 {
3004 NameVariationLast = NameVariationFatMax;
3005 }
3006
3007 for (NameVariation = 0; NameVariation <= NameVariationLast; NameVariation += 1)
3008 {
3009 DirFd = -1;
3010 switch (NameVariation)
3011 {
3012 case NameVariationFullName:
3013 SetFilename = ChildFileFullPath;
3014 SetFlags = 0;
3015 ValidateFilename = ChildFileFullPath;
3016 ValidateNoChangeFilename = LinkFullPath;
3017 break;
3018 case NameVariationCwdRelative:
3019 LxtCheckErrnoZeroSuccess(chdir(BaseDir));
3020 DirFd = AT_FDCWD;
3021 SetFilename = FS_UTIME_TESTFILE;
3022 SetFlags = 0;
3023 ValidateFilename = ChildFileFullPath;
3024 ValidateNoChangeFilename = LinkFullPath;
3025 break;
3026 case NameVariationRelative:
3027 LxtCheckErrno(DirFd = open(BaseDir, O_DIRECTORY | O_RDONLY, 0));
3028 SetFilename = FS_UTIME_TESTFILE;
3029 SetFlags = 0;
3030 ValidateFilename = ChildFileFullPath;
3031 ValidateNoChangeFilename = LinkFullPath;
3032 break;
3033 case NameVariationDescriptor:
3034 LxtCheckErrno(DirFd = open(ChildFileFullPath, O_RDWR, 0));
3035 SetFilename = NULL;
3036 SetFlags = 0;
3037 ValidateFilename = ChildFileFullPath;
3038 ValidateNoChangeFilename = LinkFullPath;
3039 break;
3040 case NameVariationFullFileViaLink:
3041 SetFilename = LinkFullPath;
3042 SetFlags = 0;
3043 ValidateFilename = ChildFileFullPath;
3044 ValidateNoChangeFilename = LinkFullPath;
3045 break;
3046 case NameVariationCwdRelativeViaLink:
3047 LxtCheckErrnoZeroSuccess(chdir(BaseDir));
3048 DirFd = AT_FDCWD;
3049 SetFilename = FS_UTIME_TESTLINK;
3050 SetFlags = 0;
3051 ValidateFilename = ChildFileFullPath;
3052 ValidateNoChangeFilename = LinkFullPath;
3053 break;
3054 case NameVariationRelativeViaLink:
3055 LxtCheckErrno(DirFd = open(BaseDir, O_DIRECTORY | O_RDONLY, 0));
3056 SetFilename = FS_UTIME_TESTLINK;
3057 SetFlags = 0;
3058 ValidateFilename = ChildFileFullPath;
3059 ValidateNoChangeFilename = LinkFullPath;
3060 break;
3061 case NameVariationDescriptorViaLink:
3062 LxtCheckErrno(DirFd = open(LinkFullPath, O_RDWR, 0));
3063 SetFilename = NULL;
3064 SetFlags = 0;
3065 ValidateFilename = ChildFileFullPath;
3066 ValidateNoChangeFilename = LinkFullPath;
3067 break;
3068 case NameVariationFullFileOnLink:
3069 SetFilename = LinkFullPath;
3070 SetFlags = AT_SYMLINK_NOFOLLOW;
3071 ValidateFilename = LinkFullPath;
3072 ValidateNoChangeFilename = ChildFileFullPath;
3073 break;
3074 case NameVariationCwdRelativeOnLink:
3075 LxtCheckErrnoZeroSuccess(chdir(BaseDir));
3076 DirFd = AT_FDCWD;
3077 SetFilename = FS_UTIME_TESTLINK;
3078 SetFlags = AT_SYMLINK_NOFOLLOW;
3079 ValidateFilename = LinkFullPath;
3080 ValidateNoChangeFilename = ChildFileFullPath;
3081 break;
3082 case NameVariationRelativeOnLink:
3083 LxtCheckErrno(DirFd = open(BaseDir, O_DIRECTORY | O_RDONLY, 0));
3084 SetFilename = FS_UTIME_TESTLINK;
3085 SetFlags = AT_SYMLINK_NOFOLLOW;
3086 ValidateFilename = LinkFullPath;
3087 ValidateNoChangeFilename = ChildFileFullPath;
3088 break;
3089 }
3090
3091 LxtLogInfo(
3092 "Name variation %i, SetFilename = %s, ValidateFileName = %s,"
3093 " ValidateNoChangeFileName = %s",
3094 NameVariation,
3095 SetFilename,
3096 ValidateFilename,
3097 ValidateNoChangeFilename);
3098
3099 //
3100 // Check that different times of timestamp operations can succeed.
3101 //
3102
3103 for (TestCase = 0; TestCase < LXT_COUNT_OF(BasicTestCases); TestCase += 1)
3104 {
3105 LxtLogInfo("Test case %i", TestCase);
3106
3107 CurrentTest = &BasicTestCases[TestCase];
3108 SetTime = CurrentTest->SetTime;
3109 if (SetTime[0].tv_nsec == UTIME_NOW && SetTime[1].tv_nsec == UTIME_NOW && SetTime[0].tv_sec == 0 && SetTime[1].tv_sec == 0)
3110 {
3111 SetTime = NULL;
3112 }
3113
3114 if ((Flags & FS_UTIME_NO_SYMLINKS) == 0)
3115 {
3116 LxtCheckErrnoZeroSuccess(lstat(ValidateNoChangeFilename, &NoChangeStatBufferOld));
3117 }
3118
3119 if (SetFilename != NULL)
3120 {
3121 LxtCheckErrnoZeroSuccess(utimensat(DirFd, SetFilename, SetTime, SetFlags));
3122 }
3123 else
3124 {
3125 LxtCheckErrnoZeroSuccess(futimens(DirFd, SetTime));
3126 }
3127
3128 LxtCheckErrnoZeroSuccess(lstat(ValidateFilename, &StatBuffer));
3129 LxtCheckErrnoZeroSuccess(clock_gettime(CLOCK_REALTIME_COARSE, &CurrentTime));
3130
3131 ExpectedAccessTime = CurrentTest->ExpectTime[0];
3132 AllowedAccessVariance = 0;
3133 ExpectedModifiedTime = CurrentTest->ExpectTime[1];
3134 AllowedModifiedVariance = 0;
3135 ExpectedChangeTime = CurrentTime;
3136 AllowedChangeVariance = FS_FAT_MODIFIED_TIME_PRECISION;
3137 if (ExpectedAccessTime.tv_nsec == UTIME_NOW)
3138 {
3139 ExpectedAccessTime = CurrentTime;
3140 AllowedAccessVariance = FS_FAT_MODIFIED_TIME_PRECISION;
3141 }
3142
3143 if (ExpectedModifiedTime.tv_nsec == UTIME_NOW)
3144 {
3145 ExpectedModifiedTime = CurrentTime;
3146 AllowedModifiedVariance = FS_FAT_MODIFIED_TIME_PRECISION;
3147 }
3148
3149 if ((Flags & FS_UTIME_FAT) != 0)
3150 {
3151 LxtFsUtimeRoundToFatAccessTime(&ExpectedAccessTime);
3152 LxtFsUtimeRoundToFatModifiedTime(&ExpectedModifiedTime);
3153
3154 //
3155 // Since FAT32 doesn't support change time, WSL reports the
3156 // same value as the modified time.
3157 //
3158
3159 ExpectedChangeTime = ExpectedModifiedTime;
3160 AllowedChangeVariance = AllowedModifiedVariance;
3161 }
3162 else if ((Flags & FS_UTIME_NT_PRECISION) != 0)
3163 {
3164 LxtFsUtimeRoundToNt(&ExpectedAccessTime);
3165 LxtFsUtimeRoundToNt(&ExpectedModifiedTime);
3166 LxtFsUtimeRoundToNt(&ExpectedChangeTime);
3167 }
3168
3169 //
3170 // Calling utime causes the ctime to be set to the current time,
3171 // so test that too.
3172 //
3173
3174 if ((LxtFsUtimeDoTimesMatch(&StatBuffer.st_atim, &ExpectedAccessTime, AllowedAccessVariance) == false) ||
3175 (LxtFsUtimeDoTimesMatch(&StatBuffer.st_mtim, &ExpectedModifiedTime, AllowedModifiedVariance) == false) ||
3176 (LxtFsUtimeDoTimesMatch(&StatBuffer.st_ctim, &ExpectedChangeTime, AllowedChangeVariance) == false))
3177 {
3178
3179 LxtLogError(
3180 "times do not match expected values for file %s, "
3181 "TestCase %i, NameVariation %i",
3182 ValidateFilename,
3183 TestCase,
3184 NameVariation);
3185
3186 LxtLogError(
3187 "atime set: %lld.%.9ld, expected: %lld.%.9ld%s, "
3188 "actual: %lld.%.9ld",
3189 CurrentTest->SetTime[0].tv_sec,
3190 CurrentTest->SetTime[0].tv_nsec,
3191 ExpectedAccessTime.tv_sec,
3192 ExpectedAccessTime.tv_nsec,
3193 (CurrentTest->ExpectTime[0].tv_nsec == UTIME_NOW ? " (UTIME_NOW)" : ""),
3194 StatBuffer.st_atim.tv_sec,
3195 StatBuffer.st_atim.tv_nsec);
3196
3197 LxtLogError(
3198 "mtime set: %lld.%.9ld, expected: %lld.%.9ld%s, "
3199 "actual: %lld.%.9ld",
3200 CurrentTest->SetTime[1].tv_sec,
3201 CurrentTest->SetTime[1].tv_nsec,
3202 ExpectedModifiedTime.tv_sec,
3203 ExpectedModifiedTime.tv_nsec,
3204 (CurrentTest->ExpectTime[1].tv_nsec == UTIME_NOW ? " (UTIME_NOW)" : ""),
3205 StatBuffer.st_mtim.tv_sec,
3206 StatBuffer.st_mtim.tv_nsec);
3207
3208 LxtLogError(
3209 "ctime expected: %lld.%.9ld (UTIME_NOW), actual: %lld.%.9ld",
3210 ExpectedChangeTime.tv_sec,
3211 ExpectedChangeTime.tv_nsec,
3212 StatBuffer.st_ctim.tv_sec,
3213 StatBuffer.st_ctim.tv_nsec);
3214
3215 Result = -1;
3216 goto ErrorExit;
3217 }
3218
3219 if ((Flags & FS_UTIME_NO_SYMLINKS) == 0)
3220 {
3221 LxtCheckErrnoZeroSuccess(lstat(ValidateNoChangeFilename, &NoChangeStatBufferNew));
3222
3223 //
3224 // This sometimes fails on real Linux since the access timestamp
3225 // is updated when a link is read. With the default relatime mount
3226 // option, this only happens the first time, since after that
3227 // atime > mtime and won't be updated.
3228 //
3229 // TODO_LX: This test should probably be revisited when proper
3230 // atime updating happens on WSL.
3231 //
3232
3233 LxtCheckMemoryEqual(&NoChangeStatBufferOld, &NoChangeStatBufferNew, sizeof(NoChangeStatBufferOld));
3234 }
3235 }
3236
3237 if (DirFd >= 0)
3238 {
3239 LxtCheckClose(DirFd);
3240 }
3241 }
3242
3243 ErrorExit:
3244 if (DirFd >= 0)
3245 {
3246 close(DirFd);
3247 }
3248
3249 return Result;
3250 }
3251
3252 void LxtFsUtimeCleanupTestFiles(const char* BaseDir)
3253
3254 /*++
3255
3256 Description:
3257
3258 This routine cleans up the utime test files.
3259
3260 Arguments:
3261
3262 BaseDir - Supplies the directory containing the test files.
3263
3264 Return Value:
3265
3266 None.
3267
3268 --*/
3269
3270 {
3271
3272 char FilePath[100];
3273 char LinkPath[100];
3274
3275 snprintf(FilePath, sizeof(FilePath), "%s/%s", BaseDir, FS_UTIME_TESTFILE);
3276 unlink(FilePath);
3277 snprintf(LinkPath, sizeof(LinkPath), "%s/%s", BaseDir, FS_UTIME_TESTLINK);
3278 unlink(LinkPath);
3279 rmdir(BaseDir);
3280
3281 ErrorExit:
3282 return;
3283 }
3284
3285 int LxtFsUtimeCreateTestFiles(const char* BaseDir, int Flags)
3286
3287 /*++
3288
3289 Description:
3290
3291 This routine creates test files for the utime tests.
3292
3293 Arguments:
3294
3295 BaseDir - Supplies the directory containing the test files.
3296
3297 Flags - Supplies the flags.
3298
3299 Return Value:
3300
3301 Returns 0 on success, -1 on failure.
3302
3303 --*/
3304
3305 {
3306
3307 int Fd;
3308 char FilePath[100];
3309 char LinkPath[100];
3310 int Result;
3311
3312 //
3313 // Make a directory, test file, and test link.
3314 //
3315
3316 LxtCheckErrnoZeroSuccess(mkdir(BaseDir, 0777));
3317 LxtCheckResult(LxtFsGetFsInfo(BaseDir, &g_LxtFsInfo));
3318 snprintf(FilePath, sizeof(FilePath), "%s/%s", BaseDir, FS_UTIME_TESTFILE);
3319 LxtCheckErrno(Fd = creat(FilePath, 0666));
3320 LxtCheckClose(Fd);
3321 if ((Flags & FS_UTIME_NO_SYMLINKS) == 0)
3322 {
3323 snprintf(LinkPath, sizeof(LinkPath), "%s/%s", BaseDir, FS_UTIME_TESTLINK);
3324 LxtCheckErrnoZeroSuccess(symlink(FilePath, LinkPath));
3325 }
3326
3327 ErrorExit:
3328 return Result;
3329 }
3330
3331 bool LxtFsUtimeDoTimesMatch(const struct timespec* Actual, const struct timespec* Expected, int AllowedVarianceSeconds)
3332
3333 /*++
3334
3335 Routine Description:
3336
3337 This routine compares two timespec structures for equality.
3338
3339 Arguments:
3340
3341 Actual - Supplies a pointer to the times encountered on the file.
3342
3343 Expected - Supplies a pointer to the times expected on the file.
3344
3345 AllowedVarianceSeconds - The amount of seconds that the actual time may
3346 be behind the expected time.
3347
3348 Return Value:
3349
3350 TRUE if the timestamps match, FALSE if they do not.
3351
3352 --*/
3353
3354 {
3355
3356 unsigned long long FullExpectedTime;
3357 unsigned long long FullTime;
3358
3359 FullTime = (Actual->tv_sec * FS_NS_PER_SEC) + Actual->tv_nsec;
3360 FullExpectedTime = (Expected->tv_sec * FS_NS_PER_SEC) + Expected->tv_nsec;
3361 if ((FullTime <= FullExpectedTime) && (FullTime >= (FullExpectedTime - (AllowedVarianceSeconds * FS_NS_PER_SEC))))
3362 {
3363 return true;
3364 }
3365
3366 //
3367 // In VM mode, also allow variance to the future to allow for clock skew between
3368 // the host and guest.
3369 //
3370
3371 if (((g_LxtFsInfo.FsType == LxtFsTypePlan9) || (g_LxtFsInfo.FsType == LxtFsTypeVirtioFs)) &&
3372 (FullTime <= (FullExpectedTime + (AllowedVarianceSeconds * FS_NS_PER_SEC))))
3373 {
3374 return true;
3375 }
3376
3377 LxtLogError(
3378 "Time %lld.%.9ld not within %ds window of expected time %lld.%.9ld",
3379 Actual->tv_sec,
3380 Actual->tv_nsec,
3381 AllowedVarianceSeconds,
3382 Expected->tv_sec,
3383 Expected->tv_nsec);
3384
3385 return false;
3386 }
3387
3388 void LxtFsUtimeRoundToFatAccessTime(struct timespec* Timespec)
3389
3390 /*++
3391
3392 Description:
3393
3394 This routine rounds a timespec to the nearest day, which is what FAT32
3395 uses for the last access time.
3396
3397 Arguments:
3398
3399 Timespec - Supplies the time value.
3400
3401 Return Value:
3402
3403 None.
3404
3405 --*/
3406
3407 {
3408
3409 struct timespec Now;
3410 time_t Time;
3411 struct tm TimeInfo;
3412
3413 //
3414 // When using the current time, there is a slight chance of this test
3415 // failing when the time set for the file and the time when the check
3416 // is done straddle midnight.
3417 //
3418
3419 clock_gettime(CLOCK_REALTIME_COARSE, &Now);
3420 if (Timespec->tv_nsec == UTIME_NOW)
3421 {
3422 *Timespec = Now;
3423 }
3424
3425 //
3426 // FAT32 stores only the day for the last access time, and it stores the
3427 // local time. Here's what happens:
3428 // - When the file time is set, Windows converts it to a local time. It
3429 // uses the current DST setting, not the DST setting that was active at
3430 // the specified time.
3431 // - The date portion of the local time is stored as the file time.
3432 // - When reading the time, Windows converts it back to UTC. Again, this is
3433 // done using the current DST setting.
3434 // - This means the returned time looks like 2017-06-26 17:00:00, based on
3435 // the UTC offset of the current timezone.
3436 //
3437 // Determine the UTC offset of the current time, which ensures we use the
3438 // current DST value.
3439 //
3440
3441 Time = Now.tv_sec;
3442 localtime_r(&Time, &TimeInfo);
3443
3444 //
3445 // Convert the specified time to local time, and round to the nearest day.
3446 //
3447
3448 Timespec->tv_sec += TimeInfo.tm_gmtoff;
3449 Timespec->tv_sec /= FS_SECONDS_PER_DAY;
3450 Timespec->tv_sec *= FS_SECONDS_PER_DAY;
3451
3452 //
3453 // Convert back to UTC.
3454 //
3455
3456 Timespec->tv_sec -= TimeInfo.tm_gmtoff;
3457
3458 //
3459 // Since FAT only stores the day, nsec is always zero.
3460 //
3461
3462 Timespec->tv_nsec = 0;
3463 return;
3464 }
3465
3466 void LxtFsUtimeRoundToFatModifiedTime(struct timespec* Timespec)
3467
3468 /*++
3469
3470 Description:
3471
3472 This routine rounds a timespec to the next highest multiple of two seconds,
3473 which FAT does for the last write time.
3474
3475 Arguments:
3476
3477 Timespec - Supplies the time value.
3478
3479 Return Value:
3480
3481 None.
3482
3483 --*/
3484
3485 {
3486
3487 time_t Time;
3488 struct tm TimeInfo;
3489
3490 if (Timespec->tv_nsec == UTIME_NOW)
3491 {
3492 clock_gettime(CLOCK_REALTIME_COARSE, Timespec);
3493 }
3494
3495 if (((Timespec->tv_sec % FS_FAT_MODIFIED_TIME_PRECISION) != 0) || (Timespec->tv_nsec != 0))
3496 {
3497
3498 Timespec->tv_sec += FS_FAT_MODIFIED_TIME_PRECISION;
3499 }
3500
3501 Timespec->tv_nsec = 0;
3502 Timespec->tv_sec /= FS_FAT_MODIFIED_TIME_PRECISION;
3503 Timespec->tv_sec *= FS_FAT_MODIFIED_TIME_PRECISION;
3504 return;
3505 }
3506
3507 void LxtFsUtimeRoundToNt(struct timespec* Timespec)
3508
3509 /*++
3510
3511 Description:
3512
3513 This routine rounds a timespec to NT precision.
3514
3515 Arguments:
3516
3517 Timespec - Supplies the time value.
3518
3519 Return Value:
3520
3521 None.
3522
3523 --*/
3524
3525 {
3526
3527 //
3528 // WSL rounds up.
3529 //
3530
3531 if (Timespec->tv_nsec != UTIME_NOW)
3532 {
3533 Timespec->tv_nsec += (FS_NS_PER_NT_UNIT - 1);
3534 Timespec->tv_nsec /= FS_NS_PER_NT_UNIT;
3535 Timespec->tv_nsec *= FS_NS_PER_NT_UNIT;
3536 }
3537
3538 return;
3539 }
3540
3541 int LxtFsWritevCommon(char* TestFile)
3542
3543 /*++
3544
3545 Description:
3546
3547 This routine tests the writev system call.
3548
3549 Arguments:
3550
3551 Args - Supplies the test arguments.
3552
3553 TestFile - Supplies the file to test on.
3554
3555 Return Value:
3556
3557 Returns 0 on success, -1 on failure.
3558
3559 --*/
3560
3561 {
3562
3563 char Buffer[100];
3564 char Buffer2[100];
3565 int Bytes;
3566 int FileDescriptor = -1;
3567 int Result;
3568 char ContentA[] = "I am your father! Noooo!";
3569 char ContentB[] = "Go big or go home.";
3570 struct iovec Iov[3];
3571
3572 LxtCheckErrno(FileDescriptor = open(TestFile, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU));
3573 Iov[0].iov_base = ContentA;
3574 Iov[0].iov_len = sizeof(ContentA);
3575 Iov[1].iov_base = ContentB;
3576 Iov[1].iov_len = sizeof(ContentB);
3577 LxtCheckErrno(Bytes = writev(FileDescriptor, Iov, 2));
3578 LxtCheckEqual(Bytes, sizeof(ContentA) + sizeof(ContentB), "%d");
3579 LxtCheckErrno(close(FileDescriptor));
3580
3581 //
3582 // Validate the data with read
3583 //
3584
3585 LxtCheckErrno(FileDescriptor = open(TestFile, O_RDWR, S_IRWXU));
3586 memset(Buffer, 0, sizeof(Buffer));
3587 LxtCheckErrno(Bytes = read(FileDescriptor, Buffer, sizeof(ContentA)));
3588 LxtCheckEqual(Bytes, sizeof(ContentA), "%d");
3589 LxtCheckMemoryEqual(Buffer, ContentA, sizeof(ContentA));
3590 memset(Buffer, 0, sizeof(Buffer));
3591 LxtCheckErrno(Bytes = read(FileDescriptor, Buffer, sizeof(ContentB)));
3592 LxtCheckEqual(Bytes, sizeof(ContentB), "%d");
3593 LxtCheckMemoryEqual(Buffer, ContentB, sizeof(ContentB));
3594 LxtCheckErrno(close(FileDescriptor));
3595
3596 //
3597 // Validate the data with readv
3598 //
3599
3600 LxtCheckErrno(FileDescriptor = open(TestFile, O_RDWR, S_IRWXU));
3601 memset(Iov, 0, sizeof(Iov));
3602 memset(Buffer, 0, sizeof(Buffer));
3603 memset(Buffer2, 0, sizeof(Buffer2));
3604 Iov[0].iov_base = Buffer;
3605 Iov[0].iov_len = sizeof(ContentA);
3606 Iov[1].iov_base = Buffer2;
3607 Iov[1].iov_len = sizeof(ContentB);
3608 LxtCheckErrno(Bytes = readv(FileDescriptor, Iov, 2));
3609 LxtCheckEqual(Bytes, sizeof(ContentA) + sizeof(ContentB), "%d");
3610 LxtCheckMemoryEqual(Iov[0].iov_base, ContentA, sizeof(ContentA));
3611 LxtCheckMemoryEqual(Iov[1].iov_base, ContentB, sizeof(ContentB));
3612 LxtCheckErrno(close(FileDescriptor));
3613
3614 //
3615 // Validate that readv\writev returns the right error code when an invalid
3616 // count is passed.
3617 //
3618
3619 LxtLogInfo("invalid vector count");
3620 LxtCheckErrno(FileDescriptor = open(TestFile, O_RDWR, S_IRWXU));
3621
3622 #ifdef __x86_64__
3623
3624 #define READV_SYSCALL_NR 19
3625
3626 #elif __aarch64__
3627
3628 #define READV_SYSCALL_NR 65
3629
3630 #endif
3631
3632 LxtCheckErrnoFailure(syscall(READV_SYSCALL_NR, FileDescriptor, Iov, -1), EINVAL);
3633 LxtCheckErrnoFailure(syscall(READV_SYSCALL_NR, FileDescriptor, Iov, -1), EINVAL);
3634 LxtCheckErrno(close(FileDescriptor));
3635
3636 //
3637 // Test a zero-length iovector at the beginning of the array, it should be skipped.
3638 //
3639
3640 LxtCheckErrno(FileDescriptor = open(TestFile, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU));
3641 memset(Iov, 0, sizeof(Iov));
3642 Iov[0].iov_base = ContentA;
3643 Iov[1].iov_base = ContentB;
3644 Iov[1].iov_len = sizeof(ContentB);
3645 LxtCheckErrno(Bytes = writev(FileDescriptor, Iov, 2));
3646 LxtCheckEqual(Bytes, sizeof(ContentB), "%d");
3647 LxtCheckErrno(close(FileDescriptor));
3648
3649 LxtCheckErrno(FileDescriptor = open(TestFile, O_RDWR, S_IRWXU));
3650 memset(Buffer, 0, sizeof(Buffer));
3651 LxtCheckErrno(Bytes = read(FileDescriptor, Buffer, sizeof(ContentB)));
3652 LxtCheckEqual(Bytes, sizeof(ContentB), "%d");
3653 LxtCheckMemoryEqual(Buffer, ContentB, sizeof(ContentB));
3654 LxtCheckErrno(close(FileDescriptor));
3655
3656 //
3657 // Test an invalid buffer after a valid buffer. The writev call should return the
3658 // number of bytes written until the invalid buffer.
3659 //
3660
3661 LxtCheckErrno(FileDescriptor = open(TestFile, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU));
3662 memset(Iov, 0, sizeof(Iov));
3663 Iov[0].iov_base = ContentA;
3664 Iov[0].iov_len = sizeof(ContentA);
3665 Iov[1].iov_base = NULL;
3666 Iov[1].iov_len = sizeof(ContentB);
3667 Iov[2].iov_base = ContentB;
3668 Iov[2].iov_len = sizeof(ContentB);
3669 LxtLogInfo("%d", g_LxtFsInfo.FsType);
3670 LxtCheckErrno(Bytes = writev(FileDescriptor, Iov, 3));
3671 LxtCheckEqual(Bytes, sizeof(ContentA), "%d");
3672 LxtCheckErrno(close(FileDescriptor));
3673
3674 LxtCheckErrno(FileDescriptor = open(TestFile, O_RDWR, S_IRWXU));
3675 memset(Buffer, 0, sizeof(Buffer));
3676 LxtCheckErrno(Bytes = read(FileDescriptor, Buffer, sizeof(ContentA)));
3677 LxtCheckEqual(Bytes, sizeof(ContentA), "%d");
3678 LxtCheckErrno(Bytes = read(FileDescriptor, Buffer, sizeof(ContentB)));
3679 LxtCheckEqual(Bytes, 0, "%d");
3680
3681 Result = LXT_RESULT_SUCCESS;
3682
3683 ErrorExit:
3684 if (FileDescriptor != -1)
3685 {
3686 close(FileDescriptor);
3687 }
3688
3689 unlink(TestFile);
3690 return Result;
3691 }
3692
3693 int LxtFsDirSeekCommon(const char* BaseDir)
3694
3695 /*++
3696
3697 Description:
3698
3699 This routine tests the seek operation on a directory.
3700
3701 Arguments:
3702
3703 BaseDir - Supplies the directory to use. for the test. The directory should
3704 not already exist.
3705
3706 Return Value:
3707
3708 Returns 0 on success, -1 on failure.
3709
3710 --*/
3711
3712 {
3713
3714 char Buffer[4096];
3715 int DirFd;
3716 int Result;
3717 int Size;
3718 int FirstSize;
3719
3720 //
3721 // Create the base directory.
3722 //
3723
3724 LxtCheckErrnoZeroSuccess(mkdir(BaseDir, 0777));
3725 LxtCheckErrno(DirFd = open(BaseDir, O_RDONLY | O_DIRECTORY));
3726 LxtCheckErrno(Size = syscall(SYS_getdents64, DirFd, Buffer, sizeof(Buffer)));
3727
3728 //
3729 // Directory should at least have one entry.
3730 //
3731
3732 if (Size == 0)
3733 {
3734 LxtLogError("Directory is expected to at least have one entry.");
3735 Result = EINVAL;
3736 goto ErrorExit;
3737 }
3738
3739 //
3740 // Store the value returned from the first call to 'getdents'.
3741 //
3742
3743 FirstSize = Size;
3744
3745 //
3746 // Once the end of directory has reached, getdents should return 0.
3747 //
3748
3749 LxtCheckErrno(Size = syscall(SYS_getdents64, DirFd, Buffer, sizeof(Buffer)));
3750 if (Size != 0)
3751 {
3752 LxtLogError(
3753 "getdents should return 0 when end of directory is reached, "
3754 "but it returned: %d.",
3755 Size);
3756
3757 Result = EINVAL;
3758 goto ErrorExit;
3759 }
3760
3761 LxtCheckErrno(lseek(DirFd, 0, SEEK_SET));
3762 LxtCheckErrno(Size = syscall(SYS_getdents64, DirFd, Buffer, sizeof(Buffer)));
3763
3764 //
3765 // Directory should at least have one entry.
3766 //
3767
3768 if (Size == 0)
3769 {
3770 LxtLogError(
3771 "lseek on a dir should rewind the cursor position, but it "
3772 "did not.");
3773
3774 Result = EINVAL;
3775 goto ErrorExit;
3776 }
3777
3778 if (Size != FirstSize)
3779 {
3780 LxtLogError(
3781 "getdents value should not have changed from first call. "
3782 "First getdents: %d, Second getdents: %d",
3783 FirstSize,
3784 Size);
3785
3786 Result = EINVAL;
3787 goto ErrorExit;
3788 }
3789
3790 Result = LXT_RESULT_SUCCESS;
3791
3792 ErrorExit:
3793 if (DirFd >= 0)
3794 {
3795 close(DirFd);
3796 }
3797
3798 rmdir(BaseDir);
3799 return Result;
3800 }