master
c 4,385 lines 122 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 drvfs.c
8
9 Abstract:
10
11 This file contains tests for the drvfs file system plugin.
12
13 The drvfs tests are kept separate from other file system tests to make it
14 possible to run the tests in "fallback mode," the mode drvfs operates in
15 when NtQueryInformationByName or FILE_STAT_INFORMATION are not supported
16 by the underlying file system.
17
18 Additionally, most of these tests do not pass on native Linux, so keeping
19 the drvfs tests apart makes it easier to validate the other file system
20 tests on native Linux.
21
22 --*/
23
24 #include "lxtcommon.h"
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/uio.h>
28 #include <sys/syscall.h>
29 #include <sys/inotify.h>
30 #include <sys/mount.h>
31 #include <sys/signalfd.h>
32 #include <sys/sysmacros.h>
33 #include <sys/wait.h>
34 #include <sys/mman.h>
35 #include <fcntl.h>
36 #include <dirent.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <libmount/libmount.h>
40 #include "lxtfs.h"
41 #include "lxtmount.h"
42
43 #define LXT_NAME_FORMAT "drvfs%d"
44
45 #define DRVFS_DRIVE "C:"
46 #define DRVFS_FAT_MOUNT_POINT "lxss_fat"
47 #define DRVFS_FAT_DRIVE "C:/" DRVFS_FAT_MOUNT_POINT
48 #define DRVFS_UNC_PATH "//localhost/C$"
49 #define DRVFS_FAT_TEST_MODE (3)
50 #define DRVFS_SMB_TEST_MODE (4)
51 #define DRVFS_METADATA_TEST_MODE (5)
52 #define DRVFS_REFS_TEST_MODE (6)
53 #define DRVFS_REFS_MOUNT_POINT "lxss_refs"
54 #define DRVFS_REFS_DRIVE "C:/" DRVFS_REFS_MOUNT_POINT
55 #define DRVFS_FS_TYPE "drvfs"
56 #define DRVFS_MOUNT_OPTIONS (MS_NOATIME)
57 #define DRVFS_PREFIX "/mnt/c"
58 #define DRVFS_CS_PREFIX DRVFS_PREFIX "/casesensitive"
59 #define DRVFS_BASIC_PREFIX DRVFS_PREFIX "/basictest"
60 #define DRVFS_RENAME_PREFIX DRVFS_PREFIX "/renametest"
61 #define DRVFS_REPARSE_PREFIX DRVFS_PREFIX "/reparsetest"
62 #define DRVFS_MOUNT_TEST_DIR "/data/mount_test"
63 #define DRVFS_ACCESS_TEST_DIR DRVFS_PREFIX "/drvfstest"
64 #define DRVFS_ACCESS_RWX_TEST_FILE DRVFS_ACCESS_TEST_DIR "/rwx"
65 #define DRVFS_ACCESS_READONLY_TEST_FILE DRVFS_ACCESS_TEST_DIR "/readonly"
66 #define DRVFS_ACCESS_WRITEONLY_TEST_FILE DRVFS_ACCESS_TEST_DIR "/writeonly"
67 #define DRVFS_ACCESS_EXECUTEONLY_TEST_FILE DRVFS_ACCESS_TEST_DIR "/executeonly"
68 #define DRVFS_ACCESS_EXECUTEONLY_TEST_DIR DRVFS_ACCESS_TEST_DIR "/executeonlydir"
69 #define DRVFS_ACCESS_READONLYATTR_TEST_FILE DRVFS_ACCESS_TEST_DIR "/readonlyattr"
70 #define DRVFS_ACCESS_READONLYATTRDEL_TEST_FILE DRVFS_ACCESS_TEST_DIR "/readonlyattrdel"
71 #define DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD DRVFS_ACCESS_EXECUTEONLY_TEST_DIR "/child"
72 #define DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD2 DRVFS_ACCESS_EXECUTEONLY_TEST_DIR "/child2"
73 #define DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD_LINK DRVFS_ACCESS_EXECUTEONLY_TEST_DIR "/link"
74 #define DRVFS_ACCESS_READONLY_TEST_DIR DRVFS_ACCESS_TEST_DIR "/noexecutedir"
75 #define DRVFS_INOTIFY_TEST_BASE_DIR DRVFS_PREFIX "/inotify_test/"
76 #define DRVFS_UTIME_TEST_DIR DRVFS_PREFIX "/utimensat_test"
77 #define DRVFS_WRITEV_TEST_DIR DRVFS_PREFIX "/writev_test"
78 #define DRVFS_RENAMEAT_TEST_DIR DRVFS_PREFIX "/renameat_test"
79 #define DRVFS_CASE_INSENSITIVE_TEST_DIR DRVFS_PREFIX "/case_insensitive_test"
80 #define DRVFS_UNSUPPORTED_TEST_DIR DRVFS_PREFIX "/unsupported_test"
81 #define DRVFS_HARDLINK_TEST_DIR DRVFS_PREFIX "/hardlink_test"
82 #define DRVFS_DELETELOOP_PREFIX DRVFS_PREFIX "/deleteloop"
83 #define DRVFS_GETDENTS_PREFIX DRVFS_PREFIX "/getdents"
84 #define DRVFS_SYMLINK_TEST_DIR DRVFS_PREFIX "/symlink"
85 #define DRVFS_METADATA_TEST_DIR DRVFS_PREFIX "/metadatatest"
86 #define DRVFS_ESCAPE_TEST_DIR DRVFS_PREFIX "/escaped"
87 #define DRVFS_ESCAPE_TEST_CHILD_NAME "\\:\b\u8a9e\uefff\uf025\uf100\ufb00\uf02f"
88 #define DRVFS_ESCAPE_TEST_CHILD DRVFS_ESCAPE_TEST_DIR "/" DRVFS_ESCAPE_TEST_CHILD_NAME
89 #define DRVFS_ESCAPE_TEST_CHILD_ESCAPED DRVFS_ESCAPE_TEST_DIR "/\uf05c\uf03a\uf008\u8a9e\uefff\uf025\uf100\ufb00\uf02f"
90
91 //
92 // The following macros are used by TestInotifyComprehensiveDrvfs.
93 //
94
95 #define DRVFS_INOTIFY_DIR_1 "a/"
96 #define DRVFS_INOTIFY_DIR_2 "a/b/"
97 #define DRVFS_INOTIFY_DIR_3 "a/b/c/"
98 #define DRVFS_INOTIFY_FILE_1_NAME_ONLY "a.txt"
99 #define DRVFS_INOTIFY_FILE_2_NAME_ONLY "b.txt"
100 #define DRVFS_INOTIFY_FILE_3_NAME_ONLY "c.txt"
101 #define DRVFS_INOTIFY_FILE_1 DRVFS_INOTIFY_DIR_3 DRVFS_INOTIFY_FILE_1_NAME_ONLY
102 #define DRVFS_INOTIFY_FILE_2 DRVFS_INOTIFY_DIR_3 DRVFS_INOTIFY_FILE_2_NAME_ONLY
103 #define DRVFS_INOTIFY_FILE_3 DRVFS_INOTIFY_DIR_3 DRVFS_INOTIFY_FILE_3_NAME_ONLY
104
105 //
106 // The following macros are used by TestInotifyStressUnlinkRenameDrvfs.
107 //
108
109 #define DRVFS_INOTIFY_STRESS_DIR "stress/"
110 #define DRVFS_INOTIFY_STRESS_NUM_FILES 2
111 #define DRVFS_INOTIFY_STRESS_NUM_TESTS 1000
112
113 #define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
114 #define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
115 #define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
116
117 #define DRVFS_EXECVE_TEST_RESULT (123)
118
119 int DrvFsCheckMode(const char* Filename, mode_t ExpectedMode);
120
121 int DrvFsCheckStat(const char* Filename, uid_t ExpectedUid, gid_t ExpectedGid, mode_t ExpectedMode, dev_t ExpectedDevice);
122
123 int DrvFsParseArgs(int Argc, char* Argv[], LXT_ARGS* Args);
124
125 LXT_VARIATION_HANDLER DrvFsTestAccess;
126
127 LXT_VARIATION_HANDLER DrvFsTestBadMetadata;
128
129 LXT_VARIATION_HANDLER DrvFsTestBasic;
130
131 LXT_VARIATION_HANDLER DrvFsTestBlockCount;
132
133 LXT_VARIATION_HANDLER DrvFsTestCaseSensitivity;
134
135 LXT_VARIATION_HANDLER DrvFsTestCaseSensitivityRoot;
136
137 LXT_VARIATION_HANDLER DrvFsTestDeleteCurrentWorkingDirectory;
138
139 LXT_VARIATION_HANDLER DrvFsTestDeleteLoop;
140
141 LXT_VARIATION_HANDLER DrvFsTestDeleteOpenFile;
142
143 LXT_VARIATION_HANDLER DrvFsTestEscapedNames;
144
145 LXT_VARIATION_HANDLER DrvFsTestExecve;
146
147 LXT_VARIATION_HANDLER DrvFsTestFatCaseInsensitive;
148
149 LXT_VARIATION_HANDLER DrvFsTestFatJunction;
150
151 LXT_VARIATION_HANDLER DrvFsTestFatUnsupported;
152
153 LXT_VARIATION_HANDLER DrvFsTestFatUtimensat;
154
155 LXT_VARIATION_HANDLER DrvFsTestFatWslPath;
156
157 LXT_VARIATION_HANDLER DrvFsTestFstat;
158
159 LXT_VARIATION_HANDLER DrvFsTestStatx;
160
161 LXT_VARIATION_HANDLER DrvFsTestGetDents64Alignment;
162
163 LXT_VARIATION_HANDLER DrvFsTestGetDentsAlignment;
164
165 LXT_VARIATION_HANDLER DrvFsTestHardLinks;
166
167 LXT_VARIATION_HANDLER DrvFsTestHiddenLxFsDirs;
168
169 int DrvFsTestHiddenLxFsDirsHelper(const char* Child, BOOLEAN DirectChild);
170
171 LXT_VARIATION_HANDLER DrvFsTestInotifyBasic;
172
173 LXT_VARIATION_HANDLER DrvFsTestInotifyEpoll;
174
175 LXT_VARIATION_HANDLER DrvFsTestInotifyPosixUnlinkRename;
176
177 LXT_VARIATION_HANDLER DrvFsTestInotifyStressUnlinkRename;
178
179 LXT_VARIATION_HANDLER DrvFsTestInotifyUnmountBind;
180
181 LXT_VARIATION_HANDLER DrvFsTestLookupPath;
182
183 LXT_VARIATION_HANDLER DrvFsTestMetadata;
184
185 LXT_VARIATION_HANDLER DrvFsTestReFsWslPath;
186
187 LXT_VARIATION_HANDLER DrvFsTestRename;
188
189 LXT_VARIATION_HANDLER DrvFsTestRenameAt;
190
191 LXT_VARIATION_HANDLER DrvFsTestRenameDir;
192
193 LXT_VARIATION_HANDLER DrvFsTestReopenUnlinked;
194
195 LXT_VARIATION_HANDLER DrvFsTestReparse;
196
197 LXT_VARIATION_HANDLER DrvFsTestSeek;
198
199 LXT_VARIATION_HANDLER DrvFsTestDirSeek;
200
201 int DrvFsTestSeekHelper(int Fd, off_t Offset, int Whence, off_t ExpectedOffset, const char* TestData, int TestDataSize);
202
203 int DrvFsTestSetup(PLXT_ARGS Args, int TestMode);
204
205 LXT_VARIATION_HANDLER DrvFsTestSmbUtimensat;
206
207 LXT_VARIATION_HANDLER DrvFsTestSmbUnsupported;
208
209 LXT_VARIATION_HANDLER DrvFsTestSmbWslPath;
210
211 LXT_VARIATION_HANDLER DrvFsTestSymlink;
212
213 int DrvFsTestSymlinkHelper(char* Target, char* Path);
214
215 int DrvFsTestUnsupportedCommon(int TestMode);
216
217 LXT_VARIATION_HANDLER DrvFsTestUtimensat;
218
219 int DrvFsTestUtimensatCommon(int Flags);
220
221 LXT_VARIATION_HANDLER DrvFsTestWritev;
222
223 //
224 // Globals.
225 //
226
227 static const LXT_VARIATION g_LxtVariations[] = {
228 {"DrvFs - basic", DrvFsTestBasic},
229 {"DrvFs - lookup by path", DrvFsTestLookupPath},
230 {"DrvFs - writev", DrvFsTestWritev},
231 {"DrvFs - rename", DrvFsTestRename},
232 {"DrvFs - renameat", DrvFsTestRenameAt},
233 {"DrvFs - rename directory", DrvFsTestRenameDir},
234 {"DrvFs - deleting an open file", DrvFsTestDeleteOpenFile},
235 {"DrvFs - deleting the working directory", DrvFsTestDeleteCurrentWorkingDirectory},
236 {"DrvFs - case-sensitivity", DrvFsTestCaseSensitivity},
237 {"DrvFs - case-sensitivity (drive root)", DrvFsTestCaseSensitivityRoot},
238 {"DrvFs - reparse points", DrvFsTestReparse},
239 {"DrvFs - access checks", DrvFsTestAccess},
240 {"DrvFs - execve", DrvFsTestExecve},
241 {"DrvFs - hidden lxfs directories", DrvFsTestHiddenLxFsDirs},
242 {"DrvFs - inotify with epoll", DrvFsTestInotifyEpoll},
243 {"DrvFs - inotify watching basic paths", DrvFsTestInotifyBasic},
244 {"DrvFs - inotify unmounting of a bind mount", DrvFsTestInotifyUnmountBind},
245 {"DrvFs - inotify POSIX unlink/rename", DrvFsTestInotifyPosixUnlinkRename},
246 {"DrvFs - inotify stress test with unlink and rename", DrvFsTestInotifyStressUnlinkRename},
247 {"DrvFs - utimensat", DrvFsTestUtimensat},
248 {"DrvFs - hard links", DrvFsTestHardLinks},
249 {"DrvFs - block count", DrvFsTestBlockCount},
250 {"DrvFs - fstat", DrvFsTestFstat},
251 {"DrvFs - statx", DrvFsTestStatx},
252 {"DrvFs - reopen unlinked file", DrvFsTestReopenUnlinked},
253 {"DrvFs - delete loop", DrvFsTestDeleteLoop},
254 {"DrvFs - seek", DrvFsTestSeek},
255 {"DrvFs - dir seek", DrvFsTestDirSeek},
256 #ifdef __NR_getdents
257 {"DrvFs - getdents alignment", DrvFsTestGetDentsAlignment},
258 #endif
259 {"DrvFs - getdents64 alignment", DrvFsTestGetDents64Alignment},
260 {"DrvFs - LX and NT symlink creation", DrvFsTestSymlink},
261 {"DrvFs - escaped names", DrvFsTestEscapedNames}};
262
263 //
264 // The following variations apply to FAT volumes.
265 //
266
267 static const LXT_VARIATION g_LxtFatVariations[] = {
268 {"DrvFs - basic", DrvFsTestBasic},
269 {"DrvFs - lookup by path", DrvFsTestLookupPath},
270 {"DrvFs - writev", DrvFsTestWritev},
271 {"DrvFs - rename", DrvFsTestRename},
272 {"DrvFs - renameat", DrvFsTestRenameAt},
273 {"DrvFs - inotify with epoll", DrvFsTestInotifyEpoll},
274 {"DrvFs - inotify unmounting of a bind mount", DrvFsTestInotifyUnmountBind},
275 {"DrvFs - block count", DrvFsTestBlockCount},
276 {"DrvFs - FAT32 case-insensitive", DrvFsTestFatCaseInsensitive},
277 {"DrvFs - FAT32 unsupported features", DrvFsTestFatUnsupported},
278 {"DrvFs - FAT32 utimensat", DrvFsTestFatUtimensat},
279 {"DrvFs - FAT32 mount point junction", DrvFsTestFatJunction},
280 {"DrvFs - fstat", DrvFsTestFstat},
281 {"DrvFs - delete loop", DrvFsTestDeleteLoop},
282 {"DrvFs - seek", DrvFsTestSeek},
283 #ifdef __NR_getdents
284 {"DrvFs - getdents alignment", DrvFsTestGetDentsAlignment},
285 #endif
286 {"DrvFs - getdents64 alignment", DrvFsTestGetDents64Alignment},
287 {"DrvFs - escaped names", DrvFsTestEscapedNames},
288 {"DrvFs - wslpath NTFS directory mount", DrvFsTestFatWslPath}};
289
290 //
291 // The following variations apply to SMB shares.
292 //
293
294 static const LXT_VARIATION g_LxtSmbVariations[] = {
295 {"DrvFs - basic", DrvFsTestBasic},
296 {"DrvFs - lookup by path", DrvFsTestLookupPath},
297 {"DrvFs - writev", DrvFsTestWritev},
298 {"DrvFs - rename", DrvFsTestRename},
299 {"DrvFs - renameat", DrvFsTestRenameAt},
300 {"DrvFs - hard links", DrvFsTestHardLinks},
301 {"DrvFs - SMB case-insensitive", DrvFsTestFatCaseInsensitive},
302 {"DrvFs - SMB unsupported features", DrvFsTestSmbUnsupported},
303 {"DrvFs - SMB utimensat", DrvFsTestSmbUtimensat},
304 {"DrvFs - fstat", DrvFsTestFstat},
305 {"DrvFs - delete loop", DrvFsTestDeleteLoop},
306 {"DrvFs - seek", DrvFsTestSeek},
307 #ifdef __NR_getdents
308 {"DrvFs - getdents alignment", DrvFsTestGetDentsAlignment},
309 #endif
310 {"DrvFs - getdents64 alignment", DrvFsTestGetDents64Alignment},
311 {"DrvFs - escaped names", DrvFsTestEscapedNames},
312 {"DrvFs - wslpath UNC", DrvFsTestSmbWslPath}};
313
314 //
315 // The following variations apply when metadata is on.
316 //
317
318 static const LXT_VARIATION g_LxtMetadataVariations[] = {
319 {"DrvFs - basic", DrvFsTestBasic},
320 {"DrvFs - lookup by path", DrvFsTestLookupPath},
321 {"DrvFs - writev", DrvFsTestWritev},
322 {"DrvFs - rename", DrvFsTestRename},
323 {"DrvFs - renameat", DrvFsTestRenameAt},
324 {"DrvFs - rename directory", DrvFsTestRenameDir},
325 {"DrvFs - deleting an open file", DrvFsTestDeleteOpenFile},
326 {"DrvFs - deleting the working directory", DrvFsTestDeleteCurrentWorkingDirectory},
327 {"DrvFs - case-sensitivity", DrvFsTestCaseSensitivity},
328 {"DrvFs - case-sensitivity (drive root)", DrvFsTestCaseSensitivityRoot},
329 {"DrvFs - reparse points", DrvFsTestReparse},
330 {"DrvFs - access checks", DrvFsTestAccess},
331 {"DrvFs - execve", DrvFsTestExecve},
332 {"DrvFs - hidden lxfs directories", DrvFsTestHiddenLxFsDirs},
333 {"DrvFs - inotify with epoll", DrvFsTestInotifyEpoll},
334 {"DrvFs - inotify watching basic paths", DrvFsTestInotifyBasic},
335 {"DrvFs - inotify unmounting of a bind mount", DrvFsTestInotifyUnmountBind},
336 {"DrvFs - inotify POSIX unlink/rename", DrvFsTestInotifyPosixUnlinkRename},
337 {"DrvFs - inotify stress test with unlink and rename", DrvFsTestInotifyStressUnlinkRename},
338 {"DrvFs - utimensat", DrvFsTestUtimensat},
339 {"DrvFs - hard links", DrvFsTestHardLinks},
340 {"DrvFs - block count", DrvFsTestBlockCount},
341 {"DrvFs - fstat", DrvFsTestFstat},
342 {"DrvFs - statx", DrvFsTestStatx},
343 {"DrvFs - reopen unlinked file", DrvFsTestReopenUnlinked},
344 {"DrvFs - delete loop", DrvFsTestDeleteLoop},
345 {"DrvFs - seek", DrvFsTestSeek},
346 {"DrvFs - dir seek", DrvFsTestDirSeek},
347 #ifdef __NR_getdents
348 {"DrvFs - getdents alignment", DrvFsTestGetDentsAlignment},
349 #endif
350 {"DrvFs - getdents64 alignment", DrvFsTestGetDents64Alignment},
351 {"DrvFs - LX and NT symlink creation", DrvFsTestSymlink},
352 {"DrvFs - bad metadata", DrvFsTestBadMetadata},
353 {"DrvFs - metadata", DrvFsTestMetadata},
354 {"DrvFs - escaped names", DrvFsTestEscapedNames}};
355
356 static const LXT_VARIATION g_LxtReFsVariations[] = {
357 {"DrvFs - basic", DrvFsTestBasic},
358 {"DrvFs - lookup by path", DrvFsTestLookupPath},
359 {"DrvFs - writev", DrvFsTestWritev},
360 {"DrvFs - rename", DrvFsTestRename},
361 {"DrvFs - renameat", DrvFsTestRenameAt},
362 {"DrvFs - rename directory", DrvFsTestRenameDir},
363 {"DrvFs - deleting an open file", DrvFsTestDeleteOpenFile},
364 {"DrvFs - deleting the working directory", DrvFsTestDeleteCurrentWorkingDirectory},
365 {"DrvFs - case-sensitivity", DrvFsTestCaseSensitivity},
366 {"DrvFs - case-sensitivity (drive root)", DrvFsTestCaseSensitivityRoot},
367 {"DrvFs - hidden lxfs directories", DrvFsTestHiddenLxFsDirs},
368 {"DrvFs - inotify with epoll", DrvFsTestInotifyEpoll},
369 {"DrvFs - inotify unmounting of a bind mount", DrvFsTestInotifyUnmountBind},
370 {"DrvFs - inotify POSIX unlink/rename", DrvFsTestInotifyPosixUnlinkRename},
371 {"DrvFs - utimensat", DrvFsTestUtimensat},
372 {"DrvFs - hard links", DrvFsTestHardLinks},
373 {"DrvFs - block count", DrvFsTestBlockCount},
374 {"DrvFs - fstat", DrvFsTestFstat},
375 {"DrvFs - statx", DrvFsTestStatx},
376 {"DrvFs - reopen unlinked file", DrvFsTestReopenUnlinked},
377 {"DrvFs - delete loop", DrvFsTestDeleteLoop},
378 {"DrvFs - seek", DrvFsTestSeek},
379 {"DrvFs - dir seek", DrvFsTestDirSeek},
380 #ifdef __NR_getdents
381 {"DrvFs - getdents alignment", DrvFsTestGetDentsAlignment},
382 #endif
383 {"DrvFs - getdents64 alignment", DrvFsTestGetDents64Alignment},
384 {"DrvFs - LX and NT symlink creation", DrvFsTestSymlink},
385 //{"DrvFs - escaped names", DrvFsTestEscapedNames},// TODO: enable this variation when lxutil is fixed
386 {"DrvFs - wslpath ReFS", DrvFsTestReFsWslPath}};
387
388 static char* VfsAccessLxssDir;
389 static int DrvFsTestMode;
390
391 int DrvfsTestEntry(int Argc, char* Argv[])
392
393 /*++
394 --*/
395
396 {
397
398 LXT_ARGS Args;
399 int Result;
400
401 if ((Argc == 2) && (strcmp(Argv[1], "execvetest") == 0))
402 {
403 return DRVFS_EXECVE_TEST_RESULT;
404 }
405
406 LXT_SYNCHRONIZATION_POINT_INIT();
407 LxtCheckResult(DrvFsParseArgs(Argc, Argv, &Args));
408
409 ErrorExit:
410 LXT_SYNCHRONIZATION_POINT_DESTROY();
411 LxtUninitialize();
412 return !LXT_SUCCESS(Result);
413 }
414
415 int DrvFsCheckMode(const char* Filename, mode_t ExpectedMode)
416
417 /*++
418
419 Description:
420
421 This routine checks if a file's mode matches the expected value.
422
423 Arguments:
424
425 Filename - Supplies the file name.
426
427 ExpectedMode - Supplies the mode.
428
429 Return Value:
430
431 Returns 0 on success, -1 on failure.
432
433 --*/
434
435 {
436
437 int Result;
438 struct stat Stat;
439
440 LxtCheckErrnoZeroSuccess(lstat(Filename, &Stat));
441 LxtLogInfo("%s: mode 0%o", Filename, Stat.st_mode);
442 LxtCheckEqual(Stat.st_mode, ExpectedMode, "0%o");
443
444 ErrorExit:
445 return Result;
446 }
447
448 int DrvFsCheckStat(const char* Filename, uid_t ExpectedUid, gid_t ExpectedGid, mode_t ExpectedMode, dev_t ExpectedDevice)
449
450 /*++
451
452 Description:
453
454 This routine checks whether the attributes of a file match the expected
455 values.
456
457 Arguments:
458
459 Filename - Supplies the name of the file.
460
461 ExpectedUid - Supplies the expected value for the uid.
462
463 ExpectedGid - Supplies the expected value for the uid.
464
465 ExpectedMode - Supplies the expected value for the mode.
466
467 ExpectedDevice - Supplies the expected value for the device.
468
469 Return Value:
470
471 Returns 0 on success, -1 on failure.
472
473 --*/
474
475 {
476
477 int Result;
478 struct stat Stat;
479
480 LxtCheckErrnoZeroSuccess(lstat(Filename, &Stat));
481 LxtCheckEqual(Stat.st_uid, ExpectedUid, "%d");
482 LxtCheckEqual(Stat.st_gid, ExpectedGid, "%d");
483 LxtCheckEqual(Stat.st_mode, ExpectedMode, "0%o");
484 LxtCheckEqual(Stat.st_rdev, ExpectedDevice, "0x%lx");
485
486 ErrorExit:
487 return Result;
488 }
489
490 int DrvFsParseArgs(int Argc, char* Argv[], LXT_ARGS* Args)
491
492 /*++
493
494 Routine Description:
495
496 This routine parses command line arguments for the vfsaccess tests.
497
498 Arguments:
499
500 Argc - Supplies the number of arguments.
501
502 Argv - Supplies an array of arguments.
503
504 Return Value:
505
506 Returns 0 on success, -1 on failure.
507
508 --*/
509
510 {
511
512 int ArgvIndex;
513 char Name[100];
514 int Result;
515 int TestMode;
516 int ValidArguments;
517 unsigned int VariationCount;
518 const LXT_VARIATION* Variations;
519
520 Result = LXT_RESULT_FAILURE;
521 Variations = g_LxtVariations;
522 VariationCount = LXT_COUNT_OF(g_LxtVariations);
523 TestMode = 0;
524 ValidArguments = 0;
525 if (Argc < 1)
526 {
527 goto ErrorExit;
528 }
529
530 for (ArgvIndex = 1; ArgvIndex < Argc; ++ArgvIndex)
531 {
532 if (Argv[ArgvIndex][0] != '-')
533 {
534 printf("Unexpected character %s", Argv[ArgvIndex]);
535 goto ErrorExit;
536 }
537
538 switch (Argv[ArgvIndex][1])
539 {
540 case 'v':
541 case 'l':
542
543 //
544 // This was already taken care of by LxtInitialize.
545 //
546
547 ++ArgvIndex;
548
549 break;
550
551 case 'd':
552 ++ArgvIndex;
553 if (ArgvIndex < Argc)
554 {
555 ValidArguments = 1;
556 VfsAccessLxssDir = Argv[ArgvIndex];
557 }
558
559 break;
560
561 case 'm':
562 ++ArgvIndex;
563 if (ArgvIndex < Argc)
564 {
565 ValidArguments = -1;
566 TestMode = atoi(Argv[ArgvIndex]);
567 switch (TestMode)
568 {
569 case DRVFS_FAT_TEST_MODE:
570 LxtLogInfo("Running FAT variations.");
571 Variations = g_LxtFatVariations;
572 VariationCount = LXT_COUNT_OF(g_LxtFatVariations);
573 break;
574
575 case DRVFS_SMB_TEST_MODE:
576 LxtLogInfo("Running SMB variations.");
577 Variations = g_LxtSmbVariations;
578 VariationCount = LXT_COUNT_OF(g_LxtSmbVariations);
579 break;
580
581 case DRVFS_METADATA_TEST_MODE:
582 LxtLogInfo("Running metadata variations.");
583 Variations = g_LxtMetadataVariations;
584 VariationCount = LXT_COUNT_OF(g_LxtMetadataVariations);
585 break;
586
587 case DRVFS_REFS_TEST_MODE:
588 LxtLogInfo("Running ReFs variations.");
589 Variations = g_LxtReFsVariations;
590 VariationCount = LXT_COUNT_OF(g_LxtReFsVariations);
591 break;
592 }
593 }
594
595 break;
596
597 case 'h':
598 case 'a':
599 break;
600
601 default:
602 goto ErrorExit;
603 }
604 }
605
606 //
607 // If -c was not specified, just run the tests
608 //
609
610 ValidArguments = 1;
611 DrvFsTestMode = TestMode;
612 snprintf(Name, sizeof(Name), LXT_NAME_FORMAT, TestMode);
613 LxtCheckResult(LxtInitialize(Argc, Argv, Args, Name));
614 LxtCheckResult(DrvFsTestSetup(Args, TestMode));
615 LxtCheckResult(LxtRunVariations(Args, Variations, VariationCount));
616
617 ErrorExit:
618
619 //
620 // Remount drvfs normally.
621 //
622
623 chdir("/");
624 umount(DRVFS_PREFIX);
625 LxtFsMountDrvFs(DRVFS_DRIVE, DRVFS_PREFIX, NULL);
626 if (ValidArguments == 0)
627 {
628 printf("\nuse: %s <One of the below arguments>\n", Argv[0]);
629 printf("\t-d : lxfs directory\n");
630 printf("\t-m : test mode\n");
631 }
632
633 return Result;
634 }
635
636 int DrvFsTestAccess(PLXT_ARGS Args)
637
638 /*++
639
640 Description:
641
642 This routine tests access permissions on DrvFs.
643
644 N.B. Test files with proper permissions are created by the TAEF DLL.
645
646 Arguments:
647
648 Args - Supplies the command line arguments.
649
650 Return Value:
651
652 Returns 0 on success, -1 on failure.
653
654 --*/
655
656 {
657
658 ssize_t Bytes;
659 char Buf[100] = {0};
660 int Fd;
661 int Result;
662
663 //
664 // File with read/write/execute access.
665 //
666
667 Fd = -1;
668 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_RWX_TEST_FILE, S_IFREG | S_IRUGO | S_IWUGO | S_IXUGO));
669
670 LxtCheckErrno(Fd = open(DRVFS_ACCESS_RWX_TEST_FILE, O_RDWR));
671 LxtCheckErrnoZeroSuccess(close(Fd));
672 Fd = -1;
673
674 //
675 // Readonly file. This file can only be opened for read, and writing should
676 // fail. O_PATH always works.
677 //
678
679 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_READONLY_TEST_FILE, S_IFREG | S_IRUGO));
680
681 LxtCheckErrno(Fd = open(DRVFS_ACCESS_READONLY_TEST_FILE, O_RDONLY));
682 LxtCheckErrno(Bytes = read(Fd, Buf, sizeof(Buf)));
683 LxtCheckEqual(Bytes, 0L, "%ld");
684 LxtCheckErrnoFailure(write(Fd, Buf, sizeof(Buf)), EBADF);
685 LxtCheckErrnoZeroSuccess(close(Fd));
686 LxtCheckErrnoFailure(Fd = open(DRVFS_ACCESS_READONLY_TEST_FILE, O_WRONLY), EACCES);
687
688 LxtCheckErrnoFailure(Fd = open(DRVFS_ACCESS_READONLY_TEST_FILE, O_RDWR), EACCES);
689
690 LxtCheckErrno(Fd = open(DRVFS_ACCESS_READONLY_TEST_FILE, O_PATH));
691 LxtCheckErrnoFailure(read(Fd, Buf, sizeof(Buf)), EBADF);
692 LxtCheckErrnoFailure(write(Fd, Buf, sizeof(Buf)), EBADF);
693 LxtCheckErrnoZeroSuccess(close(Fd));
694 Fd = -1;
695
696 //
697 // File with read/write/execute access, but the read-only attribute set.
698 // This file can only be opened for read, and writing should fail.
699 // O_PATH always works.
700 //
701
702 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_READONLYATTR_TEST_FILE, S_IFREG | S_IRUGO | S_IXUGO));
703
704 LxtCheckErrno(Fd = open(DRVFS_ACCESS_READONLY_TEST_FILE, O_RDONLY));
705 LxtCheckErrno(Bytes = read(Fd, Buf, sizeof(Buf)));
706 LxtCheckEqual(Bytes, 0L, "%ld");
707 LxtCheckErrnoFailure(write(Fd, Buf, sizeof(Buf)), EBADF);
708 LxtCheckErrnoZeroSuccess(close(Fd));
709 LxtCheckErrnoFailure(Fd = open(DRVFS_ACCESS_READONLY_TEST_FILE, O_WRONLY), EACCES);
710
711 LxtCheckErrnoFailure(Fd = open(DRVFS_ACCESS_READONLY_TEST_FILE, O_RDWR), EACCES);
712
713 LxtCheckErrno(Fd = open(DRVFS_ACCESS_READONLY_TEST_FILE, O_PATH));
714 LxtCheckErrnoFailure(read(Fd, Buf, sizeof(Buf)), EBADF);
715 LxtCheckErrnoFailure(write(Fd, Buf, sizeof(Buf)), EBADF);
716 LxtCheckErrnoZeroSuccess(close(Fd));
717 Fd = -1;
718
719 //
720 // Second file with the read-only attribute set, used to check if that
721 // file can be deleted.
722 //
723
724 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_READONLYATTRDEL_TEST_FILE, S_IFREG | S_IRUGO | S_IXUGO));
725
726 LxtCheckErrnoZeroSuccess(unlink(DRVFS_ACCESS_READONLYATTRDEL_TEST_FILE));
727
728 //
729 // Writeonly file. This file can only be opened for write and read should
730 // fail. O_PATH always works.
731 //
732
733 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_WRITEONLY_TEST_FILE, S_IFREG | S_IWUGO));
734
735 LxtCheckErrno(Fd = open(DRVFS_ACCESS_WRITEONLY_TEST_FILE, O_WRONLY));
736 LxtCheckErrnoFailure(read(Fd, Buf, sizeof(Buf)), EBADF);
737 LxtCheckErrno(Bytes = write(Fd, Buf, sizeof(Buf)));
738 LxtCheckEqual(Bytes, 100L, "%ld");
739 LxtCheckErrnoZeroSuccess(close(Fd));
740 LxtCheckErrnoFailure(Fd = open(DRVFS_ACCESS_WRITEONLY_TEST_FILE, O_RDONLY), EACCES);
741
742 LxtCheckErrnoFailure(Fd = open(DRVFS_ACCESS_WRITEONLY_TEST_FILE, O_RDWR), EACCES);
743
744 LxtCheckErrno(Fd = open(DRVFS_ACCESS_READONLY_TEST_FILE, O_PATH));
745 LxtCheckErrnoFailure(read(Fd, Buf, sizeof(Buf)), EBADF);
746 LxtCheckErrnoFailure(write(Fd, Buf, sizeof(Buf)), EBADF);
747 LxtCheckErrnoZeroSuccess(close(Fd));
748 Fd = -1;
749
750 //
751 // Directory with add/delete file and traverse permissions. Opening a file
752 // in the directory should succeed, but opening the directory itself should
753 // not. Adding and deleting a file should work, but adding a subdirectory
754 // should not. O_PATH always works.
755 //
756
757 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR, S_IFDIR | S_IWUGO | S_IXUGO));
758
759 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD, S_IFREG | S_IRUGO));
760
761 LxtCheckErrnoFailure(Fd = open(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR, O_RDONLY | O_DIRECTORY), EACCES);
762
763 LxtCheckErrno(Fd = open(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD, O_RDONLY));
764
765 LxtCheckErrnoZeroSuccess(close(Fd));
766 LxtCheckErrno(Fd = open(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR, O_PATH | O_DIRECTORY));
767
768 LxtCheckErrnoFailure(syscall(SYS_getdents64, Fd, Buf, sizeof(Buf)), EBADF);
769 LxtCheckErrnoZeroSuccess(close(Fd));
770 Fd = -1;
771
772 //
773 // Creating a readonly file should work, but the mode specified should not
774 // take effect, unless metadata is being used.
775 //
776
777 LxtCheckErrno(Fd = open(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD2, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR));
778
779 LxtCheckErrnoZeroSuccess(close(Fd));
780 Fd = -1;
781 if (DrvFsTestMode == DRVFS_METADATA_TEST_MODE)
782 {
783 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD2, S_IFREG | 0400));
784 }
785 else
786 {
787 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD2, S_IFREG | S_IRUGO | S_IXUGO));
788 }
789
790 LxtCheckErrnoZeroSuccess(unlink(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD2));
791
792 //
793 // Creating a writable file should work, but the mode specified should not
794 // take effect, unless metadata is being used.
795 //
796
797 LxtCheckErrno(Fd = open(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD2, O_WRONLY | O_CREAT | O_EXCL, S_IWUSR));
798
799 LxtCheckErrnoZeroSuccess(close(Fd));
800 Fd = -1;
801 if (DrvFsTestMode == DRVFS_METADATA_TEST_MODE)
802 {
803 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD2, S_IFREG | 0200));
804 }
805 else
806 {
807 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD2, S_IFREG | S_IRUGO | S_IWUGO | S_IXUGO));
808 }
809
810 LxtCheckErrnoZeroSuccess(unlink(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD2));
811
812 //
813 // Creating a link should work, but creating a directory should not.
814 //
815
816 LxtCheckErrno(symlink(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD, DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD_LINK));
817
818 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD_LINK, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO));
819
820 LxtCheckErrnoFailure(mkdir(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD2, S_IRWXU), EACCES);
821
822 //
823 // Directory with only list permissions.
824 //
825 // Although traverse permissions were not set on this directory, Windows
826 // still acts as if it can be traversed due to the bypass traverse checking
827 // privilege, and LX should report the directory as traversable.
828 //
829
830 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_READONLY_TEST_DIR, S_IFDIR | S_IRUGO | S_IXUGO));
831
832 //
833 // Test chmod on DrvFs. Setting any write bit on the read-only attribute
834 // file will clear the read-only attribute, which gets reported back with
835 // all write bits set because DrvFs doesn't distinguish user, group and
836 // other. Other bits cannot be affected by chmod, unless metadata is
837 // enabled.
838 //
839 // N.B. The Windows side of this test will further verify the read-only
840 // attribute.
841 //
842
843 LxtCheckErrnoZeroSuccess(chmod(DRVFS_ACCESS_READONLYATTR_TEST_FILE, S_IWUSR));
844
845 if (DrvFsTestMode == DRVFS_METADATA_TEST_MODE)
846 {
847 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_READONLYATTR_TEST_FILE, S_IFREG | 0200));
848 }
849 else
850 {
851 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_READONLYATTR_TEST_FILE, S_IFREG | S_IRUGO | S_IWUGO | S_IXUGO));
852 }
853
854 //
855 // Conversely, removing all write bits will set the read-only attribute.
856 //
857
858 LxtCheckErrnoZeroSuccess(chmod(DRVFS_ACCESS_RWX_TEST_FILE, 0));
859
860 if (DrvFsTestMode == DRVFS_METADATA_TEST_MODE)
861 {
862 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_RWX_TEST_FILE, S_IFREG));
863 }
864 else
865 {
866 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_RWX_TEST_FILE, S_IFREG | S_IRUGO | S_IXUGO));
867 }
868
869 ErrorExit:
870 if (Fd >= 0)
871 {
872 close(Fd);
873 }
874
875 unlink(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD2);
876 unlink(DRVFS_ACCESS_EXECUTEONLY_TEST_DIR_CHILD_LINK);
877 return Result;
878 }
879
880 int DrvFsTestBadMetadata(PLXT_ARGS Args)
881
882 /*++
883
884 Description:
885
886 This routine tests files that have invalid metadata attributes.
887
888 N.B. These files were created by the Windows side of the test.
889
890 Arguments:
891
892 Args - Supplies the command line arguments.
893
894 Return Value:
895
896 Returns 0 on success, -1 on failure.
897
898 --*/
899
900 {
901
902 int Result;
903
904 //
905 // Any bad metadata field will be ignored. The other fields are used.
906 //
907
908 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/baduid", 0, 3001, S_IFREG | 0644, 0));
909
910 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/badgid", 3000, 0, S_IFREG | 0644, 0));
911
912 //
913 // NTFS does not return EffectiveAccess if a file has mode metadata, so
914 // the access will be zero if it is corrupt.
915 //
916
917 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/badmode", 3000, 3001, S_IFREG, 0));
918
919 //
920 // If the file type in the mode doesn't match the actual file type, this
921 // also gets treated as invalid
922 //
923
924 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/badtype1", 3000, 3001, S_IFREG, 0));
925
926 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/badtype2", 3000, 3001, S_IFREG, 0));
927
928 //
929 // If the file is not a device, the device ID should not be reported even
930 // if it's present in the metadata.
931 //
932
933 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/nondevice", 3000, 3001, S_IFREG | 0644, 0));
934
935 //
936 // Changing metadata on a file with corrupt metadata should work.
937 //
938
939 LxtCheckErrnoZeroSuccess(chown(DRVFS_METADATA_TEST_DIR "/baduid", 1000, -1));
940 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/baduid", 1000, 3001, S_IFREG | 0644, 0));
941
942 //
943 // Also when the field being changed is not the corrupt one.
944 //
945
946 LxtCheckErrnoZeroSuccess(chown(DRVFS_METADATA_TEST_DIR "/badgid", 1000, -1));
947 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/badgid", 1000, 0, S_IFREG | 0644, 0));
948
949 ErrorExit:
950 return Result;
951 }
952
953 int DrvFsTestBasic(PLXT_ARGS Args)
954
955 /*++
956
957 Description:
958
959 This routine tests basic drvfs functionality (reading/writing).
960
961 Arguments:
962
963 Args - Supplies the command line arguments.
964
965 Return Value:
966
967 Returns 0 on success, -1 on failure.
968
969 --*/
970
971 {
972
973 char Buffer[100];
974 pid_t ChildPid;
975 int Fd;
976 struct stat FStat;
977 ssize_t Size;
978 struct stat Stat;
979 int Result;
980
981 Fd = -1;
982
983 //
984 // Create a test directory.
985 //
986
987 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_BASIC_PREFIX, 0777));
988 LxtCheckErrnoFailure(mkdir(DRVFS_BASIC_PREFIX, 0777), EEXIST);
989
990 //
991 // Verify the directory file size is equal to the file-system block-size,
992 // and that block count is zero.
993 //
994
995 LxtCheckErrno(stat(DRVFS_BASIC_PREFIX, &Stat));
996 LxtCheckGreater(Stat.st_size, 0ull, "%llu");
997 LxtCheckEqual(Stat.st_size, (unsigned long long)Stat.st_blksize, "%llu");
998 LxtCheckEqual(Stat.st_blocks, 0l, "%ld");
999
1000 //
1001 // Create a file and write to it.
1002 //
1003
1004 LxtCheckErrnoFailure(Fd = open(DRVFS_BASIC_PREFIX "/test", O_RDWR), ENOENT);
1005
1006 LxtCheckErrno(Fd = open(DRVFS_BASIC_PREFIX "/test", O_CREAT | O_RDWR, 0666));
1007 LxtCheckErrno(Size = write(Fd, "hello", 5));
1008 LxtCheckEqual(Size, 5, "%ld");
1009
1010 //
1011 // Check stat results.
1012 //
1013 // N.B. Block count is reported as zero because this file is small enough
1014 // to have its contents packed into the MFT by NTFS. This is not the
1015 // case for FAT.
1016 //
1017
1018 LxtCheckErrnoZeroSuccess(stat(DRVFS_BASIC_PREFIX "/test", &Stat));
1019 LxtCheckEqual(Stat.st_size, 5, "%lld");
1020 LxtCheckGreater(Stat.st_ino, 0, "%llu");
1021 if (DrvFsTestMode == DRVFS_FAT_TEST_MODE)
1022 {
1023 LxtCheckEqual(Stat.st_blocks, 2, "%d");
1024 }
1025 else
1026 {
1027 LxtCheckEqual(Stat.st_blocks, 0, "%d");
1028 }
1029
1030 LxtCheckEqual(Stat.st_nlink, 1, "%d");
1031 LxtCheckEqual(Stat.st_rdev, 0, "%d");
1032
1033 //
1034 // Check fstat has the same results.
1035 //
1036
1037 LxtCheckErrnoZeroSuccess(stat(DRVFS_BASIC_PREFIX "/test", &Stat));
1038 LxtCheckErrnoZeroSuccess(fstat(Fd, &FStat));
1039 LxtCheckMemoryEqual(&Stat, &FStat, sizeof(Stat));
1040
1041 //
1042 // Read back the data.
1043 //
1044
1045 memset(Buffer, 0, sizeof(Buffer));
1046 LxtCheckErrno(lseek(Fd, 0, SEEK_SET));
1047 LxtCheckErrno(Size = read(Fd, Buffer, sizeof(Buffer)));
1048 LxtCheckEqual(Size, 5, "%lld");
1049 LxtCheckStringEqual(Buffer, "hello");
1050 LxtCheckClose(Fd);
1051
1052 //
1053 // Test using O_APPEND.
1054 //
1055
1056 LxtCheckErrno(Fd = open(DRVFS_BASIC_PREFIX "/test", O_RDWR | O_APPEND, 0666));
1057
1058 LxtCheckErrno(Size = write(Fd, "foo", 3));
1059 LxtCheckEqual(Size, 3, "%ld");
1060 LxtCheckErrno(lseek(Fd, 0, SEEK_SET));
1061 LxtCheckErrno(Size = write(Fd, "bar", 3));
1062 LxtCheckEqual(Size, 3, "%ld");
1063 memset(Buffer, 0, sizeof(Buffer));
1064 LxtCheckErrno(lseek(Fd, 0, SEEK_SET));
1065 LxtCheckErrno(Size = read(Fd, Buffer, sizeof(Buffer)));
1066 LxtCheckEqual(Size, 11, "%lld");
1067 LxtCheckStringEqual(Buffer, "hellofoobar");
1068 LxtCheckClose(Fd);
1069 LxtCheckErrnoZeroSuccess(stat(DRVFS_BASIC_PREFIX "/test", &Stat));
1070 LxtCheckEqual(Stat.st_size, 11, "%lld");
1071
1072 //
1073 // Verify ftruncate succeeds on a descriptor opened with O_APPEND | O_WRONLY.
1074 // Regression test for a virtiofs bug where ftruncate returned EACCES on an
1075 // append-mode descriptor (GitHub issue #40987).
1076 //
1077
1078 LxtCheckErrno(Fd = open(DRVFS_BASIC_PREFIX "/test", O_WRONLY | O_APPEND, 0666));
1079 LxtCheckErrno(Size = write(Fd, "hello", 5));
1080 LxtCheckEqual(Size, 5, "%ld");
1081 LxtCheckErrnoZeroSuccess(ftruncate(Fd, 0));
1082 LxtCheckErrnoZeroSuccess(ftruncate(Fd, 1));
1083 LxtCheckClose(Fd);
1084 LxtCheckErrnoZeroSuccess(stat(DRVFS_BASIC_PREFIX "/test", &Stat));
1085 LxtCheckEqual(Stat.st_size, 1, "%lld");
1086
1087 //
1088 // Creating/removing items relative to the current working directory.
1089 //
1090
1091 LxtCheckErrno(ChildPid = fork());
1092 if (ChildPid == 0)
1093 {
1094 LxtCheckErrnoZeroSuccess(chdir(DRVFS_BASIC_PREFIX));
1095 LxtCheckErrnoZeroSuccess(mkdir("a", 0777));
1096 LxtCheckErrnoZeroSuccess(access("a", F_OK));
1097 LxtCheckErrnoZeroSuccess(access(DRVFS_BASIC_PREFIX "/a", F_OK));
1098 LxtCheckErrnoZeroSuccess(rmdir("a"));
1099 LxtCheckErrnoFailure(access("a", F_OK), ENOENT);
1100 LxtCheckErrnoFailure(access(DRVFS_BASIC_PREFIX "/a", F_OK), ENOENT);
1101 exit(0);
1102 }
1103
1104 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
1105
1106 //
1107 // Creating regular files with mknod should always work even without
1108 // metadata, though without metadata the exact mode won't be preserved.
1109 //
1110
1111 LxtCheckErrnoZeroSuccess(mknod(DRVFS_BASIC_PREFIX "/node", S_IFREG | 0600, 0));
1112 LxtCheckErrnoZeroSuccess(stat(DRVFS_BASIC_PREFIX "/node", &Stat));
1113 if (DrvFsTestMode == DRVFS_METADATA_TEST_MODE)
1114 {
1115 LxtCheckEqual(Stat.st_mode, S_IFREG | 0600, "0%o");
1116 }
1117 else
1118 {
1119 LxtCheckEqual(Stat.st_mode, S_IFREG | 0777, "0%o");
1120 }
1121
1122 //
1123 // Check that cleanup works.
1124 //
1125
1126 LxtCheckErrnoZeroSuccess(unlink(DRVFS_BASIC_PREFIX "/node"));
1127 LxtCheckErrnoZeroSuccess(unlink(DRVFS_BASIC_PREFIX "/test"));
1128 LxtCheckErrnoZeroSuccess(rmdir(DRVFS_BASIC_PREFIX));
1129
1130 ErrorExit:
1131 if (Fd >= 0)
1132 {
1133 close(Fd);
1134 }
1135
1136 unlink(DRVFS_BASIC_PREFIX "/node");
1137 unlink(DRVFS_BASIC_PREFIX "/test");
1138 rmdir(DRVFS_BASIC_PREFIX);
1139
1140 return Result;
1141 }
1142
1143 int DrvFsTestBlockCount(PLXT_ARGS Args)
1144
1145 /*++
1146
1147 Description:
1148
1149 This routine tests the block count reported for files.
1150
1151 Arguments:
1152
1153 Args - Supplies the command line arguments.
1154
1155 Return Value:
1156
1157 Returns 0 on success, -1 on failure.
1158
1159 --*/
1160
1161 {
1162
1163 char* Buffer;
1164 size_t BufferSize;
1165 int Fd;
1166 int Result;
1167 struct stat Stat;
1168 ssize_t Written;
1169
1170 Buffer = 0;
1171 Fd = -1;
1172 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_BASIC_PREFIX, 0777));
1173
1174 //
1175 // Create the file.
1176 //
1177
1178 LxtCheckErrno(Fd = creat(DRVFS_BASIC_PREFIX "/testfile", 0666));
1179
1180 //
1181 // Block count should be zero for an empty file.
1182 //
1183
1184 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat));
1185 LxtCheckEqual(Stat.st_size, 0, "%lld");
1186 LxtCheckEqual(Stat.st_blocks, 0, "%ld");
1187
1188 //
1189 // Write data to the file. Make sure it's a whole number of NTFS blocks.
1190 //
1191
1192 BufferSize = 2 * Stat.st_blksize;
1193 Buffer = malloc(BufferSize);
1194 LxtCheckNotEqual(Buffer, NULL, "%p");
1195 memset(Buffer, 0, BufferSize);
1196 LxtCheckErrno(Written = write(Fd, Buffer, BufferSize));
1197 LxtCheckEqual(Written, BufferSize, "%ld");
1198
1199 //
1200 // Verify the block count, which should use 512 byte blocks regardless of
1201 // the reported block size.
1202 //
1203 // N.B. NTFS can decide to allocate more blocks, so an exact test isn't
1204 // possible.
1205 //
1206
1207 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat));
1208 LxtCheckEqual(Stat.st_size, BufferSize, "%lld");
1209 LxtCheckGreaterOrEqual(Stat.st_blocks, BufferSize / 512, "%ld");
1210
1211 //
1212 // Write one more byte so the size isn't divisible by 512.
1213 //
1214
1215 LxtCheckErrno(Written = write(Fd, Buffer, 1));
1216 LxtCheckEqual(Written, 1, "%ld");
1217
1218 //
1219 // Verify the block count. Windows will have grown the file using its own
1220 // internal logic, so the exact block count is hard to predict.
1221 //
1222
1223 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat));
1224 LxtCheckEqual(Stat.st_size, BufferSize + 1, "%lld");
1225 LxtCheckGreaterOrEqual(Stat.st_blocks, ((BufferSize + Stat.st_blksize) / 512), "%ld");
1226
1227 ErrorExit:
1228 if (Fd >= 0)
1229 {
1230 close(Fd);
1231 }
1232
1233 unlink(DRVFS_BASIC_PREFIX "/testfile");
1234 rmdir(DRVFS_BASIC_PREFIX);
1235 return Result;
1236 }
1237
1238 int DrvFsTestCaseSensitivity(PLXT_ARGS Args)
1239
1240 /*++
1241
1242 Routine Description:
1243
1244 This routine tests the case-sensitivity support of DrvFS.
1245
1246 Arguments:
1247
1248 Args - Supplies the command line arguments.
1249
1250 Return Value:
1251
1252 Returns 0 on success, -1 on failure.
1253
1254 --*/
1255
1256 {
1257
1258 int Fd;
1259 int Result;
1260 struct stat StatA;
1261 struct stat StatB;
1262
1263 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_CS_PREFIX, 0777));
1264
1265 //
1266 // Create 2 sub-directories differing only by case.
1267 //
1268
1269 LxtCheckResult(mkdir(DRVFS_CS_PREFIX "/dir", 0777));
1270 LxtCheckResult(mkdir(DRVFS_CS_PREFIX "/Dir", 0777));
1271
1272 //
1273 // Create 2 files differing only by case.
1274 //
1275
1276 LxtCheckResult(Fd = open(DRVFS_CS_PREFIX "/file", O_RDWR | O_CREAT | O_EXCL, 0777));
1277
1278 close(Fd);
1279 LxtCheckResult(Fd = open(DRVFS_CS_PREFIX "/File", O_RDWR | O_CREAT | O_EXCL, 0777));
1280
1281 close(Fd);
1282
1283 //
1284 // Stat both files and make sure the inode numbers are different.
1285 //
1286
1287 LxtCheckErrnoZeroSuccess(stat(DRVFS_CS_PREFIX "/file", &StatA));
1288 LxtCheckErrnoZeroSuccess(stat(DRVFS_CS_PREFIX "/File", &StatB));
1289 LxtCheckNotEqual(StatA.st_ino, StatB.st_ino, "%llu");
1290 Result = 0;
1291
1292 ErrorExit:
1293 unlink(DRVFS_CS_PREFIX "/File");
1294 unlink(DRVFS_CS_PREFIX "/file");
1295 rmdir(DRVFS_CS_PREFIX "/Dir");
1296 rmdir(DRVFS_CS_PREFIX "/dir");
1297 rmdir(DRVFS_CS_PREFIX);
1298
1299 return Result;
1300 }
1301
1302 int DrvFsTestCaseSensitivityRoot(PLXT_ARGS Args)
1303
1304 /*++
1305
1306 Description:
1307
1308 This routine tests whether drvfs correctly disables case sensitivity in the
1309 root of a drive for various operations.
1310
1311 N.B. This test requires administrator privileges in Windows.
1312
1313 N.B. Since the tests are run with case=dir, the root behaves as a case
1314 insensitive file system.
1315
1316 Arguments:
1317
1318 Args - Supplies the command line arguments.
1319
1320 Return Value:
1321
1322 Returns 0 on success, -1 on failure.
1323
1324 --*/
1325
1326 {
1327
1328 int Fd;
1329 int Result;
1330 struct stat Stat1;
1331 struct stat Stat2;
1332
1333 //
1334 // Attempt to create two files that differ by case.
1335 //
1336
1337 LxtCheckErrno(Fd = creat(DRVFS_PREFIX "/testfile", 0666));
1338 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat1));
1339 LxtCheckNotEqual(Stat1.st_ino, 0, "%llu");
1340 LxtCheckClose(Fd);
1341 LxtCheckErrnoFailure(open(DRVFS_PREFIX "/TestFile", O_CREAT | O_EXCL, 0666), EEXIST);
1342
1343 //
1344 // Without O_EXCL, O_CREAT succeeds because this directory is case
1345 // insensitive. These should refer to the same file.
1346 //
1347
1348 LxtCheckErrno(Fd = open(DRVFS_PREFIX "/TestFile", O_CREAT, 0666));
1349 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat2));
1350 LxtCheckEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
1351 LxtCheckClose(Fd);
1352
1353 //
1354 // O_CREAT with the original name should work, of course.
1355 //
1356
1357 LxtCheckErrno(Fd = open(DRVFS_PREFIX "/testfile", O_CREAT, 0666));
1358 LxtCheckClose(Fd);
1359 LxtCheckErrnoFailure(mkdir(DRVFS_PREFIX "/TestFile", 0777), EEXIST);
1360 LxtCheckErrnoFailure(symlink(DRVFS_PREFIX "/testfile", DRVFS_PREFIX "/TestFile"), EEXIST);
1361
1362 LxtCheckErrnoFailure(link(DRVFS_PREFIX "/testfile", DRVFS_PREFIX "/TestFile"), EEXIST);
1363
1364 //
1365 // Verify mknod returns EEXIST because of the case collision.
1366 //
1367
1368 LxtCheckErrnoFailure(mknod(DRVFS_PREFIX "/TestFile", S_IFREG | 0666, 0), EEXIST);
1369
1370 //
1371 // Verify renaming to a different case.
1372 //
1373
1374 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_PREFIX "/testdir", 0777));
1375 LxtCheckErrnoZeroSuccess(stat(DRVFS_PREFIX "/testdir", &Stat1));
1376 LxtCheckErrnoZeroSuccess(rename(DRVFS_PREFIX "/testdir", DRVFS_PREFIX "/TestDir"));
1377
1378 LxtCheckErrnoZeroSuccess(stat(DRVFS_PREFIX "/TestDir", &Stat2));
1379 LxtCheckEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
1380 LxtCheckErrnoZeroSuccess(rmdir(DRVFS_PREFIX "/TestDir"));
1381
1382 ErrorExit:
1383 unlink(DRVFS_PREFIX "/TestFile");
1384 rmdir(DRVFS_PREFIX "/TestFile");
1385 unlink(DRVFS_PREFIX "/testfile");
1386 return Result;
1387 }
1388
1389 int DrvFsTestDeleteCurrentWorkingDirectory(PLXT_ARGS Args)
1390
1391 /*++
1392
1393 Description:
1394
1395 This routine tests the behavior if the current working directory is
1396 unlinked for DrvFs.
1397
1398 Arguments:
1399
1400 Args - Supplies the command line arguments.
1401
1402 Return Value:
1403
1404 Returns 0 on success, -1 on failure.
1405
1406 --*/
1407
1408 {
1409
1410 int Result;
1411
1412 LxtCheckErrno(LxtFsDeleteCurrentWorkingDirectoryCommon(DRVFS_PREFIX, FS_DELETE_DRVFS));
1413
1414 ErrorExit:
1415 return Result;
1416 }
1417
1418 int DrvFsTestDeleteLoop(PLXT_ARGS Args)
1419
1420 /*++
1421
1422 Description:
1423
1424 This routine tests deleting files in a loop with multiple getdents calls.
1425
1426 Arguments:
1427
1428 Args - Supplies the command line arguments.
1429
1430 Return Value:
1431
1432 Returns 0 on success, -1 on failure.
1433
1434 --*/
1435
1436 {
1437
1438 int Result;
1439
1440 LxtCheckResult(LxtFsDeleteLoopCommon(DRVFS_DELETELOOP_PREFIX));
1441
1442 ErrorExit:
1443 return Result;
1444 }
1445
1446 int DrvFsTestDeleteOpenFile(PLXT_ARGS Args)
1447
1448 /*++
1449
1450 Description:
1451
1452 This routine tests using unlink and rmdir on a DrvFs file/directory that's open.
1453
1454 Arguments:
1455
1456 Args - Supplies the command line arguments.
1457
1458 Return Value:
1459
1460 Returns 0 on success, -1 on failure.
1461
1462 --*/
1463
1464 {
1465
1466 int Result;
1467
1468 LxtCheckErrno(LxtFsDeleteOpenFileCommon(DRVFS_PREFIX, FS_DELETE_DRVFS));
1469
1470 ErrorExit:
1471 return Result;
1472 }
1473
1474 int DrvFsTestEscapedNames(PLXT_ARGS Args)
1475
1476 /*++
1477
1478 Description:
1479
1480 This routine tests using file names that need to be escaped.
1481
1482 Arguments:
1483
1484 Args - Supplies the command line arguments.
1485
1486 Return Value:
1487
1488 Returns 0 on success, -1 on failure.
1489
1490 --*/
1491
1492 {
1493
1494 LXT_CHILD_INFO Child;
1495 int Fd;
1496 int Result;
1497 struct stat Stat;
1498 struct stat Stat2;
1499
1500 Fd = -1;
1501 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_ESCAPE_TEST_DIR, 0777));
1502
1503 //
1504 // Check creating a file and make sure it can be accessed.
1505 //
1506
1507 LxtCheckErrno(Fd = creat(DRVFS_ESCAPE_TEST_CHILD, 0666));
1508 LxtCheckResult(LxtCheckFdPath(Fd, DRVFS_ESCAPE_TEST_CHILD));
1509 LxtCheckErrnoZeroSuccess(stat(DRVFS_ESCAPE_TEST_CHILD, &Stat));
1510 LxtCheckNotEqual(Stat.st_ino, 0, "%llu");
1511
1512 //
1513 // It's possible to use the escaped characters directly.
1514 //
1515
1516 LxtCheckErrnoZeroSuccess(stat(DRVFS_ESCAPE_TEST_CHILD_ESCAPED, &Stat2));
1517 LxtCheckEqual(Stat.st_ino, Stat2.st_ino, "%llu");
1518
1519 //
1520 // Make sure the name appears correctly in the directory listing.
1521 //
1522
1523 Child.Name = DRVFS_ESCAPE_TEST_CHILD_NAME;
1524 Child.FileType = DT_REG;
1525 LxtCheckResult(LxtCheckDirectoryContentsEx(DRVFS_ESCAPE_TEST_DIR, &Child, 1, 0));
1526
1527 //
1528 // Check unlinking.
1529 //
1530
1531 LxtCheckClose(Fd);
1532 LxtCheckErrnoZeroSuccess(unlink(DRVFS_ESCAPE_TEST_CHILD));
1533
1534 //
1535 // Check various other ways of creating a file.
1536 //
1537
1538 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_ESCAPE_TEST_CHILD, 0777));
1539 LxtCheckErrnoZeroSuccess(rmdir(DRVFS_ESCAPE_TEST_CHILD));
1540 LxtCheckErrno(Fd = creat(DRVFS_ESCAPE_TEST_DIR "/target", 0666));
1541 LxtCheckClose(Fd);
1542
1543 //
1544 // Test rename with an escape character in the source and target.
1545 //
1546
1547 LxtCheckErrnoZeroSuccess(rename(DRVFS_ESCAPE_TEST_DIR "/target", DRVFS_ESCAPE_TEST_CHILD));
1548
1549 LxtCheckErrnoZeroSuccess(rename(DRVFS_ESCAPE_TEST_CHILD, DRVFS_ESCAPE_TEST_DIR "/target"));
1550
1551 //
1552 // Symlinks are not supported on SMB or FAT.
1553 //
1554
1555 if ((DrvFsTestMode != DRVFS_FAT_TEST_MODE) && (DrvFsTestMode != DRVFS_SMB_TEST_MODE))
1556 {
1557
1558 LxtCheckErrnoZeroSuccess(symlink("target", DRVFS_ESCAPE_TEST_CHILD));
1559 LxtCheckErrnoZeroSuccess(unlink(DRVFS_ESCAPE_TEST_CHILD));
1560 }
1561
1562 //
1563 // Hard links are not supported on FAT.
1564 //
1565
1566 if (DrvFsTestMode != DRVFS_FAT_TEST_MODE)
1567 {
1568 LxtCheckErrnoZeroSuccess(link(DRVFS_ESCAPE_TEST_DIR "/target", DRVFS_ESCAPE_TEST_CHILD));
1569
1570 LxtCheckErrnoZeroSuccess(unlink(DRVFS_ESCAPE_TEST_CHILD));
1571 }
1572
1573 //
1574 // Check mknod if metadata is supported.
1575 //
1576
1577 if (DrvFsTestMode == DRVFS_METADATA_TEST_MODE)
1578 {
1579 LxtCheckErrnoZeroSuccess(mknod(DRVFS_ESCAPE_TEST_CHILD, S_IFCHR, makedev(1, 3)));
1580
1581 LxtCheckErrnoZeroSuccess(unlink(DRVFS_ESCAPE_TEST_CHILD));
1582 }
1583
1584 ErrorExit:
1585 if (Fd >= 0)
1586 {
1587 close(Fd);
1588 }
1589
1590 unlink(DRVFS_ESCAPE_TEST_DIR "/target");
1591 unlink(DRVFS_ESCAPE_TEST_CHILD);
1592 rmdir(DRVFS_ESCAPE_TEST_CHILD);
1593 rmdir(DRVFS_ESCAPE_TEST_DIR);
1594 return Result;
1595 }
1596
1597 int DrvFsTestExecve(PLXT_ARGS Args)
1598
1599 /*++
1600
1601 Description:
1602
1603 This routine tests execve on DrvFs.
1604
1605 Arguments:
1606
1607 Args - Supplies the command line arguments.
1608
1609 Return Value:
1610
1611 Returns 0 on success, -1 on failure.
1612
1613 --*/
1614
1615 {
1616
1617 char* Argv[4];
1618 pid_t ChildPid;
1619 char* Envp[1];
1620 int Result;
1621
1622 //
1623 // Check the mode of the files.
1624 //
1625
1626 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_EXECUTEONLY_TEST_FILE, S_IFREG | S_IRUGO | S_IXUGO));
1627
1628 LxtCheckResult(DrvFsCheckMode(DRVFS_ACCESS_READONLY_TEST_FILE, S_IFREG | S_IRUGO));
1629
1630 //
1631 // Fork a child.
1632 //
1633
1634 LxtCheckErrno(ChildPid = fork());
1635 if (ChildPid == 0)
1636 {
1637
1638 Argv[0] = DRVFS_ACCESS_EXECUTEONLY_TEST_FILE;
1639 Argv[1] = "drvfs";
1640 Argv[2] = "execvetest";
1641 Argv[3] = NULL;
1642 Envp[0] = NULL;
1643
1644 //
1645 // Attempt to execve the read only file, which should fail.
1646 //
1647
1648 LxtCheckErrnoFailure(execve(DRVFS_ACCESS_READONLY_TEST_FILE, Argv, Envp), EACCES);
1649
1650 //
1651 // Attempt to execve the execute only file, which should succeed even
1652 // though the user has no read access.
1653 //
1654
1655 LxtCheckErrno(execve(DRVFS_ACCESS_EXECUTEONLY_TEST_FILE, Argv, Envp));
1656
1657 LxtLogError("Execve returned");
1658 _exit(LXT_RESULT_FAILURE);
1659 }
1660
1661 LxtCheckResult(LxtWaitPidPoll(ChildPid, DRVFS_EXECVE_TEST_RESULT << 8));
1662
1663 ErrorExit:
1664 return Result;
1665 }
1666
1667 int DrvFsTestFatCaseInsensitive(PLXT_ARGS Args)
1668
1669 /*++
1670
1671 Description:
1672
1673 This routine tests the case-insensitive behavior of FAT.
1674
1675 Arguments:
1676
1677 Args - Supplies the command line arguments.
1678
1679 Return Value:
1680
1681 Returns 0 on success, -1 on failure.
1682
1683 --*/
1684
1685 {
1686
1687 const LXT_CHILD_INFO Children[] = {"foo", DT_REG};
1688 const LXT_CHILD_INFO ChildrenPlan9Smb[] = {"FOO", DT_REG};
1689 int Fd;
1690 int Fd2;
1691 int Result;
1692 struct stat Stat1;
1693 struct stat Stat2;
1694
1695 Fd = -1;
1696 Fd2 = -1;
1697
1698 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_CASE_INSENSITIVE_TEST_DIR, 0777));
1699
1700 //
1701 // Create a file.
1702 //
1703
1704 LxtCheckErrno(Fd = creat(DRVFS_CASE_INSENSITIVE_TEST_DIR "/foo", 0666));
1705 LxtCheckClose(Fd);
1706
1707 //
1708 // Stat the file with its original name and a different case, and verify
1709 // they are the same file.
1710 //
1711
1712 LxtCheckErrno(lstat(DRVFS_CASE_INSENSITIVE_TEST_DIR "/foo", &Stat1));
1713 LxtCheckErrno(lstat(DRVFS_CASE_INSENSITIVE_TEST_DIR "/FOO", &Stat2));
1714 LxtCheckEqual(Stat1.st_ino, Stat2.st_ino, "%lld");
1715
1716 //
1717 // Check name collisions on create.
1718 //
1719
1720 LxtCheckErrnoFailure(Fd2 = open(DRVFS_CASE_INSENSITIVE_TEST_DIR "/FOO", O_CREAT | O_EXCL, 0666), EEXIST);
1721
1722 LxtCheckErrnoFailure(mkdir(DRVFS_CASE_INSENSITIVE_TEST_DIR "/FOO", 0666), EEXIST);
1723
1724 //
1725 // Rename to the same file, which works but has no effect (the case is not
1726 // changed). This matches real Linux, and normal Windows behavior when
1727 // renaming on FAT.
1728 //
1729 // N.B. With SMB over Plan 9, because Linux doesn't know the file system is
1730 // case-insensitive and NTFS does let you change the case on rename,
1731 // this actually does change the case.
1732 //
1733
1734 LxtCheckErrnoZeroSuccess(rename(DRVFS_CASE_INSENSITIVE_TEST_DIR "/foo", DRVFS_CASE_INSENSITIVE_TEST_DIR "/FOO"));
1735
1736 //
1737 // If the file is opened with two different cases, both fd's report the
1738 // path with the first case. This behavior matches Linux, except Linux
1739 // "remembers" the first case used after the file is closed because the
1740 // directory entries are cached.
1741 //
1742 // N.B. This is not the case with Plan 9 because Linux doesn't know the
1743 // file system is case-insensitive. The same applies to virtiofs.
1744 //
1745
1746 if (g_LxtFsInfo.FsType != LxtFsTypePlan9 && g_LxtFsInfo.FsType != LxtFsTypeVirtioFs)
1747 {
1748 LxtCheckErrno(Fd = open(DRVFS_CASE_INSENSITIVE_TEST_DIR "/foo", O_RDONLY));
1749 LxtCheckErrno(Fd2 = open(DRVFS_CASE_INSENSITIVE_TEST_DIR "/FOO", O_RDONLY));
1750 LxtCheckResult(LxtCheckFdPath(Fd, DRVFS_CASE_INSENSITIVE_TEST_DIR "/foo"));
1751 LxtCheckResult(LxtCheckFdPath(Fd2, DRVFS_CASE_INSENSITIVE_TEST_DIR "/foo"));
1752 }
1753
1754 //
1755 // Listing the directory shows the file with the correct case.
1756 //
1757 // N.B. As remarked above, for SMB on Plan 9, the case will have changed.
1758 //
1759
1760 if ((g_LxtFsInfo.FsType == LxtFsTypePlan9) && (DrvFsTestMode == DRVFS_SMB_TEST_MODE))
1761 {
1762
1763 LxtCheckResult(LxtCheckDirectoryContentsEx(DRVFS_CASE_INSENSITIVE_TEST_DIR, ChildrenPlan9Smb, LXT_COUNT_OF(Children), 0));
1764 }
1765 else
1766 {
1767 LxtCheckResult(LxtCheckDirectoryContentsEx(DRVFS_CASE_INSENSITIVE_TEST_DIR, Children, LXT_COUNT_OF(Children), 0));
1768 }
1769
1770 ErrorExit:
1771 if (Fd >= 0)
1772 {
1773 close(Fd);
1774 }
1775
1776 if (Fd2 >= 0)
1777 {
1778 close(Fd2);
1779 }
1780
1781 unlink(DRVFS_CASE_INSENSITIVE_TEST_DIR "/foo");
1782 rmdir(DRVFS_CASE_INSENSITIVE_TEST_DIR);
1783 return Result;
1784 }
1785
1786 int DrvFsTestFatJunction(PLXT_ARGS Args)
1787
1788 /*++
1789
1790 Description:
1791
1792 This routine tests whether the NTFS mount point for the FAT volume can be
1793 used as a symlink to the mounted volume.
1794
1795 Arguments:
1796
1797 Args - Supplies the command line arguments.
1798
1799 Return Value:
1800
1801 Returns 0 on success, -1 on failure.
1802
1803 --*/
1804
1805 {
1806
1807 int Result;
1808
1809 //
1810 // This test does not apply to VM mode because Plan 9 and virtiofs don't
1811 // support junction point symlinks.
1812 //
1813
1814 if (g_LxtFsInfo.FsType == LxtFsTypePlan9 || g_LxtFsInfo.FsType == LxtFsTypeVirtioFs)
1815 {
1816 LxtLogInfo("This test is not relevant in VM mode.");
1817 Result = 0;
1818 goto ErrorExit;
1819 }
1820
1821 //
1822 // Because the real C: drive was unmounted to mount the FAT volume, mount
1823 // it in a different location.
1824 //
1825
1826 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_MOUNT_TEST_DIR, 0777));
1827 LxtCheckErrnoZeroSuccess(mount(DRVFS_DRIVE, DRVFS_MOUNT_TEST_DIR, DRVFS_FS_TYPE, DRVFS_MOUNT_OPTIONS, NULL));
1828
1829 LxtCheckResult(LxtCheckLinkTarget(DRVFS_MOUNT_TEST_DIR "/" DRVFS_FAT_MOUNT_POINT, DRVFS_PREFIX "/"));
1830
1831 ErrorExit:
1832 umount(DRVFS_MOUNT_TEST_DIR);
1833 rmdir(DRVFS_MOUNT_TEST_DIR);
1834 return Result;
1835 }
1836
1837 int DrvFsTestFatUnsupported(PLXT_ARGS Args)
1838
1839 /*++
1840
1841 Description:
1842
1843 This routine tests unsupported functionality on FAT.
1844
1845 Arguments:
1846
1847 Args - Supplies the command line arguments.
1848
1849 Return Value:
1850
1851 Returns 0 on success, -1 on failure.
1852
1853 --*/
1854
1855 {
1856
1857 return DrvFsTestUnsupportedCommon(DRVFS_FAT_TEST_MODE);
1858 }
1859
1860 int DrvFsTestFatUtimensat(PLXT_ARGS Args)
1861
1862 /*++
1863
1864 Description:
1865
1866 This routine tests the utimensat system call on drvfs for FAT volumes.
1867
1868 Arguments:
1869
1870 Args - Supplies the command line arguments.
1871
1872 Return Value:
1873
1874 Returns 0 on success, -1 on failure.
1875
1876 --*/
1877
1878 {
1879
1880 return DrvFsTestUtimensatCommon(FS_UTIME_FAT | FS_UTIME_NO_SYMLINKS);
1881 }
1882
1883 int DrvFsTestFatWslPath(PLXT_ARGS Args)
1884
1885 /*++
1886
1887 Description:
1888
1889 This routine tests using the wslpath utility against the FAT mount point.
1890
1891 Arguments:
1892
1893 Args - Supplies the command line arguments.
1894
1895 Return Value:
1896
1897 Returns 0 on success, -1 on failure.
1898
1899 --*/
1900
1901 {
1902
1903 int Result;
1904
1905 //
1906 // Previous tests may have messed up the cwd such that getcwd fails, which
1907 // wslpath won't like.
1908 //
1909
1910 LxtCheckErrnoZeroSuccess(chdir("/"));
1911
1912 //
1913 // The FAT volume in Windows is mounted on an NTFS directory mount, which
1914 // makes it an interesting case to test with wslpath.
1915 //
1916
1917 LxtCheckResult(LxtCheckWslPathTranslation(DRVFS_FAT_DRIVE, DRVFS_PREFIX, true));
1918 LxtCheckResult(LxtCheckWslPathTranslation(DRVFS_PREFIX, "C:\\" DRVFS_FAT_MOUNT_POINT, false));
1919
1920 ErrorExit:
1921 return Result;
1922 }
1923
1924 int DrvFsTestFstat(PLXT_ARGS Args)
1925
1926 /*++
1927
1928 Description:
1929
1930 This routine tests the fstat system call on drvfs files.
1931
1932 Arguments:
1933
1934 Args - Supplies the command line arguments.
1935
1936 Return Value:
1937
1938 Returns 0 on success, -1 on failure.
1939
1940 --*/
1941
1942 {
1943
1944 int Fd;
1945 int OPathFd;
1946 int Result;
1947 struct stat Stat1;
1948 struct stat Stat2;
1949
1950 Fd = -1;
1951 OPathFd = -1;
1952
1953 //
1954 // Create a test file.
1955 //
1956
1957 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_BASIC_PREFIX, 0777));
1958 LxtCheckErrno(Fd = creat(DRVFS_BASIC_PREFIX "/testfile", 0666));
1959 LxtCheckErrno(OPathFd = open(DRVFS_BASIC_PREFIX "/testfile", O_PATH));
1960
1961 //
1962 // Stat and fstat should have the same result.
1963 //
1964
1965 LxtCheckErrnoZeroSuccess(stat(DRVFS_BASIC_PREFIX "/testfile", &Stat1));
1966 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat2));
1967 LxtCheckMemoryEqual(&Stat1, &Stat2, sizeof(Stat1));
1968 LxtCheckErrnoZeroSuccess(fstat(OPathFd, &Stat2));
1969 LxtCheckMemoryEqual(&Stat1, &Stat2, sizeof(Stat1));
1970
1971 //
1972 // Fstat should still work after unlink.
1973 //
1974 // N.B. This currently doesn't work on plan9 or virtiofs.
1975 //
1976
1977 LxtCheckErrnoZeroSuccess(unlink(DRVFS_BASIC_PREFIX "/testfile"));
1978 LxtCheckErrnoFailure(stat(DRVFS_BASIC_PREFIX "/testfile", &Stat2), ENOENT);
1979 if (g_LxtFsInfo.FsType != LxtFsTypePlan9 && g_LxtFsInfo.FsType != LxtFsTypeVirtioFs)
1980 {
1981 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat2));
1982
1983 //
1984 // The result should be the same except for link count and time stamps.
1985 //
1986 // N.B. On FAT, which does not support posix unlink, the link count will
1987 // still be one.
1988 //
1989
1990 LxtCheckEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
1991 LxtCheckEqual(Stat1.st_size, Stat2.st_size, "%llu");
1992 LxtCheckEqual(Stat1.st_mode, Stat2.st_mode, "0%o");
1993 if (DrvFsTestMode == DRVFS_FAT_TEST_MODE)
1994 {
1995 LxtCheckEqual(Stat1.st_nlink, Stat2.st_nlink, "%lu");
1996 }
1997 else
1998 {
1999 LxtCheckNotEqual(Stat1.st_nlink, Stat2.st_nlink, "%lu");
2000 LxtCheckEqual(Stat2.st_nlink, 0l, "%lu");
2001 }
2002
2003 //
2004 // Check fstat on the O_PATH descriptor.
2005 //
2006
2007 LxtCheckErrnoZeroSuccess(fstat(OPathFd, &Stat1));
2008 LxtCheckMemoryEqual(&Stat2, &Stat1, sizeof(Stat1));
2009
2010 //
2011 // Fstatat should still work after unlink.
2012 //
2013
2014 LxtCheckErrnoZeroSuccess(fstatat(Fd, "", &Stat1, AT_EMPTY_PATH));
2015 LxtCheckMemoryEqual(&Stat2, &Stat1, sizeof(Stat1));
2016 LxtCheckErrnoZeroSuccess(fstatat(OPathFd, "", &Stat1, AT_EMPTY_PATH));
2017 LxtCheckMemoryEqual(&Stat2, &Stat1, sizeof(Stat1));
2018 }
2019
2020 ErrorExit:
2021 if (Fd >= 0)
2022 {
2023 close(Fd);
2024 }
2025
2026 if (OPathFd >= 0)
2027 {
2028 close(OPathFd);
2029 }
2030
2031 unlink(DRVFS_BASIC_PREFIX "/testfile");
2032 rmdir(DRVFS_BASIC_PREFIX);
2033 return Result;
2034 }
2035
2036 int DrvFsTestStatx(PLXT_ARGS Args)
2037
2038 /*++
2039
2040 Description:
2041
2042 This routine tests the statx system call on drvfs files.
2043
2044 Arguments:
2045
2046 Args - Supplies the command line arguments.
2047
2048 Return Value:
2049
2050 Returns 0 on success, -1 on failure.
2051
2052 --*/
2053
2054 {
2055
2056 int Fd;
2057 int Result;
2058 struct stat Stat1;
2059 struct statx Statx1;
2060 struct statx Statx2;
2061
2062 Fd = -1;
2063
2064 if (g_LxtFsInfo.FsType == LxtFsTypeDrvFs)
2065 {
2066 LxtLogInfo("statx is not supported on drvfs in WSL1.");
2067 Result = 0;
2068 goto ErrorExit;
2069 }
2070
2071 //
2072 // Create a test file and symlink.
2073 //
2074
2075 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_BASIC_PREFIX, 0777));
2076 LxtCheckErrno(Fd = creat(DRVFS_BASIC_PREFIX "/testfile", 0666));
2077 LxtCheckErrnoZeroSuccess(symlink(DRVFS_BASIC_PREFIX "/testfile", DRVFS_BASIC_PREFIX "/testlink"));
2078
2079 //
2080 // Stat and statx should have consistent results.
2081 //
2082
2083 LxtCheckErrnoZeroSuccess(stat(DRVFS_BASIC_PREFIX "/testfile", &Stat1));
2084 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_BASIC_STATS, &Statx1));
2085 LxtCheckEqual(Stat1.st_ino, Statx1.stx_ino, "%llu");
2086 LxtCheckEqual(Stat1.st_size, Statx1.stx_size, "%llu");
2087 LxtCheckEqual(Stat1.st_mode, Statx1.stx_mode, "0%o");
2088
2089 //
2090 // Statx with AT_EMPTY_PATH on an fd.
2091 //
2092
2093 LxtCheckErrnoZeroSuccess(statx(Fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &Statx2));
2094 LxtCheckEqual(Statx1.stx_ino, Statx2.stx_ino, "%llu");
2095
2096 //
2097 // Test AT_SYMLINK_NOFOLLOW flag.
2098 //
2099
2100 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testlink", AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, &Statx2));
2101 LxtCheckTrue(S_ISLNK(Statx2.stx_mode));
2102 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testlink", 0, STATX_BASIC_STATS, &Statx2));
2103 LxtCheckTrue(S_ISREG(Statx2.stx_mode));
2104
2105 //
2106 // Test STATX_BTIME (birth/creation time).
2107 //
2108
2109 memset(&Statx2, 0, sizeof(Statx2));
2110 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_BASIC_STATS | STATX_BTIME, &Statx2));
2111 if (Statx2.stx_mask & STATX_BTIME)
2112 {
2113 LxtLogInfo("Birth time supported: tv_sec=%lld", (long long)Statx2.stx_btime.tv_sec);
2114 }
2115
2116 //
2117 // Test sync flags.
2118 //
2119
2120 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", AT_STATX_FORCE_SYNC, STATX_BASIC_STATS, &Statx2));
2121 LxtCheckEqual(Statx1.stx_ino, Statx2.stx_ino, "%llu");
2122
2123 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", AT_STATX_DONT_SYNC, STATX_BASIC_STATS, &Statx2));
2124 LxtCheckEqual(Statx1.stx_ino, Statx2.stx_ino, "%llu");
2125
2126 //
2127 // Test individual field masks.
2128 //
2129
2130 memset(&Statx2, 0, sizeof(Statx2));
2131 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_TYPE, &Statx2));
2132 LxtCheckTrue((Statx2.stx_mask & STATX_TYPE) != 0);
2133 LxtCheckTrue(S_ISREG(Statx2.stx_mode));
2134
2135 memset(&Statx2, 0, sizeof(Statx2));
2136 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_MODE, &Statx2));
2137 LxtCheckTrue((Statx2.stx_mask & STATX_MODE) != 0);
2138 LxtCheckEqual((Statx1.stx_mode & 0777), (Statx2.stx_mode & 0777), "0%o");
2139
2140 memset(&Statx2, 0, sizeof(Statx2));
2141 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_NLINK, &Statx2));
2142 LxtCheckTrue((Statx2.stx_mask & STATX_NLINK) != 0);
2143 LxtCheckEqual(Statx1.stx_nlink, Statx2.stx_nlink, "%u");
2144
2145 memset(&Statx2, 0, sizeof(Statx2));
2146 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_UID, &Statx2));
2147 LxtCheckTrue((Statx2.stx_mask & STATX_UID) != 0);
2148 LxtCheckEqual(Statx1.stx_uid, Statx2.stx_uid, "%u");
2149
2150 memset(&Statx2, 0, sizeof(Statx2));
2151 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_GID, &Statx2));
2152 LxtCheckTrue((Statx2.stx_mask & STATX_GID) != 0);
2153 LxtCheckEqual(Statx1.stx_gid, Statx2.stx_gid, "%u");
2154
2155 memset(&Statx2, 0, sizeof(Statx2));
2156 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_ATIME, &Statx2));
2157 LxtCheckTrue((Statx2.stx_mask & STATX_ATIME) != 0);
2158 LxtCheckEqual(Statx1.stx_atime.tv_sec, Statx2.stx_atime.tv_sec, "%lld");
2159
2160 memset(&Statx2, 0, sizeof(Statx2));
2161 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_MTIME, &Statx2));
2162 LxtCheckTrue((Statx2.stx_mask & STATX_MTIME) != 0);
2163 LxtCheckEqual(Statx1.stx_mtime.tv_sec, Statx2.stx_mtime.tv_sec, "%lld");
2164
2165 memset(&Statx2, 0, sizeof(Statx2));
2166 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_CTIME, &Statx2));
2167 LxtCheckTrue((Statx2.stx_mask & STATX_CTIME) != 0);
2168 LxtCheckEqual(Statx1.stx_ctime.tv_sec, Statx2.stx_ctime.tv_sec, "%lld");
2169
2170 memset(&Statx2, 0, sizeof(Statx2));
2171 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_INO, &Statx2));
2172 LxtCheckTrue((Statx2.stx_mask & STATX_INO) != 0);
2173 LxtCheckEqual(Statx1.stx_ino, Statx2.stx_ino, "%llu");
2174
2175 memset(&Statx2, 0, sizeof(Statx2));
2176 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_SIZE, &Statx2));
2177 LxtCheckTrue((Statx2.stx_mask & STATX_SIZE) != 0);
2178 LxtCheckEqual(Statx1.stx_size, Statx2.stx_size, "%llu");
2179
2180 memset(&Statx2, 0, sizeof(Statx2));
2181 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/testfile", 0, STATX_BLOCKS, &Statx2));
2182 LxtCheckTrue((Statx2.stx_mask & STATX_BLOCKS) != 0);
2183 LxtCheckEqual(Statx1.stx_blocks, Statx2.stx_blocks, "%llu");
2184
2185 //
2186 // Test on a directory.
2187 //
2188
2189 LxtCheckErrnoZeroSuccess(statx(AT_FDCWD, DRVFS_BASIC_PREFIX, 0, STATX_BASIC_STATS, &Statx2));
2190 LxtCheckTrue(S_ISDIR(Statx2.stx_mode));
2191
2192 //
2193 // Test error case.
2194 //
2195
2196 LxtCheckErrnoFailure(statx(AT_FDCWD, DRVFS_BASIC_PREFIX "/nonexistent", 0, STATX_BASIC_STATS, &Statx2), ENOENT);
2197
2198 ErrorExit:
2199 if (Fd >= 0)
2200 {
2201 close(Fd);
2202 }
2203
2204 unlink(DRVFS_BASIC_PREFIX "/testlink");
2205 unlink(DRVFS_BASIC_PREFIX "/testfile");
2206 rmdir(DRVFS_BASIC_PREFIX);
2207 return Result;
2208 }
2209
2210 int DrvFsTestGetDents64Alignment(PLXT_ARGS Args)
2211
2212 /*++
2213
2214 Description:
2215
2216 This routine tests whether directory entries are correctly aligned and
2217 padded.
2218
2219 Arguments:
2220
2221 Args - Supplies the command line arguments.
2222
2223 Return Value:
2224
2225 Returns 0 on success, -1 on failure.
2226
2227 --*/
2228
2229 {
2230
2231 int Result;
2232
2233 LxtCheckResult(LxtFsGetDentsAlignmentCommon(DRVFS_GETDENTS_PREFIX, FS_TEST_GETDENTS64));
2234
2235 ErrorExit:
2236 return Result;
2237 }
2238
2239 int DrvFsTestGetDentsAlignment(PLXT_ARGS Args)
2240
2241 /*++
2242
2243 Description:
2244
2245 This routine tests whether directory entries are correctly aligned and
2246 padded.
2247
2248 Arguments:
2249
2250 Args - Supplies the command line arguments.
2251
2252 Return Value:
2253
2254 Returns 0 on success, -1 on failure.
2255
2256 --*/
2257
2258 {
2259
2260 int Result;
2261
2262 LxtCheckResult(LxtFsGetDentsAlignmentCommon(DRVFS_GETDENTS_PREFIX, 0));
2263
2264 ErrorExit:
2265 return Result;
2266 }
2267
2268 int DrvFsTestHardLinks(PLXT_ARGS Args)
2269
2270 /*++
2271
2272 Description:
2273
2274 This routine tests the creation of hard links.
2275
2276 Arguments:
2277
2278 Args - Supplies the command line arguments.
2279
2280 Return Value:
2281
2282 Returns 0 on success, -1 on failure.
2283
2284 --*/
2285
2286 {
2287
2288 int Fd;
2289 int Result;
2290 struct stat Stat1;
2291 struct stat Stat2;
2292
2293 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_HARDLINK_TEST_DIR, 0777));
2294 LxtCheckErrno(Fd = creat(DRVFS_HARDLINK_TEST_DIR "/target", 0666));
2295 LxtCheckClose(Fd);
2296 LxtCheckErrnoZeroSuccess(link(DRVFS_HARDLINK_TEST_DIR "/target", DRVFS_HARDLINK_TEST_DIR "/link"));
2297
2298 LxtCheckErrnoZeroSuccess(lstat(DRVFS_HARDLINK_TEST_DIR "/target", &Stat1));
2299 LxtCheckErrnoZeroSuccess(lstat(DRVFS_HARDLINK_TEST_DIR "/link", &Stat2));
2300 LxtCheckEqual(Stat1.st_ino, Stat2.st_ino, "%lld");
2301
2302 ErrorExit:
2303 unlink(DRVFS_HARDLINK_TEST_DIR "/link");
2304 unlink(DRVFS_HARDLINK_TEST_DIR "/target");
2305 rmdir(DRVFS_HARDLINK_TEST_DIR);
2306 return Result;
2307 }
2308
2309 int DrvFsTestHiddenLxFsDirs(PLXT_ARGS Args)
2310
2311 /*++
2312
2313 Description:
2314
2315 This routine tests whether various VoLFs mounts are inaccessible from
2316 DrvFs.
2317
2318 Arguments:
2319
2320 Args - Supplies the command line arguments.
2321
2322 Return Value:
2323
2324 Returns 0 on success, -1 on failure.
2325
2326 --*/
2327
2328 {
2329
2330 char Child[4096];
2331 int Children;
2332 DIR* Dir;
2333 struct dirent* Entry;
2334 void* PointerResult;
2335 int Result;
2336 char TempDirectory[4096];
2337
2338 Dir = NULL;
2339
2340 if (g_LxtFsInfo.FsType == LxtFsTypePlan9 || g_LxtFsInfo.FsType == LxtFsTypeVirtioFs)
2341 {
2342 LxtLogInfo("This test is not relevant for plan9 or virtiofs.");
2343 Result = 0;
2344 goto ErrorExit;
2345 }
2346
2347 if (VfsAccessLxssDir == NULL)
2348 {
2349 LxtLogError("Lxss directory not specified.");
2350 Result = LXT_RESULT_FAILURE;
2351 goto ErrorExit;
2352 }
2353
2354 LxtCheckResult(DrvFsTestHiddenLxFsDirsHelper("rootfs", TRUE));
2355 LxtCheckResult(DrvFsTestHiddenLxFsDirsHelper("rootfs/etc", FALSE));
2356 LxtCheckResult(DrvFsTestHiddenLxFsDirsHelper("rootfs/cache", FALSE));
2357 LxtCheckResult(DrvFsTestHiddenLxFsDirsHelper("rootfs/data", FALSE));
2358 LxtCheckResult(DrvFsTestHiddenLxFsDirsHelper("rootfs/home", FALSE));
2359 LxtCheckResult(DrvFsTestHiddenLxFsDirsHelper("rootfs/mnt", FALSE));
2360 LxtCheckResult(DrvFsTestHiddenLxFsDirsHelper("rootfs/root", FALSE));
2361
2362 //
2363 // Ensure that the temp directory cannot be opened.
2364 //
2365 // N.B. There should only be a single directory entry under the temp
2366 // directory. The only case when this will not be true is if handles
2367 // were leaked by a previous instance and are still open by the driver.
2368 //
2369
2370 Children = 0;
2371 sprintf(TempDirectory, "%s/%s", VfsAccessLxssDir, "temp");
2372 LxtCheckNullErrno(Dir = opendir(TempDirectory));
2373 while ((Entry = readdir(Dir)) != NULL)
2374 {
2375 if ((strcmp(Entry->d_name, ".") == 0) || (strcmp(Entry->d_name, "..") == 0))
2376 {
2377
2378 continue;
2379 }
2380
2381 sprintf(Child, "temp/%s", Entry->d_name);
2382 LxtCheckResult(DrvFsTestHiddenLxFsDirsHelper(Child, TRUE));
2383 Children += 1;
2384 }
2385
2386 LxtCheckEqual(Children, 1, "%d");
2387
2388 ErrorExit:
2389 if (Dir != NULL)
2390 {
2391 closedir(Dir);
2392 }
2393
2394 return Result;
2395 }
2396
2397 int DrvFsTestHiddenLxFsDirsHelper(const char* Child, BOOLEAN DirectChild)
2398
2399 /*++
2400
2401 Description:
2402
2403 This routine tests if the specified child of the LXSS directory is
2404 inaccessible.
2405
2406 Arguments:
2407
2408 Child - Supplies the path of the child.
2409
2410 DirectChild - Supplies a value that indicates whether the child name is
2411 a direct child.
2412
2413 Return Value:
2414
2415 Returns 0 on success, -1 on failure.
2416
2417 --*/
2418
2419 {
2420
2421 int Fd;
2422 char Path[4096];
2423 int Result;
2424 struct stat Stat;
2425
2426 Fd = -1;
2427 sprintf(Path, "%s/%s", VfsAccessLxssDir, Child);
2428 LxtLogInfo("Attempting to access %s", Path);
2429
2430 //
2431 // Open directly.
2432 //
2433
2434 LxtCheckErrnoFailure(open(Path, O_RDONLY), EACCES);
2435
2436 //
2437 // Open through openat.
2438 //
2439
2440 LxtCheckErrno(Fd = open(VfsAccessLxssDir, O_RDONLY | O_DIRECTORY));
2441 LxtCheckErrnoFailure(openat(Fd, Child, O_RDONLY), EACCES);
2442 LxtCheckErrnoZeroSuccess(close(Fd));
2443 Fd = -1;
2444
2445 //
2446 // On a direct child O_PATH and stat should work. On a deeper descendant
2447 // it will not.
2448 //
2449
2450 if (DirectChild != FALSE)
2451 {
2452 LxtCheckErrno(Fd = open(Path, O_PATH));
2453 LxtCheckErrnoZeroSuccess(close(Fd));
2454 Fd = -1;
2455 LxtCheckErrnoZeroSuccess(stat(Path, &Stat));
2456 LxtCheckEqual((Stat.st_mode & ~S_IFMT), 0, "%o");
2457 }
2458 else
2459 {
2460 LxtCheckErrnoFailure(open(Path, O_PATH), EACCES);
2461 LxtCheckErrnoFailure(stat(Path, &Stat), EACCES);
2462 }
2463
2464 ErrorExit:
2465 if (Fd >= 0)
2466 {
2467 close(Fd);
2468 }
2469
2470 return Result;
2471 }
2472
2473 int DrvFsTestInotifyBasic(PLXT_ARGS Args)
2474
2475 {
2476
2477 int Id;
2478 int Result;
2479 int Wd[10];
2480
2481 //
2482 // Test watching basic Drvfs paths.
2483 //
2484
2485 LxtCheckErrno(Id = inotify_init());
2486 LxtCheckErrno(Wd[0] = inotify_add_watch(Id, DRVFS_PREFIX, IN_ALL_EVENTS));
2487 LxtCheckErrno(Wd[1] = inotify_add_watch(Id, DRVFS_PREFIX "/Users", IN_ALL_EVENTS));
2488 LxtCheckErrno(Wd[2] = inotify_add_watch(Id, DRVFS_PREFIX "/Windows", IN_ALL_EVENTS));
2489 LxtCheckErrno(Wd[3] = inotify_add_watch(Id, DRVFS_PREFIX "/Windows/System32", IN_ALL_EVENTS));
2490 Result = LXT_RESULT_SUCCESS;
2491
2492 ErrorExit:
2493 close(Id);
2494 return Result;
2495 }
2496
2497 int DrvFsTestInotifyEpoll(PLXT_ARGS Args)
2498
2499 {
2500
2501 //
2502 // TODO: Investigate why this doesn't work on Plan 9. May be a Linux 9p bug.
2503 //
2504
2505 if (g_LxtFsInfo.FsType == LxtFsTypePlan9)
2506 {
2507 LxtLogInfo("This test fails in VM mode.");
2508 return 0;
2509 }
2510
2511 return LxtFsInotifyEpollCommon(DRVFS_INOTIFY_TEST_BASE_DIR);
2512 }
2513
2514 int DrvFsTestInotifyPosixUnlinkRename(PLXT_ARGS Args)
2515
2516 {
2517
2518 return LxtFsInotifyPosixUnlinkRenameCommon(DRVFS_INOTIFY_TEST_BASE_DIR);
2519 }
2520
2521 int DrvFsTestInotifyStressUnlinkRename(PLXT_ARGS Args)
2522
2523 /*++
2524 --*/
2525
2526 {
2527
2528 int Fd;
2529 int Id;
2530 char Buf[10];
2531 int Result;
2532 int Index;
2533 int UnlinkIndex;
2534 int Tests;
2535 char BaseDir[PATH_MAX];
2536 char TestDir[PATH_MAX];
2537 int ChildPid;
2538 int SignalFd;
2539 struct signalfd_siginfo SignalInfo;
2540 sigset_t SignalMask;
2541 int Status;
2542 char TestFiles[DRVFS_INOTIFY_STRESS_NUM_FILES][PATH_MAX];
2543 bool UseDirs;
2544
2545 //
2546 // TODO: Remove once the vb test image has the fix.
2547 //
2548
2549 const char* disableTest = getenv("WSL_DISABLE_VB_UNSTABLE_TESTS");
2550 if (disableTest != NULL && strcmp(disableTest, "1") == 0)
2551 {
2552 LxtLogInfo("WSL_DISABLE_VB_UNSTABLE_TESTS set, skipping inotify stress test");
2553 return 0;
2554 }
2555
2556 //
2557 // Initialize and also do cleanup if the files have not been removed.
2558 //
2559
2560 sprintf(BaseDir, "%s", DRVFS_INOTIFY_TEST_BASE_DIR);
2561 sprintf(TestDir, "%s%s", BaseDir, DRVFS_INOTIFY_STRESS_DIR);
2562 LxtCheckErrnoZeroSuccess(mkdir(BaseDir, 0777));
2563 LxtCheckErrnoZeroSuccess(mkdir(TestDir, 0777));
2564 for (Index = 0; Index < DRVFS_INOTIFY_STRESS_NUM_FILES; Index++)
2565 {
2566 sprintf(TestFiles[Index], "%sunlink_%d", TestDir, Index);
2567 }
2568
2569 //
2570 // One thread repeatedly adds and removes inotify watches.
2571 // Another thread repeatedly creates, modifies, renames, and unlinks the files.
2572 //
2573
2574 //
2575 // LX_TODO: There is a race in some scenarios where a previously deleted
2576 // directory is still being torn down and will cause creation of a
2577 // file of the same name to fail. In the below loop this can result
2578 // in spurious errors.
2579 //
2580
2581 #if 0
2582 #define WITH_ERROR(_op_) LxtCheckErrno(_op_)
2583 #else
2584 #define WITH_ERROR(_op_) _op_
2585 #endif
2586
2587 UseDirs = false;
2588 LXT_SYNCHRONIZATION_POINT_START();
2589 LxtCheckErrno(ChildPid = fork());
2590 if (ChildPid == 0)
2591 {
2592 LxtCheckResult(LxtSignalBlock(SIGQUIT));
2593 sigemptyset(&SignalMask);
2594 sigaddset(&SignalMask, SIGQUIT);
2595 LxtCheckErrno(SignalFd = signalfd(-1, &SignalMask, SFD_NONBLOCK));
2596 while (1)
2597 {
2598 for (Index = 0; Index < DRVFS_INOTIFY_STRESS_NUM_FILES; Index++)
2599 {
2600 if (UseDirs)
2601 {
2602 WITH_ERROR(mkdir(TestFiles[Index], 0777));
2603 }
2604 else
2605 {
2606 WITH_ERROR(Fd = open(TestFiles[Index], O_CREAT | O_RDWR, 0600));
2607 }
2608
2609 LXT_SYNCHRONIZATION_POINT();
2610 if (read(SignalFd, &SignalInfo, sizeof(SignalInfo)) > 0)
2611 {
2612 LxtLogInfo("Exiting child on signal");
2613 goto ErrorExit;
2614 }
2615 else if (errno != EAGAIN)
2616 {
2617 LxtLogError("Read of signalfd gave unexpected error: %d", errno);
2618 Result = -1;
2619 goto ErrorExit;
2620 }
2621
2622 usleep(random() % 50);
2623 if (!UseDirs)
2624 {
2625 write(Fd, Buf, 10);
2626 close(Fd);
2627 }
2628
2629 if (random() % 2 == 0)
2630 {
2631 UnlinkIndex = (Index + 1) % DRVFS_INOTIFY_STRESS_NUM_FILES;
2632 WITH_ERROR(rename(TestFiles[Index], TestFiles[UnlinkIndex]));
2633 }
2634 else
2635 {
2636 UnlinkIndex = Index;
2637 }
2638
2639 if (UseDirs)
2640 {
2641 WITH_ERROR(rmdir(TestFiles[UnlinkIndex]));
2642 }
2643 else
2644 {
2645 WITH_ERROR(unlink(TestFiles[UnlinkIndex]));
2646 }
2647 }
2648
2649 UseDirs = !UseDirs;
2650 }
2651 }
2652
2653 for (Tests = 0; Tests < DRVFS_INOTIFY_STRESS_NUM_TESTS; Tests++)
2654 {
2655 Id = inotify_init();
2656 for (Index = 0; Index < DRVFS_INOTIFY_STRESS_NUM_FILES; Index++)
2657 {
2658 LXT_SYNCHRONIZATION_POINT();
2659 inotify_add_watch(Id, TestFiles[Index], IN_ALL_EVENTS);
2660 }
2661
2662 close(Id);
2663 }
2664
2665 kill(ChildPid, SIGQUIT);
2666 LXT_SYNCHRONIZATION_POINT();
2667
2668 ErrorExit:
2669 LXT_SYNCHRONIZATION_POINT_END();
2670
2671 for (Index = 0; Index < DRVFS_INOTIFY_STRESS_NUM_FILES; Index++)
2672 {
2673 rmdir(TestFiles[Index]);
2674 unlink(TestFiles[Index]);
2675 }
2676
2677 rmdir(TestDir);
2678 rmdir(BaseDir);
2679 return Result;
2680 }
2681
2682 int DrvFsTestInotifyUnmountBind(PLXT_ARGS Args)
2683
2684 {
2685
2686 return LxtFsInotifyUnmountBindCommon(DRVFS_INOTIFY_TEST_BASE_DIR);
2687 }
2688
2689 int DrvFsTestLookupPath(PLXT_ARGS Args)
2690
2691 /*++
2692
2693 Description:
2694
2695 This routine tests path lookup for drive FS, testing corner cases of the
2696 fast path lookup.
2697
2698 Arguments:
2699
2700 Args - Supplies the command line arguments.
2701
2702 Return Value:
2703
2704 Returns 0 on success, -1 on failure.
2705
2706 --*/
2707
2708 {
2709
2710 int Fd;
2711 int Fd2;
2712 int Result;
2713
2714 //
2715 // Make test directories.
2716 //
2717
2718 Fd = 0;
2719 Fd2 = 0;
2720 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_PREFIX "/a"), 0777));
2721 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_PREFIX "/a/b"), 0777));
2722 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_PREFIX "/a/b/c"), 0777));
2723 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_PREFIX "/a/b/c/d"), 0777));
2724 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_PREFIX "/a/b/c/d/e"), 0777));
2725 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_PREFIX "/a/b/c/d/e/f"), 0777));
2726
2727 //
2728 // Open a directory, which should use fast path lookup.
2729 //
2730
2731 LxtCheckErrno(Fd = open(DRVFS_PREFIX "/a/b/c/d/e", O_RDONLY | O_DIRECTORY));
2732
2733 LxtCheckResult(LxtCheckFdPath(Fd, DRVFS_PREFIX "/a/b/c/d/e"));
2734
2735 //
2736 // Open the parent of the directory.
2737 //
2738
2739 LxtCheckErrno(Fd2 = openat(Fd, "..", O_RDONLY | O_DIRECTORY));
2740 LxtCheckResult(LxtCheckFdPath(Fd2, DRVFS_PREFIX "/a/b/c/d"));
2741 LxtCheckErrno(close(Fd2));
2742
2743 //
2744 // Open two levels up.
2745 //
2746
2747 LxtCheckErrno(Fd2 = openat(Fd, "../..", O_RDONLY | O_DIRECTORY));
2748 LxtCheckResult(LxtCheckFdPath(Fd2, DRVFS_PREFIX "/a/b/c"));
2749 LxtCheckErrno(close(Fd2));
2750
2751 //
2752 // Open three levels up.
2753 //
2754
2755 LxtCheckErrno(Fd2 = openat(Fd, "../../..", O_RDONLY | O_DIRECTORY));
2756 LxtCheckResult(LxtCheckFdPath(Fd2, DRVFS_PREFIX "/a/b"));
2757 LxtCheckErrno(close(Fd2));
2758
2759 //
2760 // Up and down.
2761 //
2762
2763 LxtCheckErrno(Fd2 = openat(Fd, "f/../../..", O_RDONLY | O_DIRECTORY));
2764 LxtCheckResult(LxtCheckFdPath(Fd2, DRVFS_PREFIX "/a/b/c"));
2765 LxtCheckErrno(close(Fd2));
2766
2767 //
2768 // Up beyond the fast path entry.
2769 //
2770
2771 LxtCheckErrno(Fd2 = openat(Fd, "../../../../..", O_RDONLY | O_DIRECTORY));
2772 LxtCheckResult(LxtCheckFdPath(Fd2, DRVFS_PREFIX));
2773 LxtCheckErrno(close(Fd2));
2774 LxtCheckErrno(Fd2 = openat(Fd, "../../../../../..", O_RDONLY | O_DIRECTORY));
2775 LxtCheckResult(LxtCheckFdPath(Fd2, "/mnt"));
2776 LxtCheckErrno(close(Fd2));
2777
2778 //
2779 // Create a file with a relative path
2780 //
2781
2782 LxtCheckErrno(Fd2 = openat(Fd, "../../../foo", O_RDWR | O_CREAT, 0666));
2783 LxtCheckResult(LxtCheckFdPath(Fd2, DRVFS_PREFIX "/a/b/foo"));
2784 LxtCheckErrno(close(Fd2));
2785
2786 ErrorExit:
2787 if (Fd > 0)
2788 {
2789 close(Fd);
2790 }
2791
2792 if (Fd2 > 0)
2793 {
2794 close(Fd2);
2795 }
2796
2797 unlink(DRVFS_PREFIX "/a/b/foo");
2798 rmdir(DRVFS_PREFIX "/a/b/c/d/e/f");
2799 rmdir(DRVFS_PREFIX "/a/b/c/d/e");
2800 rmdir(DRVFS_PREFIX "/a/b/c/d");
2801 rmdir(DRVFS_PREFIX "/a/b/c");
2802 rmdir(DRVFS_PREFIX "/a/b");
2803 rmdir(DRVFS_PREFIX "/a");
2804 return Result;
2805 }
2806
2807 int DrvFsTestMetadata(PLXT_ARGS Args)
2808
2809 /*++
2810
2811 Description:
2812
2813 This routine tests basic metadata functionality.
2814
2815 N.B. This test uses the metadata directory created by the Windows side.
2816
2817 Arguments:
2818
2819 Args - Supplies the command line arguments.
2820
2821 Return Value:
2822
2823 Returns 0 on success, -1 on failure.
2824
2825 --*/
2826
2827 {
2828
2829 pid_t ChildPid;
2830 int Fd;
2831 int Result;
2832
2833 Fd = -1;
2834 LxtCheckErrno(ChildPid = fork());
2835 if (ChildPid == 0)
2836 {
2837 LxtCheckErrno(LxtSetfsuid(2000));
2838 LxtCheckErrno(LxtSetfsgid(2001));
2839
2840 //
2841 // Make sure umask won't change the mode values.
2842 //
2843
2844 LxtCheckErrno(umask(0));
2845
2846 //
2847 // Check if file creation uses the thread's owner information and the
2848 // specified mode.
2849 //
2850
2851 LxtCheckErrno(Fd = creat(DRVFS_METADATA_TEST_DIR "/testfile", 0644));
2852 LxtCheckClose(Fd);
2853 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testfile", 2000, 2001, S_IFREG | 0644, 0));
2854
2855 //
2856 // Same for a directory.
2857 //
2858
2859 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_METADATA_TEST_DIR "/testdir", 0755));
2860 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testdir", 2000, 2001, S_IFDIR | 0755, 0));
2861
2862 //
2863 // Same for symlinks.
2864 //
2865
2866 LxtCheckErrnoZeroSuccess(symlink(DRVFS_METADATA_TEST_DIR "/testfile", DRVFS_METADATA_TEST_DIR "/testlink"));
2867
2868 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testlink", 2000, 2001, S_IFLNK | 0777, 0));
2869
2870 //
2871 // And files created by mknod.
2872 //
2873
2874 LxtCheckErrnoZeroSuccess(mknod(DRVFS_METADATA_TEST_DIR "/testnodereg", S_IFREG | 0640, 0));
2875
2876 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testnodereg", 2000, 2001, S_IFREG | 0640, 0));
2877
2878 LxtCheckErrnoZeroSuccess(mknod(DRVFS_METADATA_TEST_DIR "/testnodefifo", S_IFIFO | 0660, 0));
2879
2880 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testnodefifo", 2000, 2001, S_IFIFO | 0660, 0));
2881
2882 LxtCheckErrnoZeroSuccess(mknod(DRVFS_METADATA_TEST_DIR "/testnodesock", S_IFSOCK | 0600, 0));
2883
2884 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testnodesock", 2000, 2001, S_IFSOCK | 0600, 0));
2885
2886 exit(0);
2887 }
2888
2889 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
2890
2891 //
2892 // Device files are not tested in the child because the required capability
2893 // is dropped when setfsuid is used.
2894 //
2895
2896 LxtCheckErrnoZeroSuccess(mknod(DRVFS_METADATA_TEST_DIR "/testnodechr", S_IFCHR | 0666, makedev(1, 2)));
2897
2898 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testnodechr", 0, 0, S_IFCHR | 0666, makedev(1, 2)));
2899
2900 LxtCheckErrnoZeroSuccess(mknod(DRVFS_METADATA_TEST_DIR "/testnodeblk", S_IFBLK | 0606, makedev(3, 4)));
2901
2902 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testnodeblk", 0, 0, S_IFBLK | 0606, makedev(3, 4)));
2903
2904 //
2905 // Check using chmod.
2906 //
2907
2908 LxtCheckErrnoZeroSuccess(chmod(DRVFS_METADATA_TEST_DIR "/testfile", 0400));
2909 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testfile", 2000, 2001, S_IFREG | 0400, 0));
2910
2911 //
2912 // Check using chown.
2913 //
2914
2915 LxtCheckErrnoZeroSuccess(chown(DRVFS_METADATA_TEST_DIR "/testfile", 3000, 3001));
2916
2917 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testfile", 3000, 3001, S_IFREG | 0400, 0));
2918
2919 //
2920 // Chown with no changes should succeed.
2921 //
2922
2923 LxtCheckErrnoZeroSuccess(chown(DRVFS_METADATA_TEST_DIR "/testfile", -1, -1));
2924 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testfile", 3000, 3001, S_IFREG | 0400, 0));
2925
2926 //
2927 // Set the set-group-id bit on the directory.
2928 //
2929
2930 LxtCheckErrnoZeroSuccess(chmod(DRVFS_METADATA_TEST_DIR "/testdir", S_ISGID | 0755));
2931
2932 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testdir", 2000, 2001, S_IFDIR | S_ISGID | 0755, 0));
2933
2934 //
2935 // Check items created in the directory inherit the group id.
2936 //
2937
2938 LxtCheckErrno(Fd = creat(DRVFS_METADATA_TEST_DIR "/testdir/childfile", 0600));
2939
2940 LxtCheckClose(Fd);
2941 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testdir/childfile", 0, 2001, S_IFREG | 0600, 0));
2942
2943 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_METADATA_TEST_DIR "/testdir/childdir", 0700));
2944
2945 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testdir/childdir", 0, 2001, S_IFDIR | S_ISGID | 0700, 0));
2946
2947 //
2948 // The set-user-id bit doesn't have that effect.
2949 //
2950
2951 LxtCheckErrnoZeroSuccess(chmod(DRVFS_METADATA_TEST_DIR "/testdir", S_ISUID | 0755));
2952
2953 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testdir", 2000, 2001, S_IFDIR | S_ISUID | 0755, 0));
2954
2955 LxtCheckErrno(Fd = creat(DRVFS_METADATA_TEST_DIR "/testdir/childfile2", 0600));
2956
2957 LxtCheckClose(Fd);
2958 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testdir/childfile2", 0, 0, S_IFREG | 0600, 0));
2959
2960 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_METADATA_TEST_DIR "/testdir/childdir2", 0700));
2961
2962 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR "/testdir/childdir2", 0, 0, S_IFDIR | 0700, 0));
2963
2964 //
2965 // Test adding metadata to an item that doesn't have it already.
2966 //
2967 // N.B. The Windows portion of the test will attempt to read this metadata
2968 // using NtQueryEaFile.
2969 //
2970
2971 LxtCheckErrnoZeroSuccess(chmod(DRVFS_METADATA_TEST_DIR, 0775));
2972 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR, 0, 0, S_IFDIR | 0775, 0));
2973
2974 LxtCheckErrnoZeroSuccess(chown(DRVFS_METADATA_TEST_DIR, 0x11223344, 0x55667788));
2975
2976 LxtCheckResult(DrvFsCheckStat(DRVFS_METADATA_TEST_DIR, 0x11223344, 0x55667788, S_IFDIR | 0775, 0));
2977
2978 ErrorExit:
2979 if (Fd >= 0)
2980 {
2981 close(Fd);
2982 }
2983
2984 unlink(DRVFS_METADATA_TEST_DIR "/testdir/childfile");
2985 unlink(DRVFS_METADATA_TEST_DIR "/testdir/childfile2");
2986 rmdir(DRVFS_METADATA_TEST_DIR "/testdir/childdir");
2987 rmdir(DRVFS_METADATA_TEST_DIR "/testdir/childdir2");
2988 unlink(DRVFS_METADATA_TEST_DIR "/testnodereg");
2989 unlink(DRVFS_METADATA_TEST_DIR "/testnodefifo");
2990 unlink(DRVFS_METADATA_TEST_DIR "/testnodesock");
2991 unlink(DRVFS_METADATA_TEST_DIR "/testnodechr");
2992 unlink(DRVFS_METADATA_TEST_DIR "/testnodeblk");
2993 unlink(DRVFS_METADATA_TEST_DIR "/testlink");
2994 rmdir(DRVFS_METADATA_TEST_DIR "/testdir");
2995 unlink(DRVFS_METADATA_TEST_DIR "/testfile");
2996 return Result;
2997 }
2998
2999 int DrvFsTestReFsWslPath(PLXT_ARGS Args)
3000
3001 /*++
3002
3003 Description:
3004
3005 This routine tests using the wslpath utility against the FAT mount point.
3006
3007 Arguments:
3008
3009 Args - Supplies the command line arguments.
3010
3011 Return Value:
3012
3013 Returns 0 on success, -1 on failure.
3014
3015 --*/
3016
3017 {
3018
3019 int Result;
3020
3021 //
3022 // Previous tests may have messed up the cwd such that getcwd fails, which
3023 // wslpath won't like.
3024 //
3025
3026 LxtCheckErrnoZeroSuccess(chdir("/"));
3027
3028 //
3029 // The ReFS volume in Windows is mounted on an NTFS directory mount, which
3030 // makes it an interesting case to test with wslpath.
3031 //
3032
3033 LxtCheckResult(LxtCheckWslPathTranslation(DRVFS_REFS_DRIVE, DRVFS_PREFIX, true));
3034 LxtCheckResult(LxtCheckWslPathTranslation(DRVFS_PREFIX, "C:\\" DRVFS_REFS_MOUNT_POINT, false));
3035
3036 ErrorExit:
3037 return Result;
3038 }
3039
3040 int DrvFsTestRename(PLXT_ARGS Args)
3041
3042 /*++
3043
3044 Description:
3045
3046 This routine tests some basic rename scenarios on drvfs.
3047
3048 Arguments:
3049
3050 Args - Supplies the command line arguments.
3051
3052 Return Value:
3053
3054 Returns 0 on success, -1 on failure.
3055
3056 --*/
3057
3058 {
3059
3060 pid_t ChildPid;
3061 int Fd;
3062 int Result;
3063 struct stat Stat1;
3064 struct stat Stat2;
3065
3066 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_RENAME_PREFIX, 0777));
3067
3068 //
3069 // Create two files, and rename one over the other.
3070 //
3071
3072 LxtCheckErrno(Fd = creat(DRVFS_RENAME_PREFIX "/a", 0777));
3073 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat1));
3074 LxtCheckClose(Fd);
3075 LxtCheckErrno(Fd = creat(DRVFS_RENAME_PREFIX "/b", 0777));
3076 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat2));
3077 LxtCheckClose(Fd);
3078 LxtCheckNotEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
3079 LxtCheckErrnoZeroSuccess(rename(DRVFS_RENAME_PREFIX "/a", DRVFS_RENAME_PREFIX "/b"));
3080
3081 LxtCheckErrnoZeroSuccess(stat(DRVFS_RENAME_PREFIX "/b", &Stat2));
3082 LxtCheckEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
3083 LxtCheckErrnoFailure(access(DRVFS_RENAME_PREFIX "/a", F_OK), ENOENT);
3084 LxtCheckErrnoZeroSuccess(unlink(DRVFS_RENAME_PREFIX "/b"));
3085
3086 //
3087 // Create two read-only files, and rename one over the other.
3088 //
3089
3090 //
3091 // Windows 10 builds are missing a fix for this test to pass.
3092 //
3093
3094 const char* disableReadOnlyRenameTest = getenv("WSL_DISABLE_VB_UNSTABLE_TESTS");
3095 if (disableReadOnlyRenameTest == NULL || strcmp(disableReadOnlyRenameTest, "1") != 0)
3096 {
3097 LxtCheckErrno(Fd = open(DRVFS_RENAME_PREFIX "/a", O_CREAT | O_EXCL | O_RDONLY, 0444));
3098
3099 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat1));
3100 LxtCheckClose(Fd);
3101 LxtCheckErrno(Fd = open(DRVFS_RENAME_PREFIX "/b", O_CREAT | O_EXCL | O_RDONLY, 0444));
3102
3103 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat2));
3104 LxtCheckClose(Fd);
3105 LxtCheckNotEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
3106 LxtCheckErrnoZeroSuccess(rename(DRVFS_RENAME_PREFIX "/a", DRVFS_RENAME_PREFIX "/b"));
3107
3108 LxtCheckErrnoZeroSuccess(stat(DRVFS_RENAME_PREFIX "/b", &Stat2));
3109 LxtCheckEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
3110 LxtCheckErrnoFailure(access(DRVFS_RENAME_PREFIX "/a", F_OK), ENOENT);
3111 LxtCheckErrnoZeroSuccess(unlink(DRVFS_RENAME_PREFIX "/b"));
3112
3113 //
3114 // Create two directories and rename one over the other.
3115 //
3116 // N.B. This is tested separately because non-POSIX rename on Windows needs
3117 // extra steps to supersede the directory.
3118 //
3119
3120 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_RENAME_PREFIX "/a", 0777));
3121 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_RENAME_PREFIX "/a/foo", 0777));
3122 LxtCheckErrnoZeroSuccess(stat(DRVFS_RENAME_PREFIX "/a", &Stat1));
3123 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_RENAME_PREFIX "/b", 0777));
3124 LxtCheckErrnoZeroSuccess(stat(DRVFS_RENAME_PREFIX "/b", &Stat2));
3125 LxtCheckNotEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
3126 LxtCheckErrnoZeroSuccess(rename(DRVFS_RENAME_PREFIX "/a", DRVFS_RENAME_PREFIX "/b"));
3127
3128 LxtCheckErrnoZeroSuccess(stat(DRVFS_RENAME_PREFIX "/b", &Stat2));
3129 LxtCheckEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
3130
3131 LxtCheckErrnoFailure(access(DRVFS_RENAME_PREFIX "/a", F_OK), ENOENT);
3132 LxtCheckErrnoZeroSuccess(access(DRVFS_RENAME_PREFIX "/b/foo", F_OK));
3133 LxtCheckErrnoZeroSuccess(rmdir(DRVFS_RENAME_PREFIX "/b/foo"));
3134 LxtCheckErrnoZeroSuccess(rmdir(DRVFS_RENAME_PREFIX "/b"));
3135
3136 //
3137 // Rename with different case.
3138 //
3139
3140 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_RENAME_PREFIX "/a", 0777));
3141 LxtCheckErrnoZeroSuccess(stat(DRVFS_RENAME_PREFIX "/a", &Stat1));
3142 LxtCheckErrnoZeroSuccess(rename(DRVFS_RENAME_PREFIX "/a", DRVFS_RENAME_PREFIX "/A"));
3143
3144 LxtCheckErrnoZeroSuccess(stat(DRVFS_RENAME_PREFIX "/A", &Stat2));
3145 LxtCheckEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
3146 LxtCheckErrnoZeroSuccess(rmdir(DRVFS_RENAME_PREFIX "/A"));
3147 }
3148 else
3149 {
3150 LxtLogInfo("WSL_DISABLE_VB_UNSTABLE_TESTS set, skipping read-only rename tests");
3151 }
3152
3153 LxtCheckErrno(ChildPid = fork());
3154 if (ChildPid == 0)
3155 {
3156 LxtCheckErrnoZeroSuccess(chdir(DRVFS_RENAME_PREFIX));
3157
3158 //
3159 // Repeat, but with relative paths.
3160 //
3161
3162 LxtCheckErrno(Fd = creat("a", 0777));
3163 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat1));
3164 LxtCheckClose(Fd);
3165 LxtCheckErrno(Fd = creat("b", 0777));
3166 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat2));
3167 LxtCheckClose(Fd);
3168 LxtCheckNotEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
3169 LxtCheckErrnoZeroSuccess(rename("a", "b"));
3170 LxtCheckErrnoZeroSuccess(stat("b", &Stat2));
3171 LxtCheckEqual(Stat1.st_ino, Stat2.st_ino, "%llu");
3172 LxtCheckErrnoFailure(access("a", F_OK), ENOENT);
3173 LxtCheckErrnoZeroSuccess(unlink("b"));
3174
3175 //
3176 // Rename and delete the working directory.
3177 //
3178 // N.B. This will not work correctly on plan 9 and virtiofs.
3179 //
3180
3181 if (g_LxtFsInfo.FsType != LxtFsTypePlan9 && g_LxtFsInfo.FsType != LxtFsTypeVirtioFs)
3182 {
3183 LxtCheckErrnoZeroSuccess(mkdir("a", 0777));
3184 LxtCheckErrnoZeroSuccess(chdir("a"));
3185 LxtCheckErrnoZeroSuccess(mkdir("b", 0777));
3186 LxtCheckErrnoZeroSuccess(access("b", F_OK));
3187 LxtCheckErrnoZeroSuccess(access(DRVFS_RENAME_PREFIX "/a/b", F_OK));
3188 LxtCheckErrnoZeroSuccess(rename(DRVFS_RENAME_PREFIX "/a", DRVFS_RENAME_PREFIX "/b"));
3189
3190 LxtCheckErrnoZeroSuccess(access("b", F_OK));
3191 LxtCheckErrnoZeroSuccess(access(DRVFS_RENAME_PREFIX "/b/b", F_OK));
3192 LxtCheckErrnoFailure(access(DRVFS_RENAME_PREFIX "/a/b", F_OK), ENOENT);
3193
3194 LxtCheckErrnoZeroSuccess(rmdir("b"));
3195 LxtCheckErrnoZeroSuccess(rmdir(DRVFS_RENAME_PREFIX "/b"));
3196 LxtCheckResult(LxtCheckLinkTarget("/proc/self/cwd", DRVFS_RENAME_PREFIX "/b (deleted)"));
3197
3198 LxtCheckErrnoZeroSuccess(chdir(".."));
3199 LxtCheckResult(LxtCheckLinkTarget("/proc/self/cwd", DRVFS_RENAME_PREFIX));
3200
3201 LxtCheckErrnoFailure(access("a", F_OK), ENOENT);
3202 LxtCheckErrnoFailure(access("b", F_OK), ENOENT);
3203
3204 //
3205 // Rename an open directory.
3206 //
3207 // N.B. This will not work correctly on plan 9.
3208 //
3209
3210 LxtCheckErrnoZeroSuccess(mkdir("a", 0777));
3211 LxtCheckErrnoZeroSuccess(mkdir("a/b", 0777));
3212 LxtCheckErrno(Fd = open("a", O_RDONLY | O_DIRECTORY));
3213 LxtCheckErrnoZeroSuccess(rename("a", "b"));
3214 LxtCheckErrnoZeroSuccess(faccessat(Fd, "b", F_OK, 0));
3215 LxtCheckErrnoFailure(access("a/b", F_OK), ENOENT);
3216 LxtCheckErrnoFailure(access(DRVFS_RENAME_PREFIX "/a/b", F_OK), ENOENT);
3217
3218 LxtCheckErrnoZeroSuccess(access("b/b", F_OK));
3219 LxtCheckErrnoZeroSuccess(access(DRVFS_RENAME_PREFIX "/b/b", F_OK));
3220 LxtCheckErrnoZeroSuccess(rmdir("b/b"));
3221 LxtCheckErrnoZeroSuccess(rmdir("b"));
3222 }
3223
3224 exit(0);
3225 }
3226
3227 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
3228
3229 ErrorExit:
3230 rmdir(DRVFS_RENAME_PREFIX "/a/foo");
3231 rmdir(DRVFS_RENAME_PREFIX "/a/b");
3232 rmdir(DRVFS_RENAME_PREFIX "/a");
3233 rmdir(DRVFS_RENAME_PREFIX "/A");
3234 unlink(DRVFS_RENAME_PREFIX "/a");
3235 rmdir(DRVFS_RENAME_PREFIX "/b/b");
3236 rmdir(DRVFS_RENAME_PREFIX "/b");
3237 unlink(DRVFS_RENAME_PREFIX "/b");
3238 rmdir(DRVFS_RENAME_PREFIX);
3239
3240 return Result;
3241 }
3242
3243 int DrvFsTestRenameAt(PLXT_ARGS Args)
3244
3245 /*++
3246
3247 Description:
3248
3249 This routine tests the renameat system call on drivefs.
3250
3251 Arguments:
3252
3253 Args - Supplies the command line arguments.
3254
3255 Return Value:
3256
3257 Returns 0 on success, -1 on failure.
3258
3259 --*/
3260
3261 {
3262
3263 int DirFd1;
3264 int DirFd2;
3265 int Result;
3266
3267 DirFd1 = -1;
3268 DirFd2 = -1;
3269
3270 //
3271 // Create a directory structure to use for the test.
3272 //
3273
3274 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_RENAMEAT_TEST_DIR, 0777));
3275 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_RENAMEAT_TEST_DIR "/a"), 0777));
3276 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_RENAMEAT_TEST_DIR "/a/b"), 0777));
3277 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_RENAMEAT_TEST_DIR "/a/b/c"), 0777));
3278 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_RENAMEAT_TEST_DIR "/a/b/c/d"), 0777));
3279 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_RENAMEAT_TEST_DIR "/a/b/c/d/e"), 0777));
3280 LxtCheckErrnoZeroSuccess(mkdir((DRVFS_RENAMEAT_TEST_DIR "/a/b/c/d/e/f"), 0777));
3281
3282 LxtCheckErrno(DirFd1 = open(DRVFS_RENAMEAT_TEST_DIR "/a", O_DIRECTORY));
3283 LxtCheckErrno(DirFd2 = open(DRVFS_RENAMEAT_TEST_DIR "/a/b/c", O_DIRECTORY));
3284
3285 LxtCheckErrnoZeroSuccess(chdir(DRVFS_RENAMEAT_TEST_DIR));
3286
3287 LxtCheckErrno(LxtFsRenameAtCommon(DirFd1, DirFd2));
3288
3289 ErrorExit:
3290 if (DirFd1 >= 0)
3291 {
3292 LxtClose(DirFd1);
3293 }
3294
3295 if (DirFd2 >= 0)
3296 {
3297 LxtClose(DirFd2);
3298 }
3299
3300 rmdir(DRVFS_RENAMEAT_TEST_DIR "/a/b/c/d/e/f");
3301 rmdir(DRVFS_RENAMEAT_TEST_DIR "/a/b/c/d/e");
3302 rmdir(DRVFS_RENAMEAT_TEST_DIR "/a/b/c/d");
3303 rmdir(DRVFS_RENAMEAT_TEST_DIR "/a/b/c");
3304 rmdir(DRVFS_RENAMEAT_TEST_DIR "/a/b");
3305 rmdir(DRVFS_RENAMEAT_TEST_DIR "/a");
3306 rmdir(DRVFS_RENAMEAT_TEST_DIR);
3307 return Result;
3308 }
3309
3310 int DrvFsTestRenameDir(PLXT_ARGS Args)
3311
3312 /*++
3313
3314 Description:
3315
3316 This routine tests the rename system call for DrvFs directories.
3317
3318 Arguments:
3319
3320 Args - Supplies the command line arguments.
3321
3322 Return Value:
3323
3324 Returns 0 on success, -1 on failure.
3325
3326 --*/
3327
3328 {
3329
3330 int Result;
3331
3332 LxtCheckResult(LxtFsRenameDirCommon(DRVFS_PREFIX));
3333
3334 ErrorExit:
3335 return Result;
3336 }
3337
3338 int DrvFsTestReopenUnlinked(PLXT_ARGS Args)
3339
3340 /*++
3341
3342 Description:
3343
3344 This routine tests whether unlinked files can still be accessed
3345
3346 Arguments:
3347
3348 Args - Supplies the command line arguments.
3349
3350 Return Value:
3351
3352 Returns 0 on success, -1 on failure.
3353
3354 --*/
3355
3356 {
3357
3358 int Fd;
3359 int Fd2;
3360 char Path[100];
3361 int Result;
3362 struct stat Stat;
3363
3364 Fd = -1;
3365 Fd2 = -1;
3366
3367 //
3368 // This functionality is not supported on Plan 9 or virtiofs.
3369 //
3370
3371 if (g_LxtFsInfo.FsType == LxtFsTypePlan9 || g_LxtFsInfo.FsType == LxtFsTypeVirtioFs)
3372 {
3373 LxtLogInfo("This test is not supported for plan9 or virtiofs.");
3374 Result = 0;
3375 goto ErrorExit;
3376 }
3377
3378 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_BASIC_PREFIX, 0777));
3379 LxtCheckErrno(Fd = creat(DRVFS_BASIC_PREFIX "/testfile", 0666));
3380 snprintf(Path, sizeof(Path), "/proc/self/fd/%d", Fd);
3381
3382 //
3383 // Unlink the file, and try to access it through procfs.
3384 //
3385
3386 LxtCheckErrnoZeroSuccess(unlink(DRVFS_BASIC_PREFIX "/testfile"));
3387 LxtCheckErrnoFailure(access(DRVFS_BASIC_PREFIX "/testfile", F_OK), ENOENT);
3388 LxtCheckErrnoZeroSuccess(stat(Path, &Stat));
3389 LxtCheckEqual(Stat.st_nlink, 0, "%lu");
3390
3391 //
3392 // Try to reopen through procfs.
3393 //
3394
3395 LxtCheckErrno(Fd2 = open(Path, O_RDONLY));
3396
3397 ErrorExit:
3398 if (Fd2 >= 0)
3399 {
3400 close(Fd2);
3401 }
3402
3403 if (Fd >= 0)
3404 {
3405 close(Fd);
3406 }
3407
3408 unlink(DRVFS_BASIC_PREFIX "/testfile");
3409 rmdir(DRVFS_BASIC_PREFIX);
3410 return Result;
3411 }
3412
3413 int DrvFsTestReparse(PLXT_ARGS Args)
3414
3415 /*++
3416
3417 Description:
3418
3419 This routine tests whether drvfs correctly blocks access to reparse points
3420 other than its own symlinks.
3421
3422 Arguments:
3423
3424 Args - Supplies the command line arguments.
3425
3426 Return Value:
3427
3428 Returns 0 on success, -1 on failure.
3429
3430 --*/
3431
3432 {
3433
3434 bool AbsoluteLinkFound;
3435 bool AppExecLinkFound;
3436 ssize_t BytesRead;
3437 char Buffer[100];
3438 DIR* Dir;
3439 int DirFd;
3440 struct dirent* Entry;
3441 int Fd;
3442 bool FileLinkFound;
3443 bool JunctionFound;
3444 void* Mapping;
3445 void* MapResult;
3446 void* PointerResult;
3447 bool RelativeLinkFound;
3448 int Result;
3449 struct stat Stat;
3450 bool V1LinkFound;
3451
3452 //
3453 // First make sure the reparse point does not show up in the directory
3454 // listing.
3455 //
3456
3457 DirFd = -1;
3458 Fd = -1;
3459 Mapping = MAP_FAILED;
3460 LxtCheckNullErrno(Dir = opendir(DRVFS_REPARSE_PREFIX));
3461 errno = 0;
3462 AbsoluteLinkFound = false;
3463 RelativeLinkFound = false;
3464 FileLinkFound = false;
3465 JunctionFound = false;
3466 V1LinkFound = false;
3467 AppExecLinkFound = false;
3468 while ((Entry = readdir(Dir)) != NULL)
3469 {
3470 if (strcmp(Entry->d_name, "absolutelink") == 0)
3471 {
3472 AbsoluteLinkFound = true;
3473 LxtCheckEqual(Entry->d_type, DT_LNK, "%d");
3474 }
3475
3476 if (strcmp(Entry->d_name, "relativelink") == 0)
3477 {
3478 RelativeLinkFound = true;
3479 LxtCheckEqual(Entry->d_type, DT_LNK, "%d");
3480 }
3481
3482 if (strcmp(Entry->d_name, "filelink") == 0)
3483 {
3484 FileLinkFound = true;
3485 LxtCheckEqual(Entry->d_type, DT_LNK, "%d");
3486 }
3487
3488 if (strcmp(Entry->d_name, "junction") == 0)
3489 {
3490 JunctionFound = true;
3491 LxtCheckEqual(Entry->d_type, DT_LNK, "%d");
3492 }
3493
3494 if (strcmp(Entry->d_name, "v1link") == 0)
3495 {
3496 V1LinkFound = true;
3497 LxtCheckEqual(Entry->d_type, DT_LNK, "%d");
3498 }
3499
3500 if (strcmp(Entry->d_name, "appexeclink") == 0)
3501 {
3502 AppExecLinkFound = true;
3503 LxtCheckEqual(Entry->d_type, DT_REG, "%d");
3504 }
3505 }
3506
3507 if (errno != 0)
3508 {
3509 LxtLogError("readdir failed, errno %d: %s", errno, strerror(errno));
3510 Result = LXT_RESULT_FAILURE;
3511 goto ErrorExit;
3512 }
3513
3514 LxtCheckErrnoZeroSuccess(closedir(Dir));
3515 Dir = NULL;
3516 LxtCheckTrue(AbsoluteLinkFound);
3517 LxtCheckTrue(RelativeLinkFound);
3518 LxtCheckTrue(FileLinkFound);
3519 LxtCheckTrue(JunctionFound);
3520 LxtCheckTrue(V1LinkFound);
3521 LxtCheckTrue(AppExecLinkFound);
3522
3523 //
3524 // Check the absolute link can be resolved, and that the target is correct
3525 // and uses Linux separators.
3526 //
3527
3528 LxtCheckResult(LxtCheckLinkTarget(DRVFS_REPARSE_PREFIX "/absolutelink", DRVFS_REPARSE_PREFIX "/test/linktarget"));
3529
3530 LxtCheckErrnoZeroSuccess(lstat(DRVFS_REPARSE_PREFIX "/absolutelink", &Stat));
3531 LxtCheckEqual((Stat.st_mode & S_IFMT), S_IFLNK, "0%o");
3532 LxtCheckEqual(Stat.st_size, strlen(DRVFS_REPARSE_PREFIX "/test/linktarget"), "%ull");
3533
3534 LxtCheckErrno(DirFd = open(DRVFS_REPARSE_PREFIX "/absolutelink", O_DIRECTORY | O_RDONLY));
3535
3536 LxtCheckResult(LxtCheckFdPath(DirFd, DRVFS_REPARSE_PREFIX "/test/linktarget"));
3537 LxtCheckClose(DirFd);
3538
3539 //
3540 // Check the relative link can be resolved, and that the target is correct
3541 // and uses Linux separators.
3542 //
3543
3544 LxtCheckResult(LxtCheckLinkTarget(DRVFS_REPARSE_PREFIX "/relativelink", "test/linktarget"));
3545
3546 LxtCheckErrnoZeroSuccess(lstat(DRVFS_REPARSE_PREFIX "/relativelink", &Stat));
3547 LxtCheckEqual((Stat.st_mode & S_IFMT), S_IFLNK, "0%o");
3548 LxtCheckEqual(Stat.st_size, strlen("test/linktarget"), "%ull");
3549
3550 LxtCheckErrno(DirFd = open(DRVFS_REPARSE_PREFIX "/relativelink", O_DIRECTORY | O_RDONLY));
3551
3552 LxtCheckResult(LxtCheckFdPath(DirFd, DRVFS_REPARSE_PREFIX "/test/linktarget"));
3553 LxtCheckClose(DirFd);
3554
3555 //
3556 // Check the relative link to a file can be resolved.
3557 //
3558
3559 LxtCheckResult(LxtCheckLinkTarget(DRVFS_REPARSE_PREFIX "/filelink", "test/filetarget"));
3560
3561 LxtCheckErrnoZeroSuccess(lstat(DRVFS_REPARSE_PREFIX "/filelink", &Stat));
3562 LxtCheckEqual((Stat.st_mode & S_IFMT), S_IFLNK, "0%o");
3563 LxtCheckEqual(Stat.st_size, strlen("test/filetarget"), "%ull");
3564
3565 //
3566 // Check the junction can be resolved, and that the target is correct
3567 // and uses Linux separators.
3568 //
3569
3570 LxtCheckResult(LxtCheckLinkTarget(DRVFS_REPARSE_PREFIX "/junction", DRVFS_REPARSE_PREFIX "/test/linktarget"));
3571
3572 LxtCheckErrno(DirFd = open(DRVFS_REPARSE_PREFIX "/junction", O_DIRECTORY | O_RDONLY));
3573
3574 LxtCheckResult(LxtCheckFdPath(DirFd, DRVFS_REPARSE_PREFIX "/test/linktarget"));
3575 LxtCheckClose(DirFd);
3576
3577 //
3578 // Check the target of the V1 link can be resolved, and that its reported
3579 // size is correct.
3580 //
3581
3582 LxtCheckResult(LxtCheckLinkTarget(DRVFS_REPARSE_PREFIX "/v1link", "/v1/symlink/target"));
3583
3584 LxtCheckErrnoZeroSuccess(lstat(DRVFS_REPARSE_PREFIX "/v1link", &Stat));
3585 LxtCheckEqual((Stat.st_mode & S_IFMT), S_IFLNK, "0%o");
3586 LxtCheckEqual(Stat.st_size, strlen("/v1/symlink/target"), "%ull");
3587
3588 //
3589 // Check that the back-compat symlink in the drive root can be resolved.
3590 //
3591 // N.B. This file explicitly denies FILE_READ_DATA permissions.
3592 //
3593
3594 LxtCheckResult(LxtCheckLinkTarget(DRVFS_PREFIX "/Documents and Settings", "/mnt/c/Users"));
3595
3596 LxtCheckErrnoZeroSuccess(lstat(DRVFS_PREFIX "/Documents and Settings", &Stat));
3597
3598 LxtCheckEqual((Stat.st_mode & S_IFMT), S_IFLNK, "0%o");
3599 LxtCheckEqual(Stat.st_size, strlen("/mnt/c/Users"), "%ull");
3600
3601 //
3602 // Ensure rename works with an NT link in the path.
3603 //
3604
3605 LxtCheckErrno(Fd = creat(DRVFS_REPARSE_PREFIX "/renametest", 0666));
3606 LxtCheckClose(Fd);
3607 LxtCheckErrnoZeroSuccess(rename(DRVFS_REPARSE_PREFIX "/renametest", DRVFS_REPARSE_PREFIX "/absolutelink/renametest"));
3608
3609 LxtCheckErrnoZeroSuccess(rename(DRVFS_REPARSE_PREFIX "/absolutelink/renametest", DRVFS_REPARSE_PREFIX "/relativelink/renametest"));
3610
3611 //
3612 // Ensure unlink works with an NT link in the path.
3613 //
3614
3615 LxtCheckErrnoZeroSuccess(unlink(DRVFS_REPARSE_PREFIX "/relativelink/renametest"));
3616
3617 LxtCheckErrnoFailure(access(DRVFS_REPARSE_PREFIX "/relativelink/renametest", F_OK), ENOENT);
3618
3619 LxtCheckErrno(Fd = creat(DRVFS_REPARSE_PREFIX "/absolutelink/renametest", 0666));
3620
3621 LxtCheckClose(Fd);
3622 LxtCheckErrnoZeroSuccess(unlink(DRVFS_REPARSE_PREFIX "/absolutelink/renametest"));
3623
3624 LxtCheckErrnoFailure(access(DRVFS_REPARSE_PREFIX "/absolutelink/renametest", F_OK), ENOENT);
3625
3626 //
3627 // Although Windows uses a directory for the first link and a file for the
3628 // second, from WSL it should be possible to delete either using unlink,
3629 // while rmdir should not work.
3630 //
3631
3632 LxtCheckErrnoFailure(rmdir(DRVFS_REPARSE_PREFIX "/relativelink"), ENOTDIR);
3633 LxtCheckErrnoZeroSuccess(unlink(DRVFS_REPARSE_PREFIX "/relativelink"));
3634 LxtCheckErrnoFailure(faccessat(AT_FDCWD, DRVFS_REPARSE_PREFIX "/relativelink", F_OK, AT_SYMLINK_NOFOLLOW), ENOENT);
3635
3636 LxtCheckErrnoFailure(rmdir(DRVFS_REPARSE_PREFIX "/filelink"), ENOTDIR);
3637 LxtCheckErrnoZeroSuccess(unlink(DRVFS_REPARSE_PREFIX "/filelink"));
3638 LxtCheckErrnoFailure(faccessat(AT_FDCWD, DRVFS_REPARSE_PREFIX "/filelink", F_OK, AT_SYMLINK_NOFOLLOW), ENOENT);
3639
3640 //
3641 // App execution aliases are treated as regular files but have generated
3642 // contents with a fake PE header for interop purposes.
3643 //
3644
3645 LxtCheckErrnoZeroSuccess(stat(DRVFS_REPARSE_PREFIX "/appexeclink", &Stat));
3646 LxtCheckEqual(Stat.st_mode & S_IFMT, S_IFREG, "0%o");
3647 LxtCheckEqual(Stat.st_size, 2, "%llu");
3648 LxtCheckErrno(Fd = open(DRVFS_REPARSE_PREFIX "/appexeclink", O_RDONLY));
3649 LxtCheckErrno(BytesRead = read(Fd, Buffer, sizeof(Buffer)));
3650 LxtCheckEqual(BytesRead, 2, "%ld");
3651 LxtCheckMemoryEqual(Buffer, "MZ", 2);
3652
3653 //
3654 // Check using mapping as well as this is a different code path in WSL1 and
3655 // is what execve uses.
3656 //
3657
3658 LxtCheckMapErrno(Mapping = mmap(NULL, 2, PROT_READ, MAP_PRIVATE, Fd, 0));
3659 LxtCheckMemoryEqual(Mapping, "MZ", 2);
3660 LxtCheckResult(munmap(Mapping, 2));
3661
3662 LxtCheckMapErrno(Mapping = mmap(NULL, 2, PROT_READ, MAP_SHARED, Fd, 0));
3663 LxtCheckMemoryEqual(Mapping, "MZ", 2);
3664
3665 ErrorExit:
3666 if (Mapping != MAP_FAILED)
3667 {
3668 munmap(Mapping, 2);
3669 }
3670
3671 if (Dir != NULL)
3672 {
3673 closedir(Dir);
3674 }
3675
3676 if (DirFd >= 0)
3677 {
3678 close(DirFd);
3679 }
3680
3681 if (Fd >= 0)
3682 {
3683 close(Fd);
3684 }
3685
3686 unlink(DRVFS_REPARSE_PREFIX "/renametest");
3687 unlink(DRVFS_REPARSE_PREFIX "/absolutelink/renametest");
3688 unlink(DRVFS_REPARSE_PREFIX "/relativelink/renametest");
3689 return Result;
3690 }
3691
3692 int DrvFsTestSeek(PLXT_ARGS Args)
3693
3694 /*++
3695
3696 Description:
3697
3698 This routine tests seeking in drvfs files.
3699
3700 Arguments:
3701
3702 Args - Supplies the command line arguments.
3703
3704 Return Value:
3705
3706 Returns 0 on success, -1 on failure.
3707
3708 --*/
3709
3710 {
3711
3712 int Fd;
3713 int Result;
3714 const char TestData[] = "abcdefghijklmnopqrstuvwxyz0123456789";
3715
3716 Fd = -1;
3717
3718 //
3719 // Create a test file.
3720 //
3721
3722 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_BASIC_PREFIX, 0777));
3723 LxtCheckErrno(Fd = open(DRVFS_BASIC_PREFIX "/testfile", (O_RDWR | O_CREAT), 0666));
3724
3725 LxtCheckErrno(write(Fd, TestData, sizeof(TestData)));
3726
3727 //
3728 // SEEK_SET.
3729 //
3730
3731 LxtCheckResult(DrvFsTestSeekHelper(Fd, 0, SEEK_SET, 0, TestData, sizeof(TestData)));
3732
3733 LxtCheckResult(DrvFsTestSeekHelper(Fd, 100, SEEK_SET, 100, TestData, sizeof(TestData)));
3734
3735 LxtCheckResult(DrvFsTestSeekHelper(Fd, 10, SEEK_SET, 10, TestData, sizeof(TestData)));
3736
3737 LxtCheckErrnoFailure(lseek(Fd, -100, SEEK_SET), EINVAL);
3738
3739 //
3740 // SEEK_CUR.
3741 //
3742 // N.B. Start offset is 15 because of the read above.
3743 //
3744
3745 LxtCheckResult(DrvFsTestSeekHelper(Fd, 0, SEEK_CUR, 15, TestData, sizeof(TestData)));
3746
3747 LxtCheckResult(DrvFsTestSeekHelper(Fd, 5, SEEK_CUR, 25, TestData, sizeof(TestData)));
3748
3749 LxtCheckResult(DrvFsTestSeekHelper(Fd, -10, SEEK_CUR, 20, TestData, sizeof(TestData)));
3750
3751 LxtCheckResult(DrvFsTestSeekHelper(Fd, 100, SEEK_CUR, 125, TestData, sizeof(TestData)));
3752
3753 LxtCheckErrnoFailure(lseek(Fd, -200, SEEK_SET), EINVAL);
3754
3755 //
3756 // SEEK_END.
3757 //
3758
3759 LxtCheckResult(DrvFsTestSeekHelper(Fd, -10, SEEK_END, sizeof(TestData) - 10, TestData, sizeof(TestData)));
3760
3761 LxtCheckResult(DrvFsTestSeekHelper(Fd, 10, SEEK_END, sizeof(TestData) + 10, TestData, sizeof(TestData)));
3762
3763 LxtCheckResult(DrvFsTestSeekHelper(Fd, -sizeof(TestData), SEEK_END, 0, TestData, sizeof(TestData)));
3764
3765 LxtCheckErrnoFailure(lseek(Fd, -100, SEEK_END), EINVAL);
3766
3767 ErrorExit:
3768 if (Fd >= 0)
3769 {
3770 close(Fd);
3771 }
3772
3773 unlink(DRVFS_BASIC_PREFIX "/testfile");
3774 rmdir(DRVFS_BASIC_PREFIX);
3775 return Result;
3776 }
3777
3778 int DrvFsTestSeekHelper(int Fd, off_t Offset, int Whence, off_t ExpectedOffset, const char* TestData, int TestDataSize)
3779
3780 /*++
3781
3782 Description:
3783
3784 This routine is a helper for the seek test.
3785
3786 Arguments:
3787
3788 Args - Supplies the command line arguments.
3789
3790 Return Value:
3791
3792 Returns 0 on success, -1 on failure.
3793
3794 --*/
3795
3796 {
3797
3798 off_t ActualOffset;
3799 char Buffer[5];
3800 ssize_t BytesRead;
3801 int Result;
3802
3803 LxtCheckErrno(ActualOffset = lseek(Fd, Offset, Whence));
3804 LxtCheckEqual(ActualOffset, ExpectedOffset, "%ld");
3805 LxtCheckErrno(BytesRead = read(Fd, Buffer, sizeof(Buffer)));
3806 if (ExpectedOffset >= TestDataSize)
3807 {
3808 LxtCheckEqual(BytesRead, 0, "%ld");
3809 }
3810 else
3811 {
3812 LxtCheckEqual(BytesRead, sizeof(Buffer), "%ld");
3813 LxtCheckMemoryEqual(Buffer, &TestData[ExpectedOffset], sizeof(Buffer));
3814 }
3815
3816 ErrorExit:
3817 return Result;
3818 }
3819
3820 int DrvFsTestDirSeek(PLXT_ARGS Args)
3821
3822 /*++
3823
3824 Description:
3825
3826 This routine tests seeking in drvfs directory.
3827
3828 Arguments:
3829
3830 Args - Supplies the command line arguments.
3831
3832 Return Value:
3833
3834 Returns 0 on success, -1 on failure.
3835
3836 --*/
3837
3838 {
3839
3840 int Result;
3841 LxtCheckResult(LxtFsDirSeekCommon(DRVFS_GETDENTS_PREFIX));
3842
3843 ErrorExit:
3844 return Result;
3845 }
3846
3847 int DrvFsTestSetup(PLXT_ARGS Args, int TestMode)
3848
3849 /*++
3850
3851 Description:
3852
3853 This routine performs setup for the drvfs tests.
3854
3855 Arguments:
3856
3857 Args - Supplies the command line arguments.
3858
3859 TestMode - Supplies the test mode.
3860
3861 Return Value:
3862
3863 Returns 0 on success, -1 on failure.
3864
3865 --*/
3866
3867 {
3868
3869 char Buffer[100];
3870 char CombinedOptions[100];
3871 LXT_FS_INFO FsInfo;
3872 char FsOptions[100];
3873 char Options[100];
3874 int ParentId;
3875 int Result;
3876
3877 //
3878 // Don't perform setup if help was requested.
3879 //
3880
3881 if (Args->HelpRequested != false)
3882 {
3883 Result = 0;
3884 goto ErrorExit;
3885 }
3886
3887 LxtCheckResult(LxtFsGetFsInfo(DRVFS_PREFIX, &FsInfo));
3888
3889 //
3890 // For the FAT test, check the FAT volume mount point can be accessed but
3891 // not resolved (because the FAT volume is not mounted in WSL yet).
3892 //
3893 // N.B. This doesn't work on Plan 9 because it doesn't support junction
3894 // symlinks.
3895 //
3896
3897 if (TestMode == DRVFS_FAT_TEST_MODE)
3898 {
3899 LxtCheckErrnoZeroSuccess(faccessat(AT_FDCWD, DRVFS_PREFIX "/" DRVFS_FAT_MOUNT_POINT, F_OK, AT_SYMLINK_NOFOLLOW));
3900
3901 if (FsInfo.FsType != LxtFsTypePlan9)
3902 {
3903 LxtCheckErrnoFailure(readlink(DRVFS_PREFIX "/" DRVFS_FAT_MOUNT_POINT, Buffer, sizeof(Buffer)), EIO);
3904 }
3905 }
3906
3907 //
3908 // Unmount drvfs first so a new instance will be created, which allows the
3909 // fallback mode to be set.
3910 //
3911 // N.B. Make sure the cwd is not inside drvfs.
3912 //
3913
3914 LxtCheckErrnoZeroSuccess(chdir("/"));
3915 LxtCheckErrnoZeroSuccess(umount(DRVFS_PREFIX));
3916 ParentId = MountGetMountId(DRVFS_PREFIX);
3917
3918 //
3919 // For the FAT tests, fallback options aren't used (FAT doesn't support
3920 // NtQueryInformationByName or FILE_STAT_INFORMATION anyway).
3921 //
3922
3923 switch (TestMode)
3924 {
3925 case DRVFS_FAT_TEST_MODE:
3926 LxtCheckResult(LxtFsMountDrvFs(DRVFS_FAT_DRIVE, DRVFS_PREFIX, "noatime,case=off"));
3927
3928 LxtCheckResult(LxtFsCheckDrvFsMount(DRVFS_FAT_DRIVE, DRVFS_PREFIX, "case=off", ParentId, "/"));
3929
3930 Result = LXT_RESULT_SUCCESS;
3931 break;
3932
3933 case DRVFS_SMB_TEST_MODE:
3934 LxtCheckResult(LxtFsMountDrvFs(DRVFS_UNC_PATH, DRVFS_PREFIX, "noatime,case=off"));
3935
3936 LxtCheckResult(LxtFsCheckDrvFsMount(DRVFS_UNC_PATH, DRVFS_PREFIX, "case=off", ParentId, "/"));
3937
3938 Result = LXT_RESULT_SUCCESS;
3939 break;
3940
3941 case DRVFS_METADATA_TEST_MODE:
3942 LxtCheckResult(LxtFsMountDrvFs(DRVFS_DRIVE, DRVFS_PREFIX, "noatime,metadata,case=dir"));
3943
3944 LxtCheckResult(LxtFsCheckDrvFsMount(DRVFS_DRIVE, DRVFS_PREFIX, "metadata,case=dir", ParentId, "/"));
3945
3946 Result = LXT_RESULT_SUCCESS;
3947 break;
3948
3949 case DRVFS_REFS_TEST_MODE:
3950 LxtCheckResult(LxtFsMountDrvFs(DRVFS_REFS_DRIVE, DRVFS_PREFIX, "noatime,case=dir"));
3951
3952 LxtCheckResult(LxtFsCheckDrvFsMount(DRVFS_REFS_DRIVE, DRVFS_PREFIX, "case=dir", ParentId, "/"));
3953
3954 Result = LXT_RESULT_SUCCESS;
3955 break;
3956
3957 default:
3958
3959 //
3960 // Plan 9 and virtiofs don't support fallback modes, so just remount with default options in that case.
3961 //
3962
3963 if (FsInfo.FsType == LxtFsTypePlan9 || FsInfo.FsType == LxtFsTypeVirtioFs)
3964 {
3965 LxtCheckResult(LxtFsMountDrvFs(DRVFS_DRIVE, DRVFS_PREFIX, "noatime,case=dir"));
3966
3967 LxtCheckResult(LxtFsCheckDrvFsMount(DRVFS_DRIVE, DRVFS_PREFIX, "case=dir", ParentId, "/"));
3968 }
3969 else
3970 {
3971
3972 //
3973 // Remount with the desired fallback mode.
3974 //
3975
3976 snprintf(Options, sizeof(Options), "case=dir,fallback=%d", TestMode);
3977 LxtCheckErrnoZeroSuccess(mount(DRVFS_DRIVE, DRVFS_PREFIX, DRVFS_FS_TYPE, DRVFS_MOUNT_OPTIONS, Options));
3978
3979 //
3980 // Check if drvfs actually used the requested fallback mode. This guards
3981 // against a preexisting instance (e.g. in another mount namespace)
3982 // preventing the options from changing, or file system limitations causing
3983 // drvfs to use a different fallback mode than requested.
3984 //
3985
3986 snprintf(FsOptions, sizeof(FsOptions), "rw,%s", Options);
3987 snprintf(CombinedOptions, sizeof(CombinedOptions), "rw,noatime,%s", Options);
3988
3989 LxtCheckResult(MountCheckIsMount(DRVFS_PREFIX, ParentId, DRVFS_DRIVE, DRVFS_FS_TYPE, "/", "rw,noatime", FsOptions, CombinedOptions, 0));
3990 }
3991
3992 break;
3993 }
3994
3995 LxtCheckResult(LxtFsGetFsInfo(DRVFS_PREFIX, &g_LxtFsInfo));
3996
3997 ErrorExit:
3998 return Result;
3999 }
4000
4001 int DrvFsTestSmbUtimensat(PLXT_ARGS Args)
4002
4003 /*++
4004
4005 Description:
4006
4007 This routine tests the utimensat system call on drvfs for SMB shares.
4008
4009 Arguments:
4010
4011 Args - Supplies the command line arguments.
4012
4013 Return Value:
4014
4015 Returns 0 on success, -1 on failure.
4016
4017 --*/
4018
4019 {
4020
4021 return DrvFsTestUtimensatCommon(FS_UTIME_NO_SYMLINKS);
4022 }
4023
4024 int DrvFsTestSmbUnsupported(PLXT_ARGS Args)
4025
4026 /*++
4027
4028 Description:
4029
4030 This routine tests unsupported functionality on SMB.
4031
4032 Arguments:
4033
4034 Args - Supplies the command line arguments.
4035
4036 Return Value:
4037
4038 Returns 0 on success, -1 on failure.
4039
4040 --*/
4041
4042 {
4043
4044 return DrvFsTestUnsupportedCommon(DRVFS_SMB_TEST_MODE);
4045 }
4046
4047 int DrvFsTestSmbWslPath(PLXT_ARGS Args)
4048
4049 /*++
4050
4051 Description:
4052
4053 This routine tests using the wslpath utility against the FAT mount point.
4054
4055 Arguments:
4056
4057 Args - Supplies the command line arguments.
4058
4059 Return Value:
4060
4061 Returns 0 on success, -1 on failure.
4062
4063 --*/
4064
4065 {
4066
4067 int Result;
4068
4069 //
4070 // Previous tests may have messed up the cwd such that getcwd fails, which
4071 // wslpath won't like.
4072 //
4073
4074 LxtCheckErrnoZeroSuccess(chdir("/"));
4075
4076 //
4077 // Make sure translating UNC paths works.
4078 //
4079
4080 LxtCheckResult(LxtCheckWslPathTranslation(DRVFS_UNC_PATH, DRVFS_PREFIX, true));
4081 LxtCheckResult(LxtCheckWslPathTranslation(DRVFS_PREFIX, "\\\\localhost\\C$", false));
4082
4083 ErrorExit:
4084 return Result;
4085 }
4086
4087 int DrvFsTestSymlink(PLXT_ARGS Args)
4088
4089 /*++
4090
4091 Description:
4092
4093 This routine tests symlink creation.
4094
4095 Arguments:
4096
4097 Args - Supplies the command line arguments.
4098
4099 Return Value:
4100
4101 Returns 0 on success, -1 on failure.
4102
4103 --*/
4104
4105 {
4106
4107 int Fd;
4108 int Result;
4109
4110 Fd = 0;
4111 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_SYMLINK_TEST_DIR, 0777));
4112
4113 //
4114 // Create a dir and a file to serve as targets.
4115 //
4116
4117 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_SYMLINK_TEST_DIR "/dir", 0777));
4118 LxtCheckErrno(Fd = creat(DRVFS_SYMLINK_TEST_DIR "/file.txt", 0666));
4119 LxtCheckClose(Fd);
4120
4121 //
4122 // Test the scenarios that should create NT symlinks.
4123 //
4124 // Relative link to file.
4125 //
4126
4127 LxtCheckResult(DrvFsTestSymlinkHelper("file.txt", DRVFS_SYMLINK_TEST_DIR "/ntlink1"));
4128
4129 //
4130 // Relative link to dir.
4131 //
4132
4133 LxtCheckResult(DrvFsTestSymlinkHelper("dir", DRVFS_SYMLINK_TEST_DIR "/ntlink2"));
4134
4135 //
4136 // Relative links with .. components.
4137 //
4138
4139 LxtCheckResult(DrvFsTestSymlinkHelper("..", DRVFS_SYMLINK_TEST_DIR "/ntlink3"));
4140
4141 LxtCheckResult(DrvFsTestSymlinkHelper("../symlink/file.txt", DRVFS_SYMLINK_TEST_DIR "/ntlink4"));
4142
4143 LxtCheckResult(DrvFsTestSymlinkHelper("dir/../file.txt", DRVFS_SYMLINK_TEST_DIR "/ntlink5"));
4144
4145 //
4146 // Relative link to another NT link (file and dir).
4147 //
4148
4149 LxtCheckResult(DrvFsTestSymlinkHelper("ntlink1", DRVFS_SYMLINK_TEST_DIR "/ntlink6"));
4150
4151 LxtCheckResult(DrvFsTestSymlinkHelper("ntlink2", DRVFS_SYMLINK_TEST_DIR "/ntlink7"));
4152
4153 //
4154 // Relative link to a file whose name contains escaped characters.
4155 //
4156
4157 LxtCheckErrno(Fd = creat(DRVFS_SYMLINK_TEST_DIR "/foo:bar", 0666));
4158 LxtCheckClose(Fd);
4159
4160 LxtCheckResult(DrvFsTestSymlinkHelper("foo:bar", DRVFS_SYMLINK_TEST_DIR "/ntlink8"));
4161
4162 //
4163 // Test the scenarios that should create LX symlinks.
4164 //
4165 // Absolute link.
4166 //
4167
4168 LxtCheckResult(DrvFsTestSymlinkHelper(DRVFS_SYMLINK_TEST_DIR "/file.txt", DRVFS_SYMLINK_TEST_DIR "/lxlink1"));
4169
4170 //
4171 // Relative link crossing mount with ..
4172 //
4173
4174 LxtCheckResult(DrvFsTestSymlinkHelper("../..", DRVFS_SYMLINK_TEST_DIR "/lxlink2"));
4175
4176 //
4177 // Relative link traversing an NT link.
4178 //
4179
4180 LxtCheckResult(DrvFsTestSymlinkHelper("ntlink2/../file.txt", DRVFS_SYMLINK_TEST_DIR "/lxlink3"));
4181
4182 //
4183 // Relative link to another LX link.
4184 //
4185
4186 LxtCheckResult(DrvFsTestSymlinkHelper("lxlink1", DRVFS_SYMLINK_TEST_DIR "/lxlink4"));
4187
4188 //
4189 // Target doesn't exist.
4190 //
4191
4192 LxtCheckResult(DrvFsTestSymlinkHelper("foo", DRVFS_SYMLINK_TEST_DIR "/lxlink5"));
4193
4194 //
4195 // Symlink points to itself.
4196 //
4197 // N.B. The main purpose of this check is to make sure this doesn't
4198 // deadlock.
4199 //
4200
4201 LxtCheckResult(DrvFsTestSymlinkHelper("lxlink6", DRVFS_SYMLINK_TEST_DIR "/lxlink6"));
4202
4203 //
4204 // Trying to create a symlink to itself if the target file exists should
4205 // return EEXIST and not deadlock.
4206 //
4207
4208 LxtCheckErrno(Fd = creat(DRVFS_SYMLINK_TEST_DIR "/link_exist", 0777));
4209 LxtCheckClose(Fd);
4210 LxtCheckErrnoFailure(symlink("link_exist", DRVFS_SYMLINK_TEST_DIR "/link_exist"), EEXIST);
4211
4212 //
4213 // Relative link crossing mount on subdir.
4214 //
4215
4216 LxtCheckErrnoZeroSuccess(mount("mytmp", DRVFS_SYMLINK_TEST_DIR "/dir", "tmpfs", 0, NULL));
4217
4218 LxtCheckResult(DrvFsTestSymlinkHelper("dir/../file.txt", DRVFS_SYMLINK_TEST_DIR "/lxlink7"));
4219
4220 ErrorExit:
4221 if (Fd >= 0)
4222 {
4223 close(Fd);
4224 }
4225
4226 unlink(DRVFS_SYMLINK_TEST_DIR "/link_exist");
4227 umount(DRVFS_SYMLINK_TEST_DIR "/dir");
4228 return Result;
4229 }
4230
4231 int DrvFsTestSymlinkHelper(char* Target, char* Path)
4232
4233 /*++
4234
4235 Description:
4236
4237 This routine tests if a symlink can be successfully created and its path
4238 is returned correctly.
4239
4240 Arguments:
4241
4242 Path - Supplies the path of the link to create.
4243
4244 Target - Supplies the link target.
4245
4246 Return Value:
4247
4248 Returns 0 on success, -1 on failure.
4249
4250 --*/
4251
4252 {
4253
4254 int Result;
4255 struct stat Stat;
4256
4257 LxtCheckErrnoZeroSuccess(symlink(Target, Path));
4258 LxtCheckErrnoZeroSuccess(lstat(Path, &Stat));
4259 LxtCheckEqual(Stat.st_mode, S_IFLNK | 0777, "0%o");
4260 LxtCheckResult(LxtCheckLinkTarget(Path, Target));
4261 LxtCheckEqual(Stat.st_size, strlen(Target), "%ull");
4262
4263 ErrorExit:
4264 return Result;
4265 }
4266
4267 int DrvFsTestUnsupportedCommon(int TestMode)
4268
4269 /*++
4270
4271 Description:
4272
4273 This routine tests unsupported functionality on FAT and SMB.
4274
4275 Arguments:
4276
4277 TestMode - Supplies the test mode.
4278
4279 Return Value:
4280
4281 Returns 0 on success, -1 on failure.
4282
4283 --*/
4284
4285 {
4286
4287 char Buffer[1024];
4288 int Fd;
4289 int Result;
4290
4291 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_UNSUPPORTED_TEST_DIR, 0777));
4292 LxtCheckErrno(Fd = creat(DRVFS_UNSUPPORTED_TEST_DIR "/target", 0666));
4293 LxtCheckClose(Fd);
4294 LxtCheckErrnoFailure(symlink(DRVFS_UNSUPPORTED_TEST_DIR "/target", DRVFS_UNSUPPORTED_TEST_DIR "/foo"), EPERM);
4295
4296 LxtCheckErrnoFailure(mknod(DRVFS_UNSUPPORTED_TEST_DIR "/foo", S_IFIFO | 0666, 0), EPERM);
4297
4298 if (TestMode == DRVFS_FAT_TEST_MODE)
4299 {
4300 LxtCheckErrnoFailure(link(DRVFS_UNSUPPORTED_TEST_DIR "/target", DRVFS_UNSUPPORTED_TEST_DIR "/foo"), EPERM);
4301
4302 LxtCheckErrnoFailure(LxtGetxattr(DRVFS_UNSUPPORTED_TEST_DIR "/target", "user.test", Buffer, sizeof(Buffer)), ENOTSUP);
4303
4304 LxtCheckErrnoFailure(LxtSetxattr(DRVFS_UNSUPPORTED_TEST_DIR "/target", "user.test", Buffer, sizeof(Buffer), 0), ENOTSUP);
4305
4306 LxtCheckErrnoFailure(LxtListxattr(DRVFS_UNSUPPORTED_TEST_DIR "/target", Buffer, sizeof(Buffer)), ENOTSUP);
4307 }
4308
4309 ErrorExit:
4310 unlink(DRVFS_UNSUPPORTED_TEST_DIR "/target");
4311 rmdir(DRVFS_UNSUPPORTED_TEST_DIR);
4312 return Result;
4313 }
4314
4315 int DrvFsTestUtimensat(PLXT_ARGS Args)
4316
4317 /*++
4318
4319 Description:
4320
4321 This routine tests the utimensat system call on drvfs.
4322
4323 Arguments:
4324
4325 Args - Supplies the command line arguments.
4326
4327 Return Value:
4328
4329 Returns 0 on success, -1 on failure.
4330
4331 --*/
4332
4333 {
4334
4335 return DrvFsTestUtimensatCommon(0);
4336 }
4337
4338 int DrvFsTestUtimensatCommon(int Flags)
4339
4340 /*++
4341
4342 Description:
4343
4344 This routine tests the utimensat system call on drvfs.
4345
4346 Arguments:
4347
4348 Flags - Supplies the flags.
4349
4350 Return Value:
4351
4352 Returns 0 on success, -1 on failure.
4353
4354 --*/
4355
4356 {
4357
4358 int Result;
4359
4360 Flags |= FS_UTIME_NT_PRECISION;
4361 LxtCheckResult(LxtFsUtimeCreateTestFiles(DRVFS_UTIME_TEST_DIR, Flags));
4362 LxtCheckResult(LxtFsUtimeBasicCommon(DRVFS_UTIME_TEST_DIR, Flags));
4363
4364 ErrorExit:
4365 LxtFsUtimeCleanupTestFiles(DRVFS_UTIME_TEST_DIR);
4366 return Result;
4367 }
4368
4369 int DrvFsTestWritev(PLXT_ARGS Args)
4370
4371 /*++
4372 --*/
4373
4374 {
4375
4376 int Result;
4377
4378 LxtCheckErrnoZeroSuccess(mkdir(DRVFS_WRITEV_TEST_DIR, 0777));
4379 LxtCheckResult(LxtFsWritevCommon(DRVFS_WRITEV_TEST_DIR "/fs_writev_test.bin"));
4380
4381 ErrorExit:
4382 unlink(DRVFS_WRITEV_TEST_DIR "/fs_writev_test.bin");
4383 rmdir(DRVFS_WRITEV_TEST_DIR);
4384 return Result;
4385 }