• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
sparse_import_segment(void * UNUSED (priv),const void * data,int len,unsigned int block,unsigned int nr_blocks)117 static int sparse_import_segment(void *UNUSED(priv), const void *data, int len,
118 		unsigned int block, unsigned int nr_blocks)
119 {
120 	/* Ignore chunk headers, only write the data */
121 	if (!nr_blocks || len % F2FS_BLKSIZE)
122 		return 0;
123 
124 	return sparse_write_blk(block, nr_blocks, data);
125 }
126 
sparse_merge_blocks(uint64_t start,uint64_t num)127 static int sparse_merge_blocks(uint64_t start, uint64_t num)
128 {
129 	char *buf;
130 	uint64_t i;
131 
132 	buf = calloc(num, F2FS_BLKSIZE);
133 	if (!buf) {
134 		fprintf(stderr, "failed to alloc %llu\n",
135 			(unsigned long long)num * F2FS_BLKSIZE);
136 		return -ENOMEM;
137 	}
138 
139 	for (i = 0; i < num; i++) {
140 		memcpy(buf + i * F2FS_BLKSIZE, blocks[start + i], F2FS_BLKSIZE);
141 		free(blocks[start + i]);
142 		blocks[start + i] = NULL;
143 	}
144 
145 	/* free_sparse_blocks will release this buf. */
146 	blocks[start] = buf;
147 
148 	return sparse_file_add_data(f2fs_sparse_file, blocks[start],
149 					F2FS_BLKSIZE * num, start);
150 }
151 #else
sparse_read_blk(__u64 block,int count,void * buf)152 static int sparse_read_blk(__u64 block, int count, void *buf) { return 0; }
sparse_write_blk(__u64 block,int count,const void * buf)153 static int sparse_write_blk(__u64 block, int count, const void *buf) { return 0; }
154 #endif
155 
dev_read(void * buf,__u64 offset,size_t len)156 int dev_read(void *buf, __u64 offset, size_t len)
157 {
158 	int fd;
159 
160 	if (c.sparse_mode)
161 		return sparse_read_blk(offset / F2FS_BLKSIZE,
162 					len / F2FS_BLKSIZE, buf);
163 
164 	fd = __get_device_fd(&offset);
165 	if (fd < 0)
166 		return fd;
167 
168 	if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
169 		return -1;
170 	if (read(fd, buf, len) < 0)
171 		return -1;
172 	return 0;
173 }
174 
175 #ifdef POSIX_FADV_WILLNEED
dev_readahead(__u64 offset,size_t len)176 int dev_readahead(__u64 offset, size_t len)
177 #else
178 int dev_readahead(__u64 offset, size_t UNUSED(len))
179 #endif
180 {
181 	int fd = __get_device_fd(&offset);
182 
183 	if (fd < 0)
184 		return fd;
185 #ifdef POSIX_FADV_WILLNEED
186 	return posix_fadvise(fd, offset, len, POSIX_FADV_WILLNEED);
187 #else
188 	return 0;
189 #endif
190 }
191 
dev_write(void * buf,__u64 offset,size_t len)192 int dev_write(void *buf, __u64 offset, size_t len)
193 {
194 	int fd;
195 
196 	if (c.dry_run)
197 		return 0;
198 
199 	if (c.sparse_mode)
200 		return sparse_write_blk(offset / F2FS_BLKSIZE,
201 					len / F2FS_BLKSIZE, buf);
202 
203 	fd = __get_device_fd(&offset);
204 	if (fd < 0)
205 		return fd;
206 
207 	if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
208 		return -1;
209 	if (write(fd, buf, len) < 0)
210 		return -1;
211 	return 0;
212 }
213 
dev_write_block(void * buf,__u64 blk_addr)214 int dev_write_block(void *buf, __u64 blk_addr)
215 {
216 	return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
217 }
218 
dev_write_dump(void * buf,__u64 offset,size_t len)219 int dev_write_dump(void *buf, __u64 offset, size_t len)
220 {
221 	if (lseek64(c.dump_fd, (off64_t)offset, SEEK_SET) < 0)
222 		return -1;
223 	if (write(c.dump_fd, buf, len) < 0)
224 		return -1;
225 	return 0;
226 }
227 
dev_fill(void * buf,__u64 offset,size_t len)228 int dev_fill(void *buf, __u64 offset, size_t len)
229 {
230 	int fd;
231 
232 	if (c.sparse_mode)
233 		return 0;
234 
235 	fd = __get_device_fd(&offset);
236 	if (fd < 0)
237 		return fd;
238 
239 	/* Only allow fill to zero */
240 	if (*((__u8*)buf))
241 		return -1;
242 	if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
243 		return -1;
244 	if (write(fd, buf, len) < 0)
245 		return -1;
246 	return 0;
247 }
248 
dev_fill_block(void * buf,__u64 blk_addr)249 int dev_fill_block(void *buf, __u64 blk_addr)
250 {
251 	return dev_fill(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
252 }
253 
dev_read_block(void * buf,__u64 blk_addr)254 int dev_read_block(void *buf, __u64 blk_addr)
255 {
256 	return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
257 }
258 
dev_reada_block(__u64 blk_addr)259 int dev_reada_block(__u64 blk_addr)
260 {
261 	return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
262 }
263 
f2fs_fsync_device(void)264 int f2fs_fsync_device(void)
265 {
266 #ifndef ANDROID_WINDOWS_HOST
267 	int i;
268 
269 	for (i = 0; i < c.ndevs; i++) {
270 		if (fsync(c.devices[i].fd) < 0) {
271 			MSG(0, "\tError: Could not conduct fsync!!!\n");
272 			return -1;
273 		}
274 	}
275 #endif
276 	return 0;
277 }
278 
f2fs_init_sparse_file(void)279 int f2fs_init_sparse_file(void)
280 {
281 #ifdef WITH_ANDROID
282 	if (c.func == MKFS) {
283 		f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE, c.device_size);
284 	} else {
285 		f2fs_sparse_file = sparse_file_import(c.devices[0].fd,
286 							true, false);
287 		if (!f2fs_sparse_file)
288 			return -1;
289 
290 		c.device_size = sparse_file_len(f2fs_sparse_file, 0, 0);
291 		c.device_size &= (~((u_int64_t)(F2FS_BLKSIZE - 1)));
292 	}
293 
294 	if (sparse_file_block_size(f2fs_sparse_file) != F2FS_BLKSIZE) {
295 		MSG(0, "\tError: Corrupted sparse file\n");
296 		return -1;
297 	}
298 	blocks_count = c.device_size / F2FS_BLKSIZE;
299 	blocks = calloc(blocks_count, sizeof(char *));
300 
301 	return sparse_file_foreach_chunk(f2fs_sparse_file, true, false,
302 				sparse_import_segment, NULL);
303 #else
304 	MSG(0, "\tError: Sparse mode is only supported for android\n");
305 	return -1;
306 #endif
307 }
308 
f2fs_finalize_device(void)309 int f2fs_finalize_device(void)
310 {
311 	int i;
312 	int ret = 0;
313 
314 #ifdef WITH_ANDROID
315 	if (c.sparse_mode) {
316 		int64_t chunk_start = (blocks[0] == NULL) ? -1 : 0;
317 		uint64_t j;
318 
319 		if (c.func != MKFS) {
320 			sparse_file_destroy(f2fs_sparse_file);
321 			ret = ftruncate(c.devices[0].fd, 0);
322 			ASSERT(!ret);
323 			lseek(c.devices[0].fd, 0, SEEK_SET);
324 			f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE,
325 							c.device_size);
326 		}
327 
328 		for (j = 0; j < blocks_count; ++j) {
329 			if (!blocks[j] && chunk_start != -1) {
330 				ret = sparse_merge_blocks(chunk_start,
331 							j - chunk_start);
332 				chunk_start = -1;
333 			} else if (blocks[j] && chunk_start == -1) {
334 				chunk_start = j;
335 			}
336 			ASSERT(!ret);
337 		}
338 		if (chunk_start != -1) {
339 			ret = sparse_merge_blocks(chunk_start,
340 						blocks_count - chunk_start);
341 			ASSERT(!ret);
342 		}
343 
344 		sparse_file_write(f2fs_sparse_file, c.devices[0].fd,
345 				/*gzip*/0, /*sparse*/1, /*crc*/0);
346 
347 		sparse_file_destroy(f2fs_sparse_file);
348 		for (j = 0; j < blocks_count; j++)
349 			free(blocks[j]);
350 		free(blocks);
351 		blocks = NULL;
352 		f2fs_sparse_file = NULL;
353 	}
354 #endif
355 	/*
356 	 * We should call fsync() to flush out all the dirty pages
357 	 * in the block device page cache.
358 	 */
359 	for (i = 0; i < c.ndevs; i++) {
360 #ifndef ANDROID_WINDOWS_HOST
361 		ret = fsync(c.devices[i].fd);
362 		if (ret < 0) {
363 			MSG(0, "\tError: Could not conduct fsync!!!\n");
364 			break;
365 		}
366 #endif
367 		ret = close(c.devices[i].fd);
368 		if (ret < 0) {
369 			MSG(0, "\tError: Failed to close device file!!!\n");
370 			break;
371 		}
372 	}
373 	close(c.kd);
374 
375 	return ret;
376 }
377