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 #include <mntent.h>
18 #include <time.h>
19 #include <sys/stat.h>
20 #include <sys/mount.h>
21 #include <sys/ioctl.h>
22 #include <linux/hdreg.h>
23
24 #include <f2fs_fs.h>
25
26 struct f2fs_configuration c;
27
28 #ifdef WITH_ANDROID
29 #include <sparse/sparse.h>
30 struct sparse_file *f2fs_sparse_file;
31
32 struct buf_item {
33 void *buf;
34 size_t len;
35 struct buf_item *next;
36 };
37
38 struct buf_item *buf_list;
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 /*
58 * IO interfaces
59 */
dev_read_version(void * buf,__u64 offset,size_t len)60 int dev_read_version(void *buf, __u64 offset, size_t len)
61 {
62 if (c.sparse_mode)
63 return 0;
64 if (lseek64(c.kd, (off64_t)offset, SEEK_SET) < 0)
65 return -1;
66 if (read(c.kd, buf, len) < 0)
67 return -1;
68 return 0;
69 }
70
dev_read(void * buf,__u64 offset,size_t len)71 int dev_read(void *buf, __u64 offset, size_t len)
72 {
73 int fd;
74
75 if (c.sparse_mode)
76 return 0;
77
78 fd = __get_device_fd(&offset);
79 if (fd < 0)
80 return fd;
81
82 if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
83 return -1;
84 if (read(fd, buf, len) < 0)
85 return -1;
86 return 0;
87 }
88
dev_readahead(__u64 offset,size_t len)89 int dev_readahead(__u64 offset, size_t len)
90 {
91 int fd = __get_device_fd(&offset);
92
93 if (fd < 0)
94 return fd;
95 #ifdef POSIX_FADV_WILLNEED
96 return posix_fadvise(fd, offset, len, POSIX_FADV_WILLNEED);
97 #else
98 return 0;
99 #endif
100 }
101
102 #ifdef WITH_ANDROID
dev_write_sparse(void * buf,__u64 byte_offset,size_t byte_len)103 static int dev_write_sparse(void *buf, __u64 byte_offset, size_t byte_len)
104 {
105 struct buf_item *bi = calloc(1, sizeof(struct buf_item));
106
107 if (bi == NULL) {
108 return -1;
109 }
110 bi->buf = malloc(byte_len);
111 if (bi->buf == NULL) {
112 free(bi);
113 return -1;
114 }
115
116 bi->len = byte_len;
117 memcpy(bi->buf, buf, byte_len);
118 bi->next = buf_list;
119 buf_list = bi;
120
121 sparse_file_add_data(f2fs_sparse_file, bi->buf, byte_len, byte_offset/F2FS_BLKSIZE);
122 return 0;
123 }
124 #else
dev_write_sparse(void * buf,__u64 byte_offset,size_t byte_len)125 static int dev_write_sparse(void *buf, __u64 byte_offset, size_t byte_len) { return 0; }
126 #endif
127
dev_write(void * buf,__u64 offset,size_t len)128 int dev_write(void *buf, __u64 offset, size_t len)
129 {
130 int fd;
131
132 if (c.sparse_mode)
133 return dev_write_sparse(buf, offset, len);
134
135 fd = __get_device_fd(&offset);
136 if (fd < 0)
137 return fd;
138
139 if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
140 return -1;
141 if (write(fd, buf, len) < 0)
142 return -1;
143 return 0;
144 }
145
dev_write_block(void * buf,__u64 blk_addr)146 int dev_write_block(void *buf, __u64 blk_addr)
147 {
148 return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
149 }
150
dev_write_dump(void * buf,__u64 offset,size_t len)151 int dev_write_dump(void *buf, __u64 offset, size_t len)
152 {
153 if (lseek64(c.dump_fd, (off64_t)offset, SEEK_SET) < 0)
154 return -1;
155 if (write(c.dump_fd, buf, len) < 0)
156 return -1;
157 return 0;
158 }
159
dev_fill(void * buf,__u64 offset,size_t len)160 int dev_fill(void *buf, __u64 offset, size_t len)
161 {
162 int fd;
163
164 if (c.sparse_mode)
165 return 0;
166
167 fd = __get_device_fd(&offset);
168 if (fd < 0)
169 return fd;
170
171 /* Only allow fill to zero */
172 if (*((__u8*)buf))
173 return -1;
174 if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
175 return -1;
176 if (write(fd, buf, len) < 0)
177 return -1;
178 return 0;
179 }
180
dev_fill_block(void * buf,__u64 blk_addr)181 int dev_fill_block(void *buf, __u64 blk_addr)
182 {
183 return dev_fill(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
184 }
185
dev_read_block(void * buf,__u64 blk_addr)186 int dev_read_block(void *buf, __u64 blk_addr)
187 {
188 return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
189 }
190
dev_reada_block(__u64 blk_addr)191 int dev_reada_block(__u64 blk_addr)
192 {
193 return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE);
194 }
195
f2fs_finalize_device(void)196 void f2fs_finalize_device(void)
197 {
198 int i;
199
200 #ifdef WITH_ANDROID
201 if (c.sparse_mode) {
202 sparse_file_write(f2fs_sparse_file, c.devices[0].fd, /*gzip*/0, /*sparse*/1, /*crc*/0);
203 sparse_file_destroy(f2fs_sparse_file);
204 while (buf_list) {
205 struct buf_item *bi = buf_list;
206 buf_list = buf_list->next;
207 free(bi->buf);
208 free(bi);
209 }
210 f2fs_sparse_file = NULL;
211 }
212 #endif
213
214 /*
215 * We should call fsync() to flush out all the dirty pages
216 * in the block device page cache.
217 */
218 for (i = 0; i < c.ndevs; i++) {
219 if (fsync(c.devices[i].fd) < 0)
220 MSG(0, "\tError: Could not conduct fsync!!!\n");
221
222 if (close(c.devices[i].fd) < 0)
223 MSG(0, "\tError: Failed to close device file!!!\n");
224 }
225 close(c.kd);
226 }
227