libf2fs.c revision e69e4378500b836863dfb7f6e88e39935f23ae80
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
109/*
110 * device information
111 */
112void f2fs_init_configuration(struct f2fs_configuration *c)
113{
114	c->sector_size = DEFAULT_SECTOR_SIZE;
115	c->sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK;
116	c->blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT;
117
118	/* calculated by overprovision ratio */
119	c->reserved_segments = 48;
120	c->overprovision = 5;
121	c->segs_per_sec = 1;
122	c->secs_per_zone = 1;
123	c->heap = 1;
124	memset(c->vol_label, 0, sizeof(c->vol_label));
125
126	c->vol_label[0] = 'F';
127	c->vol_label[1] = '2';
128	c->vol_label[2] = 'F';
129	c->vol_label[3] = 'S';
130	c->vol_label[4] = '\0';
131	c->device_name = NULL;
132}
133
134int f2fs_dev_is_mounted(struct f2fs_configuration *c)
135{
136	FILE *file = NULL;
137	struct mntent *mnt = NULL;
138
139	file = setmntent(MOUNTED, "r");
140	if (file == NULL)
141		return 0;
142
143	while (1) {
144		mnt = getmntent(file);
145		if (mnt == NULL)
146			break;
147		if (!strcmp(c->device_name, mnt->mnt_fsname)) {
148			endmntent(file);
149			return -1;
150		}
151	}
152	endmntent(file);
153	return 0;
154}
155
156int f2fs_get_device_info(struct f2fs_configuration *c)
157{
158	int32_t fd = 0;
159	int32_t sector_size;
160	struct stat stat_buf;
161	struct hd_geometry geom;
162
163	fd = open(c->device_name, O_RDWR);
164	if (fd < 0) {
165		MSG(0, "\tError: Failed to open the device!\n");
166		return -1;
167	}
168	c->fd = fd;
169
170	if (fstat(fd, &stat_buf) < 0 ) {
171		MSG(0, "\tError: Failed to get the device stat!\n");
172		return -1;
173	}
174
175	if (S_ISREG(stat_buf.st_mode)) {
176		c->total_sectors = stat_buf.st_size / c->sector_size;
177	} else if (S_ISBLK(stat_buf.st_mode)) {
178		if (ioctl(fd, BLKSSZGET, &sector_size) < 0) {
179			MSG(0, "\tError: Using the default sector size\n");
180		} else {
181			if (c->sector_size < sector_size) {
182				MSG(0, "\tError: Cannot set the sector size to:"
183					" %d as the device does not support"
184					"\nSetting the sector size to : %d\n",
185					c->sector_size, sector_size);
186				c->sector_size = sector_size;
187				c->sectors_per_blk = PAGE_SIZE / sector_size;
188			}
189		}
190
191		if (ioctl(fd, BLKGETSIZE, &c->total_sectors) < 0) {
192			MSG(0, "\tError: Cannot get the device size\n");
193			return -1;
194		}
195
196		if (ioctl(fd, HDIO_GETGEO, &geom) < 0)
197			c->start_sector = 0;
198		else
199			c->start_sector = geom.start;
200	} else {
201		MSG(0, "\tError: Volume type is not supported!!!\n");
202		return -1;
203	}
204
205	MSG(0, "Info: sector size = %u\n", c->sector_size);
206	MSG(0, "Info: total sectors = %"PRIu64" (in 512bytes)\n",
207					c->total_sectors);
208	if (c->total_sectors <
209			(F2FS_MIN_VOLUME_SIZE / DEFAULT_SECTOR_SIZE)) {
210		MSG(0, "Error: Min volume size supported is %d\n",
211				F2FS_MIN_VOLUME_SIZE);
212		return -1;
213	}
214
215	return 0;
216}
217
218/*
219 * IO interfaces
220 */
221int dev_read(int fd, void *buf, __u64 offset, size_t len)
222{
223	if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
224		return -1;
225	if (read(fd, buf, len) < 0)
226		return -1;
227	return 0;
228}
229
230int dev_write(int fd, void *buf, __u64 offset, size_t len)
231{
232	if (lseek64(fd, (off64_t)offset, SEEK_SET) < 0)
233		return -1;
234	if (write(fd, buf, len) < 0)
235		return -1;
236	return 0;
237}
238
239int dev_read_block(int fd, void *buf, __u64 blk_addr)
240{
241	return dev_read(fd, buf, blk_addr * F2FS_BLKSIZE, F2FS_BLKSIZE);
242}
243
244int dev_read_blocks(int fd, void *buf, __u64 addr, __u32 nr_blks)
245{
246	return dev_read(fd, buf, addr * F2FS_BLKSIZE, nr_blks * F2FS_BLKSIZE);
247}
248