libf2fs.c revision 9799d6364dc93e1fd259d812d4a50ed984a6456b
1/**
2 * libf2fs.c
3 *
4 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
5 *             http://www.samsung.com/
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#define _LARGEFILE64_SOURCE
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17#include <fcntl.h>
18#include <mntent.h>
19#include <time.h>
20#include <sys/stat.h>
21#include <sys/mount.h>
22#include <sys/ioctl.h>
23#include <linux/hdreg.h>
24#include <linux/fs.h>
25
26#include "f2fs_fs.h"
27
28struct f2fs_configuration config;
29
30void ASCIIToUNICODE(u_int16_t *out_buf, u_int8_t *in_buf)
31{
32	u_int8_t *pchTempPtr = in_buf;
33	u_int16_t *pwTempPtr = out_buf;
34
35	while (*pchTempPtr != '\0') {
36		*pwTempPtr = (u_int16_t)*pchTempPtr;
37		pchTempPtr++;
38		pwTempPtr++;
39	}
40	*pwTempPtr = '\0';
41	return;
42}
43
44int log_base_2(u_int32_t num)
45{
46	int ret = 0;
47	if (num <= 0 || (num & (num - 1)) != 0)
48		return -1;
49
50	while (num >>= 1)
51		ret++;
52	return ret;
53}
54
55/*
56 * f2fs bit operations
57 */
58int f2fs_test_bit(unsigned int nr, const char *p)
59{
60	int mask;
61	char *addr = (char *)p;
62
63	addr += (nr >> 3);
64	mask = 1 << (7 - (nr & 0x07));
65	return (mask & *addr) != 0;
66}
67
68int f2fs_set_bit(unsigned int nr, unsigned char *addr)
69{
70	int mask;
71	int ret;
72
73	addr += (nr >> 3);
74	mask = 1 << (7 - (nr & 0x07));
75	ret = mask & *addr;
76	*addr |= mask;
77	return ret;
78}
79
80int f2fs_clear_bit(unsigned int nr, char *addr)
81{
82	int mask;
83	int ret;
84
85	addr += (nr >> 3);
86	mask = 1 << (7 - (nr & 0x07));
87	ret = mask & *addr;
88	*addr &= ~mask;
89	return ret;
90}
91
92/*
93 * CRC32
94 */
95#define CRCPOLY_LE 0xedb88320
96
97u_int32_t f2fs_cal_crc32(u_int32_t crc, void *buf, int len)
98{
99	int i;
100	unsigned char *p = (unsigned char *)buf;
101	while (len--) {
102		crc ^= *p++;
103		for (i = 0; i < 8; i++)
104			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
105	}
106	return crc;
107}
108
109int f2fs_crc_valid(u_int32_t blk_crc, void *buf, int len)
110{
111	u_int32_t cal_crc = 0;
112
113	cal_crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, buf, len);
114
115	if (cal_crc != blk_crc)	{
116		DBG(0,"CRC validation failed: cal_crc = %u \
117			blk_crc = %u buff_size = 0x%x",
118			cal_crc, blk_crc, len);
119		return -1;
120	}
121	return 0;
122}
123
124/*
125 * device information
126 */
127void f2fs_init_configuration(struct f2fs_configuration *c)
128{
129	c->sector_size = DEFAULT_SECTOR_SIZE;
130	c->sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK;
131	c->blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT;
132
133	/* calculated by overprovision ratio */
134	c->reserved_segments = 48;
135	c->overprovision = 5;
136	c->segs_per_sec = 1;
137	c->secs_per_zone = 1;
138	c->heap = 1;
139	c->vol_label = "";
140	c->device_name = NULL;
141}
142
143int f2fs_dev_is_mounted(struct f2fs_configuration *c)
144{
145	FILE *file = NULL;
146	struct mntent *mnt = NULL;
147
148	file = setmntent(MOUNTED, "r");
149	if (file == NULL) {
150		/* if failed due to /etc/mtab file not present
151		   try with /proc/mounts */
152		file = setmntent("/proc/mounts", "r");
153		if (file == NULL)
154			return 0;
155	}
156
157	while (1) {
158		mnt = getmntent(file);
159		if (mnt == NULL)
160			break;
161		if (!strcmp(c->device_name, mnt->mnt_fsname)) {
162			endmntent(file);
163			return -1;
164		}
165	}
166	endmntent(file);
167	return 0;
168}
169
170int f2fs_get_device_info(struct f2fs_configuration *c)
171{
172	int32_t fd = 0;
173	int32_t sector_size;
174	struct stat stat_buf;
175	struct hd_geometry geom;
176
177	fd = open(c->device_name, O_RDWR);
178	if (fd < 0) {
179		MSG(0, "\tError: Failed to open the device!\n");
180		return -1;
181	}
182	c->fd = fd;
183
184	if (fstat(fd, &stat_buf) < 0 ) {
185		MSG(0, "\tError: Failed to get the device stat!\n");
186		return -1;
187	}
188
189	if (S_ISREG(stat_buf.st_mode)) {
190		c->total_sectors = stat_buf.st_size / c->sector_size;
191	} else if (S_ISBLK(stat_buf.st_mode)) {
192		if (ioctl(fd, BLKSSZGET, &sector_size) < 0) {
193			MSG(0, "\tError: Using the default sector size\n");
194		} else {
195			if (c->sector_size < sector_size) {
196				MSG(0, "\tError: Cannot set the sector size to:"
197					" %d as the device does not support"
198					"\nSetting the sector size to : %d\n",
199					c->sector_size, sector_size);
200				c->sector_size = sector_size;
201				c->sectors_per_blk = PAGE_SIZE / sector_size;
202			}
203		}
204
205		if (ioctl(fd, BLKGETSIZE, &c->total_sectors) < 0) {
206			MSG(0, "\tError: Cannot get the device size\n");
207			return -1;
208		}
209
210		if (ioctl(fd, HDIO_GETGEO, &geom) < 0)
211			c->start_sector = 0;
212		else
213			c->start_sector = geom.start;
214	} else {
215		MSG(0, "\tError: Volume type is not supported!!!\n");
216		return -1;
217	}
218
219	MSG(0, "Info: sector size = %u\n", c->sector_size);
220	MSG(0, "Info: total sectors = %"PRIu64" (in 512bytes)\n",
221					c->total_sectors);
222	if (c->total_sectors <
223			(F2FS_MIN_VOLUME_SIZE / DEFAULT_SECTOR_SIZE)) {
224		MSG(0, "Error: Min volume size supported is %d\n",
225				F2FS_MIN_VOLUME_SIZE);
226		return -1;
227	}
228
229	return 0;
230}
231
232/*
233 * IO interfaces
234 */
235int dev_read(void *buf, __u64 offset, size_t len)
236{
237	if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0)
238		return -1;
239	if (read(config.fd, buf, len) < 0)
240		return -1;
241	return 0;
242}
243
244int dev_write(void *buf, __u64 offset, size_t len)
245{
246	if (lseek64(config.fd, (off64_t)offset, SEEK_SET) < 0)
247		return -1;
248	if (write(config.fd, buf, len) < 0)
249		return -1;
250	return 0;
251}
252
253int dev_read_block(void *buf, __u64 blk_addr)
254{
255	return dev_read(buf, blk_addr * F2FS_BLKSIZE, F2FS_BLKSIZE);
256}
257
258int dev_read_blocks(void *buf, __u64 addr, __u32 nr_blks)
259{
260	return dev_read(buf, addr * F2FS_BLKSIZE, nr_blks * F2FS_BLKSIZE);
261}
262