]> git.saurik.com Git - apple/hfs.git/blob - tests/cases/test-map-private.m
hfs-366.70.1.tar.gz
[apple/hfs.git] / tests / cases / test-map-private.m
1 #include <TargetConditionals.h>
2
3 #if !TARGET_OS_EMBEDDED
4
5 #include <sys/mman.h>
6 #include <unistd.h>
7 #include <spawn.h>
8 #include <fcntl.h>
9 #include <sys/stat.h>
10 #include <sys/param.h>
11 #include <sys/mount.h>
12
13 #include <Foundation/Foundation.h>
14
15 #include "hfs-tests.h"
16 #include "test-utils.h"
17 #include "systemx.h"
18 #include "disk-image.h"
19
20 TEST(map_private)
21
22 #define DISK_IMAGE "/tmp/map-private.sparseimage"
23
24 static char zero[65536];
25
26 static jmp_buf jmp_env;
27
28 static void handle_sigbus(int signal)
29 {
30 assert(signal == SIGBUS);
31
32 longjmp(jmp_env, 1);
33 }
34
35 int run_map_private(__unused test_ctx_t *ctx)
36 {
37 disk_image_t *di = disk_image_create(DISK_IMAGE, &(disk_image_opts_t){
38 .size = 64 * 1024 * 1024
39 });
40
41 char *path;
42 asprintf(&path, "%s/map-private.data", di->mount_point);
43
44 int fd;
45 void *p;
46
47 assert_with_errno((fd = open(path, O_RDWR | O_CREAT, 0666)) >= 0);
48
49 assert_no_err(ftruncate(fd, 65536));
50
51 assert_no_err(fcntl(fd, F_FULLFSYNC));
52
53 assert_with_errno((p = mmap(NULL, 65536, PROT_READ | PROT_WRITE,
54 MAP_PRIVATE, fd, 0)) != MAP_FAILED);
55
56 assert_no_err(close(fd));
57
58 assert_no_err(unlink(path));
59
60 // Create a second file that we keep open via a file descriptor
61 char *path2;
62 asprintf(&path2, "%s/map-private-2.data", di->mount_point);
63
64 assert_with_errno((fd = open(path2, O_RDWR | O_CREAT, 0666)) >= 0);
65
66 assert_no_err(ftruncate(fd, 65536));
67
68 assert_no_err(fcntl(fd, F_FULLFSYNC));
69
70 assert_no_err(unlink(path2));
71
72 assert(!systemx("/usr/sbin/diskutil", SYSTEMX_QUIET, "unmount", "force", di->mount_point, NULL));
73
74 /*
75 * Forcibly unmounting should not have caused all the data
76 * to be paged in so this should result in a fault.
77 */
78
79 // Set things up to catch the SIGBUS
80 sigset_t set;
81 sigemptyset(&set);
82 sigaddset(&set, SIGBUS);
83
84 sigprocmask(SIG_BLOCK, &set, NULL);
85
86 struct sigaction sa = {
87 .sa_handler = handle_sigbus,
88 .sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO,
89 };
90
91 sigaction(SIGBUS, &sa, NULL);
92 pthread_sigmask(SIG_UNBLOCK, &set, NULL);
93
94 if (!setjmp(jmp_env)) {
95 if(memcmp(p, zero, 65536)) // Need this if statement so the memcmp isn't optimized out
96 assert_fail("memcmp should have faulted");
97 else
98 assert_fail("... memcmp should have faulted");
99 }
100
101 // Now remount the volume and make sure file has been deleted
102 assert(!systemx("/usr/sbin/diskutil", SYSTEMX_QUIET, "mount", di->disk, NULL));
103
104 /*
105 * We assume that it will get mounted at the same place, which
106 * is reasonable given the environment this should be running
107 * in.
108 */
109 struct stat sb;
110 assert(stat(path, &sb) == -1 && errno == ENOENT);
111
112 // Now check that common open unlink behaviour isn't broken
113
114 // First check disk space
115 struct statfs sfs;
116 assert_no_err(statfs(di->mount_point, &sfs));
117
118 // Should be at least 7 MB
119 uint64_t space = sfs.f_bfree * sfs.f_bsize;
120
121 #define MB * 1024 * 1024
122
123 assert(space > 7 MB);
124
125 assert_with_errno((fd = open(path, O_RDWR | O_CREAT, 0666)) >= 0);
126
127 assert_no_err(ftruncate(fd, 7 MB));
128
129 assert_no_err(statfs(di->mount_point, &sfs));
130
131 // Space should have dropped by at least 5 MB
132 assert(sfs.f_bfree * sfs.f_bsize < space - 5 MB);
133
134 assert_no_err(unlink(path));
135
136 // Map the file
137 assert_with_errno((p = mmap(NULL, 65536, PROT_READ | PROT_WRITE,
138 MAP_PRIVATE, fd, 0)) != MAP_FAILED);
139
140 assert_no_err(close(fd));
141
142 // File is still in use, so space should not have changed
143 assert_no_err(statfs(di->mount_point, &sfs));
144
145 assert(sfs.f_bfree * sfs.f_bsize < space - 5 MB);
146
147 // Get rid of the last reference
148 assert_no_err(munmap(p, 65536));
149
150 // Just in case we collide with sync
151 sleep(1);
152
153 // Space should be back up to at least 7 MB free
154 assert_no_err(statfs(di->mount_point, &sfs));
155
156 assert(sfs.f_bfree * sfs.f_bsize > 7 MB);
157
158 return 0;
159 }
160
161 #endif