1 #include <TargetConditionals.h>
3 #if !TARGET_OS_EMBEDDED
10 #include <sys/param.h>
11 #include <sys/mount.h>
13 #include <Foundation/Foundation.h>
15 #include "hfs-tests.h"
16 #include "test-utils.h"
18 #include "disk-image.h"
22 #define DISK_IMAGE "/tmp/map-private.sparseimage"
24 static char zero[65536];
26 static jmp_buf jmp_env;
28 static void handle_sigbus(int signal)
30 assert(signal == SIGBUS);
35 int run_map_private(__unused test_ctx_t *ctx)
37 disk_image_t *di = disk_image_create(DISK_IMAGE, &(disk_image_opts_t){
38 .size = 64 * 1024 * 1024
42 asprintf(&path, "%s/map-private.data", di->mount_point);
47 assert_with_errno((fd = open(path, O_RDWR | O_CREAT, 0666)) >= 0);
49 assert_no_err(ftruncate(fd, 65536));
51 assert_no_err(fcntl(fd, F_FULLFSYNC));
53 assert_with_errno((p = mmap(NULL, 65536, PROT_READ | PROT_WRITE,
54 MAP_PRIVATE, fd, 0)) != MAP_FAILED);
56 assert_no_err(close(fd));
58 assert_no_err(unlink(path));
60 // Create a second file that we keep open via a file descriptor
62 asprintf(&path2, "%s/map-private-2.data", di->mount_point);
64 assert_with_errno((fd = open(path2, O_RDWR | O_CREAT, 0666)) >= 0);
66 assert_no_err(ftruncate(fd, 65536));
68 assert_no_err(fcntl(fd, F_FULLFSYNC));
70 assert_no_err(unlink(path2));
72 assert(!systemx("/usr/sbin/diskutil", SYSTEMX_QUIET, "unmount", "force", di->mount_point, NULL));
75 * Forcibly unmounting should not have caused all the data
76 * to be paged in so this should result in a fault.
79 // Set things up to catch the SIGBUS
82 sigaddset(&set, SIGBUS);
84 sigprocmask(SIG_BLOCK, &set, NULL);
86 struct sigaction sa = {
87 .sa_handler = handle_sigbus,
88 .sa_flags = SA_NODEFER | SA_RESETHAND | SA_SIGINFO,
91 sigaction(SIGBUS, &sa, NULL);
92 pthread_sigmask(SIG_UNBLOCK, &set, NULL);
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");
98 assert_fail("... memcmp should have faulted");
101 // Now remount the volume and make sure file has been deleted
102 assert(!systemx("/usr/sbin/diskutil", SYSTEMX_QUIET, "mount", di->disk, NULL));
105 * We assume that it will get mounted at the same place, which
106 * is reasonable given the environment this should be running
110 assert(stat(path, &sb) == -1 && errno == ENOENT);
112 // Now check that common open unlink behaviour isn't broken
114 // First check disk space
116 assert_no_err(statfs(di->mount_point, &sfs));
118 // Should be at least 7 MB
119 uint64_t space = sfs.f_bfree * sfs.f_bsize;
121 #define MB * 1024 * 1024
123 assert(space > 7 MB);
125 assert_with_errno((fd = open(path, O_RDWR | O_CREAT, 0666)) >= 0);
127 assert_no_err(ftruncate(fd, 7 MB));
129 assert_no_err(statfs(di->mount_point, &sfs));
131 // Space should have dropped by at least 5 MB
132 assert(sfs.f_bfree * sfs.f_bsize < space - 5 MB);
134 assert_no_err(unlink(path));
137 assert_with_errno((p = mmap(NULL, 65536, PROT_READ | PROT_WRITE,
138 MAP_PRIVATE, fd, 0)) != MAP_FAILED);
140 assert_no_err(close(fd));
142 // File is still in use, so space should not have changed
143 assert_no_err(statfs(di->mount_point, &sfs));
145 assert(sfs.f_bfree * sfs.f_bsize < space - 5 MB);
147 // Get rid of the last reference
148 assert_no_err(munmap(p, 65536));
150 // Just in case we collide with sync
153 // Space should be back up to at least 7 MB free
154 assert_no_err(statfs(di->mount_point, &sfs));
156 assert(sfs.f_bfree * sfs.f_bsize > 7 MB);