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 #define _FILE_OFFSET_BITS 64
11
12 #include <f2fs_fs.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <libgen.h>
20 #ifdef HAVE_MNTENT_H
21 #include <mntent.h>
22 #endif
23 #include <time.h>
24 #include <sys/stat.h>
25 #ifndef ANDROID_WINDOWS_HOST
26 #include <sys/mount.h>
27 #include <sys/ioctl.h>
28 #endif
29 #ifdef HAVE_SYS_SYSMACROS_H
30 #include <sys/sysmacros.h>
31 #endif
32 #ifdef HAVE_SYS_UTSNAME_H
33 #include <sys/utsname.h>
34 #endif
35 #ifndef WITH_ANDROID
36 #ifdef HAVE_SCSI_SG_H
37 #include <scsi/sg.h>
38 #endif
39 #endif
40 #ifdef HAVE_LINUX_HDREG_H
41 #include <linux/hdreg.h>
42 #endif
43 #ifdef HAVE_LINUX_LIMITS_H
44 #include <linux/limits.h>
45 #endif
46
47 #ifndef WITH_ANDROID
48 /* SCSI command for standard inquiry*/
49 #define MODELINQUIRY 0x12,0x00,0x00,0x00,0x4A,0x00
50 #endif
51
52 #ifndef ANDROID_WINDOWS_HOST /* O_BINARY is windows-specific flag */
53 #define O_BINARY 0
54 #else
55 /* On Windows, wchar_t is 8 bit sized and it causes compilation errors. */
56 #define wchar_t int
57 #endif
58
59 /*
60 * UTF conversion codes are Copied from exfat tools.
61 */
utf8_to_wchar(const char * input,wchar_t * wc,size_t insize)62 static const char *utf8_to_wchar(const char *input, wchar_t *wc,
63 size_t insize)
64 {
65 if ((input[0] & 0x80) == 0 && insize >= 1) {
66 *wc = (wchar_t) input[0];
67 return input + 1;
68 }
69 if ((input[0] & 0xe0) == 0xc0 && insize >= 2) {
70 *wc = (((wchar_t) input[0] & 0x1f) << 6) |
71 ((wchar_t) input[1] & 0x3f);
72 return input + 2;
73 }
74 if ((input[0] & 0xf0) == 0xe0 && insize >= 3) {
75 *wc = (((wchar_t) input[0] & 0x0f) << 12) |
76 (((wchar_t) input[1] & 0x3f) << 6) |
77 ((wchar_t) input[2] & 0x3f);
78 return input + 3;
79 }
80 if ((input[0] & 0xf8) == 0xf0 && insize >= 4) {
81 *wc = (((wchar_t) input[0] & 0x07) << 18) |
82 (((wchar_t) input[1] & 0x3f) << 12) |
83 (((wchar_t) input[2] & 0x3f) << 6) |
84 ((wchar_t) input[3] & 0x3f);
85 return input + 4;
86 }
87 if ((input[0] & 0xfc) == 0xf8 && insize >= 5) {
88 *wc = (((wchar_t) input[0] & 0x03) << 24) |
89 (((wchar_t) input[1] & 0x3f) << 18) |
90 (((wchar_t) input[2] & 0x3f) << 12) |
91 (((wchar_t) input[3] & 0x3f) << 6) |
92 ((wchar_t) input[4] & 0x3f);
93 return input + 5;
94 }
95 if ((input[0] & 0xfe) == 0xfc && insize >= 6) {
96 *wc = (((wchar_t) input[0] & 0x01) << 30) |
97 (((wchar_t) input[1] & 0x3f) << 24) |
98 (((wchar_t) input[2] & 0x3f) << 18) |
99 (((wchar_t) input[3] & 0x3f) << 12) |
100 (((wchar_t) input[4] & 0x3f) << 6) |
101 ((wchar_t) input[5] & 0x3f);
102 return input + 6;
103 }
104 return NULL;
105 }
106
wchar_to_utf16(u_int16_t * output,wchar_t wc,size_t outsize)107 static u_int16_t *wchar_to_utf16(u_int16_t *output, wchar_t wc, size_t outsize)
108 {
109 if (wc <= 0xffff) {
110 if (outsize == 0)
111 return NULL;
112 output[0] = cpu_to_le16(wc);
113 return output + 1;
114 }
115 if (outsize < 2)
116 return NULL;
117 wc -= 0x10000;
118 output[0] = cpu_to_le16(0xd800 | ((wc >> 10) & 0x3ff));
119 output[1] = cpu_to_le16(0xdc00 | (wc & 0x3ff));
120 return output + 2;
121 }
122
utf8_to_utf16(u_int16_t * output,const char * input,size_t outsize,size_t insize)123 int utf8_to_utf16(u_int16_t *output, const char *input, size_t outsize,
124 size_t insize)
125 {
126 const char *inp = input;
127 u_int16_t *outp = output;
128 wchar_t wc;
129
130 while ((size_t)(inp - input) < insize && *inp) {
131 inp = utf8_to_wchar(inp, &wc, insize - (inp - input));
132 if (inp == NULL) {
133 DBG(0, "illegal UTF-8 sequence\n");
134 return -EILSEQ;
135 }
136 outp = wchar_to_utf16(outp, wc, outsize - (outp - output));
137 if (outp == NULL) {
138 DBG(0, "name is too long\n");
139 return -ENAMETOOLONG;
140 }
141 }
142 *outp = cpu_to_le16(0);
143 return 0;
144 }
145
utf16_to_wchar(const u_int16_t * input,wchar_t * wc,size_t insize)146 static const u_int16_t *utf16_to_wchar(const u_int16_t *input, wchar_t *wc,
147 size_t insize)
148 {
149 if ((le16_to_cpu(input[0]) & 0xfc00) == 0xd800) {
150 if (insize < 2 || (le16_to_cpu(input[1]) & 0xfc00) != 0xdc00)
151 return NULL;
152 *wc = ((wchar_t) (le16_to_cpu(input[0]) & 0x3ff) << 10);
153 *wc |= (le16_to_cpu(input[1]) & 0x3ff);
154 *wc += 0x10000;
155 return input + 2;
156 } else {
157 *wc = le16_to_cpu(*input);
158 return input + 1;
159 }
160 }
161
wchar_to_utf8(char * output,wchar_t wc,size_t outsize)162 static char *wchar_to_utf8(char *output, wchar_t wc, size_t outsize)
163 {
164 if (wc <= 0x7f) {
165 if (outsize < 1)
166 return NULL;
167 *output++ = (char) wc;
168 } else if (wc <= 0x7ff) {
169 if (outsize < 2)
170 return NULL;
171 *output++ = 0xc0 | (wc >> 6);
172 *output++ = 0x80 | (wc & 0x3f);
173 } else if (wc <= 0xffff) {
174 if (outsize < 3)
175 return NULL;
176 *output++ = 0xe0 | (wc >> 12);
177 *output++ = 0x80 | ((wc >> 6) & 0x3f);
178 *output++ = 0x80 | (wc & 0x3f);
179 } else if (wc <= 0x1fffff) {
180 if (outsize < 4)
181 return NULL;
182 *output++ = 0xf0 | (wc >> 18);
183 *output++ = 0x80 | ((wc >> 12) & 0x3f);
184 *output++ = 0x80 | ((wc >> 6) & 0x3f);
185 *output++ = 0x80 | (wc & 0x3f);
186 } else if (wc <= 0x3ffffff) {
187 if (outsize < 5)
188 return NULL;
189 *output++ = 0xf8 | (wc >> 24);
190 *output++ = 0x80 | ((wc >> 18) & 0x3f);
191 *output++ = 0x80 | ((wc >> 12) & 0x3f);
192 *output++ = 0x80 | ((wc >> 6) & 0x3f);
193 *output++ = 0x80 | (wc & 0x3f);
194 } else if (wc <= 0x7fffffff) {
195 if (outsize < 6)
196 return NULL;
197 *output++ = 0xfc | (wc >> 30);
198 *output++ = 0x80 | ((wc >> 24) & 0x3f);
199 *output++ = 0x80 | ((wc >> 18) & 0x3f);
200 *output++ = 0x80 | ((wc >> 12) & 0x3f);
201 *output++ = 0x80 | ((wc >> 6) & 0x3f);
202 *output++ = 0x80 | (wc & 0x3f);
203 } else
204 return NULL;
205
206 return output;
207 }
208
utf16_to_utf8(char * output,const u_int16_t * input,size_t outsize,size_t insize)209 int utf16_to_utf8(char *output, const u_int16_t *input, size_t outsize,
210 size_t insize)
211 {
212 const u_int16_t *inp = input;
213 char *outp = output;
214 wchar_t wc;
215
216 while ((size_t)(inp - input) < insize && le16_to_cpu(*inp)) {
217 inp = utf16_to_wchar(inp, &wc, insize - (inp - input));
218 if (inp == NULL) {
219 DBG(0, "illegal UTF-16 sequence\n");
220 return -EILSEQ;
221 }
222 outp = wchar_to_utf8(outp, wc, outsize - (outp - output));
223 if (outp == NULL) {
224 DBG(0, "name is too long\n");
225 return -ENAMETOOLONG;
226 }
227 }
228 *outp = '\0';
229 return 0;
230 }
231
log_base_2(u_int32_t num)232 int log_base_2(u_int32_t num)
233 {
234 int ret = 0;
235 if (num <= 0 || (num & (num - 1)) != 0)
236 return -1;
237
238 while (num >>= 1)
239 ret++;
240 return ret;
241 }
242
243 /*
244 * f2fs bit operations
245 */
246 static const int bits_in_byte[256] = {
247 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
248 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
249 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
250 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
251 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
252 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
253 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
254 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
255 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
256 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
257 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
258 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
259 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
260 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
261 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
262 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8,
263 };
264
get_bits_in_byte(unsigned char n)265 int get_bits_in_byte(unsigned char n)
266 {
267 return bits_in_byte[n];
268 }
269
test_and_set_bit_le(u32 nr,u8 * addr)270 int test_and_set_bit_le(u32 nr, u8 *addr)
271 {
272 int mask, retval;
273
274 addr += nr >> 3;
275 mask = 1 << ((nr & 0x07));
276 retval = mask & *addr;
277 *addr |= mask;
278 return retval;
279 }
280
test_and_clear_bit_le(u32 nr,u8 * addr)281 int test_and_clear_bit_le(u32 nr, u8 *addr)
282 {
283 int mask, retval;
284
285 addr += nr >> 3;
286 mask = 1 << ((nr & 0x07));
287 retval = mask & *addr;
288 *addr &= ~mask;
289 return retval;
290 }
291
test_bit_le(u32 nr,const u8 * addr)292 int test_bit_le(u32 nr, const u8 *addr)
293 {
294 return ((1 << (nr & 7)) & (addr[nr >> 3]));
295 }
296
f2fs_test_bit(unsigned int nr,const char * p)297 int f2fs_test_bit(unsigned int nr, const char *p)
298 {
299 int mask;
300 char *addr = (char *)p;
301
302 addr += (nr >> 3);
303 mask = 1 << (7 - (nr & 0x07));
304 return (mask & *addr) != 0;
305 }
306
f2fs_set_bit(unsigned int nr,char * addr)307 int f2fs_set_bit(unsigned int nr, char *addr)
308 {
309 int mask;
310 int ret;
311
312 addr += (nr >> 3);
313 mask = 1 << (7 - (nr & 0x07));
314 ret = mask & *addr;
315 *addr |= mask;
316 return ret;
317 }
318
f2fs_clear_bit(unsigned int nr,char * addr)319 int f2fs_clear_bit(unsigned int nr, char *addr)
320 {
321 int mask;
322 int ret;
323
324 addr += (nr >> 3);
325 mask = 1 << (7 - (nr & 0x07));
326 ret = mask & *addr;
327 *addr &= ~mask;
328 return ret;
329 }
330
__ffs(u8 word)331 static inline u64 __ffs(u8 word)
332 {
333 int num = 0;
334
335 if ((word & 0xf) == 0) {
336 num += 4;
337 word >>= 4;
338 }
339 if ((word & 0x3) == 0) {
340 num += 2;
341 word >>= 2;
342 }
343 if ((word & 0x1) == 0)
344 num += 1;
345 return num;
346 }
347
348 /* Copied from linux/lib/find_bit.c */
349 #define BITMAP_FIRST_BYTE_MASK(start) (0xff << ((start) & (BITS_PER_BYTE - 1)))
350
_find_next_bit_le(const u8 * addr,u64 nbits,u64 start,char invert)351 static u64 _find_next_bit_le(const u8 *addr, u64 nbits, u64 start, char invert)
352 {
353 u8 tmp;
354
355 if (!nbits || start >= nbits)
356 return nbits;
357
358 tmp = addr[start / BITS_PER_BYTE] ^ invert;
359
360 /* Handle 1st word. */
361 tmp &= BITMAP_FIRST_BYTE_MASK(start);
362 start = round_down(start, BITS_PER_BYTE);
363
364 while (!tmp) {
365 start += BITS_PER_BYTE;
366 if (start >= nbits)
367 return nbits;
368
369 tmp = addr[start / BITS_PER_BYTE] ^ invert;
370 }
371
372 return min(start + __ffs(tmp), nbits);
373 }
374
find_next_bit_le(const u8 * addr,u64 size,u64 offset)375 u64 find_next_bit_le(const u8 *addr, u64 size, u64 offset)
376 {
377 return _find_next_bit_le(addr, size, offset, 0);
378 }
379
380
find_next_zero_bit_le(const u8 * addr,u64 size,u64 offset)381 u64 find_next_zero_bit_le(const u8 *addr, u64 size, u64 offset)
382 {
383 return _find_next_bit_le(addr, size, offset, 0xff);
384 }
385
386 /*
387 * Hashing code adapted from ext3
388 */
389 #define DELTA 0x9E3779B9
390
TEA_transform(unsigned int buf[4],unsigned int const in[])391 static void TEA_transform(unsigned int buf[4], unsigned int const in[])
392 {
393 __u32 sum = 0;
394 __u32 b0 = buf[0], b1 = buf[1];
395 __u32 a = in[0], b = in[1], c = in[2], d = in[3];
396 int n = 16;
397
398 do {
399 sum += DELTA;
400 b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
401 b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
402 } while (--n);
403
404 buf[0] += b0;
405 buf[1] += b1;
406
407 }
408
str2hashbuf(const unsigned char * msg,int len,unsigned int * buf,int num)409 static void str2hashbuf(const unsigned char *msg, int len,
410 unsigned int *buf, int num)
411 {
412 unsigned pad, val;
413 int i;
414
415 pad = (__u32)len | ((__u32)len << 8);
416 pad |= pad << 16;
417
418 val = pad;
419 if (len > num * 4)
420 len = num * 4;
421 for (i = 0; i < len; i++) {
422 if ((i % 4) == 0)
423 val = pad;
424 val = msg[i] + (val << 8);
425 if ((i % 4) == 3) {
426 *buf++ = val;
427 val = pad;
428 num--;
429 }
430 }
431 if (--num >= 0)
432 *buf++ = val;
433 while (--num >= 0)
434 *buf++ = pad;
435
436 }
437
438 /**
439 * Return hash value of directory entry
440 * @param name dentry name
441 * @param len name lenth
442 * @return return on success hash value, errno on failure
443 */
__f2fs_dentry_hash(const unsigned char * name,int len)444 static f2fs_hash_t __f2fs_dentry_hash(const unsigned char *name, int len)/* Need update */
445 {
446 __u32 hash;
447 f2fs_hash_t f2fs_hash;
448 const unsigned char *p;
449 __u32 in[8], buf[4];
450
451 /* special hash codes for special dentries */
452 if ((len <= 2) && (name[0] == '.') &&
453 (name[1] == '.' || name[1] == '\0'))
454 return 0;
455
456 /* Initialize the default seed for the hash checksum functions */
457 buf[0] = 0x67452301;
458 buf[1] = 0xefcdab89;
459 buf[2] = 0x98badcfe;
460 buf[3] = 0x10325476;
461
462 p = name;
463 while (1) {
464 str2hashbuf(p, len, in, 4);
465 TEA_transform(buf, in);
466 p += 16;
467 if (len <= 16)
468 break;
469 len -= 16;
470 }
471 hash = buf[0];
472
473 f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT);
474 return f2fs_hash;
475 }
476
f2fs_dentry_hash(int encoding,int casefolded,const unsigned char * name,int len)477 f2fs_hash_t f2fs_dentry_hash(int encoding, int casefolded,
478 const unsigned char *name, int len)
479 {
480 const struct f2fs_nls_table *table = f2fs_load_nls_table(encoding);
481 int r, dlen;
482 unsigned char *buff;
483
484 if (len && casefolded) {
485 buff = malloc(sizeof(char) * PATH_MAX);
486 if (!buff)
487 return -ENOMEM;
488 dlen = table->ops->casefold(table, name, len, buff, PATH_MAX);
489 if (dlen < 0) {
490 free(buff);
491 goto opaque_seq;
492 }
493 r = __f2fs_dentry_hash(buff, dlen);
494
495 free(buff);
496 return r;
497 }
498 opaque_seq:
499 return __f2fs_dentry_hash(name, len);
500 }
501
502 #define ALIGN_DOWN(addrs, size) (((addrs) / (size)) * (size))
addrs_per_inode(struct f2fs_inode * i)503 unsigned int addrs_per_inode(struct f2fs_inode *i)
504 {
505 unsigned int addrs = CUR_ADDRS_PER_INODE(i) - get_inline_xattr_addrs(i);
506
507 if (!LINUX_S_ISREG(le16_to_cpu(i->i_mode)) ||
508 !(le32_to_cpu(i->i_flags) & F2FS_COMPR_FL))
509 return addrs;
510 return ALIGN_DOWN(addrs, 1 << i->i_log_cluster_size);
511 }
512
addrs_per_block(struct f2fs_inode * i)513 unsigned int addrs_per_block(struct f2fs_inode *i)
514 {
515 if (!LINUX_S_ISREG(le16_to_cpu(i->i_mode)) ||
516 !(le32_to_cpu(i->i_flags) & F2FS_COMPR_FL))
517 return DEF_ADDRS_PER_BLOCK;
518 return ALIGN_DOWN(DEF_ADDRS_PER_BLOCK, 1 << i->i_log_cluster_size);
519 }
520
521 /*
522 * CRC32
523 */
524 #define CRCPOLY_LE 0xedb88320
525
f2fs_cal_crc32(u_int32_t crc,void * buf,int len)526 u_int32_t f2fs_cal_crc32(u_int32_t crc, void *buf, int len)
527 {
528 int i;
529 unsigned char *p = (unsigned char *)buf;
530 while (len--) {
531 crc ^= *p++;
532 for (i = 0; i < 8; i++)
533 crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
534 }
535 return crc;
536 }
537
f2fs_crc_valid(u_int32_t blk_crc,void * buf,int len)538 int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len)
539 {
540 u_int32_t cal_crc = 0;
541
542 cal_crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, buf, len);
543
544 if (cal_crc != blk_crc) {
545 DBG(0,"CRC validation failed: cal_crc = %u, "
546 "blk_crc = %u buff_size = 0x%x\n",
547 cal_crc, blk_crc, len);
548 return -1;
549 }
550 return 0;
551 }
552
f2fs_inode_chksum(struct f2fs_node * node)553 __u32 f2fs_inode_chksum(struct f2fs_node *node)
554 {
555 struct f2fs_inode *ri = &node->i;
556 __le32 ino = node->footer.ino;
557 __le32 gen = ri->i_generation;
558 __u32 chksum, chksum_seed;
559 __u32 dummy_cs = 0;
560 unsigned int offset = offsetof(struct f2fs_inode, i_inode_checksum);
561 unsigned int cs_size = sizeof(dummy_cs);
562
563 chksum = f2fs_cal_crc32(c.chksum_seed, (__u8 *)&ino,
564 sizeof(ino));
565 chksum_seed = f2fs_cal_crc32(chksum, (__u8 *)&gen, sizeof(gen));
566
567 chksum = f2fs_cal_crc32(chksum_seed, (__u8 *)ri, offset);
568 chksum = f2fs_cal_crc32(chksum, (__u8 *)&dummy_cs, cs_size);
569 offset += cs_size;
570 chksum = f2fs_cal_crc32(chksum, (__u8 *)ri + offset,
571 F2FS_BLKSIZE - offset);
572 return chksum;
573 }
574
f2fs_checkpoint_chksum(struct f2fs_checkpoint * cp)575 __u32 f2fs_checkpoint_chksum(struct f2fs_checkpoint *cp)
576 {
577 unsigned int chksum_ofs = le32_to_cpu(cp->checksum_offset);
578 __u32 chksum;
579
580 chksum = f2fs_cal_crc32(F2FS_SUPER_MAGIC, cp, chksum_ofs);
581 if (chksum_ofs < CP_CHKSUM_OFFSET) {
582 chksum_ofs += sizeof(chksum);
583 chksum = f2fs_cal_crc32(chksum, (__u8 *)cp + chksum_ofs,
584 F2FS_BLKSIZE - chksum_ofs);
585 }
586 return chksum;
587 }
588
write_inode(struct f2fs_node * inode,u64 blkaddr)589 int write_inode(struct f2fs_node *inode, u64 blkaddr)
590 {
591 if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM))
592 inode->i.i_inode_checksum =
593 cpu_to_le32(f2fs_inode_chksum(inode));
594 return dev_write_block(inode, blkaddr);
595 }
596
597 /*
598 * try to identify the root device
599 */
get_rootdev()600 char *get_rootdev()
601 {
602 #if defined(ANDROID_WINDOWS_HOST) || defined(WITH_ANDROID)
603 return NULL;
604 #else
605 struct stat sb;
606 int fd, ret;
607 char buf[PATH_MAX + 1];
608 char *uevent, *ptr;
609 char *rootdev;
610
611 if (stat("/", &sb) == -1)
612 return NULL;
613
614 snprintf(buf, PATH_MAX, "/sys/dev/block/%u:%u/uevent",
615 major(sb.st_dev), minor(sb.st_dev));
616
617 fd = open(buf, O_RDONLY);
618
619 if (fd < 0)
620 return NULL;
621
622 ret = lseek(fd, (off_t)0, SEEK_END);
623 (void)lseek(fd, (off_t)0, SEEK_SET);
624
625 if (ret == -1) {
626 close(fd);
627 return NULL;
628 }
629
630 uevent = malloc(ret + 1);
631 ASSERT(uevent);
632
633 uevent[ret] = '\0';
634
635 ret = read(fd, uevent, ret);
636 close(fd);
637
638 ptr = strstr(uevent, "DEVNAME");
639 if (!ptr)
640 goto out_free;
641
642 ret = sscanf(ptr, "DEVNAME=%s\n", buf);
643 if (strlen(buf) == 0)
644 goto out_free;
645
646 ret = strlen(buf) + 5;
647 rootdev = malloc(ret + 1);
648 if (!rootdev)
649 goto out_free;
650 rootdev[ret] = '\0';
651
652 snprintf(rootdev, ret + 1, "/dev/%s", buf);
653 free(uevent);
654 return rootdev;
655
656 out_free:
657 free(uevent);
658 return NULL;
659 #endif
660 }
661
662 /*
663 * device information
664 */
f2fs_init_configuration(void)665 void f2fs_init_configuration(void)
666 {
667 int i;
668
669 memset(&c, 0, sizeof(struct f2fs_configuration));
670 c.ndevs = 1;
671 c.sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK;
672 c.blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT;
673 c.wanted_total_sectors = -1;
674 c.wanted_sector_size = -1;
675 #ifndef WITH_ANDROID
676 c.preserve_limits = 1;
677 c.no_kernel_check = 1;
678 #else
679 c.no_kernel_check = 0;
680 #endif
681
682 for (i = 0; i < MAX_DEVICES; i++) {
683 c.devices[i].fd = -1;
684 c.devices[i].sector_size = DEFAULT_SECTOR_SIZE;
685 c.devices[i].end_blkaddr = -1;
686 c.devices[i].zoned_model = F2FS_ZONED_NONE;
687 }
688
689 /* calculated by overprovision ratio */
690 c.segs_per_sec = 1;
691 c.secs_per_zone = 1;
692 c.segs_per_zone = 1;
693 c.vol_label = "";
694 c.trim = 1;
695 c.kd = -1;
696 c.fixed_time = -1;
697 c.s_encoding = 0;
698 c.s_encoding_flags = 0;
699
700 /* default root owner */
701 c.root_uid = getuid();
702 c.root_gid = getgid();
703 }
704
f2fs_dev_is_writable(void)705 int f2fs_dev_is_writable(void)
706 {
707 return !c.ro || c.force;
708 }
709
710 #ifdef HAVE_SETMNTENT
is_mounted(const char * mpt,const char * device)711 static int is_mounted(const char *mpt, const char *device)
712 {
713 FILE *file = NULL;
714 struct mntent *mnt = NULL;
715
716 file = setmntent(mpt, "r");
717 if (file == NULL)
718 return 0;
719
720 while ((mnt = getmntent(file)) != NULL) {
721 if (!strcmp(device, mnt->mnt_fsname)) {
722 #ifdef MNTOPT_RO
723 if (hasmntopt(mnt, MNTOPT_RO))
724 c.ro = 1;
725 #endif
726 break;
727 }
728 }
729 endmntent(file);
730 return mnt ? 1 : 0;
731 }
732 #endif
733
f2fs_dev_is_umounted(char * path)734 int f2fs_dev_is_umounted(char *path)
735 {
736 #ifdef ANDROID_WINDOWS_HOST
737 return 0;
738 #else
739 struct stat *st_buf;
740 int is_rootdev = 0;
741 int ret = 0;
742 char *rootdev_name = get_rootdev();
743
744 if (rootdev_name) {
745 if (!strcmp(path, rootdev_name))
746 is_rootdev = 1;
747 free(rootdev_name);
748 }
749
750 /*
751 * try with /proc/mounts fist to detect RDONLY.
752 * f2fs_stop_checkpoint makes RO in /proc/mounts while RW in /etc/mtab.
753 */
754 #ifdef __linux__
755 ret = is_mounted("/proc/mounts", path);
756 if (ret) {
757 MSG(0, "Info: Mounted device!\n");
758 return -1;
759 }
760 #endif
761 #if defined(MOUNTED) || defined(_PATH_MOUNTED)
762 #ifndef MOUNTED
763 #define MOUNTED _PATH_MOUNTED
764 #endif
765 ret = is_mounted(MOUNTED, path);
766 if (ret) {
767 MSG(0, "Info: Mounted device!\n");
768 return -1;
769 }
770 #endif
771 /*
772 * If we are supposed to operate on the root device, then
773 * also check the mounts for '/dev/root', which sometimes
774 * functions as an alias for the root device.
775 */
776 if (is_rootdev) {
777 #ifdef __linux__
778 ret = is_mounted("/proc/mounts", "/dev/root");
779 if (ret) {
780 MSG(0, "Info: Mounted device!\n");
781 return -1;
782 }
783 #endif
784 }
785
786 /*
787 * If f2fs is umounted with -l, the process can still use
788 * the file system. In this case, we should not format.
789 */
790 st_buf = malloc(sizeof(struct stat));
791 ASSERT(st_buf);
792
793 if (stat(path, st_buf) == 0 && S_ISBLK(st_buf->st_mode)) {
794 int fd = open(path, O_RDONLY | O_EXCL);
795
796 if (fd >= 0) {
797 close(fd);
798 } else if (errno == EBUSY) {
799 MSG(0, "\tError: In use by the system!\n");
800 free(st_buf);
801 return -1;
802 }
803 }
804 free(st_buf);
805 return ret;
806 #endif
807 }
808
f2fs_devs_are_umounted(void)809 int f2fs_devs_are_umounted(void)
810 {
811 int i;
812
813 for (i = 0; i < c.ndevs; i++)
814 if (f2fs_dev_is_umounted((char *)c.devices[i].path))
815 return -1;
816 return 0;
817 }
818
get_kernel_version(__u8 * version)819 void get_kernel_version(__u8 *version)
820 {
821 int i;
822 for (i = 0; i < VERSION_LEN; i++) {
823 if (version[i] == '\n')
824 break;
825 }
826 memset(version + i, 0, VERSION_LEN + 1 - i);
827 }
828
get_kernel_uname_version(__u8 * version)829 void get_kernel_uname_version(__u8 *version)
830 {
831 #ifdef HAVE_SYS_UTSNAME_H
832 struct utsname buf;
833
834 memset(version, 0, VERSION_LEN);
835 if (uname(&buf))
836 return;
837
838 #if defined(WITH_KERNEL_VERSION)
839 snprintf((char *)version,
840 VERSION_LEN, "%s %s", buf.release, buf.version);
841 #else
842 snprintf((char *)version,
843 VERSION_LEN, "%s", buf.release);
844 #endif
845 #else
846 memset(version, 0, VERSION_LEN);
847 #endif
848 }
849
850 #if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
851 #define BLKGETSIZE _IO(0x12,96)
852 #endif
853
854 #if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
855 #define BLKGETSIZE64 _IOR(0x12,114, size_t)
856 #endif
857
858 #if defined(__linux__) && defined(_IO) && !defined(BLKSSZGET)
859 #define BLKSSZGET _IO(0x12,104)
860 #endif
861
862 #if defined(__APPLE__)
863 #include <sys/disk.h>
864 #define BLKGETSIZE DKIOCGETBLOCKCOUNT
865 #define BLKSSZGET DKIOCGETBLOCKCOUNT
866 #endif /* APPLE_DARWIN */
867
868 #ifndef ANDROID_WINDOWS_HOST
open_check_fs(char * path,int flag)869 static int open_check_fs(char *path, int flag)
870 {
871 if (c.func != DUMP && (c.func != FSCK || c.fix_on || c.auto_fix))
872 return -1;
873
874 /* allow to open ro */
875 return open(path, O_RDONLY | flag);
876 }
877
get_device_info(int i)878 int get_device_info(int i)
879 {
880 int32_t fd = 0;
881 uint32_t sector_size;
882 #ifndef BLKGETSIZE64
883 uint32_t total_sectors;
884 #endif
885 struct stat *stat_buf;
886 #ifdef HDIO_GETGIO
887 struct hd_geometry geom;
888 #endif
889 #if !defined(WITH_ANDROID) && defined(__linux__)
890 sg_io_hdr_t io_hdr;
891 unsigned char reply_buffer[96] = {0};
892 unsigned char model_inq[6] = {MODELINQUIRY};
893 #endif
894 struct device_info *dev = c.devices + i;
895
896 if (c.sparse_mode) {
897 fd = open(dev->path, O_RDWR | O_CREAT | O_BINARY, 0644);
898 if (fd < 0) {
899 fd = open_check_fs(dev->path, O_BINARY);
900 if (fd < 0) {
901 MSG(0, "\tError: Failed to open a sparse file!\n");
902 return -1;
903 }
904 }
905 }
906
907 stat_buf = malloc(sizeof(struct stat));
908 ASSERT(stat_buf);
909
910 if (!c.sparse_mode) {
911 if (stat(dev->path, stat_buf) < 0 ) {
912 MSG(0, "\tError: Failed to get the device stat!\n");
913 free(stat_buf);
914 return -1;
915 }
916
917 if (S_ISBLK(stat_buf->st_mode) &&
918 !c.force && c.func != DUMP && !c.dry_run) {
919 fd = open(dev->path, O_RDWR | O_EXCL);
920 if (fd < 0)
921 fd = open_check_fs(dev->path, O_EXCL);
922 } else {
923 fd = open(dev->path, O_RDWR);
924 if (fd < 0)
925 fd = open_check_fs(dev->path, 0);
926 }
927 }
928 if (fd < 0) {
929 MSG(0, "\tError: Failed to open the device!\n");
930 free(stat_buf);
931 return -1;
932 }
933
934 dev->fd = fd;
935
936 if (c.sparse_mode) {
937 if (f2fs_init_sparse_file()) {
938 free(stat_buf);
939 return -1;
940 }
941 }
942
943 if (c.kd == -1) {
944 #if !defined(WITH_ANDROID) && defined(__linux__)
945 c.kd = open("/proc/version", O_RDONLY);
946 #endif
947 if (c.kd < 0) {
948 MSG(0, "\tInfo: No support kernel version!\n");
949 c.kd = -2;
950 }
951 }
952
953 if (c.sparse_mode) {
954 dev->total_sectors = c.device_size / dev->sector_size;
955 } else if (S_ISREG(stat_buf->st_mode)) {
956 dev->total_sectors = stat_buf->st_size / dev->sector_size;
957 } else if (S_ISBLK(stat_buf->st_mode)) {
958 #ifdef BLKSSZGET
959 if (ioctl(fd, BLKSSZGET, §or_size) < 0)
960 MSG(0, "\tError: Using the default sector size\n");
961 else if (dev->sector_size < sector_size)
962 dev->sector_size = sector_size;
963 #endif
964 #ifdef BLKGETSIZE64
965 if (ioctl(fd, BLKGETSIZE64, &dev->total_sectors) < 0) {
966 MSG(0, "\tError: Cannot get the device size\n");
967 free(stat_buf);
968 return -1;
969 }
970 #else
971 if (ioctl(fd, BLKGETSIZE, &total_sectors) < 0) {
972 MSG(0, "\tError: Cannot get the device size\n");
973 free(stat_buf);
974 return -1;
975 }
976 dev->total_sectors = total_sectors;
977 #endif
978 dev->total_sectors /= dev->sector_size;
979
980 if (i == 0) {
981 #ifdef HDIO_GETGIO
982 if (ioctl(fd, HDIO_GETGEO, &geom) < 0)
983 c.start_sector = 0;
984 else
985 c.start_sector = geom.start;
986 #else
987 c.start_sector = 0;
988 #endif
989 }
990
991 #if !defined(WITH_ANDROID) && defined(__linux__)
992 /* Send INQUIRY command */
993 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
994 io_hdr.interface_id = 'S';
995 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
996 io_hdr.dxfer_len = sizeof(reply_buffer);
997 io_hdr.dxferp = reply_buffer;
998 io_hdr.cmd_len = sizeof(model_inq);
999 io_hdr.cmdp = model_inq;
1000 io_hdr.timeout = 1000;
1001
1002 if (!ioctl(fd, SG_IO, &io_hdr)) {
1003 MSG(0, "Info: [%s] Disk Model: %.16s\n",
1004 dev->path, reply_buffer+16);
1005 }
1006 #endif
1007 } else {
1008 MSG(0, "\tError: Volume type is not supported!!!\n");
1009 free(stat_buf);
1010 return -1;
1011 }
1012
1013 if (!c.sector_size) {
1014 c.sector_size = dev->sector_size;
1015 c.sectors_per_blk = F2FS_BLKSIZE / c.sector_size;
1016 } else if (c.sector_size != c.devices[i].sector_size) {
1017 MSG(0, "\tError: Different sector sizes!!!\n");
1018 free(stat_buf);
1019 return -1;
1020 }
1021
1022 #if !defined(WITH_ANDROID) && defined(__linux__)
1023 if (S_ISBLK(stat_buf->st_mode)) {
1024 if (f2fs_get_zoned_model(i) < 0) {
1025 free(stat_buf);
1026 return -1;
1027 }
1028 }
1029
1030 if (dev->zoned_model != F2FS_ZONED_NONE) {
1031
1032 /* Get the number of blocks per zones */
1033 if (f2fs_get_zone_blocks(i)) {
1034 MSG(0, "\tError: Failed to get number of blocks per zone\n");
1035 free(stat_buf);
1036 return -1;
1037 }
1038
1039 /*
1040 * Check zone configuration: for the first disk of a
1041 * multi-device volume, conventional zones are needed.
1042 */
1043 if (f2fs_check_zones(i)) {
1044 MSG(0, "\tError: Failed to check zone configuration\n");
1045 free(stat_buf);
1046 return -1;
1047 }
1048 MSG(0, "Info: Host-%s zoned block device:\n",
1049 (dev->zoned_model == F2FS_ZONED_HA) ?
1050 "aware" : "managed");
1051 MSG(0, " %u zones, %u randomly writeable zones\n",
1052 dev->nr_zones, dev->nr_rnd_zones);
1053 MSG(0, " %lu blocks per zone\n",
1054 dev->zone_blocks);
1055 }
1056 #endif
1057 /* adjust wanted_total_sectors */
1058 if (c.wanted_total_sectors != -1) {
1059 MSG(0, "Info: wanted sectors = %"PRIu64" (in %"PRIu64" bytes)\n",
1060 c.wanted_total_sectors, c.wanted_sector_size);
1061 if (c.wanted_sector_size == -1) {
1062 c.wanted_sector_size = dev->sector_size;
1063 } else if (dev->sector_size != c.wanted_sector_size) {
1064 c.wanted_total_sectors *= c.wanted_sector_size;
1065 c.wanted_total_sectors /= dev->sector_size;
1066 }
1067 }
1068
1069 c.total_sectors += dev->total_sectors;
1070 free(stat_buf);
1071 return 0;
1072 }
1073
1074 #else
1075
1076 #include "windows.h"
1077 #include "winioctl.h"
1078
1079 #if (_WIN32_WINNT >= 0x0500)
1080 #define HAVE_GET_FILE_SIZE_EX 1
1081 #endif
1082
win_get_device_size(const char * file,uint64_t * device_size)1083 static int win_get_device_size(const char *file, uint64_t *device_size)
1084 {
1085 HANDLE dev;
1086 PARTITION_INFORMATION pi;
1087 DISK_GEOMETRY gi;
1088 DWORD retbytes;
1089 #ifdef HAVE_GET_FILE_SIZE_EX
1090 LARGE_INTEGER filesize;
1091 #else
1092 DWORD filesize;
1093 #endif /* HAVE_GET_FILE_SIZE_EX */
1094
1095 dev = CreateFile(file, GENERIC_READ,
1096 FILE_SHARE_READ | FILE_SHARE_WRITE ,
1097 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1098
1099 if (dev == INVALID_HANDLE_VALUE)
1100 return EBADF;
1101 if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO,
1102 &pi, sizeof(PARTITION_INFORMATION),
1103 &pi, sizeof(PARTITION_INFORMATION),
1104 &retbytes, NULL)) {
1105
1106 *device_size = pi.PartitionLength.QuadPart;
1107
1108 } else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY,
1109 &gi, sizeof(DISK_GEOMETRY),
1110 &gi, sizeof(DISK_GEOMETRY),
1111 &retbytes, NULL)) {
1112
1113 *device_size = gi.BytesPerSector *
1114 gi.SectorsPerTrack *
1115 gi.TracksPerCylinder *
1116 gi.Cylinders.QuadPart;
1117
1118 #ifdef HAVE_GET_FILE_SIZE_EX
1119 } else if (GetFileSizeEx(dev, &filesize)) {
1120 *device_size = filesize.QuadPart;
1121 }
1122 #else
1123 } else {
1124 filesize = GetFileSize(dev, NULL);
1125 if (INVALID_FILE_SIZE != filesize)
1126 return -1;
1127 *device_size = filesize;
1128 }
1129 #endif /* HAVE_GET_FILE_SIZE_EX */
1130
1131 CloseHandle(dev);
1132 return 0;
1133 }
1134
get_device_info(int i)1135 int get_device_info(int i)
1136 {
1137 struct device_info *dev = c.devices + i;
1138 uint64_t device_size = 0;
1139 int32_t fd = 0;
1140
1141 /* Block device target is not supported on Windows. */
1142 if (!c.sparse_mode) {
1143 if (win_get_device_size(dev->path, &device_size)) {
1144 MSG(0, "\tError: Failed to get device size!\n");
1145 return -1;
1146 }
1147 } else {
1148 device_size = c.device_size;
1149 }
1150 if (c.sparse_mode) {
1151 fd = open((char *)dev->path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
1152 } else {
1153 fd = open((char *)dev->path, O_RDWR | O_BINARY);
1154 }
1155 if (fd < 0) {
1156 MSG(0, "\tError: Failed to open the device!\n");
1157 return -1;
1158 }
1159 dev->fd = fd;
1160 dev->total_sectors = device_size / dev->sector_size;
1161 c.start_sector = 0;
1162 c.sector_size = dev->sector_size;
1163 c.sectors_per_blk = F2FS_BLKSIZE / c.sector_size;
1164 c.total_sectors += dev->total_sectors;
1165
1166 if (c.sparse_mode && f2fs_init_sparse_file())
1167 return -1;
1168 return 0;
1169 }
1170 #endif
1171
f2fs_get_device_info(void)1172 int f2fs_get_device_info(void)
1173 {
1174 int i;
1175
1176 for (i = 0; i < c.ndevs; i++)
1177 if (get_device_info(i))
1178 return -1;
1179
1180 if (c.wanted_total_sectors < c.total_sectors) {
1181 MSG(0, "Info: total device sectors = %"PRIu64" (in %u bytes)\n",
1182 c.total_sectors, c.sector_size);
1183 c.total_sectors = c.wanted_total_sectors;
1184 c.devices[0].total_sectors = c.total_sectors;
1185 }
1186 if (c.total_sectors * c.sector_size >
1187 (u_int64_t)F2FS_MAX_SEGMENT * 2 * 1024 * 1024) {
1188 MSG(0, "\tError: F2FS can support 16TB at most!!!\n");
1189 return -1;
1190 }
1191
1192 /*
1193 * Check device types and determine the final volume operation mode:
1194 * - If all devices are regular block devices, default operation.
1195 * - If at least one HM device is found, operate in HM mode (BLKZONED
1196 * feature will be enabled by mkfs).
1197 * - If an HA device is found, let mkfs decide based on the -m option
1198 * setting by the user.
1199 */
1200 c.zoned_model = F2FS_ZONED_NONE;
1201 for (i = 0; i < c.ndevs; i++) {
1202 switch (c.devices[i].zoned_model) {
1203 case F2FS_ZONED_NONE:
1204 continue;
1205 case F2FS_ZONED_HM:
1206 c.zoned_model = F2FS_ZONED_HM;
1207 break;
1208 case F2FS_ZONED_HA:
1209 if (c.zoned_model != F2FS_ZONED_HM)
1210 c.zoned_model = F2FS_ZONED_HA;
1211 break;
1212 }
1213 }
1214
1215 if (c.zoned_model != F2FS_ZONED_NONE) {
1216
1217 /*
1218 * For zoned model, the zones sizes of all zoned devices must
1219 * be equal.
1220 */
1221 for (i = 0; i < c.ndevs; i++) {
1222 if (c.devices[i].zoned_model == F2FS_ZONED_NONE)
1223 continue;
1224 if (c.zone_blocks &&
1225 c.zone_blocks != c.devices[i].zone_blocks) {
1226 MSG(0, "\tError: zones of different size are "
1227 "not supported\n");
1228 return -1;
1229 }
1230 c.zone_blocks = c.devices[i].zone_blocks;
1231 }
1232
1233 /*
1234 * Align sections to the device zone size and align F2FS zones
1235 * to the device zones. For F2FS_ZONED_HA model without the
1236 * BLKZONED feature set at format time, this is only an
1237 * optimization as sequential writes will not be enforced.
1238 */
1239 c.segs_per_sec = c.zone_blocks / DEFAULT_BLOCKS_PER_SEGMENT;
1240 c.secs_per_zone = 1;
1241 } else {
1242 if(c.zoned_mode != 0) {
1243 MSG(0, "\n Error: %s may not be a zoned block device \n",
1244 c.devices[0].path);
1245 return -1;
1246 }
1247 }
1248
1249 c.segs_per_zone = c.segs_per_sec * c.secs_per_zone;
1250
1251 MSG(0, "Info: Segments per section = %d\n", c.segs_per_sec);
1252 MSG(0, "Info: Sections per zone = %d\n", c.secs_per_zone);
1253 MSG(0, "Info: sector size = %u\n", c.sector_size);
1254 MSG(0, "Info: total sectors = %"PRIu64" (%"PRIu64" MB)\n",
1255 c.total_sectors, (c.total_sectors *
1256 (c.sector_size >> 9)) >> 11);
1257 return 0;
1258 }
1259
calc_extra_isize(void)1260 unsigned int calc_extra_isize(void)
1261 {
1262 unsigned int size = offsetof(struct f2fs_inode, i_projid);
1263
1264 if (c.feature & cpu_to_le32(F2FS_FEATURE_FLEXIBLE_INLINE_XATTR))
1265 size = offsetof(struct f2fs_inode, i_projid);
1266 if (c.feature & cpu_to_le32(F2FS_FEATURE_PRJQUOTA))
1267 size = offsetof(struct f2fs_inode, i_inode_checksum);
1268 if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM))
1269 size = offsetof(struct f2fs_inode, i_crtime);
1270 if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CRTIME))
1271 size = offsetof(struct f2fs_inode, i_compr_blocks);
1272 if (c.feature & cpu_to_le32(F2FS_FEATURE_COMPRESSION))
1273 size = offsetof(struct f2fs_inode, i_extra_end);
1274
1275 return size - F2FS_EXTRA_ISIZE_OFFSET;
1276 }
1277
1278 #define ARRAY_SIZE(array) \
1279 (sizeof(array) / sizeof(array[0]))
1280
1281 static const struct {
1282 char *name;
1283 __u16 encoding_magic;
1284 __u16 default_flags;
1285
1286 } f2fs_encoding_map[] = {
1287 {
1288 .encoding_magic = F2FS_ENC_UTF8_12_1,
1289 .name = "utf8",
1290 .default_flags = 0,
1291 },
1292 };
1293
1294 static const struct enc_flags {
1295 __u16 flag;
1296 char *param;
1297 } encoding_flags[] = {
1298 { F2FS_ENC_STRICT_MODE_FL, "strict" },
1299 };
1300
1301 /* Return a positive number < 0xff indicating the encoding magic number
1302 * or a negative value indicating error. */
f2fs_str2encoding(const char * string)1303 int f2fs_str2encoding(const char *string)
1304 {
1305 int i;
1306
1307 for (i = 0 ; i < ARRAY_SIZE(f2fs_encoding_map); i++)
1308 if (!strcmp(string, f2fs_encoding_map[i].name))
1309 return f2fs_encoding_map[i].encoding_magic;
1310
1311 return -EINVAL;
1312 }
1313
f2fs_encoding2str(const int encoding)1314 char *f2fs_encoding2str(const int encoding)
1315 {
1316 int i;
1317
1318 for (i = 0 ; i < ARRAY_SIZE(f2fs_encoding_map); i++)
1319 if (f2fs_encoding_map[i].encoding_magic == encoding)
1320 return f2fs_encoding_map[i].name;
1321
1322 return NULL;
1323 }
1324
f2fs_get_encoding_flags(int encoding)1325 int f2fs_get_encoding_flags(int encoding)
1326 {
1327 int i;
1328
1329 for (i = 0 ; i < ARRAY_SIZE(f2fs_encoding_map); i++)
1330 if (f2fs_encoding_map[i].encoding_magic == encoding)
1331 return f2fs_encoding_map[encoding].default_flags;
1332
1333 return 0;
1334 }
1335
f2fs_str2encoding_flags(char ** param,__u16 * flags)1336 int f2fs_str2encoding_flags(char **param, __u16 *flags)
1337 {
1338 char *f = strtok(*param, ",");
1339 const struct enc_flags *fl;
1340 int i, neg = 0;
1341
1342 while (f) {
1343 neg = 0;
1344 if (!strncmp("no", f, 2)) {
1345 neg = 1;
1346 f += 2;
1347 }
1348
1349 for (i = 0; i < ARRAY_SIZE(encoding_flags); i++) {
1350 fl = &encoding_flags[i];
1351 if (!strcmp(fl->param, f)) {
1352 if (neg) {
1353 MSG(0, "Sub %s\n", fl->param);
1354 *flags &= ~fl->flag;
1355 } else {
1356 MSG(0, "Add %s\n", fl->param);
1357 *flags |= fl->flag;
1358 }
1359
1360 goto next_flag;
1361 }
1362 }
1363 *param = f;
1364 return -EINVAL;
1365 next_flag:
1366 f = strtok(NULL, ":");
1367 }
1368 return 0;
1369 }
1370