1 /**
2 * libf2fs.c
3 *
4 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
5 * http://www.samsung.com/
6 *
7 * Dual licensed under the GPL or LGPL version 2 licenses.
8 */
9 #define _LARGEFILE64_SOURCE
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #ifdef HAVE_MNTENT_H
18 #include <mntent.h>
19 #endif
20 #include <time.h>
21 #ifndef ANDROID_WINDOWS_HOST
22 #include <sys/stat.h>
23 #include <sys/mount.h>
24 #include <sys/ioctl.h>
25 #endif
26 #ifdef HAVE_LINUX_HDREG_H
27 #include <linux/hdreg.h>
28 #endif
29
30 #include <f2fs_fs.h>
31
32 struct f2fs_configuration c;
33
34 #ifdef WITH_ANDROID
35 #include <sparse/sparse.h>
36 struct sparse_file *f2fs_sparse_file;
37 static char **blocks;
38 u_int64_t blocks_count;
39 #endif
40
__get_device_fd(__u64 * offset)41 static int __get_device_fd(__u64 *offset)
42 {
43 __u64 blk_addr = *offset >> F2FS_BLKSIZE_BITS;
44 int i;
45
46 for (i = 0; i < c.ndevs; i++) {
47 if (c.devices[i].start_blkaddr <= blk_addr &&
48 c.devices[i].end_blkaddr >= blk_addr) {
49 *offset -=
50 c.devices[i].start_blkaddr << F2FS_BLKSIZE_BITS;
51 return c.devices[i].fd;
52 }
53 }
54 return -1;
55 }
56
57 #ifndef HAVE_LSEEK64
58 typedef off_t off64_t;
59
lseek64(int fd,__u64 offset,int set)60 static inline off64_t lseek64(int fd, __u64 offset, int set)
61 {
62 return lseek(fd, offset, set);
63 }
64 #endif
65
66 /*
67 * IO interfaces
68 */
dev_read_version(void * buf,__u64 offset,size_t len)69 int dev_read_version(void *buf, __u64 offset, size_t len)
70 {
71 if (c.sparse_mode)
72 return 0;
73 if (lseek64(c.kd, (off64_t)offset, SEEK_SET) < 0)
74 return -1;
75 if (read(c.kd, buf, len) < 0)
76 return -1;
77 return 0;
78 }
79
80 #ifdef WITH_ANDROID
sparse_read_blk(__u64 block,int count,void * buf)81 static int sparse_read_blk(__u64 block, int count, void *buf)
82 {
83 int i;
84 char *out = buf;
85 __u64 cur_block;
86
87 for (i = 0; i < count; ++i) {
88 cur_block = block + i;
89 if (blocks[cur_block])
90 memcpy(out + (i * F2FS_BLKSIZE),
91 blocks[cur_block], F2FS_BLKSIZE);
92 else if (blocks)
93 memset(out + (i * F2FS_BLKSIZE), 0, F2FS_BLKSIZE);
94 }
95 return 0;
96 }
97
sparse_write_blk(__u64 block,int count,const void * buf)98 static int sparse_write_blk(__u64 block, int count, const void *buf)
99 {
100 int i;
101 __u64 cur_block;
102 const char *in = buf;
103
104 for (i = 0; i < count; ++i) {
105 cur_block = block + i;
106 if (!blocks[cur_block]) {
107 blocks[cur_block] = calloc(1, F2FS_BLKSIZE);
108 if (!blocks[cur_block])
109 return -ENOMEM;
110 }
111 memcpy(blocks[cur_block], in + (i * F2FS_BLKSIZE),
112 F2FS_BLKSIZE);
113 }
114 return 0;
115 }
116
117 #ifdef SPARSE_CALLBACK_USES_SIZE_T
sparse_import_segment(void * UNUSED (priv),const void * data,size_t len,unsigned int block,unsigned int nr_blocks)118 static int sparse_import_segment(void *UNUSED(priv), const void *data,
119 size_t len, unsigned int block, unsigned int nr_blocks)
120 #else
121 static int sparse_import_segment(void *UNUSED(priv), const void *data, int len,
122 unsigned int block, unsigned int nr_blocks)
123 #endif
124 {
125 /* Ignore chunk headers, only write the data */
126 if (!nr_blocks || len % F2FS_BLKSIZE)
127 return 0;
128
129 return sparse_write_blk(block, nr_blocks, data);
130 }
131
sparse_merge_blocks(uint64_t start,uint64_t num)132 static int sparse_merge_blocks(uint64_t start, uint64_t num)
133 {
134 char *buf;
135 uint64_t i;
136
137 buf = calloc(num, F2FS_BLKSIZE);
138 if (!buf) {
139 fprintf(stderr, "failed to alloc %llu\n",
140 (unsigned long long)num * F2FS_BLKSIZE);
141 return -ENOMEM;
142 }
143
144 for (i = 0; i < num; i++) {
145 memcpy(buf + i * F2FS_BLKSIZE, blocks[start + i], F2FS_BLKSIZE);
146 free(blocks[start + i]);
147 blocks[start + i] = NULL;
148 }
149
150 /* free_sparse_blocks will release this buf. */
151 blocks[start] = buf;
152
153 return sparse_file_add_data(f2fs_sparse_file, blocks[start],
154 F2FS_BLKSIZE * num, start);
155 }
156 #else
sparse_read_blk(__u64 block,int count,void * buf)157 static int sparse_read_blk(__u64 block, int count, void *buf) { return 0; }
sparse_write_blk(__u64 block,int count,const void * buf)158 static int sparse_write_blk(__u64 block, int count, const void *buf) { return 0; }
159 #endif
160
dev_read(void * buf,__u64 offset,size_t len)161 int dev_read(void *buf, __u64 offset, size_t len)
162 {
163 int fd;
164
165 if (c.sparse_mode)
166 return sparse_read_blk(offset / F2FS_BLKSIZE,
167 len / F2FS_BLKSIZE, buf);
168
169 fd = __get_device_fd(&offset);
170 if (fd < 0)
171 return fd;
172
173 if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
174 return -1;
175 if (read(fd, buf, len) < 0)
176 return -1;
177 return 0;
178 }
179
180 #ifdef POSIX_FADV_WILLNEED
dev_readahead(__u64 offset,size_t len)181 int dev_readahead(__u64 offset, size_t len)
182 #else
183 int dev_readahead(__u64 offset, size_t UNUSED(len))
184 #endif
185 {
186 int fd = __get_device_fd(&offset);
187
188 if (fd < 0)
189 return fd;
190 #ifdef POSIX_FADV_WILLNEED
191 return posix_fadvise(fd, offset, len, POSIX_FADV_WILLNEED);
192 #else
193 return 0;
194 #endif
195 }
196
dev_write(void * buf,__u64 offset,size_t len)197 int dev_write(void *buf, __u64 offset, size_t len)
198 {
199 int fd;
200
201 if (c.dry_run)
202 return 0;
203
204 if (c.sparse_mode)
205 return sparse_write_blk(offset / F2FS_BLKSIZE,
206 len / F2FS_BLKSIZE, buf);
207
208 fd = __get_device_fd(&offset);
209 if (fd < 0)
210 return fd;
211
212 if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
213 return -1;
214 if (write(fd, buf, len) < 0)
215 return -1;
216 return 0;
217 }
218
dev_write_block(void * buf,__u64 blk_addr)219 int dev_write_block(void *buf, __u64 blk_addr)
220 {
221 return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
222 }
223
dev_write_dump(void * buf,__u64 offset,size_t len)224 int dev_write_dump(void *buf, __u64 offset, size_t len)
225 {
226 if (lseek64(c.dump_fd, (off64_t)offset, SEEK_SET) < 0)
227 return -1;
228 if (write(c.dump_fd, buf, len) < 0)
229 return -1;
230 return 0;
231 }
232
dev_fill(void * buf,__u64 offset,size_t len)233 int dev_fill(void *buf, __u64 offset, size_t len)
234 {
235 int fd;
236
237 if (c.sparse_mode)
238 return 0;
239
240 fd = __get_device_fd(&offset);
241 if (fd < 0)
242 return fd;
243
244 /* Only allow fill to zero */
245 if (*((__u8*)buf))
246 return -1;
247 if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
248 return -1;
249 if (write(fd, buf, len) < 0)
250 return -1;
251 return 0;
252 }
253
dev_fill_block(void * buf,__u64 blk_addr)254 int dev_fill_block(void *buf, __u64 blk_addr)
255 {
256 return dev_fill(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
257 }
258
dev_read_block(void * buf,__u64 blk_addr)259 int dev_read_block(void *buf, __u64 blk_addr)
260 {
261 return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
262 }
263
dev_reada_block(__u64 blk_addr)264 int dev_reada_block(__u64 blk_addr)
265 {
266 return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
267 }
268
f2fs_fsync_device(void)269 int f2fs_fsync_device(void)
270 {
271 #ifndef ANDROID_WINDOWS_HOST
272 int i;
273
274 for (i = 0; i < c.ndevs; i++) {
275 if (fsync(c.devices[i].fd) < 0) {
276 MSG(0, "\tError: Could not conduct fsync!!!\n");
277 return -1;
278 }
279 }
280 #endif
281 return 0;
282 }
283
f2fs_init_sparse_file(void)284 int f2fs_init_sparse_file(void)
285 {
286 #ifdef WITH_ANDROID
287 if (c.func == MKFS) {
288 f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE, c.device_size);
289 } else {
290 f2fs_sparse_file = sparse_file_import(c.devices[0].fd,
291 true, false);
292 if (!f2fs_sparse_file)
293 return -1;
294
295 c.device_size = sparse_file_len(f2fs_sparse_file, 0, 0);
296 c.device_size &= (~((u_int64_t)(F2FS_BLKSIZE - 1)));
297 }
298
299 if (sparse_file_block_size(f2fs_sparse_file) != F2FS_BLKSIZE) {
300 MSG(0, "\tError: Corrupted sparse file\n");
301 return -1;
302 }
303 blocks_count = c.device_size / F2FS_BLKSIZE;
304 blocks = calloc(blocks_count, sizeof(char *));
305 if (!blocks) {
306 MSG(0, "\tError: Calloc Failed for blocks!!!\n");
307 return -1;
308 }
309
310 return sparse_file_foreach_chunk(f2fs_sparse_file, true, false,
311 sparse_import_segment, NULL);
312 #else
313 MSG(0, "\tError: Sparse mode is only supported for android\n");
314 return -1;
315 #endif
316 }
317
318 #define MAX_CHUNK_SIZE (1 * 1024 * 1024 * 1024ULL)
f2fs_finalize_device(void)319 int f2fs_finalize_device(void)
320 {
321 int i;
322 int ret = 0;
323
324 #ifdef WITH_ANDROID
325 if (c.sparse_mode) {
326 int64_t chunk_start = (blocks[0] == NULL) ? -1 : 0;
327 uint64_t j;
328
329 if (c.func != MKFS) {
330 sparse_file_destroy(f2fs_sparse_file);
331 ret = ftruncate(c.devices[0].fd, 0);
332 ASSERT(!ret);
333 lseek(c.devices[0].fd, 0, SEEK_SET);
334 f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE,
335 c.device_size);
336 }
337
338 for (j = 0; j < blocks_count; ++j) {
339 if (!blocks[j] && chunk_start != -1) {
340 ret = sparse_merge_blocks(chunk_start,
341 j - chunk_start);
342 chunk_start = -1;
343 } else if (blocks[j] && chunk_start == -1) {
344 chunk_start = j;
345 } else if (blocks[j] && (chunk_start != -1) &&
346 (j + 1 - chunk_start >=
347 (MAX_CHUNK_SIZE / F2FS_BLKSIZE))) {
348 ret = sparse_merge_blocks(chunk_start,
349 j + 1 - chunk_start);
350 chunk_start = -1;
351 }
352 ASSERT(!ret);
353 }
354 if (chunk_start != -1) {
355 ret = sparse_merge_blocks(chunk_start,
356 blocks_count - chunk_start);
357 ASSERT(!ret);
358 }
359
360 sparse_file_write(f2fs_sparse_file, c.devices[0].fd,
361 /*gzip*/0, /*sparse*/1, /*crc*/0);
362
363 sparse_file_destroy(f2fs_sparse_file);
364 for (j = 0; j < blocks_count; j++)
365 free(blocks[j]);
366 free(blocks);
367 blocks = NULL;
368 f2fs_sparse_file = NULL;
369 }
370 #endif
371 /*
372 * We should call fsync() to flush out all the dirty pages
373 * in the block device page cache.
374 */
375 for (i = 0; i < c.ndevs; i++) {
376 #ifndef ANDROID_WINDOWS_HOST
377 ret = fsync(c.devices[i].fd);
378 if (ret < 0) {
379 MSG(0, "\tError: Could not conduct fsync!!!\n");
380 break;
381 }
382 #endif
383 ret = close(c.devices[i].fd);
384 if (ret < 0) {
385 MSG(0, "\tError: Failed to close device file!!!\n");
386 break;
387 }
388 free(c.devices[i].path);
389 }
390 close(c.kd);
391
392 return ret;
393 }
394