master
c 4,210 lines 114 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 fscommon.c
8
9 Abstract:
10
11 This file contains common FS unit tests that are run on both LxFs and DrvFs.
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <poll.h>
18 #include <dirent.h>
19 #include <sys/time.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/ioctl.h>
23 #include <sys/uio.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <sys/syscall.h>
28 #include <fcntl.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <linux/capability.h>
32 #include <sys/mount.h>
33 #include <sys/sysmacros.h>
34 #include <libmount/libmount.h>
35 #include "lxtmount.h"
36 #include "lxtfs.h"
37
38 #define LXT_NAME_LXFS "fscommon_lxfs"
39 #define LXT_NAME_DRVFS "fscommon_drvfs"
40
41 #define FS_TEST_DIR_PARENT "/data/fstest"
42 #define FS_CLEX_TEST_DIR_NAME FS_TEST_DIR_PARENT "/CLEX_test"
43 #define FS_READLINK_TEST_FILE FS_TEST_DIR_PARENT "/readlink_testfile"
44 #define FS_READLINK_TEST_LINK FS_TEST_DIR_PARENT "/readlink_testlink"
45 #define FS_RENAMEAT_TEST_DIR FS_TEST_DIR_PARENT "/rename_test"
46 #define FS_TRAILING_TEST_FILE FS_TEST_DIR_PARENT "/trailing_test_file"
47 #define FS_TRAILING_TEST_DIR FS_TEST_DIR_PARENT "/trailing_test_dir"
48 #define FS_TRAILING_TEST_LINK FS_TEST_DIR_PARENT "/trailing_test_link"
49 #define FS_MKNOD_TEST_FILE FS_TEST_DIR_PARENT "/myzero"
50 #define FS_MKNOD_TEST_FILE2 FS_TEST_DIR_PARENT "/myzero2"
51 #define FS_CHROOT_TEST_DIR FS_TEST_DIR_PARENT "/chroot_test"
52 #define FS_CHROOT_TEST_DIR_CHILD_FROM_ROOT "/child"
53 #define FS_CHROOT_TEST_DIR_CHILD FS_CHROOT_TEST_DIR FS_CHROOT_TEST_DIR_CHILD_FROM_ROOT
54 #define FS_CHROOT_TEST_DIR_PROC FS_CHROOT_TEST_DIR "/proc"
55 #define FS_FALLOCATE_TEST_FILE FS_TEST_DIR_PARENT "/fallocate_test_file"
56 #define FS_RMDIR_TEST_DIR FS_TEST_DIR_PARENT "/rmdir_test"
57 #define FS_POWERSHELL "/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe"
58 #define FS_POWERSHELL_MOUNT_COMMAND \
59 FS_POWERSHELL " -Command \"& { (Mount-DiskImage " FS_DRVFS_CD_TEST_ISO_NT " -PassThru | Get-Volume).DriveLetter }\""
60 #define FS_POWERSHELL_UNMOUNT_COMMAND FS_POWERSHELL " -Command \"& { Dismount-DiskImage " FS_DRVFS_CD_TEST_ISO_NT " }\""
61 #define FS_GENISOIMAGE_COMMAND "genisoimage -JR -o " FS_DRVFS_CD_TEST_ISO " " FS_DRVFS_CD_CONTENTS_DIR
62 #define FS_LINKAT_TEST_DIR FS_TEST_DIR_PARENT "/linkat_test"
63 #define FS_LINKAT_TEST_DIR2 FS_TEST_DIR_PARENT "/linkat_test2"
64 #define FS_FCHOWNAT_TEST_DIR FS_TEST_DIR_PARENT "/fchownat_test"
65 #define FS_DELETELOOP_TEST_DIR FS_TEST_DIR_PARENT "/deleteloop"
66 #define FS_FSYNC_TEST_DIR FS_TEST_DIR_PARENT "/fsync_test"
67
68 LXT_VARIATION_HANDLER FsCommonTestCreateAndRename;
69 LXT_VARIATION_HANDLER FsCommonTestDeleteCurrentWorkingDirectory;
70 LXT_VARIATION_HANDLER FsCommonTestDeleteLoop;
71 LXT_VARIATION_HANDLER FsCommonTestDeleteOpenFile;
72 LXT_VARIATION_HANDLER FsCommonTestChroot;
73 LXT_VARIATION_HANDLER FsCommonTestClex;
74 LXT_VARIATION_HANDLER FsCommonTestCreateSymlinkTarget;
75 LXT_VARIATION_HANDLER FsCommonTestDeviceId;
76 LXT_VARIATION_HANDLER FsCommonTestFchownAt;
77 LXT_VARIATION_HANDLER FsCommonTestReadlinkat;
78 LXT_VARIATION_HANDLER FsCommonTestRemoveSelfOrParent;
79 LXT_VARIATION_HANDLER FsCommonTestRenameAt;
80 LXT_VARIATION_HANDLER FsCommonTestRenameDir;
81 LXT_VARIATION_HANDLER FsCommonTestSetEof;
82 LXT_VARIATION_HANDLER FsCommonTestTrailingSlash;
83 LXT_VARIATION_HANDLER FsCommonTestLinkAt;
84 LXT_VARIATION_HANDLER FsCommonTestMkdir;
85 LXT_VARIATION_HANDLER FsCommonTestMkDirAt;
86 LXT_VARIATION_HANDLER FsCommonTestMknod;
87 LXT_VARIATION_HANDLER FsCommonTestMknodSecurity;
88 LXT_VARIATION_HANDLER FsCommonTestOpen;
89 LXT_VARIATION_HANDLER FsCommonTestOpenAt;
90 LXT_VARIATION_HANDLER FsCommonTestOpenCreateSymlink;
91 LXT_VARIATION_HANDLER FsCommonTestOpenCreateSymlinkDir;
92 #ifdef __NR_getdents
93 LXT_VARIATION_HANDLER FsCommonTestGetDents;
94 #endif
95 LXT_VARIATION_HANDLER FsCommonTestGetDents64Alignment;
96 #ifdef __NR_getdents
97 LXT_VARIATION_HANDLER FsCommonTestGetDentsAlignment;
98 #endif
99 LXT_VARIATION_HANDLER FsCommonTestGetDentsTypes;
100 LXT_VARIATION_HANDLER FsCommonTestChdir;
101 LXT_VARIATION_HANDLER FsCommonTestUnlinkAt;
102 LXT_VARIATION_HANDLER FsCommonTestFstatAt64;
103 LXT_VARIATION_HANDLER FsCommonTestFchdir;
104 LXT_VARIATION_HANDLER FsCommonTestNoatimeFlag;
105 LXT_VARIATION_HANDLER FsCommonTestWritev;
106 LXT_VARIATION_HANDLER FsCommonTestFallocate;
107 LXT_VARIATION_HANDLER FsCommonTestDirSeek;
108 LXT_VARIATION_HANDLER FsCommonTestFsync;
109
110 //
111 // Global constants
112 //
113
114 static const LXT_VARIATION g_LxtVariations[] = {
115 {"Test mkdir/rmdir", FsCommonTestMkdir},
116 {"Test SetEof", FsCommonTestSetEof},
117 {"Test Create, Rename and unlink", FsCommonTestCreateAndRename},
118 {"Test Open", FsCommonTestOpen},
119 {"Test OpenAt", FsCommonTestOpenAt},
120 {"Test Open symlink with O_CREAT", FsCommonTestOpenCreateSymlink},
121 {"Test creating a symlink to a directory", FsCommonTestOpenCreateSymlinkDir},
122 {"Test Chdir", FsCommonTestChdir},
123 #ifdef __NR_getdents
124 {"Test GetDents", FsCommonTestGetDents},
125 #endif
126 {"Test UnlinkAt", FsCommonTestUnlinkAt},
127 {"Test fstatat64", FsCommonTestFstatAt64},
128 {"Test Fchdir", FsCommonTestFchdir},
129 {"Test mkdirat", FsCommonTestMkDirAt},
130 {"Test O_NOATIME flag", FsCommonTestNoatimeFlag},
131 {"Test deleting an open file", FsCommonTestDeleteOpenFile},
132 {"Test deleting the working directory", FsCommonTestDeleteCurrentWorkingDirectory},
133 {"Test rename directory", FsCommonTestRenameDir},
134 {"Test writev", FsCommonTestWritev},
135 {"Test readlinkat", FsCommonTestReadlinkat},
136 {"Test renameat", FsCommonTestRenameAt},
137 {"Test DeviceId", FsCommonTestDeviceId},
138 {"Test FIOCLEX/FIONCLEX", FsCommonTestClex},
139 {"Test create symlink target", FsCommonTestCreateSymlinkTarget},
140 {"Test trailing slash", FsCommonTestTrailingSlash},
141 {"Test mknod", FsCommonTestMknod},
142 {"Test mknod CAP_MKNOD", FsCommonTestMknodSecurity},
143 {"Test chroot", FsCommonTestChroot},
144 {"Test fallocate", FsCommonTestFallocate},
145 {"Test remove self or parent", FsCommonTestRemoveSelfOrParent},
146 {"Test linkat", FsCommonTestLinkAt},
147 {"Test fchownat", FsCommonTestFchownAt},
148 {"Test delete loop", FsCommonTestDeleteLoop},
149 #ifdef __NR_getdents
150 {"Test getdents alignment", FsCommonTestGetDentsAlignment},
151 #endif
152 {"Test getdents64 alignment", FsCommonTestGetDents64Alignment},
153 {"Test lseek on directory", FsCommonTestDirSeek},
154 {"Test getdents file types", FsCommonTestGetDentsTypes},
155 {"Test fsync", FsCommonTestFsync}};
156
157 int FsCommonTestEntry(int Argc, char* Argv[])
158
159 /*++
160 --*/
161
162 {
163
164 LXT_ARGS Args;
165 int Index;
166 const char* Name;
167 int Result;
168 bool UseDrvFs;
169
170 //
171 // Check if drvfs should be used.
172 //
173
174 Name = LXT_NAME_LXFS;
175 UseDrvFs = false;
176 for (Index = 1; Index < Argc; Index += 1)
177 {
178 if (strcmp(Argv[Index], "drvfs") == 0)
179 {
180 UseDrvFs = true;
181 Name = LXT_NAME_DRVFS;
182 break;
183 }
184 }
185
186 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, Name));
187 LXT_SYNCHRONIZATION_POINT_INIT();
188 LxtCheckResult(LxtFsTestSetup(&Args, FS_TEST_DIR_PARENT, "/fstest", UseDrvFs));
189
190 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
191
192 ErrorExit:
193 LxtFsTestCleanup(FS_TEST_DIR_PARENT, "/fstest", UseDrvFs);
194 LXT_SYNCHRONIZATION_POINT_DESTROY();
195 LxtUninitialize();
196 return !LXT_SUCCESS(Result);
197 }
198
199 #if !defined(__amd64__) && !defined(__aarch64__)
200
201 struct dirent64
202 {
203 __u64 d_ino;
204 __s64 d_off;
205 unsigned short d_reclen;
206 unsigned char d_type;
207 char d_name[1];
208 };
209
210 #endif
211
212 struct GetDentsPaths
213 {
214 const char* Path;
215 int MinElements;
216 int MaxElements;
217 };
218
219 #define LXT_GET_DENTS_FOLDER FS_TEST_DIR_PARENT "/getdents"
220
221 int FsCommonTestChroot(PLXT_ARGS Args)
222
223 /*++
224
225 Description:
226
227 This routine tests some chroot effects that are not covered by LTP.
228
229 Arguments:
230
231 Args - Supplies the command line arguments.
232
233 Return Value:
234
235 Returns 0 on success, -1 on failure.
236
237 --*/
238
239 {
240
241 pid_t ChildPid;
242 int Fd;
243 int Fd2;
244 char Path[PATH_MAX];
245 int Result;
246
247 Fd = -1;
248 Fd2 = -2;
249
250 //
251 // This test is not really relevant to VM mode, and currently doesn't pass
252 // because VM mode already runs in a chroot environment, changing some of
253 // paths.
254 //
255 // TODO_LX: Re-enable this when init switches to using pivot_root.
256 //
257
258 if (g_LxtFsInfo.FsType == LxtFsTypePlan9)
259 {
260 LxtLogInfo("Skipping chroot test in VM mode.");
261 Result = LXT_RESULT_SUCCESS;
262 goto ErrorExit;
263 }
264
265 //
266 // Set up the directories needed for the chroot environment.
267 //
268
269 LxtCheckResult(LxtSignalBlock(SIGUSR1));
270 LxtCheckErrnoZeroSuccess(mkdir(FS_CHROOT_TEST_DIR, 0777));
271 LxtCheckErrnoZeroSuccess(mkdir(FS_CHROOT_TEST_DIR_CHILD, 0777));
272 LxtCheckErrnoZeroSuccess(mkdir(FS_CHROOT_TEST_DIR_PROC, 0777));
273 LxtCheckErrnoZeroSuccess(mount("/proc", FS_CHROOT_TEST_DIR_PROC, NULL, MS_BIND, NULL));
274
275 //
276 // First test with the cwd inside the new root when chroot is called.
277 //
278 // N.B. The parent cwd is outside the new root.
279 //
280
281 LxtLogInfo("Cwd inside new root...");
282 LxtCheckErrnoZeroSuccess(chdir(FS_TEST_DIR_PARENT));
283 LxtCheckErrno(ChildPid = fork());
284 if (ChildPid == 0)
285 {
286 //
287 // Change current directory and open a file both in and outside the
288 // new root.
289 //
290
291 LxtCheckErrnoZeroSuccess(chdir(FS_CHROOT_TEST_DIR_CHILD));
292 LxtCheckErrno(Fd = open("/etc/hosts", O_RDONLY));
293 LxtCheckErrno(Fd2 = open(FS_CHROOT_TEST_DIR_CHILD, O_DIRECTORY));
294 LxtCheckErrnoZeroSuccess(access("../../../../etc", F_OK));
295 LxtCheckErrnoZeroSuccess(faccessat(Fd2, "../../../../etc", F_OK, 0));
296
297 //
298 // Change the root directory.
299 //
300
301 LxtCheckErrnoZeroSuccess(chroot(FS_CHROOT_TEST_DIR));
302
303 //
304 // The working directory path and fd inside the new root should
305 // reflect the new root.
306 //
307 // N.B. The working directory is not changed by chroot; because it is
308 // inside the reported path is changed automatically.
309 //
310
311 LxtCheckErrno(LxtGetcwd(Path, sizeof(Path)));
312 LxtCheckStringEqual(Path, FS_CHROOT_TEST_DIR_CHILD_FROM_ROOT);
313 LxtCheckResult(LxtCheckLinkTarget("/proc/self/cwd", FS_CHROOT_TEST_DIR_CHILD_FROM_ROOT));
314
315 LxtCheckResult(LxtCheckFdPath(Fd2, FS_CHROOT_TEST_DIR_CHILD_FROM_ROOT));
316
317 //
318 // The file descriptor outside the root still reports its old path.
319 //
320
321 LxtCheckResult(LxtCheckFdPath(Fd, "/etc/hosts"));
322
323 //
324 // Check that the root can't be escaped.
325 //
326
327 LxtCheckErrnoFailure(access("/etc", F_OK), ENOENT);
328 LxtCheckErrnoFailure(access("../../../../etc", F_OK), ENOENT);
329 LxtCheckErrnoFailure(faccessat(Fd2, "../../../../etc", F_OK, 0), ENOENT);
330
331 //
332 // The root symlink should say /, and refer to the new root.
333 //
334
335 LxtCheckResult(LxtCheckLinkTarget("/proc/self/root", "/"));
336 LxtCheckErrnoFailure(access("/proc/self/root/etc", F_OK), ENOENT);
337
338 //
339 // The parent's root symlink also says /, even though it's not the same
340 // path. It can be used to escape the chroot jail.
341 //
342
343 sprintf(Path, "/proc/%d/root", getppid());
344 LxtCheckResult(LxtCheckLinkTarget(Path, "/"));
345 sprintf(Path, "/proc/%d/root/etc", getppid());
346 LxtCheckErrnoZeroSuccess(access(Path, F_OK));
347
348 //
349 // The parent's cwd is not inside the new root, so the link returns
350 // its actual path. It can also be used to escape the chroot jail.
351 //
352
353 sprintf(Path, "/proc/%d/cwd", getppid());
354 LxtCheckResult(LxtCheckLinkTarget(Path, FS_TEST_DIR_PARENT));
355 sprintf(Path, "/proc/%d/cwd/chroot_test", getppid());
356 LxtCheckErrnoZeroSuccess(access(Path, F_OK));
357
358 //
359 // Signal the parent.
360 //
361
362 LxtCheckErrnoZeroSuccess(kill(getppid(), SIGUSR1));
363 LxtCheckResult(LxtSignalWaitBlocked(SIGUSR1, getppid(), 2));
364 exit(0);
365 }
366
367 LxtCheckResult(LxtSignalWaitBlocked(SIGUSR1, ChildPid, 2));
368
369 //
370 // Check the root symlink for the child returns the new root path.
371 //
372
373 sprintf(Path, "/proc/%d/root", ChildPid);
374 LxtCheckResult(LxtCheckLinkTarget(Path, FS_CHROOT_TEST_DIR));
375 sprintf(Path, "/proc/%d/cwd", ChildPid);
376 LxtCheckResult(LxtCheckLinkTarget(Path, FS_CHROOT_TEST_DIR_CHILD));
377 LxtCheckErrnoZeroSuccess(kill(ChildPid, SIGUSR1));
378 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
379
380 //
381 // Now test with cwd outside the new root, in which case the path reported
382 // by getcwd should indicate unreachable, but /proc/self/cwd should give
383 // the normal path.
384 //
385 // N.B. The parent cwd is inside the new root for this test.
386 //
387
388 LxtLogInfo("Cwd outside new root...");
389 LxtCheckErrnoZeroSuccess(chdir(FS_CHROOT_TEST_DIR_CHILD));
390 LxtCheckErrno(ChildPid = fork());
391 if (ChildPid == 0)
392 {
393 LxtCheckErrnoZeroSuccess(chdir(FS_TEST_DIR_PARENT));
394 LxtCheckErrnoZeroSuccess(chroot(FS_CHROOT_TEST_DIR));
395
396 //
397 // Glibc getcwd in newer versions returns NULL if the path doesn't
398 // start with a /, which would be the case here, so call the syscall
399 // directly.
400 //
401
402 LxtCheckErrno(LxtGetcwd(Path, sizeof(Path)));
403 LxtCheckStringEqual(Path, "(unreachable)" FS_TEST_DIR_PARENT);
404 LxtCheckResult(LxtCheckLinkTarget("/proc/self/cwd", FS_TEST_DIR_PARENT));
405
406 //
407 // The parent's cwd is reported using the new root.
408 //
409
410 sprintf(Path, "/proc/%d/cwd", getppid());
411 LxtCheckResult(LxtCheckLinkTarget(Path, FS_CHROOT_TEST_DIR_CHILD_FROM_ROOT));
412
413 exit(0);
414 }
415
416 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
417
418 //
419 // Cwd matches the new root.
420 //
421
422 LxtLogInfo("Cwd exactly new root...");
423 LxtCheckErrno(ChildPid = fork());
424 if (ChildPid == 0)
425 {
426 LxtCheckErrnoZeroSuccess(chdir(FS_CHROOT_TEST_DIR));
427 LxtCheckErrnoZeroSuccess(chroot(FS_CHROOT_TEST_DIR));
428 LxtCheckErrno(LxtGetcwd(Path, sizeof(Path)));
429 LxtCheckStringEqual(Path, "/");
430 LxtCheckResult(LxtCheckLinkTarget("/proc/self/cwd", "/"));
431 exit(0);
432 }
433
434 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
435
436 //
437 // Cwd is the old root.
438 //
439
440 LxtLogInfo("Cwd exactly old root...");
441 LxtCheckErrno(ChildPid = fork());
442 if (ChildPid == 0)
443 {
444 LxtCheckErrnoZeroSuccess(chdir("/"));
445 LxtCheckErrnoZeroSuccess(chroot(FS_CHROOT_TEST_DIR));
446
447 //
448 // Glibc getcwd in newer versions returns NULL if the path doesn't
449 // start with a /, which would be the case here, so call the syscall
450 // directly.
451 //
452
453 LxtCheckErrno(LxtGetcwd(Path, sizeof(Path)));
454 LxtCheckStringEqual(Path, "(unreachable)/");
455 memset(Path, 0, sizeof(Path));
456 LxtCheckErrno(readlink("/proc/self/cwd", Path, sizeof(Path)));
457 LxtCheckStringEqual(Path, "/");
458 exit(0);
459 }
460
461 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
462
463 ErrorExit:
464 if (Fd >= 0)
465 {
466 close(Fd);
467 }
468
469 if (Fd2 >= 0)
470 {
471 close(Fd2);
472 }
473
474 umount(FS_CHROOT_TEST_DIR_PROC);
475 rmdir(FS_CHROOT_TEST_DIR_PROC);
476 rmdir(FS_CHROOT_TEST_DIR_CHILD);
477 rmdir(FS_CHROOT_TEST_DIR);
478 return Result;
479 }
480
481 int FsCommonTestClex(PLXT_ARGS Args)
482
483 /*++
484
485 Description:
486
487 This routine tests the FIONCLEX / FIONCLEX file descriptor ioctls.
488
489 Arguments:
490
491 Args - Supplies the command line arguments.
492
493 Return Value:
494
495 Returns 0 on success, -1 on failure.
496
497 --*/
498
499 {
500
501 pid_t ChildPid;
502 int Fd = -1;
503 int Result;
504
505 //
506 // Don't set close on exec on file descriptors in the main test process;
507 // this would cause later tests to fail.
508 //
509
510 LxtCheckErrno(ChildPid = fork());
511 if (ChildPid == 0)
512 {
513
514 //
515 // First set the ioctls on stdin.
516 //
517
518 LxtCheckErrno(ioctl(0, FIONCLEX, NULL));
519 LxtCheckErrno(ioctl(0, FIOCLEX, NULL));
520
521 //
522 // Create a directory and open a file descriptor with O_PATH.
523 //
524
525 LxtCheckErrno(mkdir(FS_CLEX_TEST_DIR_NAME, 0777));
526 LxtCheckErrno(Fd = open(FS_CLEX_TEST_DIR_NAME, O_PATH | O_DIRECTORY));
527
528 //
529 // Setting the CLOEXEC flag with fcntl should work even though the file
530 // was opened with O_PATH.
531 //
532
533 LxtCheckErrno(fcntl(Fd, F_SETFD, FD_CLOEXEC));
534
535 //
536 // Setting FIONCLEX / FIOCLEX with the ioctl syscall should fail.
537 //
538
539 LxtCheckErrnoFailure(ioctl(Fd, FIONCLEX, NULL), EBADF);
540 LxtCheckErrnoFailure(ioctl(Fd, FIOCLEX, NULL), EBADF);
541 exit(0);
542 }
543
544 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
545 Result = LXT_RESULT_SUCCESS;
546
547 ErrorExit:
548 rmdir(FS_CLEX_TEST_DIR_NAME);
549 if (Fd != -1)
550 {
551 LxtClose(Fd);
552 }
553
554 return Result;
555 }
556
557 typedef struct _LXSS_BYTE_ALIGNED_DIRENTS
558 {
559 char Padding;
560 char Buffer[sizeof(struct dirent64)];
561 } LXSS_BYTE_ALIGNED_DIRENTS;
562
563 #ifdef __NR_getdents
564 int FsCommonTestGetDents(PLXT_ARGS Args)
565
566 /*++
567 --*/
568
569 {
570
571 LXSS_BYTE_ALIGNED_DIRENTS ByteAlignedDirents;
572 char* Buffer;
573 struct dirent64* BufferEntries[2000];
574 int BufferEntriesCount;
575 int BufferIndex;
576 int BufferLoopIndex;
577 int BufferSize = 2 * 1024 * 1024;
578 int BytePos;
579 int BytesRead;
580 int DirFd;
581 struct dirent64* Entry;
582 int ExpectedLength;
583 bool FoundDot;
584 bool FoundDotDot;
585 int NameLength;
586 int Pass;
587 size_t PathIndex;
588
589 //
590 // TODO: use cgroups path once it is mounted for 64 bit lxss.
591 //
592
593 struct GetDentsPaths Paths[] = {
594 {"/proc/self/", 18, 64},
595 {"/proc/", 10, 500},
596 {"/dev/", 14, 1000},
597 //{"/acct/", 7, 64},
598 {"/", 4, 64},
599 {LXT_GET_DENTS_FOLDER, 2, 2}};
600
601 Buffer = NULL;
602 DirFd = -1;
603 int Result;
604 char SingleEntry[100];
605 int SingleEntrySize;
606 rmdir(LXT_GET_DENTS_FOLDER);
607
608 //
609 // Check the expected getdents results for each directory;
610 //
611
612 Buffer = malloc(BufferSize);
613 if (Buffer == NULL)
614 {
615 Result = LXT_RESULT_FAILURE;
616 LxtLogError("malloc");
617 goto ErrorExit;
618 }
619
620 LxtCheckErrno(mkdir(LXT_GET_DENTS_FOLDER, 0777));
621 for (PathIndex = 0; PathIndex < LXT_COUNT_OF(Paths); PathIndex += 1)
622 {
623
624 //
625 // First read all of the entries in a single call.
626 //
627
628 memset(Buffer, 1, BufferSize);
629 LxtLogInfo("Opening %s...", Paths[PathIndex].Path);
630 LxtCheckErrno(DirFd = open(Paths[PathIndex].Path, O_RDONLY | O_DIRECTORY));
631 LxtCheckErrno(BytesRead = LxtGetdents64(DirFd, Buffer, BufferSize));
632 if (BytesRead == 0)
633 {
634 Result = LXT_RESULT_FAILURE;
635 LxtLogError("BytesRead == 0");
636 goto ErrorExit;
637 }
638
639 LxtCheckErrno(LxtGetdents(DirFd, SingleEntry, sizeof(SingleEntry)));
640 if (Result != 0)
641 {
642 Result = LXT_RESULT_FAILURE;
643 LxtLogError("BytesRead Result ! 0");
644 goto ErrorExit;
645 }
646
647 FoundDot = false;
648 FoundDotDot = false;
649 BufferIndex = 0;
650 for (BytePos = 0; BytePos < BytesRead;)
651 {
652 Entry = (struct dirent64*)(Buffer + BytePos);
653 BufferEntries[BufferIndex] = Entry;
654 NameLength = strlen(Entry->d_name);
655
656 if (strcmp(Entry->d_name, ".") == 0)
657 {
658 FoundDot = true;
659 }
660
661 if (strcmp(Entry->d_name, "..") == 0)
662 {
663 FoundDotDot = true;
664 }
665
666 BufferIndex += 1;
667 BytePos += Entry->d_reclen;
668 }
669
670 if ((FoundDot == false) || (FoundDotDot == false))
671 {
672 Result = LXT_RESULT_FAILURE;
673 LxtLogError("Missing entries for . or .. or both.");
674 goto ErrorExit;
675 }
676
677 BufferEntriesCount = BufferIndex;
678 if (BufferEntriesCount < Paths[PathIndex].MinElements)
679 {
680 Result = LXT_RESULT_FAILURE;
681 LxtLogError("Unexpected number of elements %d < %d", BufferEntriesCount, Paths[PathIndex].MinElements);
682 goto ErrorExit;
683 }
684
685 if (BufferEntriesCount > Paths[PathIndex].MaxElements)
686 {
687 Result = LXT_RESULT_FAILURE;
688 LxtLogError("Unexpected number of elements %d > %d", BufferEntriesCount, Paths[PathIndex].MaxElements);
689 goto ErrorExit;
690 }
691
692 LxtClose(DirFd);
693 DirFd = -1;
694
695 //
696 // Then read each entry in a single call and make sure it matches the
697 // previous data returned.
698 //
699 // In pass 0, just read sequentially. In pass 1, seek to each offset
700 // in reverse order to ensure that seek works.
701 //
702
703 for (Pass = 0; Pass < 2; Pass++)
704 {
705 LxtLogInfo("Reopening %s...", Paths[PathIndex].Path);
706 LxtCheckErrno(DirFd = open(Paths[PathIndex].Path, O_RDONLY | O_DIRECTORY));
707 for (BufferLoopIndex = 0; BufferLoopIndex < BufferEntriesCount; BufferLoopIndex += 1)
708 {
709 if (Pass == 0)
710 {
711 BufferIndex = BufferLoopIndex;
712 }
713 else
714 {
715 BufferIndex = BufferEntriesCount - BufferLoopIndex - 1;
716
717 //
718 // Plan 9 client in Linux has a bug where seek does not
719 // take effect if not all entries were consumed. Reopen
720 // the FD to allow seek to work.
721 //
722 // TODO_LX: Remove this one the plan 9 bug is fixed.
723 //
724
725 if (g_LxtFsInfo.FsType == LxtFsTypePlan9)
726 {
727 LxtCheckClose(DirFd);
728 LxtCheckErrno(DirFd = open(Paths[PathIndex].Path, O_RDONLY | O_DIRECTORY));
729 }
730
731 LxtCheckErrno(lseek(DirFd, BufferIndex == 0 ? 0 : BufferEntries[BufferIndex - 1]->d_off, SEEK_SET));
732 }
733
734 SingleEntrySize = BufferEntries[BufferIndex]->d_reclen;
735 BytesRead = LxtGetdents64(DirFd, SingleEntry, SingleEntrySize);
736 if (BytesRead < 0)
737 {
738 Result = LXT_RESULT_FAILURE;
739 LxtLogError("Failed on %s with %s", BufferEntries[BufferIndex]->d_name, strerror(errno));
740 goto ErrorExit;
741 }
742
743 if (BytesRead == 0)
744 {
745 Result = LXT_RESULT_FAILURE;
746 LxtLogError("BytesRead == 0");
747 goto ErrorExit;
748 }
749
750 Entry = (struct dirent64*)SingleEntry;
751 if (Entry->d_reclen != BufferEntries[BufferIndex]->d_reclen)
752 {
753 Result = LXT_RESULT_FAILURE;
754 LxtLogInfo("Unexpected d_reclen %d != %d", Entry->d_reclen, BufferEntries[BufferIndex]->d_reclen);
755 goto ErrorExit;
756 }
757
758 if (strcmp(Entry->d_name, BufferEntries[BufferIndex]->d_name) != 0)
759 {
760 Result = LXT_RESULT_FAILURE;
761 LxtLogError("Unexpected name %s != %s", Entry->d_name, BufferEntries[BufferIndex]->d_name);
762 goto ErrorExit;
763 }
764
765 if (Entry->d_type != BufferEntries[BufferIndex]->d_type)
766 {
767 Result = LXT_RESULT_FAILURE;
768 LxtLogInfo("Unexpected d_type %d != %d", Entry->d_type, BufferEntries[BufferIndex]->d_type);
769 goto ErrorExit;
770 }
771
772 if (Entry->d_reclen != BufferEntries[BufferIndex]->d_reclen)
773 {
774 Result = LXT_RESULT_FAILURE;
775 LxtLogInfo("Unexpected d_reclen %d != %d", Entry->d_reclen, BufferEntries[BufferIndex]->d_reclen);
776 goto ErrorExit;
777 }
778
779 if (Entry->d_off != BufferEntries[BufferIndex]->d_off)
780 {
781 Result = LXT_RESULT_FAILURE;
782 LxtLogInfo("Unexpected d_off %d != %d", Entry->d_off, BufferEntries[BufferIndex]->d_off);
783 goto ErrorExit;
784 }
785 }
786
787 if (Pass == 0)
788 {
789 LxtCheckErrno(LxtGetdents64(DirFd, SingleEntry, sizeof(SingleEntry)));
790 if (Result != 0)
791 {
792 Result = LXT_RESULT_FAILURE;
793 LxtLogError("BytesRead Result ! 0");
794 goto ErrorExit;
795 }
796 }
797
798 LxtClose(DirFd);
799 DirFd = -1;
800 }
801 }
802
803 //
804 // Test alignment of getdents syscall.
805 //
806
807 LxtCheckErrno(DirFd = open(".", O_RDONLY | O_DIRECTORY));
808 LxtLogInfo("Calling getdents with input buffer %p", &ByteAlignedDirents.Buffer);
809 LxtCheckErrno(LxtGetdents64(DirFd, &ByteAlignedDirents.Buffer, sizeof(ByteAlignedDirents.Buffer)));
810
811 LxtLogInfo("getdents test successful!");
812
813 Result = LXT_RESULT_SUCCESS;
814
815 ErrorExit:
816 if (Buffer != NULL)
817 {
818 free(Buffer);
819 }
820
821 if (DirFd != -1)
822 {
823 LxtClose(DirFd);
824 }
825
826 rmdir(LXT_GET_DENTS_FOLDER);
827 return Result;
828 }
829 #endif
830
831 int FsCommonTestGetDents64Alignment(PLXT_ARGS Args)
832
833 /*++
834
835 Description:
836
837 This routine tests whether directory entries are correctly aligned and
838 padded.
839
840 Arguments:
841
842 Args - Supplies the command line arguments.
843
844 Return Value:
845
846 Returns 0 on success, -1 on failure.
847
848 --*/
849
850 {
851
852 int Result;
853
854 LxtCheckResult(LxtFsGetDentsAlignmentCommon(LXT_GET_DENTS_FOLDER, FS_TEST_GETDENTS64));
855
856 ErrorExit:
857 return Result;
858 }
859
860 #ifdef __NR_getdents
861 int FsCommonTestGetDentsAlignment(PLXT_ARGS Args)
862
863 /*++
864
865 Description:
866
867 This routine tests whether directory entries are correctly aligned and
868 padded.
869
870 Arguments:
871
872 Args - Supplies the command line arguments.
873
874 Return Value:
875
876 Returns 0 on success, -1 on failure.
877
878 --*/
879
880 {
881
882 int Result;
883
884 LxtCheckResult(LxtFsGetDentsAlignmentCommon(LXT_GET_DENTS_FOLDER, 0));
885
886 ErrorExit:
887 return Result;
888 }
889 #endif
890
891 int FsCommonTestGetDentsTypes(PLXT_ARGS Args)
892
893 /*++
894
895 Description:
896
897 This routine tests whether all files are reported as the correct types by
898 getdents.
899
900 Arguments:
901
902 Args - Supplies the command line arguments.
903
904 Return Value:
905
906 Returns 0 on success, -1 on failure.
907
908 --*/
909
910 {
911
912 LXT_CHILD_INFO Children[] = {
913 {"regchild", DT_REG},
914 {"dirchild", DT_DIR},
915 {"linkchild1", DT_LNK},
916 {"linkchild2", DT_LNK},
917 {"linkchild3", DT_LNK},
918 {"dirchild", DT_DIR},
919 {"fifochild", DT_FIFO},
920 {"sockchild", DT_SOCK},
921 {"chrchild", DT_CHR},
922 {"blkchild", DT_BLK}};
923
924 int Result;
925
926 LxtCheckErrnoZeroSuccess(mkdir(LXT_GET_DENTS_FOLDER, 0777));
927 LxtCheckErrnoZeroSuccess(mkdir(LXT_GET_DENTS_FOLDER "/dirchild", 0777));
928 LxtCheckErrnoZeroSuccess(mknod(LXT_GET_DENTS_FOLDER "/regchild", S_IFREG | 0666, 0));
929 LxtCheckErrnoZeroSuccess(mknod(LXT_GET_DENTS_FOLDER "/fifochild", S_IFIFO | 0666, 0));
930 LxtCheckErrnoZeroSuccess(mknod(LXT_GET_DENTS_FOLDER "/sockchild", S_IFSOCK | 0666, 0));
931 LxtCheckErrnoZeroSuccess(mknod(LXT_GET_DENTS_FOLDER "/chrchild", S_IFCHR | 0666, makedev(1, 3)));
932 LxtCheckErrnoZeroSuccess(mknod(LXT_GET_DENTS_FOLDER "/blkchild", S_IFBLK | 0666, makedev(1, 1)));
933 LxtCheckErrnoZeroSuccess(symlink("regchild", LXT_GET_DENTS_FOLDER "/linkchild1"));
934
935 //
936 // Directory symlinks and absolute symlinks may have different representations on DrvFs, so test them too.
937 //
938
939 LxtCheckErrnoZeroSuccess(symlink("dirchild", LXT_GET_DENTS_FOLDER "/linkchild2"));
940 LxtCheckErrnoZeroSuccess(symlink("/proc", LXT_GET_DENTS_FOLDER "/linkchild3"));
941 LxtCheckResult(LxtCheckDirectoryContentsEx(LXT_GET_DENTS_FOLDER, Children, LXT_COUNT_OF(Children), 0));
942
943 ErrorExit:
944 unlink(LXT_GET_DENTS_FOLDER "/linkchild1");
945 unlink(LXT_GET_DENTS_FOLDER "/linkchild2");
946 unlink(LXT_GET_DENTS_FOLDER "/linkchild3");
947 unlink(LXT_GET_DENTS_FOLDER "/fifochild");
948 unlink(LXT_GET_DENTS_FOLDER "/sockchild");
949 unlink(LXT_GET_DENTS_FOLDER "/chrchild");
950 unlink(LXT_GET_DENTS_FOLDER "/blkchild");
951 unlink(LXT_GET_DENTS_FOLDER "/regchild");
952 rmdir(LXT_GET_DENTS_FOLDER "/dirchild");
953 rmdir(LXT_GET_DENTS_FOLDER);
954 return Result;
955 }
956
957 int FsCommonTestLinkAt(PLXT_ARGS Args)
958
959 /*++
960
961 Description:
962
963 This routine tests the linkat system call.
964
965 Arguments:
966
967 Args - Supplies the command line arguments.
968
969 Return Value:
970
971 Returns 0 on success, -1 on failure.
972
973 --*/
974
975 {
976
977 int Fd;
978 struct stat FileStat;
979 int Result;
980 int SourceDirFd;
981 struct stat Stat;
982 int SymlinkFd;
983 struct stat SymlinkStat;
984 int TargetDirFd;
985
986 SourceDirFd = -1;
987 TargetDirFd = -1;
988 Fd = -1;
989 SymlinkFd = -1;
990
991 //
992 // Set up the test files.
993 //
994
995 LxtCheckErrnoZeroSuccess(mkdir(FS_LINKAT_TEST_DIR, 0777));
996 LxtCheckErrnoZeroSuccess(mkdir(FS_LINKAT_TEST_DIR2, 0777));
997 LxtCheckErrno(Fd = creat(FS_LINKAT_TEST_DIR "/testfile", 0666));
998 LxtCheckClose(Fd);
999 LxtCheckErrnoZeroSuccess(symlink(FS_LINKAT_TEST_DIR "/testfile", FS_LINKAT_TEST_DIR "/testsymlink"));
1000
1001 LxtCheckErrnoZeroSuccess(symlink(FS_LINKAT_TEST_DIR, FS_LINKAT_TEST_DIR "/testdirsymlink"));
1002
1003 LxtCheckErrnoZeroSuccess(lstat(FS_LINKAT_TEST_DIR "/testfile", &FileStat));
1004 LxtCheckErrnoZeroSuccess(lstat(FS_LINKAT_TEST_DIR "/testsymlink", &SymlinkStat));
1005
1006 //
1007 // Create a regular hard link.
1008 //
1009
1010 LxtCheckErrno(SourceDirFd = open(FS_LINKAT_TEST_DIR, O_RDONLY | O_DIRECTORY));
1011 LxtCheckErrno(TargetDirFd = open(FS_LINKAT_TEST_DIR2, O_RDONLY | O_DIRECTORY));
1012 LxtCheckErrnoZeroSuccess(linkat(SourceDirFd, "testfile", TargetDirFd, "testlink", 0));
1013
1014 LxtCheckErrnoZeroSuccess(lstat(FS_LINKAT_TEST_DIR2 "/testlink", &Stat));
1015 LxtCheckEqual(FileStat.st_ino, Stat.st_ino, "%lld");
1016 LxtCheckTrue(S_ISREG(Stat.st_mode));
1017 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink"));
1018
1019 //
1020 // Using AT_FDCWD.
1021 //
1022
1023 LxtCheckErrnoZeroSuccess(chdir(FS_LINKAT_TEST_DIR));
1024 LxtCheckErrnoZeroSuccess(linkat(AT_FDCWD, "testfile", TargetDirFd, "testlink", 0));
1025
1026 LxtCheckErrnoZeroSuccess(lstat(FS_LINKAT_TEST_DIR2 "/testlink", &Stat));
1027 LxtCheckEqual(FileStat.st_ino, Stat.st_ino, "%lld");
1028 LxtCheckTrue(S_ISREG(Stat.st_mode));
1029 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink"));
1030 LxtCheckErrnoZeroSuccess(chdir(FS_LINKAT_TEST_DIR2));
1031 LxtCheckErrnoZeroSuccess(linkat(SourceDirFd, "testfile", AT_FDCWD, "testlink", 0));
1032
1033 LxtCheckErrnoZeroSuccess(lstat(FS_LINKAT_TEST_DIR2 "/testlink", &Stat));
1034 LxtCheckEqual(FileStat.st_ino, Stat.st_ino, "%lld");
1035 LxtCheckTrue(S_ISREG(Stat.st_mode));
1036 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink"));
1037
1038 //
1039 // Symlinks are not followed by default.
1040 //
1041
1042 LxtCheckErrnoZeroSuccess(linkat(SourceDirFd, "testsymlink", TargetDirFd, "testlink", 0));
1043
1044 LxtCheckErrnoZeroSuccess(lstat(FS_LINKAT_TEST_DIR2 "/testlink", &Stat));
1045 LxtCheckEqual(SymlinkStat.st_ino, Stat.st_ino, "%lld");
1046 LxtCheckTrue(S_ISLNK(Stat.st_mode));
1047 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink"));
1048
1049 //
1050 // Use AT_SYMLINK_FOLLOW to follow the link.
1051 //
1052
1053 LxtCheckErrnoZeroSuccess(linkat(SourceDirFd, "testsymlink", TargetDirFd, "testlink", AT_SYMLINK_FOLLOW));
1054
1055 LxtCheckErrnoZeroSuccess(lstat(FS_LINKAT_TEST_DIR2 "/testlink", &Stat));
1056 LxtCheckEqual(FileStat.st_ino, Stat.st_ino, "%lld");
1057 LxtCheckTrue(S_ISREG(Stat.st_mode));
1058 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink"));
1059
1060 //
1061 // Fd must a directory, not a symlink to a directory.
1062 //
1063
1064 LxtCheckErrno(SymlinkFd = open(FS_LINKAT_TEST_DIR "/testdirsymlink", O_NOFOLLOW | O_PATH));
1065
1066 LxtCheckErrnoFailure(linkat(SymlinkFd, "testfile", TargetDirFd, "testlink", 0), ENOTDIR);
1067
1068 LxtCheckErrnoFailure(linkat(SymlinkFd, "testfile", TargetDirFd, "testlink", AT_SYMLINK_FOLLOW), ENOTDIR);
1069
1070 LxtCheckErrnoFailure(linkat(SourceDirFd, "testfile", SymlinkFd, "testlink", AT_SYMLINK_FOLLOW), ENOTDIR);
1071
1072 LxtCheckClose(SymlinkFd);
1073
1074 //
1075 // AT_EMPTY_PATH creates a link to the specified item.
1076 //
1077
1078 LxtCheckErrno(Fd = open(FS_LINKAT_TEST_DIR "/testfile", O_RDONLY));
1079 LxtCheckErrnoZeroSuccess(linkat(Fd, "", TargetDirFd, "testlink", AT_EMPTY_PATH));
1080
1081 LxtCheckErrnoZeroSuccess(lstat(FS_LINKAT_TEST_DIR2 "/testlink", &Stat));
1082 LxtCheckEqual(FileStat.st_ino, Stat.st_ino, "%lld");
1083 LxtCheckTrue(S_ISREG(Stat.st_mode));
1084 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink"));
1085 LxtCheckClose(Fd);
1086
1087 if (g_LxtFsInfo.FsType == LxtFsTypeVirtioFs)
1088 {
1089 LxtLogInfo("TODO: debug this test on virtiofs");
1090 Result = 0;
1091 goto ErrorExit;
1092 }
1093
1094 //
1095 // If the fd is a symlink, it's not followed regardless of flags.
1096 //
1097
1098 LxtCheckErrno(SymlinkFd = open(FS_LINKAT_TEST_DIR "/testsymlink", O_NOFOLLOW | O_PATH));
1099
1100 LxtCheckErrnoZeroSuccess(linkat(SymlinkFd, "", TargetDirFd, "testlink", AT_EMPTY_PATH));
1101
1102 LxtCheckErrnoZeroSuccess(lstat(FS_LINKAT_TEST_DIR2 "/testlink", &Stat));
1103 LxtCheckEqual(SymlinkStat.st_ino, Stat.st_ino, "%lld");
1104 LxtCheckTrue(S_ISLNK(Stat.st_mode));
1105 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink"));
1106 LxtCheckErrnoZeroSuccess(linkat(SymlinkFd, "", TargetDirFd, "testlink", AT_EMPTY_PATH | AT_SYMLINK_FOLLOW));
1107
1108 LxtCheckErrnoZeroSuccess(lstat(FS_LINKAT_TEST_DIR2 "/testlink", &Stat));
1109 LxtCheckEqual(SymlinkStat.st_ino, Stat.st_ino, "%lld");
1110 LxtCheckTrue(S_ISLNK(Stat.st_mode));
1111 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink"));
1112
1113 //
1114 // Directory FD should not work.
1115 //
1116
1117 LxtCheckErrnoFailure(linkat(SourceDirFd, "", TargetDirFd, "testlink", AT_EMPTY_PATH), EPERM);
1118
1119 //
1120 // AT_EMPTY_PATH only affects the source FD.
1121 //
1122
1123 LxtCheckErrnoFailure(linkat(SourceDirFd, "testfile", Fd, "", AT_EMPTY_PATH), ENOENT);
1124
1125 //
1126 // Create a link when the original link is removed.
1127 //
1128 // N.B. In WSL 1, the inode keeps a handle to the original link even after
1129 // it has been removed, which is why this test is interesting.
1130 //
1131
1132 LxtCheckErrnoZeroSuccess(linkat(SourceDirFd, "testfile", TargetDirFd, "testlink", 0));
1133 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR "/testfile"));
1134 LxtCheckErrnoZeroSuccess(linkat(TargetDirFd, "testlink", TargetDirFd, "testlink2", 0));
1135 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink"));
1136 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink2"));
1137
1138 //
1139 // Same using the original fd.
1140 //
1141 // N.B. This test does not pass on WSL 2 DrvFs, because the 9p server stores
1142 // a path in the fid and that path is no longer valid after the unlink.
1143 //
1144
1145 if (g_LxtFsInfo.FsType != LxtFsTypePlan9)
1146 {
1147 LxtCheckErrno(Fd = creat(FS_LINKAT_TEST_DIR "/testfile", 0666));
1148 LxtCheckErrnoZeroSuccess(linkat(Fd, "", TargetDirFd, "testlink", AT_EMPTY_PATH));
1149 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR "/testfile"));
1150 LxtCheckErrnoZeroSuccess(linkat(Fd, "", TargetDirFd, "testlink2", AT_EMPTY_PATH));
1151 LxtCheckClose(Fd);
1152 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink"));
1153 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR2 "/testlink2"));
1154 }
1155
1156 //
1157 // You cannot resurrect a file with link count 0.
1158 //
1159 // N.B. On real Linux, the error code this produces is ENOENT, but since
1160 // NTFS returns STATUS_ACCESS_DENIED for this, WSL gives EACCES
1161 // instead. On WSL 2, 9p gives the Linux error code.
1162 //
1163
1164 LxtCheckErrno(Fd = creat(FS_LINKAT_TEST_DIR "/testfile", 0666));
1165 LxtCheckErrnoZeroSuccess(unlink(FS_LINKAT_TEST_DIR "/testfile"));
1166 if (g_LxtFsInfo.FsType == LxtFsTypePlan9)
1167 {
1168 LxtCheckErrnoFailure(linkat(Fd, "", TargetDirFd, "testlink", AT_EMPTY_PATH), ENOENT);
1169 }
1170 else
1171 {
1172 LxtCheckErrnoFailure(linkat(Fd, "", TargetDirFd, "testlink", AT_EMPTY_PATH), EACCES);
1173 }
1174
1175 LxtCheckClose(Fd);
1176
1177 ErrorExit:
1178 if (Fd >= 0)
1179 {
1180 close(Fd);
1181 }
1182
1183 if (SourceDirFd >= 0)
1184 {
1185 close(SourceDirFd);
1186 }
1187
1188 if (TargetDirFd >= 0)
1189 {
1190 close(TargetDirFd);
1191 }
1192
1193 if (SymlinkFd >= 0)
1194 {
1195 close(SymlinkFd);
1196 }
1197
1198 unlink(FS_LINKAT_TEST_DIR "/testdirsymlink");
1199 unlink(FS_LINKAT_TEST_DIR "/testsymlink");
1200 unlink(FS_LINKAT_TEST_DIR "/testfile");
1201 unlink(FS_LINKAT_TEST_DIR2 "/testlink");
1202 unlink(FS_LINKAT_TEST_DIR2 "/testlink2");
1203 rmdir(FS_LINKAT_TEST_DIR);
1204 rmdir(FS_LINKAT_TEST_DIR2);
1205 return Result;
1206 }
1207
1208 int FsCommonTestOpen(PLXT_ARGS Args)
1209
1210 /*++
1211
1212 Description:
1213
1214 This routine tests the open syscall.
1215
1216 Arguments:
1217
1218 Args - Supplies the command line arguments.
1219
1220 Return Value:
1221
1222 Returns 0 on success, -1 on failure.
1223
1224 --*/
1225
1226 {
1227
1228 int Result;
1229
1230 //
1231 // Test that opening a directory with O_CREAT always fails with EISDIR.
1232 //
1233
1234 LxtCheckErrnoFailure(open(FS_TEST_DIR_PARENT, O_RDONLY | O_CREAT), EISDIR);
1235 LxtCheckErrnoFailure(open(FS_TEST_DIR_PARENT, O_RDONLY | O_CREAT | O_EXCL), EEXIST);
1236
1237 ErrorExit:
1238 return Result;
1239 }
1240
1241 int FsCommonTestOpenAt(PLXT_ARGS Args)
1242
1243 /*++
1244 --*/
1245
1246 {
1247
1248 int Result;
1249 int DirFd;
1250 int ChildFd1;
1251 int ChildFd2;
1252 const char DirPath[] = FS_TEST_DIR_PARENT "/test_openat";
1253 const char Child1[] = "newfile";
1254 const char Child1FullPath[] = FS_TEST_DIR_PARENT "/test_openat/newfile";
1255 const char* UnlinkName = NULL;
1256 const char* RmdirPath = NULL;
1257
1258 //
1259 // Initialize locals.
1260 //
1261
1262 DirFd = -1;
1263 ChildFd1 = -1;
1264 ChildFd2 = -1;
1265 UnlinkName = NULL;
1266 RmdirPath = NULL;
1267
1268 //
1269 // Make a directory.
1270 //
1271
1272 LxtLogInfo("Creating test directory folder %s", DirPath);
1273
1274 Result = mkdir(DirPath, 0777);
1275 if (Result < 0)
1276 {
1277 LxtLogError("Could not create test directory: %d", Result);
1278 goto cleanup;
1279 }
1280
1281 LxtLogInfo("Created test directory folder!");
1282 RmdirPath = DirPath;
1283
1284 //
1285 // Open the directory.
1286 //
1287
1288 LxtLogInfo("Opening test directory folder %s", DirPath);
1289
1290 Result = open(DirPath, O_RDONLY);
1291 if (Result < 0)
1292 {
1293 LxtLogError("Could not open test directory: %d", Result);
1294 goto cleanup;
1295 }
1296
1297 DirFd = Result;
1298 LxtLogInfo("Opened test directory folder, fd = %d", DirFd);
1299
1300 //
1301 // Open a child relative to the directory. This should fail.
1302 //
1303
1304 LxtLogInfo("Opening child %s without create flag", Child1);
1305
1306 Result = openat(DirFd, Child1, O_RDONLY);
1307 if (Result >= 0)
1308 {
1309 LxtLogError("Unexpectedly opened child: %d", Result);
1310 ChildFd1 = Result;
1311 Result = -1;
1312 goto cleanup;
1313 }
1314
1315 //
1316 // Create child directory. This should succeed.
1317 //
1318
1319 LxtLogInfo("Opening child %s with create flag", Child1);
1320
1321 Result = openat(DirFd, Child1, O_RDONLY | O_CREAT, S_IRWXU);
1322 if (Result < 0)
1323 {
1324 LxtLogError("Failed to create child %d", Result);
1325 Result = -1;
1326 goto cleanup;
1327 }
1328
1329 ChildFd1 = Result;
1330 LxtLogInfo("Created child, fd = %d", ChildFd1);
1331
1332 UnlinkName = Child1FullPath;
1333
1334 //
1335 // Open child directory using a full path. This should succeed.
1336 //
1337
1338 LxtLogInfo("Opening child with full path %s", Child1FullPath);
1339
1340 Result = open(Child1FullPath, O_RDONLY);
1341 if (Result < 0)
1342 {
1343 LxtLogError("Failed to open child full path %s: %d", Child1FullPath, Result);
1344 Result = -1;
1345 goto cleanup;
1346 }
1347
1348 ChildFd2 = Result;
1349 Result = 0;
1350
1351 LxtLogInfo("Opened child with full path, fd = %d", ChildFd2);
1352
1353 LxtLogInfo("FsCommonTestOpenAt succeeded! Party in the USA!");
1354
1355 cleanup:
1356
1357 if (ChildFd1 != -1)
1358 {
1359 close(ChildFd1);
1360 }
1361
1362 if (ChildFd2 != -1)
1363 {
1364 close(ChildFd2);
1365 }
1366
1367 if (DirFd != -1)
1368 {
1369 close(DirFd);
1370 }
1371
1372 if (UnlinkName != NULL)
1373 {
1374 unlink(UnlinkName);
1375 }
1376
1377 if (RmdirPath != NULL)
1378 {
1379 rmdir(RmdirPath);
1380 }
1381
1382 return Result;
1383 }
1384
1385 int FsCommonTestOpenCreateSymlink(PLXT_ARGS Args)
1386
1387 /*++
1388
1389 Description:
1390
1391 This routine tests opening files through existing symlinks with O_CREAT.
1392
1393 Arguments:
1394
1395 Args - Supplies the command line arguments.
1396
1397 Return Value:
1398
1399 Returns 0 on success, -1 on failure.
1400
1401 --*/
1402
1403 {
1404
1405 ssize_t BytesWritten;
1406 int Fd;
1407 const char* LinkPath = FS_TEST_DIR_PARENT "/test_opencreatelink";
1408 const char* Path = FS_TEST_DIR_PARENT "/test_opencreate";
1409 int Result;
1410 struct stat Stat;
1411
1412 //
1413 // Create a test file and link.
1414 //
1415
1416 LxtCheckErrno(Fd = creat(Path, 0777));
1417 LxtCheckErrnoZeroSuccess(close(Fd));
1418 Fd = -1;
1419 LxtCheckErrnoZeroSuccess(symlink(Path, LinkPath));
1420
1421 //
1422 // Try to open the file through the link with O_CREAT and write some data.
1423 //
1424
1425 LxtCheckErrno(Fd = open(LinkPath, O_RDWR | O_CREAT));
1426 LxtCheckErrno(BytesWritten = write(Fd, "test", 4));
1427 LxtCheckEqual(BytesWritten, 4, "%ld");
1428 LxtCheckErrnoZeroSuccess(close(Fd));
1429 Fd = -1;
1430
1431 //
1432 // Check the file was written to.
1433 //
1434
1435 LxtCheckErrnoZeroSuccess(stat(Path, &Stat));
1436 LxtCheckEqual(Stat.st_size, 4, "%ld");
1437 LxtCheckErrnoZeroSuccess(stat(LinkPath, &Stat));
1438 LxtCheckEqual(Stat.st_size, 4, "%ld");
1439
1440 //
1441 // Point the link at /dev/null and try again.
1442 //
1443
1444 LxtCheckErrnoZeroSuccess(unlink(LinkPath));
1445 LxtCheckErrnoZeroSuccess(symlink("/dev/null", LinkPath));
1446 LxtCheckErrno(Fd = open(LinkPath, O_RDWR | O_CREAT));
1447 LxtCheckErrno(BytesWritten = write(Fd, "test", 4));
1448 LxtCheckEqual(BytesWritten, 4, "%ld");
1449 LxtCheckErrnoZeroSuccess(close(Fd));
1450 Fd = -1;
1451 LxtCheckErrnoZeroSuccess(stat("/dev/null", &Stat));
1452 LxtCheckEqual(Stat.st_size, 0, "%ld");
1453 LxtCheckErrnoZeroSuccess(stat(LinkPath, &Stat));
1454 LxtCheckEqual(Stat.st_size, 0, "%ld");
1455
1456 ErrorExit:
1457 if (Fd >= 0)
1458 {
1459 close(Fd);
1460 }
1461
1462 unlink(LinkPath);
1463 unlink(Path);
1464
1465 return Result;
1466 }
1467
1468 int FsCommonTestOpenCreateSymlinkDir(PLXT_ARGS Args)
1469
1470 /*++
1471
1472 Description:
1473
1474 This routine tests creating a symlink to a directory.
1475
1476 Arguments:
1477
1478 Args - Supplies the command line arguments.
1479
1480 Return Value:
1481
1482 Returns 0 on success, -1 on failure.
1483
1484 --*/
1485
1486 {
1487
1488 ssize_t BytesWritten;
1489 int Fd;
1490 const char* LinkDir = FS_TEST_DIR_PARENT "/test_dir_link";
1491 const char* Dir = FS_TEST_DIR_PARENT "/test_dir/";
1492 const char* LinkFile = FS_TEST_DIR_PARENT "/test_dir_link/test.txt";
1493 const char* File = FS_TEST_DIR_PARENT "/test_dir/test.txt";
1494 int Result;
1495 struct stat Stat;
1496
1497 //
1498 // Create a new directory and a link to the directory.
1499 // Note that the link's target directory contains a trailing slash.
1500 //
1501
1502 LxtCheckErrnoZeroSuccess(mkdir(Dir, 0777));
1503 LxtCheckErrnoZeroSuccess(symlink(Dir, LinkDir));
1504
1505 //
1506 // Create a new file in the new directory (without using the
1507 // directory symlink), and write 4 bytes to the file.
1508 //
1509
1510 LxtCheckErrno(Fd = creat(File, 0777));
1511 LxtCheckErrno(BytesWritten = write(Fd, "test", 4));
1512 LxtCheckEqual(BytesWritten, 4, "%ld");
1513 LxtCheckErrnoZeroSuccess(close(Fd));
1514
1515 //
1516 // Check that the file was written to.
1517 //
1518
1519 LxtCheckErrnoZeroSuccess(stat(File, &Stat));
1520 LxtCheckEqual(Stat.st_size, 4, "%ld");
1521
1522 //
1523 // Check that accessing the file through the directory
1524 // symlink works properly.
1525 //
1526
1527 LxtCheckErrnoZeroSuccess(stat(LinkFile, &Stat));
1528 LxtCheckEqual(Stat.st_size, 4, "%ld");
1529
1530 ErrorExit:
1531 if (Fd >= 0)
1532 {
1533 close(Fd);
1534 }
1535
1536 unlink(LinkFile);
1537 unlink(File);
1538 unlink(LinkDir);
1539 rmdir(Dir);
1540
1541 return Result;
1542 }
1543
1544 int FsCommonTestCreateAndRename(PLXT_ARGS Args)
1545
1546 /*++
1547 --*/
1548
1549 {
1550
1551 int ChildPid;
1552 int ExpectedError;
1553 int FileDescriptor;
1554 int Result;
1555 const char Source[] = FS_TEST_DIR_PARENT "/fs_test.bin";
1556 const char SourceLink[] = FS_TEST_DIR_PARENT "/fs_test.bin.link";
1557 const char Target1[] = FS_TEST_DIR_PARENT "/test/fs_test.bin";
1558 const char Target2[] = FS_TEST_DIR_PARENT "/test/fs_test.bin.bak";
1559 const char TestPath[] = FS_TEST_DIR_PARENT "/test";
1560 const char TestPathError[] = FS_TEST_DIR_PARENT "/test/test";
1561 const char* UnlinkName = NULL;
1562 const char* RmdirName = NULL;
1563
1564 //
1565 // Open the test file; this should fail.
1566 //
1567
1568 FileDescriptor = open(Source, O_RDWR);
1569 if (FileDescriptor != -1)
1570 {
1571 Result = errno;
1572 LxtLogError("Found '%s' at the start; it should not exist!", Source);
1573 goto ErrorExit;
1574 }
1575
1576 if (mkdir(TestPath, 0777) == 0)
1577 {
1578 RmdirName = TestPath;
1579 }
1580
1581 //
1582 // Create the test file; this should succeed.
1583 //
1584
1585 FileDescriptor = open(Source, O_RDWR | O_CREAT, S_IRWXU);
1586 if (FileDescriptor == -1)
1587 {
1588 Result = errno;
1589 LxtLogError("Could not create '%s', %d", Source, Result);
1590 goto ErrorExit;
1591 }
1592
1593 UnlinkName = Source;
1594 close(FileDescriptor);
1595 FileDescriptor = -1;
1596
1597 //
1598 // Create the test link.
1599 //
1600
1601 LxtCheckErrno(symlink(Source, SourceLink));
1602
1603 //
1604 // Rename the file and directory to itself.
1605 //
1606
1607 LxtCheckErrno(rename(TestPath, TestPath));
1608 LxtCheckErrno(rename(Source, Source));
1609 LxtCheckErrno(rename(SourceLink, SourceLink));
1610 LxtCheckErrnoFailure(rename(TestPath, TestPathError), EINVAL);
1611
1612 //
1613 // Various invalid renames (requires chroot).
1614 //
1615
1616 LxtCheckErrno(ChildPid = fork());
1617 if (ChildPid == 0)
1618 {
1619 const char* RelativePath = "foo";
1620
1621 LxtCheckErrno(chdir(TestPath));
1622 LxtCheckErrno(chroot("."));
1623 mkdir(RelativePath, 0777);
1624 LxtCheckErrnoFailure(rename(RelativePath, "."), EBUSY);
1625 LxtCheckErrnoFailure(rename(RelativePath, ".."), EBUSY);
1626 LxtCheckErrnoFailure(rename(RelativePath, "/"), EBUSY);
1627 LxtCheckErrnoFailure(rename(RelativePath, "./"), EBUSY);
1628 LxtCheckErrnoFailure(rename(RelativePath, "../"), EBUSY);
1629 LxtCheckErrnoFailure(rename(RelativePath, "//"), EBUSY);
1630 LxtCheckErrnoFailure(rename(".", RelativePath), EBUSY);
1631 LxtCheckErrnoFailure(rename("..", RelativePath), EBUSY);
1632 LxtCheckErrnoFailure(rename("/", RelativePath), EBUSY);
1633 LxtCheckErrno(rmdir(RelativePath));
1634 exit(0);
1635 }
1636
1637 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
1638
1639 //
1640 // Rename across directories.
1641 //
1642
1643 Result = rename(Source, Target1);
1644 if (Result < 0)
1645 {
1646 Result = errno;
1647 LxtLogError("Could not rename '%s' to '%s', %d", Source, Target1, Result);
1648 goto ErrorExit;
1649 }
1650
1651 UnlinkName = Target1;
1652
1653 //
1654 // Rename within the same directory.
1655 //
1656
1657 Result = rename(Target1, Target2);
1658 if (Result < 0)
1659 {
1660 Result = errno;
1661 LxtLogError("Could not rename '%s' to '%s', %d", Target1, Target2, Result);
1662 goto ErrorExit;
1663 }
1664
1665 UnlinkName = Target2;
1666
1667 //
1668 // Rename with an open file in the directory.
1669 //
1670
1671 LxtCheckErrno(FileDescriptor = open(Target2, O_RDONLY));
1672 LxtCheckErrnoFailure(rename(TestPath, FS_TEST_DIR_PARENT "/test_fail"), EACCES);
1673
1674 LxtCheckClose(FileDescriptor);
1675
1676 //
1677 // The previous failed rename may have flushed directory entries, so try
1678 // another rename inside of the directory.
1679 //
1680
1681 Result = rename(Target2, Target1);
1682 if (Result < 0)
1683 {
1684 Result = errno;
1685 LxtLogError("Could not rename '%s' to '%s', %d", Source, Target1, Result);
1686 goto ErrorExit;
1687 }
1688
1689 UnlinkName = Target1;
1690
1691 //
1692 // Unlink the final file.
1693 //
1694
1695 Result = unlink(UnlinkName);
1696 if (Result < 0)
1697 {
1698 Result = errno;
1699 LxtLogError("Could not unlink '%s', %d", Target2, Result);
1700 goto ErrorExit;
1701 }
1702
1703 UnlinkName = NULL;
1704
1705 Result = LXT_RESULT_SUCCESS;
1706
1707 ErrorExit:
1708
1709 if (FileDescriptor != -1)
1710 {
1711 close(FileDescriptor);
1712 }
1713
1714 if (NULL != UnlinkName)
1715 {
1716 (void)unlink(UnlinkName);
1717 }
1718
1719 if (NULL != RmdirName)
1720 {
1721 (void)rmdir(RmdirName);
1722 }
1723
1724 remove(SourceLink);
1725
1726 return Result;
1727 }
1728
1729 int FsCommonTestCreateSymlinkTarget(PLXT_ARGS Args)
1730
1731 /*++
1732
1733 Description:
1734
1735 This routine tests creating the target of a symlink through the symlink.
1736
1737 Arguments:
1738
1739 Args - Supplies the command line arguments.
1740
1741 Return Value:
1742
1743 Returns 0 on success, -1 on failure.
1744
1745 --*/
1746
1747 {
1748
1749 int Fd;
1750 int Result;
1751 const char* SymlinkPath = FS_TEST_DIR_PARENT "/fs_createsymlink";
1752 const char* SymlinkTarget = "fs_createsymlinktarget";
1753 const char* SymlinkTargetAbsolute = FS_TEST_DIR_PARENT "/fs_createsymlinktarget";
1754
1755 Fd = -1;
1756
1757 //
1758 // Create the symlink, and verify the target does not exist.
1759 //
1760
1761 LxtCheckErrnoZeroSuccess(symlink(SymlinkTarget, SymlinkPath));
1762 LxtCheckErrnoFailure(open(SymlinkPath, O_RDONLY), ENOENT);
1763 LxtCheckErrnoFailure(open(SymlinkTargetAbsolute, O_RDONLY), ENOENT);
1764 LxtCheckErrno(Fd = open(SymlinkPath, O_PATH | O_NOFOLLOW));
1765 LxtCheckErrnoZeroSuccess(close(Fd));
1766 Fd = -1;
1767
1768 //
1769 // Using O_EXCL will fail even if the target does not exist.
1770 //
1771
1772 LxtCheckErrnoFailure(Fd = open(SymlinkPath, O_CREAT | O_EXCL), EEXIST);
1773
1774 //
1775 // Using O_NOFOLLOW will fail as usual.
1776 //
1777
1778 LxtCheckErrnoFailure(Fd = open(SymlinkPath, O_CREAT | O_NOFOLLOW), ELOOP);
1779 LxtCheckErrnoFailure(open(SymlinkPath, O_RDONLY), ENOENT);
1780 LxtCheckErrnoFailure(open(SymlinkTargetAbsolute, O_RDONLY), ENOENT);
1781
1782 //
1783 // Create the target through the symlink, and check it got created.
1784 //
1785
1786 LxtCheckErrno(Fd = open(SymlinkPath, O_CREAT));
1787 LxtCheckErrnoZeroSuccess(close(Fd));
1788 Fd = -1;
1789 LxtCheckErrnoZeroSuccess(access(SymlinkTargetAbsolute, F_OK));
1790
1791 ErrorExit:
1792 if (Fd >= 0)
1793 {
1794 close(Fd);
1795 }
1796
1797 unlink(SymlinkTargetAbsolute);
1798 unlink(SymlinkPath);
1799 return Result;
1800 }
1801
1802 int FsCommonTestReadlinkat(PLXT_ARGS Args)
1803
1804 /*++
1805
1806 Description:
1807
1808 This routine tests the readlinkat function.
1809
1810 Arguments:
1811
1812 Args - Supplies the command line arguments.
1813
1814 Return Value:
1815
1816 Returns 0 on success, -1 on failure.
1817
1818 --*/
1819
1820 {
1821
1822 char Buffer[PATH_MAX];
1823 ssize_t BytesRead;
1824 int Fd;
1825 int Result;
1826
1827 //
1828 // Create a symlink to test.
1829 //
1830
1831 LxtCheckErrno(Fd = creat(FS_READLINK_TEST_FILE, 0666));
1832 LxtCheckErrnoZeroSuccess(close(Fd));
1833 Fd = -1;
1834 LxtCheckErrnoZeroSuccess(symlink(FS_READLINK_TEST_FILE, FS_READLINK_TEST_LINK));
1835
1836 //
1837 // Test the ability to operate directly on a symlink.
1838 //
1839
1840 LxtCheckErrno(Fd = open(FS_READLINK_TEST_LINK, O_PATH | O_NOFOLLOW));
1841 memset(Buffer, 0, sizeof(Buffer));
1842 LxtCheckErrno(BytesRead = readlinkat(Fd, "", Buffer, sizeof(Buffer)));
1843 LxtCheckEqual(BytesRead, strlen(FS_READLINK_TEST_FILE), "%ld");
1844 LxtCheckStringEqual(Buffer, FS_READLINK_TEST_FILE);
1845
1846 //
1847 // Path specified with symlink file descriptor.
1848 //
1849
1850 LxtCheckErrnoFailure(readlinkat(Fd, "foo", Buffer, sizeof(Buffer)), ENOTDIR);
1851 LxtCheckErrnoZeroSuccess(close(Fd));
1852 Fd = -1;
1853
1854 //
1855 // Empty path with non-symlink file descriptor.
1856 //
1857
1858 LxtCheckErrno(Fd = open(FS_READLINK_TEST_FILE, O_RDONLY));
1859 LxtCheckErrnoFailure(readlinkat(Fd, "", Buffer, sizeof(Buffer)), ENOENT);
1860
1861 ErrorExit:
1862 if (Fd >= 0)
1863 {
1864 close(Fd);
1865 }
1866
1867 unlink(FS_READLINK_TEST_LINK);
1868 unlink(FS_READLINK_TEST_FILE);
1869 return Result;
1870 }
1871
1872 int FsCommonTestRemoveSelfOrParent(PLXT_ARGS Args)
1873
1874 /*++
1875
1876 Description:
1877
1878 This routine tests some corner cases of the rmdir function.
1879
1880 Arguments:
1881
1882 Args - Supplies the command line arguments.
1883
1884 Return Value:
1885
1886 Returns 0 on success, -1 on failure.
1887
1888 --*/
1889
1890 {
1891
1892 pid_t ChildPid;
1893 int Fd;
1894 int Result;
1895
1896 ChildPid = -1;
1897 Fd = -1;
1898 LxtCheckErrnoZeroSuccess(mkdir(FS_RMDIR_TEST_DIR, 0777));
1899 LxtCheckErrnoZeroSuccess(mkdir(FS_RMDIR_TEST_DIR "/test", 0777));
1900
1901 //
1902 // Test relative to current working directory.
1903 //
1904
1905 LxtCheckErrno(ChildPid = fork());
1906 if (ChildPid == 0)
1907 {
1908 LxtCheckErrnoZeroSuccess(chdir(FS_RMDIR_TEST_DIR "/test"));
1909
1910 //
1911 // Can't remove . or ..
1912 //
1913
1914 LxtCheckErrnoFailure(rmdir(".."), ENOTEMPTY);
1915 LxtCheckErrnoFailure(unlink(".."), EISDIR);
1916 LxtCheckErrnoFailure(rmdir("."), EINVAL);
1917 LxtCheckErrnoFailure(unlink("."), EISDIR);
1918
1919 //
1920 // Even when the directory is empty, rmdir("..") says ENOTEMPTY.
1921 //
1922 // N.B. On Plan9, using the current working directory after deleting it
1923 // does not work, even if just to say "..".
1924 //
1925
1926 LxtCheckErrnoZeroSuccess(rmdir(FS_RMDIR_TEST_DIR "/test"));
1927 if (g_LxtFsInfo.FsType != LxtFsTypePlan9)
1928 {
1929 LxtCheckErrnoFailure(rmdir(".."), ENOTEMPTY);
1930 }
1931
1932 LxtCheckErrnoZeroSuccess(rmdir(FS_RMDIR_TEST_DIR));
1933
1934 //
1935 // Root path.
1936 //
1937 // N.B. Cannot chroot to a deleted working directory on plan 9.
1938 //
1939
1940 if (g_LxtFsInfo.FsType != LxtFsTypePlan9)
1941 {
1942 LxtCheckErrno(chroot("."));
1943 }
1944
1945 LxtCheckErrnoFailure(rmdir("/"), EBUSY);
1946 LxtCheckErrnoFailure(unlink("/"), EISDIR);
1947 LxtCheckErrnoFailure(rmdir("//"), EBUSY);
1948 LxtCheckErrnoFailure(unlink("//"), EISDIR);
1949 LxtCheckErrnoFailure(rmdir("/."), EINVAL);
1950 LxtCheckErrnoFailure(unlink("/."), EISDIR);
1951 LxtCheckErrnoFailure(rmdir("/.."), ENOTEMPTY);
1952 LxtCheckErrnoFailure(unlink("/.."), EISDIR);
1953
1954 exit(0);
1955 }
1956
1957 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
1958 LxtCheckErrnoZeroSuccess(mkdir(FS_RMDIR_TEST_DIR, 0777));
1959 LxtCheckErrnoZeroSuccess(mkdir(FS_RMDIR_TEST_DIR "/test", 0777));
1960
1961 //
1962 // Same tests, with unlinkat.
1963 //
1964
1965 LxtCheckErrno(Fd = open(FS_RMDIR_TEST_DIR "/test", O_DIRECTORY));
1966 LxtCheckErrnoFailure(unlinkat(Fd, "..", AT_REMOVEDIR), ENOTEMPTY);
1967 LxtCheckErrnoFailure(unlinkat(Fd, "..", 0), EISDIR);
1968 LxtCheckErrnoFailure(unlinkat(Fd, ".", AT_REMOVEDIR), EINVAL);
1969 LxtCheckErrnoFailure(unlinkat(Fd, ".", 0), EISDIR);
1970 LxtCheckClose(Fd);
1971
1972 //
1973 // Full paths ending in . or ..
1974 //
1975
1976 LxtCheckErrnoFailure(rmdir(FS_RMDIR_TEST_DIR "/test/.."), ENOTEMPTY);
1977 LxtCheckErrnoFailure(unlink(FS_RMDIR_TEST_DIR "/test/.."), EISDIR);
1978 LxtCheckErrnoFailure(rmdir(FS_RMDIR_TEST_DIR "/test/."), EINVAL);
1979 LxtCheckErrnoFailure(unlink(FS_RMDIR_TEST_DIR "/test/."), EISDIR);
1980
1981 //
1982 // Nonexistent paths.
1983 //
1984
1985 LxtCheckErrnoFailure(rmdir(FS_RMDIR_TEST_DIR "/test2/.."), ENOENT);
1986 LxtCheckErrnoFailure(rmdir(FS_RMDIR_TEST_DIR "/test2/."), ENOENT);
1987 LxtCheckErrnoFailure(unlink(FS_RMDIR_TEST_DIR "/test2/.."), ENOENT);
1988 LxtCheckErrnoFailure(unlink(FS_RMDIR_TEST_DIR "/test2/."), ENOENT);
1989
1990 //
1991 // Having a . anywhere but the last component does work.
1992 //
1993
1994 LxtCheckErrnoZeroSuccess(rmdir(FS_RMDIR_TEST_DIR "/./test"));
1995 LxtCheckErrnoFailure(access(FS_RMDIR_TEST_DIR "/test", F_OK), ENOENT);
1996
1997 ErrorExit:
1998 if (Fd >= 0)
1999 {
2000 close(Fd);
2001 }
2002
2003 if (ChildPid == 0)
2004 {
2005 exit(LXT_RESULT_FAILURE);
2006 }
2007
2008 rmdir(FS_RMDIR_TEST_DIR "/test");
2009 rmdir(FS_RMDIR_TEST_DIR);
2010 return Result;
2011 }
2012
2013 int FsCommonTestRenameAt(PLXT_ARGS Args)
2014
2015 /*++
2016
2017 Description:
2018
2019 This routine tests the renameat system call on volfs.
2020
2021 Arguments:
2022
2023 Args - Supplies the command line arguments.
2024
2025 Return Value:
2026
2027 Returns 0 on success, -1 on failure.
2028
2029 --*/
2030
2031 {
2032
2033 int DirFd1;
2034 int DirFd2;
2035 int Result;
2036
2037 DirFd1 = -1;
2038 DirFd2 = -1;
2039
2040 //
2041 // Create a directory structure to use for the test.
2042 //
2043
2044 LxtCheckResult(LxtFsCreateTestDir((FS_RENAMEAT_TEST_DIR)));
2045 LxtCheckResult(LxtFsCreateTestDir((FS_RENAMEAT_TEST_DIR "/a")));
2046 LxtCheckResult(LxtFsCreateTestDir((FS_RENAMEAT_TEST_DIR "/a/b")));
2047 LxtCheckResult(LxtFsCreateTestDir((FS_RENAMEAT_TEST_DIR "/a/b/c")));
2048 LxtCheckResult(LxtFsCreateTestDir((FS_RENAMEAT_TEST_DIR "/a/b/c/d")));
2049 LxtCheckResult(LxtFsCreateTestDir((FS_RENAMEAT_TEST_DIR "/a/b/c/d/e")));
2050 LxtCheckResult(LxtFsCreateTestDir((FS_RENAMEAT_TEST_DIR "/a/b/c/d/e/f")));
2051
2052 LxtCheckErrno(DirFd1 = open(FS_RENAMEAT_TEST_DIR "/a", O_DIRECTORY));
2053 LxtCheckErrno(DirFd2 = open(FS_RENAMEAT_TEST_DIR "/a/b/c", O_DIRECTORY));
2054
2055 LxtCheckErrnoZeroSuccess(chdir(FS_RENAMEAT_TEST_DIR));
2056
2057 LxtCheckErrno(LxtFsRenameAtCommon(DirFd1, DirFd2));
2058
2059 ErrorExit:
2060 if (DirFd1 >= 0)
2061 {
2062 LxtClose(DirFd1);
2063 }
2064
2065 if (DirFd2 >= 0)
2066 {
2067 LxtClose(DirFd2);
2068 }
2069
2070 rmdir(FS_RENAMEAT_TEST_DIR "/a/b/c/d/e/f");
2071 rmdir(FS_RENAMEAT_TEST_DIR "/a/b/c/d/e");
2072 rmdir(FS_RENAMEAT_TEST_DIR "/a/b/c/d");
2073 rmdir(FS_RENAMEAT_TEST_DIR "/a/b/c");
2074 rmdir(FS_RENAMEAT_TEST_DIR "/a/b");
2075 rmdir(FS_RENAMEAT_TEST_DIR "/a");
2076 rmdir(FS_RENAMEAT_TEST_DIR);
2077
2078 return Result;
2079 }
2080
2081 int FsCommonTestRenameDir(PLXT_ARGS Args)
2082
2083 /*++
2084
2085 Description:
2086
2087 This routine tests the rename system call for LxFs directories.
2088
2089 Arguments:
2090
2091 Args - Supplies the command line arguments.
2092
2093 Return Value:
2094
2095 Returns 0 on success, -1 on failure.
2096
2097 --*/
2098
2099 {
2100
2101 int Result;
2102
2103 LxtCheckErrno(LxtFsRenameDirCommon(FS_TEST_DIR_PARENT));
2104
2105 ErrorExit:
2106 return Result;
2107 }
2108
2109 int FsCommonTestSetEofCheckTimeLessThan(struct timespec* X, struct timespec* Y)
2110
2111 {
2112
2113 int Result;
2114
2115 Result = LXT_RESULT_FAILURE;
2116 if (X->tv_sec > Y->tv_sec)
2117 {
2118 LxtLogError("Unexpected seconds");
2119 goto ErrorExit;
2120 }
2121
2122 if ((X->tv_sec == Y->tv_sec) && (X->tv_nsec >= Y->tv_nsec))
2123 {
2124 LxtLogError("Unexpected nano seconds");
2125 goto ErrorExit;
2126 }
2127
2128 Result = LXT_RESULT_SUCCESS;
2129
2130 ErrorExit:
2131 return Result;
2132 }
2133
2134 int FsCommonTestSetEof(PLXT_ARGS Args)
2135
2136 /*++
2137 --*/
2138
2139 {
2140
2141 int Result = LXT_RESULT_FAILURE;
2142 int fd;
2143 const char TestFileName[] = FS_TEST_DIR_PARENT "/fs_test.bin";
2144 struct stat statbuf;
2145 struct stat statbuf2;
2146
2147 //
2148 // Create the test file.
2149 //
2150
2151 LxtCheckErrno(fd = open(TestFileName, O_RDWR | O_CREAT, S_IRWXU));
2152 LxtCheckErrno(ftruncate(fd, 54321));
2153 LxtCheckErrno(stat(TestFileName, &statbuf));
2154 LxtCheckErrnoFailure(stat(FS_TEST_DIR_PARENT "/*", &statbuf), ENOENT);
2155 LxtCheckErrnoFailure(stat(FS_TEST_DIR_PARENT "/*.bin", &statbuf), ENOENT);
2156 LxtCheckErrno(fstat(fd, &statbuf));
2157 if (54321 != statbuf.st_size)
2158 {
2159 Result = LXT_RESULT_FAILURE;
2160 LxtLogError("size mismatch after ftruncate64.");
2161 goto ErrorExit;
2162 }
2163
2164 LxtCheckErrno(ftruncate(fd, 12345));
2165 if (Result < 0)
2166 {
2167 Result = errno;
2168 LxtLogError("ftruncate('%fs') failed, %d", TestFileName, Result);
2169 goto ErrorExit;
2170 }
2171
2172 LxtCheckErrno(fstat(fd, &statbuf));
2173 if (12345 != statbuf.st_size)
2174 {
2175 Result = LXT_RESULT_FAILURE;
2176 LxtLogError("size mismatch after ftruncate.");
2177 goto ErrorExit;
2178 }
2179
2180 //
2181 // Check that setting the eof does change the file times even if there
2182 // was no change.
2183 //
2184
2185 LxtCheckErrno(ftruncate(fd, 0));
2186 if (Result < 0)
2187 {
2188 Result = errno;
2189 LxtLogError("ftruncate('%fs') failed, %d", TestFileName, Result);
2190 goto ErrorExit;
2191 }
2192
2193 LxtCheckErrno(fstat(fd, &statbuf));
2194 if (0 != statbuf.st_size)
2195 {
2196 Result = LXT_RESULT_FAILURE;
2197 LxtLogError("size mismatch after ftruncate.");
2198 goto ErrorExit;
2199 }
2200
2201 usleep(500000);
2202 LxtCheckErrno(ftruncate(fd, 0));
2203 if (Result < 0)
2204 {
2205 Result = errno;
2206 LxtLogError("ftruncate('%fs') failed, %d", TestFileName, Result);
2207 goto ErrorExit;
2208 }
2209
2210 LxtCheckErrno(fstat(fd, &statbuf2));
2211 if (0 != statbuf.st_size)
2212 {
2213 Result = LXT_RESULT_FAILURE;
2214 LxtLogError("size mismatch after ftruncate.");
2215 goto ErrorExit;
2216 }
2217
2218 //
2219 // NTFS updates the atime when other timestamps are updated, even when
2220 // access time is otherwise disabled.
2221 //
2222
2223 if (g_LxtFsInfo.Flags.DrvFsBehavior == 0)
2224 {
2225 LxtCheckEqual(statbuf.st_atim.tv_sec, statbuf2.st_atim.tv_sec, "%d");
2226 LxtCheckEqual(statbuf.st_atim.tv_nsec, statbuf2.st_atim.tv_nsec, "%d");
2227 }
2228
2229 if (FS_IS_PLAN9_CACHED() == FALSE)
2230 {
2231 LxtCheckResult(FsCommonTestSetEofCheckTimeLessThan(&statbuf.st_mtim, &statbuf2.st_mtim));
2232 LxtCheckResult(FsCommonTestSetEofCheckTimeLessThan(&statbuf.st_ctim, &statbuf2.st_ctim));
2233 }
2234
2235 close(fd);
2236 fd = -1;
2237
2238 usleep(500000);
2239 LxtCheckErrno(fd = open(TestFileName, O_RDWR | O_TRUNC, S_IRWXU));
2240 LxtCheckErrno(fstat(fd, &statbuf));
2241 if (0 != statbuf.st_size)
2242 {
2243 Result = LXT_RESULT_FAILURE;
2244 LxtLogError("size mismatch after ftruncate.");
2245 goto ErrorExit;
2246 }
2247
2248 if (g_LxtFsInfo.Flags.DrvFsBehavior == 0)
2249 {
2250 LxtCheckEqual(statbuf.st_atim.tv_sec, statbuf2.st_atim.tv_sec, "%d");
2251 LxtCheckEqual(statbuf.st_atim.tv_nsec, statbuf2.st_atim.tv_nsec, "%d");
2252 }
2253
2254 if (FS_IS_PLAN9_CACHED() == FALSE)
2255 {
2256 LxtCheckResult(FsCommonTestSetEofCheckTimeLessThan(&statbuf2.st_mtim, &statbuf.st_mtim));
2257 LxtCheckResult(FsCommonTestSetEofCheckTimeLessThan(&statbuf2.st_ctim, &statbuf.st_ctim));
2258 }
2259
2260 close(fd);
2261 fd = -1;
2262
2263 LxtCheckErrno(unlink(TestFileName));
2264
2265 Result = LXT_RESULT_SUCCESS;
2266
2267 ErrorExit:
2268
2269 if (-1 != fd)
2270 {
2271 close(fd);
2272 (void)unlink(TestFileName);
2273 }
2274
2275 return Result;
2276 }
2277
2278 int FsCommonTestTrailingSlash(PLXT_ARGS Args)
2279
2280 /*++
2281
2282 Description:
2283
2284 This routine tests the behavior of open with trailing slashes.
2285
2286 Arguments:
2287
2288 Args - Supplies the command line arguments.
2289
2290 Return Value:
2291
2292 Returns 0 on success, -1 on failure.
2293
2294 --*/
2295
2296 {
2297
2298 int Fd;
2299 int Result;
2300 struct stat Stat;
2301
2302 Fd = -1;
2303
2304 //
2305 // Nonexistent file tests.
2306 //
2307
2308 LxtCheckErrnoFailure(creat(FS_TRAILING_TEST_FILE "/", 0666), EISDIR);
2309 LxtCheckErrnoFailure(creat(FS_TRAILING_TEST_FILE "/foo/", 0666), ENOENT);
2310 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_FILE "/", O_RDONLY), ENOENT);
2311 LxtCheckErrnoFailure(stat(FS_TRAILING_TEST_FILE "/", &Stat), ENOENT);
2312
2313 //
2314 // Create a directory.
2315 //
2316
2317 LxtCheckErrnoZeroSuccess(mkdir(FS_TRAILING_TEST_DIR "/", 0777));
2318 LxtCheckErrno(Fd = open(FS_TRAILING_TEST_DIR "/", O_RDONLY | O_DIRECTORY));
2319 LxtCheckErrnoZeroSuccess(close(Fd));
2320 Fd = -1;
2321 LxtCheckErrno(Fd = open(FS_TRAILING_TEST_DIR "//", O_RDONLY | O_DIRECTORY));
2322 LxtCheckErrnoZeroSuccess(close(Fd));
2323 Fd = -1;
2324 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_DIR "/", O_RDONLY | O_CREAT), EISDIR);
2325
2326 //
2327 // Create a symlink to a directory.
2328 //
2329
2330 LxtCheckErrnoFailure(symlink(FS_TRAILING_TEST_DIR, FS_TRAILING_TEST_LINK "/"), ENOENT);
2331
2332 LxtCheckErrnoZeroSuccess(symlink(FS_TRAILING_TEST_DIR, FS_TRAILING_TEST_LINK));
2333
2334 LxtCheckErrnoFailure(symlink(FS_TRAILING_TEST_DIR, FS_TRAILING_TEST_LINK "/"), EEXIST);
2335
2336 //
2337 // Test the symlink with and without trailing slash.
2338 //
2339
2340 LxtCheckErrnoZeroSuccess(lstat(FS_TRAILING_TEST_LINK "/", &Stat));
2341 LxtCheckTrue(S_ISDIR(Stat.st_mode));
2342 LxtCheckErrnoZeroSuccess(lstat(FS_TRAILING_TEST_LINK "//", &Stat));
2343 LxtCheckTrue(S_ISDIR(Stat.st_mode));
2344 LxtCheckErrnoZeroSuccess(lstat(FS_TRAILING_TEST_LINK, &Stat));
2345 LxtCheckTrue(S_ISLNK(Stat.st_mode));
2346 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_LINK, O_RDONLY | O_NOFOLLOW), ELOOP);
2347
2348 LxtCheckErrno(Fd = open(FS_TRAILING_TEST_LINK "/", O_RDONLY | O_NOFOLLOW | O_DIRECTORY));
2349
2350 LxtCheckErrnoZeroSuccess(close(Fd));
2351 Fd = -1;
2352
2353 //
2354 // Create a file and test using it with a trailing slash.
2355 //
2356
2357 LxtCheckErrno(Fd = creat(FS_TRAILING_TEST_FILE, 0666));
2358 LxtCheckErrnoZeroSuccess(close(Fd));
2359 Fd = -1;
2360 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_FILE "/", O_RDONLY), ENOTDIR);
2361 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_FILE "//", O_RDONLY), ENOTDIR);
2362 LxtCheckErrnoFailure(stat(FS_TRAILING_TEST_FILE "/", &Stat), ENOTDIR);
2363 LxtCheckErrnoFailure(stat(FS_TRAILING_TEST_FILE "//", &Stat), ENOTDIR);
2364 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_FILE "/", O_RDONLY | O_CREAT), EISDIR);
2365
2366 //
2367 // Create a symlink to a file and test using with a trailing slash.
2368 //
2369
2370 LxtCheckErrnoZeroSuccess(unlink(FS_TRAILING_TEST_LINK));
2371 LxtCheckErrnoZeroSuccess(symlink(FS_TRAILING_TEST_FILE, FS_TRAILING_TEST_LINK));
2372
2373 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_LINK "/", O_RDONLY), ENOTDIR);
2374 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_LINK "/", O_RDONLY | O_NOFOLLOW), ENOTDIR);
2375
2376 LxtCheckErrnoFailure(stat(FS_TRAILING_TEST_LINK "/", &Stat), ENOTDIR);
2377 LxtCheckErrnoFailure(lstat(FS_TRAILING_TEST_LINK "/", &Stat), ENOTDIR);
2378
2379 //
2380 // Create a symlink where the target has a trailing slash.
2381 //
2382
2383 LxtCheckErrnoZeroSuccess(unlink(FS_TRAILING_TEST_LINK));
2384 LxtCheckErrnoZeroSuccess(symlink(FS_TRAILING_TEST_FILE "/", FS_TRAILING_TEST_LINK));
2385
2386 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_LINK, O_RDONLY), ENOTDIR);
2387 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_LINK, O_RDONLY | O_CREAT), EISDIR);
2388
2389 LxtCheckErrnoFailure(stat(FS_TRAILING_TEST_LINK, &Stat), ENOTDIR);
2390
2391 //
2392 // Mkdir over an existing file.
2393 //
2394
2395 LxtCheckErrnoFailure(mkdir(FS_TRAILING_TEST_FILE "/", 0777), EEXIST);
2396
2397 //
2398 // Unlink/rmdir
2399 //
2400
2401 LxtCheckErrnoFailure(unlink(FS_TRAILING_TEST_FILE "/"), ENOTDIR);
2402 LxtCheckErrnoFailure(unlink(FS_TRAILING_TEST_DIR "/"), EISDIR);
2403 LxtCheckErrnoZeroSuccess(rmdir(FS_TRAILING_TEST_DIR "/"));
2404 LxtCheckErrnoFailure(rmdir(FS_TRAILING_TEST_FILE "/"), ENOTDIR);
2405
2406 //
2407 // Test a symlink to a nonexistent target.
2408 //
2409
2410 LxtCheckErrnoZeroSuccess(unlink(FS_TRAILING_TEST_LINK));
2411 LxtCheckErrnoZeroSuccess(symlink(FS_TRAILING_TEST_FILE, FS_TRAILING_TEST_LINK));
2412
2413 LxtCheckErrnoZeroSuccess(unlink(FS_TRAILING_TEST_FILE));
2414 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_LINK "/", O_RDONLY), ENOENT);
2415 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_LINK "/", O_RDONLY | O_NOFOLLOW), ENOENT);
2416
2417 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_LINK "/", O_RDONLY | O_CREAT), EISDIR);
2418
2419 LxtCheckErrnoFailure(stat(FS_TRAILING_TEST_LINK "/", &Stat), ENOENT);
2420 LxtCheckErrnoFailure(lstat(FS_TRAILING_TEST_LINK "/", &Stat), ENOENT);
2421
2422 //
2423 // Symlink to a nonexistent target with trailing slash.
2424 //
2425
2426 LxtCheckErrnoZeroSuccess(unlink(FS_TRAILING_TEST_LINK));
2427 LxtCheckErrnoZeroSuccess(symlink(FS_TRAILING_TEST_FILE "/", FS_TRAILING_TEST_LINK));
2428
2429 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_LINK, O_RDONLY), ENOENT);
2430 LxtCheckErrnoFailure(open(FS_TRAILING_TEST_LINK, O_RDONLY | O_CREAT), EISDIR);
2431
2432 LxtCheckErrnoFailure(stat(FS_TRAILING_TEST_LINK, &Stat), ENOENT);
2433
2434 //
2435 // Other creation functions.
2436 //
2437
2438 LxtCheckErrnoFailure(link(FS_TRAILING_TEST_LINK, FS_TRAILING_TEST_FILE "/"), ENOENT);
2439
2440 LxtCheckErrnoFailure(mknod(FS_TRAILING_TEST_FILE "/", S_IFIFO | 0666, 0), ENOENT);
2441
2442 LxtCheckErrnoZeroSuccess(mkdir(FS_TRAILING_TEST_DIR, 0777));
2443 LxtCheckErrnoFailure(link(FS_TRAILING_TEST_LINK, FS_TRAILING_TEST_DIR "/"), EEXIST);
2444
2445 LxtCheckErrnoFailure(mknod(FS_TRAILING_TEST_DIR "/", S_IFIFO | 0666, 0), EEXIST);
2446
2447 ErrorExit:
2448 if (Fd >= 0)
2449 {
2450 close(Fd);
2451 }
2452
2453 unlink(FS_TRAILING_TEST_FILE);
2454 unlink(FS_TRAILING_TEST_LINK);
2455 rmdir(FS_TRAILING_TEST_DIR);
2456 return Result;
2457 }
2458
2459 int FsCommonTestMkdir(PLXT_ARGS Args)
2460
2461 /*++
2462 --*/
2463
2464 {
2465
2466 int Fd;
2467 const char* ParentDirName = FS_TEST_DIR_PARENT;
2468 const char* TestDirName = FS_TEST_DIR_PARENT "/test_dir";
2469 const char* TestSubDirName = FS_TEST_DIR_PARENT "/test_dir/foo";
2470 const char* RelativeDirName = "test_dir";
2471 const char* RelativeDotSlashDirName = "./test_dir/";
2472 const char* RelativeSubDirName = "test_dir/foo";
2473 int Result;
2474 struct stat Stat;
2475
2476 //
2477 // Ensure the dir doesn't exist.
2478 //
2479
2480 unlink(TestDirName);
2481 rmdir(TestSubDirName);
2482 rmdir(TestDirName);
2483
2484 //
2485 // Create the subdir while the parent doesn't exist.
2486 //
2487
2488 LxtCheckErrnoFailure(mkdir(TestSubDirName, 0777), ENOENT);
2489
2490 //
2491 // Create the test dir as a file.
2492 //
2493
2494 LxtCheckErrno(Fd = open(TestDirName, O_RDWR | O_CREAT, S_IRWXU));
2495
2496 //
2497 // Verify the file size is 0.
2498 //
2499
2500 LxtCheckErrno(fstat(Fd, &Stat));
2501 LxtCheckEqual(Stat.st_size, 0, "%ld");
2502 LxtCheckErrnoZeroSuccess(close(Fd));
2503
2504 //
2505 // Try to create a dir with this name, and a dir under that name.
2506 //
2507
2508 LxtCheckErrnoFailure(mkdir(TestDirName, 0777), EEXIST);
2509 LxtCheckErrnoFailure(mkdir(TestSubDirName, 0777), ENOTDIR);
2510 LxtCheckErrnoZeroSuccess(unlink(TestDirName));
2511
2512 //
2513 // Create a dir with no collisions expected.
2514 //
2515
2516 LxtCheckErrnoZeroSuccess(mkdir(TestDirName, 0777));
2517
2518 //
2519 // Verify the directory file size is equal to the file-system block-size.
2520 //
2521 // N.B. Plan 9 in cached mode doesn't return the block size reported by the
2522 // server.
2523 //
2524
2525 LxtCheckErrno(stat(TestDirName, &Stat));
2526 if (FS_IS_PLAN9_CACHED() == FALSE)
2527 {
2528 LxtCheckEqual(Stat.st_size, Stat.st_blksize, "%ld");
2529 }
2530
2531 //
2532 // Test a directory name collision.
2533 //
2534
2535 LxtCheckErrnoFailure(mkdir(TestDirName, 0777), EEXIST);
2536
2537 //
2538 // Test the rmdir.
2539 //
2540
2541 LxtCheckErrnoZeroSuccess(rmdir(TestDirName));
2542 LxtCheckErrnoFailure(rmdir(TestDirName), ENOENT);
2543
2544 //
2545 // Test mkdir with a relative path. Change the working directory first
2546 // since it's normally / for tests which is not interesting.
2547 //
2548
2549 LxtCheckErrnoZeroSuccess(chdir(ParentDirName));
2550 LxtCheckErrnoFailure(mkdir(RelativeSubDirName, 0777), ENOENT);
2551 LxtCheckErrnoZeroSuccess(mkdir(RelativeDirName, 0777));
2552 LxtCheckErrnoFailure(mkdir(RelativeDirName, 0777), EEXIST);
2553 LxtCheckErrnoFailure(mkdir(TestDirName, 0777), EEXIST);
2554 LxtCheckErrnoZeroSuccess(mkdir(RelativeSubDirName, 0777));
2555 LxtCheckErrnoFailure(mkdir(RelativeSubDirName, 0777), EEXIST);
2556 LxtCheckErrnoFailure(mkdir(TestSubDirName, 0777), EEXIST);
2557 LxtCheckErrnoZeroSuccess(rmdir(TestSubDirName));
2558 LxtCheckErrnoZeroSuccess(rmdir(TestDirName));
2559
2560 //
2561 // Relative path starting with "./" and ending in "/".
2562 //
2563
2564 LxtCheckErrnoZeroSuccess(mkdir(RelativeDotSlashDirName, 0777));
2565 LxtCheckErrnoFailure(mkdir(RelativeDotSlashDirName, 0777), EEXIST);
2566 LxtCheckErrnoFailure(mkdir(TestDirName, 0777), EEXIST);
2567
2568 //
2569 // Empty path should return ENOENT
2570 //
2571
2572 LxtCheckErrnoFailure(mkdir("", 0777), ENOENT);
2573
2574 //
2575 // Special path edge cases.
2576 //
2577
2578 LxtCheckErrnoFailure(mkdir(".", 0777), EEXIST);
2579 LxtCheckErrnoFailure(mkdir("..", 0777), EEXIST);
2580 LxtCheckErrnoFailure(mkdir("/", 0777), EEXIST);
2581 LxtCheckErrnoFailure(mkdir("/.", 0777), EEXIST);
2582 LxtCheckErrnoFailure(mkdir("/..", 0777), EEXIST);
2583 LxtCheckErrnoFailure(mkdir("/data/", 0777), EEXIST);
2584 LxtCheckErrnoFailure(mkdir("/data/.", 0777), EEXIST);
2585 LxtCheckErrnoFailure(mkdir("/data/..", 0777), EEXIST);
2586
2587 //
2588 // Variation succeeded.
2589 //
2590
2591 ErrorExit:
2592 unlink(TestDirName);
2593 rmdir(TestSubDirName);
2594 rmdir(TestDirName);
2595 rmdir(RelativeDirName);
2596
2597 //
2598 // Restore working directory (other tests depend on it)
2599 //
2600
2601 chdir("/");
2602 return Result;
2603 }
2604
2605 int FsCommonTestMkDirAt(PLXT_ARGS Args)
2606
2607 /*++
2608
2609 Routine Description:
2610
2611 This routine tests the mkdirat system call.
2612
2613 Arguments:
2614
2615 Args - Supplies the command line arguments.
2616
2617 Return Value:
2618
2619 0 on success, -1 on failure.
2620
2621 --*/
2622
2623 {
2624
2625 int Fd;
2626 const char* ParentDirName = FS_TEST_DIR_PARENT;
2627 int ParentFd;
2628 const char* TestDirName = FS_TEST_DIR_PARENT "/test_dir";
2629 const char* TestSubDirName = FS_TEST_DIR_PARENT "/test_dir/foo";
2630 const char* RelativeDirName = "test_dir";
2631 const char* RelativeDotSlashDirName = "./test_dir/";
2632 const char* RelativeSubDirName = "test_dir/foo";
2633 int Result;
2634
2635 Fd = -1;
2636
2637 //
2638 // Ensure the dir doesn't exist.
2639 //
2640
2641 unlink(TestDirName);
2642 rmdir(TestSubDirName);
2643 rmdir(TestDirName);
2644
2645 //
2646 // Open the parent.
2647 //
2648
2649 LxtCheckErrno(ParentFd = open(ParentDirName, O_DIRECTORY));
2650
2651 //
2652 // Create the subdir while the parent doesn't exist.
2653 //
2654
2655 LxtCheckErrnoFailure(mkdirat(ParentFd, RelativeSubDirName, 0777), ENOENT);
2656
2657 //
2658 // Create the test dir as a file.
2659 //
2660
2661 LxtCheckErrno(Fd = open(TestDirName, O_RDWR | O_CREAT, S_IRWXU));
2662
2663 //
2664 // Try using the file fd as the parent.
2665 //
2666
2667 LxtCheckErrnoFailure(mkdirat(Fd, RelativeDirName, 0777), ENOTDIR);
2668 LxtCheckErrnoZeroSuccess(close(Fd));
2669
2670 //
2671 // Try to create a dir with this name, and a dir under that name.
2672 //
2673
2674 LxtCheckErrnoFailure(mkdirat(ParentFd, RelativeDirName, 0777), EEXIST);
2675 LxtCheckErrnoFailure(mkdirat(ParentFd, RelativeSubDirName, 0777), ENOTDIR);
2676 LxtCheckErrnoZeroSuccess(unlink(TestDirName));
2677
2678 //
2679 // Create a dir with no collisions expected.
2680 //
2681
2682 LxtCheckErrnoZeroSuccess(mkdirat(ParentFd, RelativeDirName, 0777));
2683
2684 //
2685 // Test a directory name collision.
2686 //
2687
2688 LxtCheckErrnoFailure(mkdirat(ParentFd, RelativeDirName, 0777), EEXIST);
2689 LxtCheckErrnoFailure(mkdir(TestDirName, 0777), EEXIST);
2690
2691 //
2692 // Test the rmdir.
2693 //
2694
2695 LxtCheckErrnoZeroSuccess(rmdir(TestDirName));
2696 LxtCheckErrnoFailure(rmdir(TestDirName), ENOENT);
2697
2698 //
2699 // Relative path starting with "./" and ending in "/".
2700 //
2701
2702 LxtCheckErrnoZeroSuccess(mkdirat(ParentFd, RelativeDotSlashDirName, 0777));
2703 LxtCheckErrnoFailure(mkdirat(ParentFd, RelativeDotSlashDirName, 0777), EEXIST);
2704 LxtCheckErrnoFailure(mkdir(TestDirName, 0777), EEXIST);
2705 LxtCheckErrnoZeroSuccess(rmdir(TestDirName));
2706
2707 //
2708 // Test mkdirat with a AT_FDCWD. Change the working directory first
2709 // since it's normally / for tests which is not interesting.
2710 //
2711
2712 LxtCheckErrnoZeroSuccess(chdir(FS_TEST_DIR_PARENT));
2713 LxtCheckErrnoFailure(mkdirat(AT_FDCWD, RelativeSubDirName, 0777), ENOENT);
2714 LxtCheckErrnoZeroSuccess(mkdir(RelativeDirName, 0777));
2715 LxtCheckErrnoFailure(mkdirat(AT_FDCWD, RelativeDirName, 0777), EEXIST);
2716 LxtCheckErrnoFailure(mkdir(TestDirName, 0777), EEXIST);
2717 LxtCheckErrnoZeroSuccess(mkdir(RelativeSubDirName, 0777));
2718 LxtCheckErrnoFailure(mkdirat(AT_FDCWD, RelativeSubDirName, 0777), EEXIST);
2719 LxtCheckErrnoFailure(mkdir(TestSubDirName, 0777), EEXIST);
2720 LxtCheckErrnoZeroSuccess(rmdir(TestSubDirName));
2721 LxtCheckErrnoZeroSuccess(rmdir(TestDirName));
2722
2723 //
2724 // Empty path should return ENOENT, even with invalid fd.
2725 //
2726
2727 LxtCheckErrnoFailure(mkdirat(AT_FDCWD, "", 0777), ENOENT);
2728 LxtCheckErrnoFailure(mkdirat(-1, "", 0777), ENOENT);
2729
2730 //
2731 // Invalid fd.
2732 //
2733
2734 LxtCheckErrnoFailure(mkdirat(-1, RelativeDirName, 0777), EBADF);
2735
2736 //
2737 // Special path edge cases.
2738 //
2739
2740 LxtCheckErrnoFailure(mkdirat(ParentFd, ".", 0777), EEXIST);
2741 LxtCheckErrnoFailure(mkdirat(ParentFd, "..", 0777), EEXIST);
2742 LxtCheckErrnoFailure(mkdirat(ParentFd, "/", 0777), EEXIST);
2743 LxtCheckErrnoFailure(mkdirat(ParentFd, "/.", 0777), EEXIST);
2744 LxtCheckErrnoFailure(mkdirat(ParentFd, "/..", 0777), EEXIST);
2745 LxtCheckErrnoFailure(mkdirat(ParentFd, "/data/", 0777), EEXIST);
2746 LxtCheckErrnoFailure(mkdirat(ParentFd, "/data/.", 0777), EEXIST);
2747 LxtCheckErrnoFailure(mkdirat(ParentFd, "/data/..", 0777), EEXIST);
2748
2749 //
2750 // Variation succeeded.
2751 //
2752
2753 ErrorExit:
2754 if (Fd >= 0)
2755 {
2756 close(Fd);
2757 }
2758
2759 if (ParentFd >= 0)
2760 {
2761 close(ParentFd);
2762 }
2763
2764 unlink(TestDirName);
2765 rmdir(TestSubDirName);
2766 rmdir(TestDirName);
2767 rmdir(RelativeDirName);
2768
2769 //
2770 // Restore working directory (other tests depend on it)
2771 //
2772
2773 chdir("/");
2774 return Result;
2775 }
2776
2777 int FsCommonTestChdir(PLXT_ARGS Args)
2778
2779 /*++
2780 --*/
2781
2782 {
2783 int Result;
2784 int FileDescriptor;
2785 const char TestFilePath1[] = "data/fstest/test_chdir.txt";
2786 const char TestFilePath2[] = "test_chdir.txt";
2787 const char DataTestDirPath[] = FS_TEST_DIR_PARENT;
2788 const char DataTestDirPath2[] = FS_TEST_DIR_PARENT "/";
2789 const char FailureDirPath[] = "/system12314/";
2790
2791 LxtCheckErrno(Result = chdir("/"));
2792
2793 //
2794 // Since the working directory is "/", create a file under /data/fstest
2795 //
2796
2797 LxtLogInfo("Creating file using path %s", TestFilePath1);
2798 LxtCheckErrno(FileDescriptor = open(TestFilePath1, O_RDWR | O_CREAT, S_IRWXU));
2799 LxtLogInfo("Opened file using path %s, closing now", TestFilePath1);
2800 LxtCheckClose(FileDescriptor);
2801
2802 //
2803 // Change working directory to /system
2804 //
2805
2806 LxtLogInfo("Changing working dir to %s", DataTestDirPath);
2807 LxtCheckErrno(Result = chdir(DataTestDirPath));
2808
2809 //
2810 // Open the same file now that the working directory is different.
2811 //
2812
2813 LxtLogInfo("Opening file using path %s", TestFilePath2);
2814 LxtCheckErrno(FileDescriptor = open(TestFilePath2, O_RDWR));
2815 LxtCheckClose(FileDescriptor);
2816 LxtLogInfo("Opened file using path %s successfully!", TestFilePath2);
2817
2818 //
2819 // Change working directory to /system/
2820 //
2821
2822 LxtLogInfo("Changing working dir to %s", DataTestDirPath2);
2823 LxtCheckErrno(Result = chdir(DataTestDirPath2));
2824
2825 //
2826 // Open the same file now that the working directory is different.
2827 //
2828
2829 LxtLogInfo("Opening file using path %s", TestFilePath2);
2830 LxtCheckErrno(FileDescriptor = open(TestFilePath2, O_RDWR));
2831 LxtCheckClose(FileDescriptor);
2832 LxtLogInfo("Opened file using path %s successfully!", TestFilePath2);
2833
2834 //
2835 // Change working directory to a bogus path; this should fail.
2836 //
2837
2838 LxtLogInfo("Changing working dir to %s", FailureDirPath);
2839 Result = chdir(FailureDirPath);
2840 if (Result != -1)
2841 {
2842 LxtLogError("Chdir to directory ('%s') succeeded unexpectedly, %d", FailureDirPath, errno);
2843 Result = -1;
2844 goto ErrorExit;
2845 }
2846
2847 LxtLogInfo("Changing working dir to %s failed as expected", FailureDirPath);
2848
2849 Result = 0;
2850
2851 LxtLogInfo("TEST SUCCESSFUL!");
2852
2853 ErrorExit:
2854
2855 if (FileDescriptor != -1)
2856 {
2857 close(FileDescriptor);
2858 }
2859
2860 unlink(FS_TEST_DIR_PARENT "/test_chdir.txt");
2861 return Result;
2862 }
2863
2864 typedef struct _UNLINK_AT_VARIATION
2865 {
2866 const char* Description;
2867 const int* Fd;
2868 const char* Path;
2869 const unsigned int Flags;
2870 const int DesiredResult;
2871 const int DesiredError;
2872 } UNLINK_AT_VARIATION, *PUNLINK_AT_VARIATION;
2873
2874 int FsCommonTestUnlinkAt(PLXT_ARGS Args)
2875
2876 /*++
2877
2878 Routine Description:
2879
2880 This routine runs tests associated with the unlinkat syscall.
2881
2882 Arguments:
2883
2884 Args - Supplies the command line arguments.
2885
2886 Return Value:
2887
2888 Returns 0 on success, -1 on failure.
2889
2890 --*/
2891
2892 {
2893
2894 const char Child1[] = "newfile";
2895 const char Child1FullPath[] = FS_TEST_DIR_PARENT "/test_unlinkat/newfile";
2896 int DirFd;
2897 const char DirPath[] = FS_TEST_DIR_PARENT "/test_unlinkat";
2898 int Result;
2899 const char* RmdirPath = NULL;
2900 PUNLINK_AT_VARIATION ThisVariation;
2901 UNLINK_AT_VARIATION UnlinkAtVariations[] = {
2902 {"unlinkat with invalid flags", &DirFd, Child1, 0x80000000, -1, EINVAL},
2903 {"unlink via unlinkat with full path", &DirFd, Child1FullPath, 0, 0, 0},
2904 {"unlink via unlinkat with relative path", &DirFd, Child1, 0, 0, 0},
2905 {"rmdir via unlinkat with full path", &DirFd, Child1FullPath, AT_REMOVEDIR, 0, 0},
2906 {"rmdir via unlinkat with relative path", &DirFd, Child1, AT_REMOVEDIR, 0, 0}};
2907 const char* UnlinkName = NULL;
2908 unsigned int Variation;
2909
2910 //
2911 // Initialize locals.
2912 //
2913
2914 DirFd = -1;
2915 RmdirPath = NULL;
2916 UnlinkName = NULL;
2917 Variation = 0;
2918
2919 //
2920 // Make a directory.
2921 //
2922
2923 LxtLogInfo("Creating test directory folder %s", DirPath);
2924 LxtCheckErrnoZeroSuccess(mkdir(DirPath, 0777));
2925 RmdirPath = DirPath;
2926
2927 //
2928 // Open the directory.
2929 //
2930
2931 LxtCheckErrno(open(DirPath, O_RDONLY));
2932 DirFd = Result;
2933 LxtLogInfo("Opened test directory folder, fd = %d", DirFd);
2934
2935 //
2936 // Unlink a child that we haven't created yet. This should fail.
2937 // umount
2938
2939 LxtLogInfo("Unlinking child %s without creating it", Child1);
2940 LxtCheckErrnoFailure(unlinkat(DirFd, Child1, 0), ENOENT);
2941
2942 //
2943 // Test various things that should succeed.
2944 //
2945
2946 for (Variation = 0; Variation < sizeof(UnlinkAtVariations) / sizeof(UnlinkAtVariations[0]); Variation += 1)
2947 {
2948
2949 ThisVariation = &UnlinkAtVariations[Variation];
2950
2951 //
2952 // Create child file. This should succeed.
2953 //
2954
2955 LxtLogInfo("Attempting %s", ThisVariation->Description);
2956
2957 if ((ThisVariation->Flags & AT_REMOVEDIR) == 0)
2958 {
2959 LxtLogInfo("Creating child file %s", Child1);
2960
2961 LxtCheckErrno(openat(DirFd, Child1, O_RDWR | O_CREAT, S_IRWXU));
2962 close(Result);
2963 }
2964 else
2965 {
2966 LxtLogInfo("Creating child directory %s", Child1);
2967
2968 LxtCheckErrnoZeroSuccess(mkdir(Child1FullPath, S_IRWXU));
2969 }
2970
2971 UnlinkName = Child1FullPath;
2972
2973 //
2974 // Execute the desired test variation.
2975 //
2976
2977 Result = unlinkat(*ThisVariation->Fd, ThisVariation->Path, ThisVariation->Flags);
2978
2979 if (Result != ThisVariation->DesiredResult)
2980 {
2981 LxtLogError("unlinkat returned unexpected result; returned %d, expected %d", Result, ThisVariation->DesiredResult);
2982 Result = -1;
2983 goto ErrorExit;
2984 }
2985
2986 if (Result != 0 && errno != ThisVariation->DesiredError)
2987 {
2988 LxtLogError("unlinkat failed with unexpected error; errno %d, expected %d", errno, ThisVariation->DesiredError);
2989 Result = -1;
2990 goto ErrorExit;
2991 }
2992
2993 //
2994 // If the variation expected success, we've already deleted the object.
2995 // If not, we need to delete it below.
2996 //
2997
2998 if (Result == 0)
2999 {
3000 UnlinkName = NULL;
3001 }
3002
3003 if (UnlinkName != NULL)
3004 {
3005 unlink(UnlinkName);
3006 UnlinkName = NULL;
3007 }
3008 }
3009
3010 LxtLogInfo("FsCommonTestUnlinkAt succeeded!");
3011
3012 ErrorExit:
3013 if (DirFd >= 0)
3014 {
3015 close(DirFd);
3016 }
3017
3018 if (UnlinkName != NULL)
3019 {
3020 unlink(UnlinkName);
3021 }
3022
3023 if (RmdirPath != NULL)
3024 {
3025 rmdir(RmdirPath);
3026 }
3027
3028 return Result;
3029 }
3030
3031 int FsCommonTestFchownAt(PLXT_ARGS Args)
3032
3033 /*++
3034
3035 Description:
3036
3037 This routine tests the fchownat system call.
3038
3039 Arguments:
3040
3041 Args - Supplies the command line arguments.
3042
3043 Return Value:
3044
3045 Returns 0 on success, -1 on failure.
3046
3047 --*/
3048
3049 {
3050
3051 int DirFd;
3052 int Fd;
3053 struct stat Original;
3054 int Result;
3055 struct stat Stat;
3056
3057 DirFd = -1;
3058 Fd = -1;
3059
3060 //
3061 // Set up the test environment.
3062 //
3063
3064 LxtCheckErrnoZeroSuccess(mkdir(FS_FCHOWNAT_TEST_DIR, 0777));
3065 LxtCheckErrno(Fd = creat(FS_FCHOWNAT_TEST_DIR "/testfile", 0666));
3066 LxtCheckClose(Fd);
3067 LxtCheckErrnoZeroSuccess(symlink(FS_FCHOWNAT_TEST_DIR "/testfile", FS_FCHOWNAT_TEST_DIR "/testlink"));
3068
3069 LxtCheckErrnoZeroSuccess(symlink(FS_FCHOWNAT_TEST_DIR, FS_FCHOWNAT_TEST_DIR "/dirlink"));
3070
3071 LxtCheckErrno(DirFd = open(FS_FCHOWNAT_TEST_DIR, O_RDONLY | O_DIRECTORY));
3072
3073 //
3074 // Change owner.
3075 //
3076
3077 LxtCheckErrnoZeroSuccess(fchownat(DirFd, "testfile", 2000, 3000, 0));
3078 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testfile", &Stat));
3079 LxtCheckEqual(Stat.st_uid, 2000, "%d");
3080 LxtCheckEqual(Stat.st_gid, 3000, "%d");
3081
3082 //
3083 // Using AT_FDCWD.
3084 //
3085
3086 LxtCheckErrnoZeroSuccess(chdir(FS_FCHOWNAT_TEST_DIR));
3087 LxtCheckErrnoZeroSuccess(fchownat(AT_FDCWD, "testfile", 2001, 3001, 0));
3088 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testfile", &Stat));
3089 LxtCheckEqual(Stat.st_uid, 2001, "%d");
3090 LxtCheckEqual(Stat.st_gid, 3001, "%d");
3091
3092 //
3093 // Symlinks should be followed.
3094 //
3095
3096 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testlink", &Original));
3097 LxtCheckErrnoZeroSuccess(fchownat(DirFd, "testlink", 2002, 3002, 0));
3098 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testfile", &Stat));
3099 LxtCheckEqual(Stat.st_uid, 2002, "%d");
3100 LxtCheckEqual(Stat.st_gid, 3002, "%d");
3101 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testlink", &Stat));
3102 LxtCheckEqual(Stat.st_uid, Original.st_uid, "%d");
3103 LxtCheckEqual(Stat.st_gid, Original.st_gid, "%d");
3104
3105 //
3106 // Not followed with AT_SYMLINK_NOFOLLOW.
3107 //
3108
3109 LxtCheckErrnoZeroSuccess(fchownat(DirFd, "testlink", 2003, 3003, AT_SYMLINK_NOFOLLOW));
3110
3111 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testfile", &Stat));
3112 LxtCheckEqual(Stat.st_uid, 2002, "%d");
3113 LxtCheckEqual(Stat.st_gid, 3002, "%d");
3114 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testlink", &Stat));
3115 LxtCheckEqual(Stat.st_uid, 2003, "%d");
3116 LxtCheckEqual(Stat.st_gid, 3003, "%d");
3117
3118 //
3119 // Fd must be a directory, not a symlink to a directory.
3120 //
3121
3122 LxtCheckErrno(Fd = open(FS_FCHOWNAT_TEST_DIR "/dirlink", O_NOFOLLOW | O_PATH));
3123 LxtCheckErrnoFailure(fchownat(Fd, "testlink", 2004, 3004, 0), ENOTDIR);
3124 LxtCheckErrnoFailure(fchownat(Fd, "testlink", 2004, 3004, AT_SYMLINK_NOFOLLOW), ENOTDIR);
3125
3126 LxtCheckClose(Fd);
3127
3128 //
3129 // AT_EMPTY_PATH changes the file itself.
3130 //
3131
3132 LxtCheckErrno(Fd = open(FS_FCHOWNAT_TEST_DIR "/testfile", O_RDONLY));
3133 LxtCheckErrnoZeroSuccess(fchownat(Fd, "", 2005, 3005, AT_EMPTY_PATH));
3134
3135 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testfile", &Stat));
3136 LxtCheckEqual(Stat.st_uid, 2005, "%d");
3137 LxtCheckEqual(Stat.st_gid, 3005, "%d");
3138 LxtCheckClose(Fd);
3139
3140 //
3141 // If the symlink is an FD, it's not followed regardless of flags.
3142 //
3143
3144 LxtCheckErrno(Fd = open(FS_FCHOWNAT_TEST_DIR "/testlink", O_NOFOLLOW | O_PATH));
3145 LxtCheckErrnoZeroSuccess(fchownat(Fd, "", 2006, 3006, AT_EMPTY_PATH));
3146
3147 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testlink", &Stat));
3148 LxtCheckEqual(Stat.st_uid, 2006, "%d");
3149 LxtCheckEqual(Stat.st_gid, 3006, "%d");
3150 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testfile", &Stat));
3151 LxtCheckEqual(Stat.st_uid, 2005, "%d");
3152 LxtCheckEqual(Stat.st_gid, 3005, "%d");
3153 LxtCheckErrnoZeroSuccess(fchownat(Fd, "", 2007, 3007, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW));
3154
3155 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testlink", &Stat));
3156 LxtCheckEqual(Stat.st_uid, 2007, "%d");
3157 LxtCheckEqual(Stat.st_gid, 3007, "%d");
3158 LxtCheckErrnoZeroSuccess(lstat(FS_FCHOWNAT_TEST_DIR "/testfile", &Stat));
3159 LxtCheckEqual(Stat.st_uid, 2005, "%d");
3160 LxtCheckEqual(Stat.st_gid, 3005, "%d");
3161
3162 ErrorExit:
3163 if (DirFd >= 0)
3164 {
3165 close(DirFd);
3166 }
3167
3168 if (Fd >= 0)
3169 {
3170 close(Fd);
3171 }
3172
3173 unlink(FS_FCHOWNAT_TEST_DIR "/dirlink");
3174 unlink(FS_FCHOWNAT_TEST_DIR "/testlink");
3175 unlink(FS_FCHOWNAT_TEST_DIR "/testfile");
3176 rmdir(FS_FCHOWNAT_TEST_DIR);
3177 return Result;
3178 }
3179
3180 int FsCommonTestFstatAt64(PLXT_ARGS Args)
3181
3182 /*++
3183
3184 Routine Description:
3185
3186 This routine runs tests associated with the fstatat64 syscall.
3187
3188 Arguments:
3189
3190 Args - Supplies the command line arguments.
3191
3192 Return Value:
3193
3194 Returns 0 on success, -1 on failure.
3195
3196 --*/
3197
3198 {
3199
3200 #if !defined(__amd64__)
3201 struct stat Buffer;
3202 #else
3203 struct stat64 Buffer;
3204 #endif
3205
3206 const char Child1[] = "newfile";
3207 const char Child1FullPath[] = FS_TEST_DIR_PARENT "/test_fstatat64/newfile";
3208 int Child1Fd;
3209 int DirFd;
3210 const char DirPath[] = FS_TEST_DIR_PARENT "/test_fstatat64";
3211 int Result;
3212 const char Symlink[] = "symlink1";
3213 int SymlinkFd;
3214 const char SymlinkFullPath[] = FS_TEST_DIR_PARENT "/test_fstatat64/symlink1";
3215 const char DirSymlinkPath[] = FS_TEST_DIR_PARENT "/test_fstatat64/symlink2";
3216
3217 //
3218 // Initialize locals.
3219 //
3220
3221 Child1Fd = -1;
3222 DirFd = -1;
3223 SymlinkFd = -1;
3224
3225 //
3226 // Make a directory.
3227 //
3228
3229 LxtLogInfo("Creating test directory folder %s", DirPath);
3230 LxtCheckErrnoZeroSuccess(mkdir(DirPath, 0777));
3231
3232 //
3233 // Open the directory.
3234 //
3235
3236 LxtCheckErrno(open(DirPath, O_RDONLY));
3237 DirFd = Result;
3238 LxtLogInfo("Opened test directory folder, fd = %d", DirFd);
3239
3240 //
3241 // Create a file.
3242 //
3243
3244 LxtCheckErrno(Child1Fd = creat(Child1FullPath, 0777 | S_IRWXU | S_ISGID | S_ISUID));
3245
3246 //
3247 // Create the symlinks.
3248 //
3249
3250 LxtCheckErrnoZeroSuccess(symlink(Child1FullPath, SymlinkFullPath));
3251 LxtCheckErrnoZeroSuccess(symlink(DirPath, DirSymlinkPath));
3252
3253 //
3254 // Call fstatat64 with an absolute path.
3255 //
3256
3257 LxtCheckErrno(LxtFStatAt64(DirFd, Child1FullPath, &Buffer, 0));
3258
3259 //
3260 // Call fstatat64 with a relative path.
3261 //
3262
3263 LxtCheckErrno(LxtFStatAt64(DirFd, Child1, &Buffer, 0));
3264
3265 //
3266 // Call fstatat64 on the symlink.
3267 //
3268
3269 LxtCheckErrno(LxtFStatAt64(DirFd, Symlink, &Buffer, 0));
3270 LxtLogInfo("symlink mode: %o", Buffer.st_mode);
3271 if ((Buffer.st_mode & S_IFMT) != S_IFREG)
3272 {
3273 LxtLogError("Expected regular file, got: %x", Buffer.st_mode & S_IFMT);
3274 }
3275
3276 //
3277 // Call fstatat64 on the symlink with the AT_SYMLINK_NOFOLLOW flag.
3278 //
3279
3280 LxtCheckErrno(LxtFStatAt64(DirFd, Symlink, &Buffer, AT_SYMLINK_NOFOLLOW));
3281 LxtLogInfo("symlink mode with AT_SYMLINK_NOFOLLOW: %o", Buffer.st_mode);
3282 if ((Buffer.st_mode & S_IFMT) != S_IFLNK)
3283 {
3284 LxtLogError("Expected symlink, got: %x", Buffer.st_mode & S_IFMT);
3285 }
3286
3287 //
3288 // Ensure that fstatat fails if the file descriptor is not a directory.
3289 //
3290
3291 LxtCheckErrnoFailure(LxtFStatAt64(Child1Fd, "foo", &Buffer, 0), ENOTDIR);
3292
3293 //
3294 // Use AT_EMPTY_PATH to directly stat the file descriptor.
3295 //
3296
3297 LxtCheckErrnoZeroSuccess(LxtFStatAt64(DirFd, "", &Buffer, AT_EMPTY_PATH));
3298 LxtLogInfo("dir mode with AT_EMPTY_PATH: %o", Buffer.st_mode);
3299 LxtCheckTrue(S_ISDIR(Buffer.st_mode));
3300
3301 //
3302 // AT_EMPTY_PATH does nothing if the path is not empty.
3303 //
3304
3305 LxtCheckErrnoZeroSuccess(LxtFStatAt64(DirFd, Child1, &Buffer, AT_EMPTY_PATH));
3306 LxtLogInfo("child mode with AT_EMPTY_PATH: %o", Buffer.st_mode);
3307 LxtCheckTrue(S_ISREG(Buffer.st_mode));
3308
3309 //
3310 // AT_EMPTY_PATH on a symlink does not follow the link regardless of
3311 // AT_SYMLINK_NOFOLLOW.
3312 //
3313
3314 LxtCheckErrno(SymlinkFd = open(SymlinkFullPath, O_NOFOLLOW | O_PATH));
3315 LxtCheckErrnoZeroSuccess(LxtFStatAt64(SymlinkFd, "", &Buffer, AT_EMPTY_PATH));
3316 LxtLogInfo("symlink mode with AT_EMPTY_PATH: %o", Buffer.st_mode);
3317 LxtCheckTrue(S_ISLNK(Buffer.st_mode));
3318 LxtCheckErrnoZeroSuccess(LxtFStatAt64(SymlinkFd, "", &Buffer, (AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW)));
3319
3320 LxtLogInfo("symlink mode with AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW: %o", Buffer.st_mode);
3321
3322 LxtCheckTrue(S_ISLNK(Buffer.st_mode));
3323 LxtCheckClose(SymlinkFd);
3324
3325 //
3326 // If the path is not empty, the FD must be a directory; a symlink
3327 // to a directory does not work.
3328 //
3329
3330 LxtCheckErrno(SymlinkFd = open(DirSymlinkPath, O_NOFOLLOW | O_PATH));
3331 LxtCheckErrnoFailure(LxtFStatAt64(SymlinkFd, Child1, &Buffer, 0), ENOTDIR);
3332
3333 ErrorExit:
3334 if (Child1Fd != -1)
3335 {
3336 LxtClose(Child1Fd);
3337 }
3338
3339 if (DirFd != -1)
3340 {
3341 LxtClose(DirFd);
3342 }
3343
3344 if (SymlinkFd != -1)
3345 {
3346 close(SymlinkFd);
3347 }
3348
3349 unlink(DirSymlinkPath);
3350 remove(Child1FullPath);
3351 remove(SymlinkFullPath);
3352 rmdir(DirPath);
3353
3354 return Result;
3355 }
3356
3357 int FsCommonTestDeleteCurrentWorkingDirectory(PLXT_ARGS Args)
3358
3359 /*++
3360
3361 Description:
3362
3363 This routine tests the behavior if the current working directory is
3364 unlinked for LxFs.
3365
3366 Arguments:
3367
3368 Args - Supplies the command line arguments.
3369
3370 Return Value:
3371
3372 Returns 0 on success, -1 on failure.
3373
3374 --*/
3375
3376 {
3377
3378 int Result;
3379
3380 LxtCheckErrno(LxtFsDeleteCurrentWorkingDirectoryCommon(FS_TEST_DIR_PARENT, 0));
3381
3382 ErrorExit:
3383 return Result;
3384 }
3385
3386 int FsCommonTestDeleteLoop(PLXT_ARGS Args)
3387
3388 /*++
3389
3390 Description:
3391
3392 This routine tests deleting files in a loop with multiple getdents calls.
3393
3394 Arguments:
3395
3396 Args - Supplies the command line arguments.
3397
3398 Return Value:
3399
3400 Returns 0 on success, -1 on failure.
3401
3402 --*/
3403
3404 {
3405
3406 int Result;
3407
3408 LxtCheckResult(LxtFsDeleteLoopCommon(FS_DELETELOOP_TEST_DIR));
3409
3410 ErrorExit:
3411 return Result;
3412 }
3413
3414 int FsCommonTestDeleteOpenFile(PLXT_ARGS Args)
3415
3416 /*++
3417
3418 Description:
3419
3420 This routine tests using unlink and rmdir on a LxFs file/directory that's open.
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 int Result;
3435
3436 LxtCheckErrno(LxtFsDeleteOpenFileCommon(FS_TEST_DIR_PARENT, 0));
3437
3438 ErrorExit:
3439 return Result;
3440 }
3441
3442 int FsCommonTestFchdir(PLXT_ARGS Args)
3443
3444 /*++
3445 --*/
3446
3447 {
3448 int Result;
3449 int FileDescriptor;
3450 const char TestFilePath1[] = "data/fstest/test_chdir.txt";
3451 const char TestFilePath2[] = "test_chdir.txt";
3452 const char DataTestDirPath[] = FS_TEST_DIR_PARENT;
3453 const char DataTestDirPath2[] = FS_TEST_DIR_PARENT "/";
3454 const char FailureDirPath[] = "/system12314/";
3455
3456 FileDescriptor = -1;
3457 LxtCheckErrno(chdir("/"));
3458
3459 //
3460 // Since the working directory is "/", create a file under /data/fstest
3461 //
3462
3463 LxtLogInfo("Creating file using path %s", TestFilePath1);
3464 LxtCheckErrno(FileDescriptor = open(TestFilePath1, O_RDWR | O_CREAT, S_IRWXU));
3465 LxtCheckClose(FileDescriptor);
3466
3467 //
3468 // Change working directory to /data/fstest
3469 //
3470
3471 LxtLogInfo("Changing working dir to %s", DataTestDirPath);
3472 LxtCheckErrno(FileDescriptor = open(DataTestDirPath, O_RDONLY | O_DIRECTORY, 0));
3473 LxtCheckErrno(fchdir(FileDescriptor));
3474 LxtCheckClose(FileDescriptor);
3475
3476 //
3477 // Open the same file now that the working directory is different.
3478 //
3479
3480 LxtLogInfo("Opening file using path %s", TestFilePath2);
3481 LxtCheckErrno(FileDescriptor = open(TestFilePath2, O_RDWR));
3482 LxtLogInfo("Opened file using path %s successfully!", TestFilePath2);
3483 LxtCheckClose(FileDescriptor);
3484
3485 //
3486 // Change working directory to /system/
3487 //
3488
3489 LxtLogInfo("Changing working dir to %s", DataTestDirPath2);
3490 LxtCheckErrno(FileDescriptor = open(DataTestDirPath2, O_RDONLY | O_DIRECTORY, 0));
3491 LxtCheckErrno(fchdir(FileDescriptor));
3492 LxtCheckClose(FileDescriptor);
3493
3494 //
3495 // Open the same file now that the working directory is different.
3496 //
3497
3498 LxtLogInfo("Opening file using path %s", TestFilePath2);
3499 LxtCheckErrno(FileDescriptor = open(TestFilePath2, O_RDWR));
3500 LxtCheckClose(FileDescriptor);
3501 LxtLogInfo("Opened file using path %s successfully!", TestFilePath2);
3502
3503 //
3504 // Change working directory to a bogus fd; this should fail.
3505 //
3506
3507 LxtLogInfo("Changing working dir to %s", FailureDirPath);
3508 LxtCheckErrnoFailure(fchdir(-1), EBADF);
3509 LxtLogInfo("Changing working dir to %s failed as expected", FailureDirPath);
3510
3511 Result = 0;
3512
3513 LxtLogInfo("TEST SUCCESSFUL!");
3514
3515 ErrorExit:
3516 if (FileDescriptor != -1)
3517 {
3518 close(FileDescriptor);
3519 }
3520
3521 unlink(FS_TEST_DIR_PARENT "/test_chdir.txt");
3522 return Result;
3523 }
3524
3525 int FsCommonTestMknod(PLXT_ARGS Args)
3526
3527 /*++
3528
3529 Description:
3530
3531 This routine tests creation of device nodes using mknod.
3532
3533 N.B. Creation of fifos is covered by the pipe unit tests, and other types
3534 of files are sufficiently covered by the LTP tests.
3535
3536 Arguments:
3537
3538 Args - Supplies the command line arguments.
3539
3540 Return Value:
3541
3542 Returns 0 on success, -1 on failure.
3543
3544 --*/
3545
3546 {
3547
3548 char Buffer[10];
3549 ssize_t BytesRead;
3550 int Fd;
3551 struct stat FileStat;
3552 int Result;
3553 struct stat Stat;
3554 char Zero[10];
3555
3556 Fd = -1;
3557
3558 //
3559 // Test basic device node creation.
3560 //
3561
3562 umask(0);
3563 LxtCheckErrnoZeroSuccess(mknod(FS_MKNOD_TEST_FILE, S_IFCHR | 0666, makedev(1, 5)));
3564
3565 LxtCheckErrnoZeroSuccess(stat(FS_MKNOD_TEST_FILE, &Stat));
3566 LxtCheckEqual(Stat.st_mode, S_IFCHR | 0666, "0%o");
3567 LxtCheckNotEqual(Stat.st_ino, 0, "%llu");
3568 LxtCheckEqual(Stat.st_rdev, makedev(1, 5), "0x%x");
3569 LxtCheckNotEqual(Stat.st_rdev, Stat.st_dev, "0x%x");
3570
3571 //
3572 // Test using the device node.
3573 //
3574
3575 LxtCheckErrno(Fd = open(FS_MKNOD_TEST_FILE, O_RDONLY));
3576 memset(Zero, 0, sizeof(Buffer));
3577 memset(Buffer, 1, sizeof(Buffer));
3578 LxtCheckErrno(BytesRead = read(Fd, Buffer, sizeof(Buffer)));
3579 LxtCheckEqual(BytesRead, sizeof(Buffer), "%d");
3580 LxtCheckMemoryEqual(Buffer, Zero, sizeof(Buffer));
3581
3582 //
3583 // Check the fd's inode matches the stat results.
3584 //
3585
3586 LxtCheckErrnoZeroSuccess(fstat(Fd, &FileStat));
3587 LxtCheckEqual(FileStat.st_ino, Stat.st_ino, "%llu");
3588 LxtCheckEqual(FileStat.st_dev, Stat.st_dev, "0x%x");
3589 LxtCheckEqual(FileStat.st_rdev, Stat.st_rdev, "0x%x");
3590 LxtCheckEqual(FileStat.st_mode, Stat.st_mode, "0%o");
3591
3592 //
3593 // Check the fd's path follows renames.
3594 //
3595
3596 LxtCheckResult(LxtCheckFdPath(Fd, FS_MKNOD_TEST_FILE));
3597 LxtCheckErrnoZeroSuccess(rename(FS_MKNOD_TEST_FILE, FS_MKNOD_TEST_FILE2));
3598 LxtCheckResult(LxtCheckFdPath(Fd, FS_MKNOD_TEST_FILE2));
3599 LxtCheckErrnoZeroSuccess(close(Fd));
3600 Fd = -1;
3601
3602 //
3603 // Check opening with O_PATH.
3604 //
3605
3606 LxtCheckErrno(Fd = open(FS_MKNOD_TEST_FILE2, O_PATH));
3607 LxtCheckErrnoFailure(read(Fd, Buffer, sizeof(Buffer)), EBADF);
3608 LxtCheckErrnoZeroSuccess(fstat(Fd, &FileStat));
3609 LxtCheckEqual(FileStat.st_ino, Stat.st_ino, "%llu");
3610 LxtCheckEqual(FileStat.st_dev, Stat.st_dev, "0x%x");
3611 LxtCheckEqual(FileStat.st_rdev, Stat.st_rdev, "0x%x");
3612 LxtCheckEqual(FileStat.st_mode, Stat.st_mode, "0%o");
3613 LxtCheckErrnoZeroSuccess(close(Fd));
3614 Fd = -1;
3615 LxtCheckErrnoZeroSuccess(unlink(FS_MKNOD_TEST_FILE2));
3616
3617 //
3618 // Check mknod applies the umask.
3619 //
3620
3621 umask(022);
3622 LxtCheckErrnoZeroSuccess(mknod(FS_MKNOD_TEST_FILE, S_IFCHR | 0666, makedev(1, 5)));
3623
3624 LxtCheckErrnoZeroSuccess(stat(FS_MKNOD_TEST_FILE, &Stat));
3625 LxtCheckEqual(Stat.st_mode, S_IFCHR | 0644, "0%o");
3626 LxtCheckErrnoZeroSuccess(unlink(FS_MKNOD_TEST_FILE));
3627
3628 //
3629 // Create a device with a non-existing major number.
3630 //
3631 // N.B. This test could fail on real Linux if at any point a device is
3632 // added with this number.
3633 //
3634
3635 LxtCheckErrnoZeroSuccess(mknod(FS_MKNOD_TEST_FILE, S_IFCHR | 0666, makedev(200, 0)));
3636
3637 LxtCheckErrnoFailure(open(FS_MKNOD_TEST_FILE, O_RDONLY), ENXIO);
3638 LxtCheckErrnoZeroSuccess(unlink(FS_MKNOD_TEST_FILE));
3639
3640 //
3641 // Existing major number, non-existing minor number.
3642 //
3643
3644 LxtCheckErrnoZeroSuccess(mknod(FS_MKNOD_TEST_FILE, S_IFCHR | 0666, makedev(1, 200)));
3645
3646 LxtCheckErrnoFailure(open(FS_MKNOD_TEST_FILE, O_RDONLY), ENXIO);
3647 LxtCheckErrnoZeroSuccess(unlink(FS_MKNOD_TEST_FILE));
3648
3649 //
3650 // Major number 10 returns different error code for unknown devices.
3651 //
3652
3653 LxtCheckErrnoZeroSuccess(mknod(FS_MKNOD_TEST_FILE, S_IFCHR | 0666, makedev(10, 100)));
3654
3655 LxtCheckErrnoFailure(open(FS_MKNOD_TEST_FILE, O_RDONLY), ENODEV);
3656 LxtCheckErrnoZeroSuccess(unlink(FS_MKNOD_TEST_FILE));
3657
3658 //
3659 // Nonexistent block device.
3660 //
3661 // N.B. Currently, no block devices exist in WSL.
3662 //
3663
3664 LxtCheckErrnoZeroSuccess(mknod(FS_MKNOD_TEST_FILE, S_IFBLK | 0666, makedev(200, 0)));
3665
3666 LxtCheckErrnoFailure(open(FS_MKNOD_TEST_FILE, O_RDONLY), ENXIO);
3667 LxtCheckErrnoZeroSuccess(unlink(FS_MKNOD_TEST_FILE));
3668
3669 ErrorExit:
3670 if (Fd >= 0)
3671 {
3672 close(Fd);
3673 }
3674
3675 unlink(FS_MKNOD_TEST_FILE);
3676 unlink(FS_MKNOD_TEST_FILE2);
3677 return Result;
3678 }
3679
3680 int FsCommonTestMknodSecurity(PLXT_ARGS Args)
3681
3682 /*++
3683
3684 Description:
3685
3686 This routine tests whether mknod correctly checks capabilities.
3687
3688 Arguments:
3689
3690 Args - Supplies the command line arguments.
3691
3692 Return Value:
3693
3694 Returns 0 on success, -1 on failure.
3695
3696 --*/
3697
3698 {
3699
3700 struct __user_cap_data_struct CapData[2];
3701 struct __user_cap_header_struct CapHeader;
3702 pid_t ChildPid;
3703 int Result;
3704
3705 LxtCheckErrno(ChildPid = fork());
3706 if (ChildPid == 0)
3707 {
3708
3709 //
3710 // Drop the CAP_MKNOD capability.
3711 //
3712
3713 memset(&CapData, 0, sizeof(CapData));
3714 memset(&CapHeader, 0, sizeof(CapHeader));
3715 CapHeader.version = _LINUX_CAPABILITY_VERSION_3;
3716 LxtCheckErrno(LxtCapGet(&CapHeader, CapData)) CapData[CAP_TO_INDEX(CAP_MKNOD)].effective &= ~CAP_TO_MASK(CAP_MKNOD);
3717 LxtCheckErrno(LxtCapSet(&CapHeader, CapData));
3718
3719 //
3720 // Creating devices should fail.
3721 //
3722
3723 LxtCheckErrnoFailure(mknod(FS_MKNOD_TEST_FILE, S_IFCHR | 0666, makedev(1, 5)), EPERM);
3724
3725 LxtCheckErrnoFailure(mknod(FS_MKNOD_TEST_FILE, S_IFBLK | 0666, makedev(1, 5)), EPERM);
3726
3727 //
3728 // Other file types should still succeed.
3729 //
3730
3731 LxtCheckErrnoZeroSuccess(mknod(FS_MKNOD_TEST_FILE, S_IFREG | 0666, 0));
3732 LxtCheckErrnoZeroSuccess(unlink(FS_MKNOD_TEST_FILE));
3733 LxtCheckErrnoZeroSuccess(mknod(FS_MKNOD_TEST_FILE, S_IFIFO | 0666, 0));
3734 LxtCheckErrnoZeroSuccess(unlink(FS_MKNOD_TEST_FILE));
3735 LxtCheckErrnoZeroSuccess(mknod(FS_MKNOD_TEST_FILE, S_IFSOCK | 0666, 0));
3736 LxtCheckErrnoZeroSuccess(unlink(FS_MKNOD_TEST_FILE));
3737 exit(0);
3738 }
3739
3740 LxtCheckResult(LxtWaitPidPoll(ChildPid, 0));
3741
3742 ErrorExit:
3743 unlink(FS_MKNOD_TEST_FILE);
3744 return Result;
3745 }
3746
3747 int FsCommonTestNoatimeFlag(PLXT_ARGS Args)
3748
3749 /*++
3750 --*/
3751
3752 {
3753
3754 char Buffer[100];
3755 int Bytes;
3756 char* DentsBuffer = NULL;
3757 int DentsBufferSize = 2 * 1024 * 1024;
3758 int FileDescriptor = -1;
3759 int Result;
3760 const char SourceGetdents[] = FS_TEST_DIR_PARENT "/";
3761 const char SourceOpen[] = FS_TEST_DIR_PARENT "/fs_access_time_test.bin";
3762 const char Content[] = "I am your father! Noooo!";
3763 struct iovec Iov;
3764 char SingleEntry[100];
3765 int SingleEntrySize;
3766 struct stat StatA;
3767 struct stat StatB;
3768
3769 //
3770 // Plan 9 and virtiofs do not forward O_NOATIME to the server.
3771 //
3772
3773 if (g_LxtFsInfo.FsType == LxtFsTypePlan9 || g_LxtFsInfo.FsType == LxtFsTypeVirtioFs)
3774 {
3775 LxtLogInfo("This test is not supported for plan9 or virtiofs.");
3776 Result = 0;
3777 goto ErrorExit;
3778 }
3779
3780 //
3781 // Create the test file; this should succeed.
3782 //
3783
3784 LxtCheckErrno(FileDescriptor = open(SourceOpen, O_RDWR | O_CREAT, S_IRWXU));
3785
3786 //
3787 // Test O_NOATIME for read no access time changes.
3788 //
3789
3790 LxtCheckErrno(fstat(FileDescriptor, &StatA));
3791 LxtCheckErrno(close(FileDescriptor));
3792 LxtCheckErrno(FileDescriptor = open(SourceOpen, O_RDWR));
3793 LxtCheckErrno(fstat(FileDescriptor, &StatB));
3794 LxtCheckMemoryEqual(&StatA.st_atim, &StatB.st_atim, sizeof(StatA.st_atim));
3795
3796 usleep(10 * 1000);
3797 LxtCheckErrno(Bytes = write(FileDescriptor, Content, sizeof(Content)));
3798 LxtCheckEqual(Bytes, sizeof(Content), "%d");
3799 LxtCheckErrno(fstat(FileDescriptor, &StatB));
3800
3801 //
3802 // NTFS updates the atime when other timestamps are updated, even when
3803 // O_NOATIME is specified.
3804 //
3805
3806 if (g_LxtFsInfo.Flags.DrvFsBehavior == 0)
3807 {
3808 LxtCheckMemoryEqual(&StatA.st_atim, &StatB.st_atim, sizeof(StatA.st_atim));
3809 }
3810
3811 LxtCheckErrno(close(FileDescriptor));
3812 LxtCheckErrno(FileDescriptor = open(SourceOpen, O_RDWR));
3813 memset(&Buffer, 0, sizeof(Buffer));
3814 usleep(10 * 1000);
3815 LxtCheckErrno(Bytes = read(FileDescriptor, Buffer, sizeof(Buffer)));
3816 LxtCheckEqual(Bytes, sizeof(Content), "%d");
3817
3818 //
3819 // Close first; with DrvFs, in case NTFS has atime updates enabled it
3820 // won't do it until the handle is closed.
3821 //
3822 // TODO_LX: Once NTFS timestamp updating is fixed, change this back.
3823 //
3824
3825 LxtCheckErrno(close(FileDescriptor));
3826 LxtCheckErrno(stat(SourceOpen, &StatA));
3827
3828 //
3829 // TODO_LX: Uncomment when the file system is mounted without noatime.
3830 //
3831 // if (memcmp(&StatA.st_atim, &StatB.st_atim, sizeof(StatA.st_atim)) == 0) {
3832 // LxtLogError("Access time was supposed to be updated.");
3833 // Result = -1;
3834 // goto ErrorExit;
3835 // }
3836 //
3837
3838 LxtCheckErrno(FileDescriptor = open(SourceOpen, O_RDWR | O_NOATIME));
3839 memset(&Buffer, 0, sizeof(Buffer));
3840 usleep(10 * 1000);
3841 LxtCheckErrno(Bytes = read(FileDescriptor, Buffer, sizeof(Buffer)));
3842 LxtCheckEqual(Bytes, sizeof(Content), "%d");
3843 LxtCheckErrno(fstat(FileDescriptor, &StatB));
3844 LxtCheckMemoryEqual(&StatA.st_atim, &StatB.st_atim, sizeof(StatA.st_atim));
3845
3846 LxtCheckErrno(close(FileDescriptor));
3847 LxtCheckErrno(stat(SourceOpen, &StatB));
3848 LxtCheckMemoryEqual(&StatA.st_atim, &StatB.st_atim, sizeof(StatA.st_atim));
3849
3850 FileDescriptor = -1;
3851
3852 //
3853 // Test O_NOATIME for readv no access time changes.
3854 //
3855
3856 LxtCheckErrno(FileDescriptor = open(SourceOpen, O_RDWR | O_NOATIME));
3857 Iov.iov_base = Buffer;
3858 Iov.iov_len = sizeof(Buffer);
3859 usleep(10 * 1000);
3860 LxtCheckErrno(Bytes = readv(FileDescriptor, &Iov, 1));
3861 LxtCheckEqual(Bytes, sizeof(Content), "%d");
3862 LxtCheckErrno(fstat(FileDescriptor, &StatB));
3863 LxtCheckMemoryEqual(&StatA.st_atim, &StatB.st_atim, sizeof(StatA.st_atim));
3864
3865 LxtCheckErrno(close(FileDescriptor));
3866 LxtCheckErrno(stat(SourceOpen, &StatB));
3867 LxtCheckMemoryEqual(&StatA.st_atim, &StatB.st_atim, sizeof(StatA.st_atim));
3868
3869 FileDescriptor = -1;
3870
3871 //
3872 // Test O_NOATIME for getdents no access time changes.
3873 //
3874
3875 rmdir(LXT_GET_DENTS_FOLDER);
3876
3877 //
3878 // Check the expected getdents results for each directory;
3879 //
3880
3881 DentsBuffer = malloc(DentsBufferSize);
3882 if (DentsBuffer == NULL)
3883 {
3884 Result = LXT_RESULT_FAILURE;
3885 LxtLogError("malloc");
3886 goto ErrorExit;
3887 }
3888
3889 LxtCheckErrno(mkdir(LXT_GET_DENTS_FOLDER, 0777));
3890 memset(DentsBuffer, 1, DentsBufferSize);
3891 LxtCheckErrno(FileDescriptor = open(SourceGetdents, O_RDONLY | O_DIRECTORY));
3892
3893 LxtCheckErrno(fstat(FileDescriptor, &StatA));
3894 usleep(10 * 1000);
3895 LxtCheckErrno(Bytes = LxtGetdents64(FileDescriptor, DentsBuffer, DentsBufferSize));
3896
3897 if (Bytes == 0)
3898 {
3899 Result = LXT_RESULT_FAILURE;
3900 LxtLogError("BytesRead == 0");
3901 goto ErrorExit;
3902 }
3903
3904 LxtCheckErrno(fstat(FileDescriptor, &StatB));
3905
3906 //
3907 // TODO_LX: Uncomment when the file system is mounted without noatime.
3908 //
3909 // if (memcmp(&StatA.st_atim, &StatB.st_atim, sizeof(StatA.st_atim)) == 0) {
3910 // LxtLogError("Access time was supposed to be updated.");
3911 // Result = -1;
3912 // goto ErrorExit;
3913 // }
3914 //
3915
3916 LxtCheckErrno(close(FileDescriptor));
3917 FileDescriptor = -1;
3918 LxtCheckErrno(FileDescriptor = open(SourceGetdents, O_RDONLY | O_DIRECTORY | O_NOATIME));
3919
3920 usleep(100 * 1000);
3921 LxtCheckErrno(Bytes = LxtGetdents64(FileDescriptor, DentsBuffer, DentsBufferSize));
3922
3923 if (Bytes == 0)
3924 {
3925 Result = LXT_RESULT_FAILURE;
3926 LxtLogError("BytesRead == 0");
3927 goto ErrorExit;
3928 }
3929
3930 LxtCheckErrno(fstat(FileDescriptor, &StatA));
3931 LxtCheckMemoryEqual(&StatA.st_atim, &StatB.st_atim, sizeof(StatA.st_atim));
3932
3933 LxtCheckClose(FileDescriptor);
3934 LxtCheckErrno(stat(SourceGetdents, &StatA));
3935 LxtCheckMemoryEqual(&StatA.st_atim, &StatB.st_atim, sizeof(StatA.st_atim));
3936
3937 Result = LXT_RESULT_SUCCESS;
3938
3939 ErrorExit:
3940
3941 if (FileDescriptor != -1)
3942 {
3943 close(FileDescriptor);
3944 }
3945
3946 if (DentsBuffer != NULL)
3947 {
3948 free(DentsBuffer);
3949 }
3950
3951 unlink(SourceOpen);
3952 rmdir(LXT_GET_DENTS_FOLDER);
3953 return Result;
3954 }
3955
3956 int FsCommonTestWritev(PLXT_ARGS Args)
3957
3958 /*++
3959 --*/
3960
3961 {
3962
3963 //
3964 // This test doesn't pass on real Linux, so it's skipped for VM mode.
3965 //
3966
3967 if (g_LxtFsInfo.FsType == LxtFsTypePlan9)
3968 {
3969 LxtLogInfo("Skipping writev test in VM mode.");
3970 return LXT_RESULT_SUCCESS;
3971 }
3972
3973 return LxtFsWritevCommon(FS_TEST_DIR_PARENT "/fs_writev_test.bin");
3974 }
3975
3976 int FsCommonTestDeviceId(PLXT_ARGS Args)
3977
3978 /*++
3979
3980 Description:
3981
3982 This routine tests that mounts have unique device id's.
3983
3984 Arguments:
3985
3986 Args - Supplies the command line arguments.
3987
3988 Return Value:
3989
3990 Returns 0 on success, -1 on failure.
3991
3992 --*/
3993
3994 {
3995
3996 dev_t DevDeviceId;
3997 dev_t ProcDeviceId;
3998 int Result;
3999 dev_t RootDeviceId;
4000 struct stat Stat;
4001
4002 //
4003 // Test that various directories device id's are reported correctly.
4004 //
4005
4006 LxtCheckErrnoZeroSuccess(stat("/", &Stat));
4007 RootDeviceId = Stat.st_dev;
4008
4009 LxtCheckErrnoZeroSuccess(stat("/proc", &Stat));
4010 ProcDeviceId = Stat.st_dev;
4011
4012 LxtCheckErrnoZeroSuccess(stat("/dev", &Stat));
4013 DevDeviceId = Stat.st_dev;
4014
4015 LxtLogInfo("DeviceId's: / = %lld /proc = %lld /dev = %lld", RootDeviceId, ProcDeviceId, DevDeviceId);
4016
4017 if ((RootDeviceId == ProcDeviceId) || (RootDeviceId == DevDeviceId) || (ProcDeviceId == DevDeviceId))
4018 {
4019
4020 LxtLogError("Detected non-unique device id's");
4021 }
4022
4023 ErrorExit:
4024 return Result;
4025 }
4026
4027 int FsCommonTestFallocate(PLXT_ARGS Args)
4028
4029 /*++
4030
4031 Description:
4032
4033 This routine tests the fallocate system call.
4034
4035 Arguments:
4036
4037 Args - Supplies the command line arguments.
4038
4039 Return Value:
4040
4041 Returns 0 on success, -1 on failure.
4042
4043 --*/
4044
4045 {
4046
4047 int Fd;
4048 dev_t ProcDeviceId;
4049 int Result;
4050 dev_t RootDeviceId;
4051 struct stat Stat;
4052
4053 unlink(FS_FALLOCATE_TEST_FILE);
4054 LxtCheckErrno(Fd = creat(FS_FALLOCATE_TEST_FILE, 0666));
4055
4056 //
4057 // Plan 9 and virtiofs do not support fallocate.
4058 //
4059
4060 if (g_LxtFsInfo.FsType == LxtFsTypePlan9 || g_LxtFsInfo.FsType == LxtFsTypeVirtioFs)
4061 {
4062 LxtCheckErrnoFailure(fallocate(Fd, 0, 0, 1024), ENOTSUP);
4063 LxtLogInfo("Fallocate is not supported on Plan 9.");
4064 goto ErrorExit;
4065 }
4066
4067 //
4068 // Allocate some space.
4069 //
4070
4071 LxtCheckErrnoZeroSuccess(fallocate(Fd, 0, 0, 1024));
4072 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat));
4073 LxtCheckEqual(Stat.st_size, 1024, "%lld");
4074 LxtCheckGreaterOrEqual(Stat.st_blocks, 2, "%ld");
4075
4076 //
4077 // Don't change the length.
4078 //
4079
4080 LxtCheckErrnoZeroSuccess(fallocate(Fd, FALLOC_FL_KEEP_SIZE, 0, 16384));
4081 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat));
4082 LxtCheckEqual(Stat.st_size, 1024, "%lld");
4083 LxtCheckGreaterOrEqual(Stat.st_blocks, 32, "%ld");
4084
4085 //
4086 // Fallocate won't shrink the file.
4087 //
4088
4089 LxtCheckErrnoZeroSuccess(fallocate(Fd, 0, 0, 512));
4090 LxtCheckErrnoZeroSuccess(fstat(Fd, &Stat));
4091 LxtCheckEqual(Stat.st_size, 1024, "%lld");
4092 LxtCheckGreaterOrEqual(Stat.st_blocks, 32, "%ld");
4093
4094 //
4095 // Attempt to make the file very very large.
4096 //
4097 // N.B. On some machines with very large hard drives (larger than 1TB) this
4098 // can succeed.
4099 //
4100
4101 Result = fallocate(Fd, 0, 0, 0xffffffffff);
4102 if (Result < 0)
4103 {
4104 LxtCheckErrnoFailure(Result, ENOSPC);
4105 }
4106
4107 ErrorExit:
4108 unlink(FS_FALLOCATE_TEST_FILE);
4109 if (Fd != -1)
4110 {
4111 LxtClose(Fd);
4112 }
4113
4114 return Result;
4115 }
4116
4117 int FsCommonTestDirSeek(PLXT_ARGS Args)
4118
4119 /*++
4120
4121 Description:
4122
4123 This routine tests the seek operation on directory.
4124
4125 Arguments:
4126
4127 Args - Supplies the command line arguments.
4128
4129 Return Value:
4130
4131 Returns 0 on success, -1 on failure.
4132
4133 --*/
4134
4135 {
4136
4137 int Result;
4138 LxtCheckResult(LxtFsDirSeekCommon(LXT_GET_DENTS_FOLDER));
4139
4140 ErrorExit:
4141 return Result;
4142 }
4143
4144 int FsCommonTestFsync(PLXT_ARGS Args)
4145
4146 /*++
4147
4148 Description:
4149
4150 This routine tests the fsync system call.
4151
4152 Arguments:
4153
4154 Args - Supplies the command line arguments.
4155
4156 Return Value:
4157
4158 Returns 0 on success, -1 on failure.
4159
4160 --*/
4161
4162 {
4163
4164 int Fd;
4165 int Result;
4166 struct stat St;
4167
4168 Fd = -1;
4169
4170 LxtCheckErrnoZeroSuccess(mkdir(FS_FSYNC_TEST_DIR, 0777));
4171 LxtCheckErrno(Fd = creat(FS_FSYNC_TEST_DIR "/testfile", 0666));
4172 LxtCheckErrnoZeroSuccess(fsync(Fd));
4173 LxtCheckClose(Fd);
4174
4175 //
4176 // Open the file as read-only and attempt to call fsync on it.
4177 //
4178
4179 LxtCheckErrno(Fd = open(FS_FSYNC_TEST_DIR "/testfile", O_RDONLY));
4180 LxtCheckErrnoZeroSuccess(fsync(Fd));
4181 LxtCheckClose(Fd);
4182
4183 //
4184 // Create a file with no write access and call fsync on it.
4185
4186 LxtCheckErrno(Fd = creat(FS_FSYNC_TEST_DIR "/testfile2", 0444));
4187 LxtCheckErrnoZeroSuccess(fstat(Fd, &St));
4188 LxtCheckEqual(St.st_mode, S_IFREG | 0444, "0%o");
4189 LxtCheckErrnoZeroSuccess(fsync(Fd));
4190 LxtCheckClose(Fd);
4191
4192 //
4193 // Open that file as read-only and attempt to call fsync on it.
4194 //
4195
4196 LxtCheckErrno(Fd = open(FS_FSYNC_TEST_DIR "/testfile2", O_RDONLY));
4197 LxtCheckErrnoZeroSuccess(fsync(Fd));
4198 LxtCheckClose(Fd);
4199
4200 ErrorExit:
4201 if (Fd >= 0)
4202 {
4203 close(Fd);
4204 }
4205
4206 unlink(FS_FSYNC_TEST_DIR "/testfile2");
4207 unlink(FS_FSYNC_TEST_DIR "/testfile");
4208 rmdir(FS_FSYNC_TEST_DIR);
4209 return Result;
4210 }