]>
git.saurik.com Git - apple/hfs.git/blob - tests/cases/test-move-data-extents.c
1 #include <TargetConditionals.h>
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,
63 if (fcntl(fd
, F_LOG2PHYS_EXT
, &l2p
)) {
66 assert_fail("fcntl failed: %s", strerror(errno
));
69 fstore
.fst_posmode
= F_VOLPOSMODE
;
70 fstore
.fst_offset
= l2p
.l2p_devoffset
+ 1 + sfs
.f_bsize
;
73 len
+= blocks_per_extent
* sfs
.f_bsize
;
75 fstore
.fst_length
= len
;
77 assert_no_err(fcntl(fd
, F_PREALLOCATE
, &fstore
));
80 assert_no_err(ftruncate(fd
, len
));
85 int run_move_data_extents(__unused test_ctx_t
*ctx
)
87 di
= disk_image_get();
89 int frag_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(frag_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
);
136 * Make sure that the extents from move_data_extents.1 got deleted
137 * properly. To test this, we do another F_MOVEDATAEXTENTS and
138 * this time if it's broken it will move the bad extents.
141 fd
= make_frag_file(2);
143 assert_with_errno((fd2
= open(file2
,
144 O_RDWR
| O_TRUNC
| O_CREAT
, 0666)) >= 0);
146 assert_no_err(fcntl(fd
, F_MOVEDATAEXTENTS
, fd2
));
151 // And this time it should fail if there's a bug
152 fd
= make_frag_file(1);
154 assert_with_errno((fd2
= open(file2
,
155 O_RDWR
| O_TRUNC
| O_CREAT
, 0666)) >= 0);
157 assert_no_err(fcntl(fd
, F_MOVEDATAEXTENTS
, fd2
));
159 assert_no_err(unlink(file1
));
160 assert_no_err(unlink(file2
));
161 assert_no_err(close(fd
));
162 assert_no_err(close(fd2
));
164 assert_no_err(copyfile("/bin/bash", file1
, NULL
, COPYFILE_ALL
));
166 assert_no_err(chmod(file1
, 0777));
168 assert_no_err(stat(file1
, &sb
));
170 assert(sb
.st_flags
& UF_COMPRESSED
);
172 assert_with_errno((fd
= open(file1
, O_RDONLY
| O_EVTONLY
)) >= 0);
174 assert_with_errno((fd2
= open(file2
,
175 O_RDWR
| O_TRUNC
| O_CREAT
, 0666)) >= 0);
180 asprintf(&file3
, "%s/..namedfork/rsrc", file2
);
181 assert_with_errno((fd3
= open(file3
,
182 O_RDWR
| O_TRUNC
| O_CREAT
, 0666)) >= 0);
184 assert_no_err(fcntl(fd
, F_MOVEDATAEXTENTS
, fd2
));
186 assert_no_err(unlink(file1
));
187 assert_no_err(close(fd
));
189 assert_no_err(chflags(file2
, 0));
191 assert_with_errno((fd
= open(file3
,
194 check_io(pwrite(fd
, "append", 6, sb
.st_size
), 6);
196 assert_no_err(unlink(file2
));
198 assert_no_err (close(fd
));
199 assert_no_err (close(fd2
));
200 assert_no_err (close(fd3
));
209 #endif // !TARGET_OS_IPHONE