]>
git.saurik.com Git - apple/hfs.git/blob - tests/cases/test-move-data-extents.c
1 #include <TargetConditionals.h>
3 #if !TARGET_OS_EMBEDDED
11 #include <sys/mount.h>
12 #include <sys/param.h>
15 #include "hfs-tests.h"
16 #include "test-utils.h"
17 #include "disk-image.h"
19 TEST(move_data_extents
)
21 static disk_image_t
*di
;
22 static char *file1
, *file2
;
24 #define TEST_FILE_1 "/tmp/move_data_extents.1"
25 #define TEST_FILE_2 "/tmp/move_data_extents.2"
27 static volatile bool run_thread
;
29 static void *write_thread(void *param
)
31 int fd
= (int)(uintptr_t)param
;
39 static int make_frag_file(int blocks_per_extent
)
43 asprintf(&file1
, "%s/move_data_extents.1", di
->mount_point
);
44 assert_with_errno((fd
= open(file1
,
45 O_CREAT
| O_RDWR
| O_TRUNC
| O_EVTONLY
, 0666)) >= 0);
48 assert_no_err(statfs(file1
, &sfs
));
51 .fst_flags
= F_ALLOCATECONTIG
| F_ALLOCATEALL
,
52 .fst_posmode
= F_PEOFPOSMODE
,
57 for (int i
= 0; i
< 9; ++i
) {
59 struct log2phys l2p
= {
60 .l2p_contigbytes
= 1024 * 1024,
61 .l2p_devoffset
= len
- 1,
64 if (fcntl(fd
, F_LOG2PHYS_EXT
, &l2p
)) {
67 assert_fail("fcntl failed: %s", strerror(errno
));
70 fstore
.fst_posmode
= F_VOLPOSMODE
;
71 fstore
.fst_offset
= l2p
.l2p_devoffset
+ 1 + sfs
.f_bsize
;
74 len
+= blocks_per_extent
* sfs
.f_bsize
;
76 fstore
.fst_length
= len
;
78 assert_no_err(fcntl(fd
, F_PREALLOCATE
, &fstore
));
81 assert_no_err(ftruncate(fd
, len
));
86 int run_move_data_extents(__unused test_ctx_t
*ctx
)
88 di
= disk_image_get();
90 int fd
= make_frag_file(1);
97 asprintf(&file2
, "%s/move_data_extents.2", di
->mount_point
);
98 assert_with_errno((fd2
= open(file2
,
99 O_RDWR
| O_TRUNC
| O_CREAT
, 0666)) >= 0);
101 #define F_MOVEDATAEXTENTS 69
103 assert_no_err(fcntl(fd
, F_MOVEDATAEXTENTS
, fd2
));
106 check_io(pread(fd2
, buf
, 4096, sb
.st_size
- 4096), 4096);
108 check_io(pwrite(fd2
, buf
, 100, sb
.st_size
), 100);
112 assert_with_errno((fd
= open(file1
,
113 O_APPEND
| O_RDWR
)) >= 0);
118 pthread_create(&thread
, NULL
, write_thread
, (void *)(uintptr_t)fd
);
120 for (int i
= 0; i
< 500; ++i
) {
121 assert_with_errno((fd2
= open(file2
,
122 O_RDWR
| O_TRUNC
| O_CREAT
, 0666)) >= 0);
124 assert(fcntl(fd
, F_MOVEDATAEXTENTS
, fd2
) == -1 && errno
== EBUSY
);
126 assert_no_err(close(fd2
));
130 pthread_join(thread
, NULL
);
135 * Make sure that the extents from move_data_extents.1 got deleted
136 * properly. To test this, we do another F_MOVEDATAEXTENTS and
137 * this time if it's broken it will move the bad extents.
140 fd
= make_frag_file(2);
142 assert_with_errno((fd2
= open(file2
,
143 O_RDWR
| O_TRUNC
| O_CREAT
, 0666)) >= 0);
145 assert_no_err(fcntl(fd
, F_MOVEDATAEXTENTS
, fd2
));
150 // And this time it should fail if there's a bug
151 fd
= make_frag_file(1);
153 assert_with_errno((fd2
= open(file2
,
154 O_RDWR
| O_TRUNC
| O_CREAT
, 0666)) >= 0);
156 assert_no_err(fcntl(fd
, F_MOVEDATAEXTENTS
, fd2
));
158 assert_no_err(unlink(file1
));
159 assert_no_err(unlink(file2
));
160 assert_no_err(close(fd
));
161 assert_no_err(close(fd2
));
163 assert_no_err(copyfile("/bin/bash", file1
, NULL
, COPYFILE_ALL
));
165 assert_no_err(chmod(file1
, 0777));
167 assert_no_err(stat(file1
, &sb
));
169 assert(sb
.st_flags
& UF_COMPRESSED
);
171 assert_with_errno((fd
= open(file1
, O_RDONLY
| O_EVTONLY
)) >= 0);
173 assert_with_errno((fd2
= open(file2
,
174 O_RDWR
| O_TRUNC
| O_CREAT
, 0666)) >= 0);
179 asprintf(&file3
, "%s/..namedfork/rsrc", file2
);
180 assert_with_errno((fd3
= open(file3
,
181 O_RDWR
| O_TRUNC
| O_CREAT
, 0666)) >= 0);
183 assert_no_err(fcntl(fd
, F_MOVEDATAEXTENTS
, fd2
));
185 assert_no_err(unlink(file1
));
186 assert_no_err(close(fd
));
188 assert_no_err(chflags(file2
, 0));
190 assert_with_errno((fd
= open(file3
,
193 check_io(pwrite(fd
, "append", 6, sb
.st_size
), 6);
195 assert_no_err(unlink(file2
));