fs.c revision f79b2dff1024db4f6326f3422236bed169dd902f
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <assert.h>
18#include <string.h>
19#include <sys/endian.h>
20
21#include "extent.h"
22#include "errors.h"
23#include "fat.h"
24#include "fs.h"
25#include "types.h"
26#include "utils.h"
27
28#define DEFAULT_SECTOR_SIZE 512
29
30static void fs_add_extent(struct fs *fs, struct extent *extent,
31                          offset_t start, offset_t len, int type)
32{
33	assert(fs);
34	assert(extent);
35
36	extent->start = start;
37	extent->len = len;
38	extent->type = type;
39
40	extent->next = fs->extents;
41	fs->extents = extent;
42}
43
44struct extent *fs_find_extent(struct fs *fs, offset_t start, offset_t len,
45                              struct extent *last,
46                              offset_t *r_start_out,
47                              offset_t *e_start_out,
48                              offset_t *len_out)
49{
50	struct extent *e;
51	offset_t end;
52	offset_t e_start, e_end, e_len, e_rel_start, r_rel_start, rel_len;
53
54	assert(fs);
55
56	end = start + len;
57
58	e = last ? last->next : fs->extents;
59	for (; e; e = e->next) {
60		e_start = e->start;
61		e_len = e->len;
62		e_end = e_start + e_len;
63
64		if (start >= e_end)
65			continue;
66
67		if (end <= e_start)
68			continue;
69
70		if (e_start <= start) {
71			r_rel_start = 0;
72			e_rel_start = start - e_start;
73			if (end <= e_end)
74				rel_len = len;
75			else
76				rel_len = e_end - start;
77		} else {
78			e_rel_start = 0;
79			r_rel_start = e_start - start;
80			if (e_end <= end)
81				rel_len = e_len;
82			else
83				rel_len = end - e_start;
84		}
85
86		assert(e_rel_start < e_len);
87		assert(e_rel_start + rel_len <= e_len);
88		assert(r_rel_start < len);
89		assert(r_rel_start + rel_len <= len);
90
91		if (r_start_out)
92			*r_start_out = r_rel_start;
93		if (e_start_out)
94			*e_start_out = e_rel_start;
95		if (len_out)
96			*len_out = rel_len;
97
98		return e;
99	}
100
101	return NULL;
102}
103
104static void fs_set_fat(struct fs *fs, cluster_t cluster, fat_entry_t entry)
105{
106	assert(fs);
107
108	fs->fat[cluster] = htole32(entry);
109}
110
111int fs_alloc_extent(struct fs *fs, struct extent *extent,
112                    offset_t len, int type, cluster_t *first_cluster_out)
113{
114	assert(fs);
115	assert(extent);
116
117	cluster_t clusters_needed, start;
118	cluster_t i;
119
120	if (len == 0) {
121		extent->start = 0;
122		extent->len = 0;
123		extent->type = type;
124		*first_cluster_out = 0;
125		return 0;
126	}
127
128	clusters_needed = (len + fs->cluster_size - 1) / fs->cluster_size;
129
130	/* Check for adequate space. */
131	if (fs->next_cluster + clusters_needed > fs->num_clusters) {
132		WARN("allocating extent: filesystem is full!\n");
133		return -1;
134	}
135
136	/* Allocate clusters. */
137	start = fs->next_cluster;
138	fs->next_cluster += clusters_needed;
139
140	/* Update FAT. */
141	for (i = 0; i < clusters_needed - 1; i++) {
142		fs_set_fat(fs, start + i, start + i + 1);
143	}
144	fs_set_fat(fs, start + clusters_needed - 1, FAT_ENTRY_EOC);
145
146	*first_cluster_out = start;
147
148	fs_add_extent(fs,
149                      extent,
150                      fs->data_offset + (offset_t)(start - FAT_CLUSTER_ZERO)
151                                        * fs->cluster_size,
152                      (offset_t)clusters_needed * fs->cluster_size,
153                      type);
154
155	return 0;
156}
157
158int fs_init(struct fs *fs, uint16_t cluster_size, offset_t data_size, offset_t *total_size_out)
159{
160	uint16_t sector_size;
161	cluster_t data_clusters;
162	sector_t reserved_sectors, fat_sectors, data_sectors, total_sectors;
163	sector_t sectors_per_cluster;
164	int fat_entries_per_sector;
165	fat_entry_t *fat;
166	struct fat_boot_sector *bs;
167	struct fat_info_sector *is;
168
169	assert(fs);
170
171	sector_size = DEFAULT_SECTOR_SIZE;
172	fs->cluster_size = cluster_size;
173
174	sectors_per_cluster = cluster_size / DEFAULT_SECTOR_SIZE;
175	fat_entries_per_sector = sector_size / sizeof(fat_entry_t);
176
177	data_clusters = (data_size + cluster_size - 1) / cluster_size;
178	data_sectors = data_clusters * sectors_per_cluster;
179	fat_sectors = ((data_clusters + 2) + fat_entries_per_sector - 1)
180                      / fat_entries_per_sector;
181	reserved_sectors = 3;
182	total_sectors = reserved_sectors + fat_sectors + data_sectors;
183
184	memset(&fs->boot, 0, sizeof(fs->boot));
185	bs = &fs->boot;
186
187	strpadcpy(bs->name, "FATBLOCK", ' ', sizeof(bs->name));
188	bs->sector_size = htole16(sector_size);
189	bs->sectors_per_cluster = sectors_per_cluster;
190	bs->reserved_sectors = htole16(reserved_sectors);
191	bs->fats = 1;
192	bs->media_desc = FAT_MEDIA_DESC_FIXED;
193	/* TODO: Calculate geometry? */
194	bs->sectors_per_track = htole16(42);
195	bs->heads = htole16(42);
196	bs->sectors32 = htole32(total_sectors);
197	bs->fat_sectors32 = htole32(fat_sectors);
198	/* bs->rootdir_start will be set later. */
199	bs->fs_info_sector = htole16(1);
200	bs->backup_boot_sector = htole16(2);
201	bs->phys_drive = FAT_PHYS_DRIVE_REMOVABLE;
202	bs->ext_boot_sig = FAT_EXT_BOOT_SIG;
203	bs->serial = 0x42424242;
204	strpadcpy(bs->vol_label, "FATBLOCK", ' ', sizeof(bs->vol_label));
205	strpadcpy(bs->type, "FAT32", ' ', sizeof(bs->type));
206	memcpy(bs->boot_sig, FAT_BOOT_SIG, sizeof(bs->boot_sig));
207
208	memset(&fs->info, 0, sizeof(fs->info));
209	is = &fs->info;
210
211	memcpy(is->info_sig1, FAT_INFO_SIG1, sizeof(is->info_sig1));
212	memcpy(is->info_sig2, FAT_INFO_SIG2, sizeof(is->info_sig2));
213	is->free_clusters = htole32(-1);
214	is->last_cluster = htole32(FAT_CLUSTER_ZERO);
215	memcpy(is->info_sig3, FAT_INFO_SIG3, sizeof(is->info_sig3));
216
217	fs->num_clusters = FAT_CLUSTER_ZERO + data_clusters;
218	fs->next_cluster = FAT_CLUSTER_ZERO;
219
220	fs->fat_size = fat_sectors * sector_size;
221	fs->fat = malloc(fs->fat_size);
222	if (!fs->fat) {
223		WARN("initializing filesystem: couldn't allocate FAT extent: out of memory\n");
224		return MALLOC_FAIL;
225	}
226	memset(fs->fat, 0, fs->fat_size);
227
228	fs->data_offset = (reserved_sectors + fat_sectors) * sector_size;
229
230	fs->extents = NULL;
231	fs_add_extent(fs, &fs->boot_extent,
232                      0, sector_size,
233                      EXTENT_TYPE_BOOT);
234	fs_add_extent(fs, &fs->info_extent,
235                      sector_size, sector_size,
236                      EXTENT_TYPE_INFO);
237	fs_add_extent(fs, &fs->backup_boot_extent,
238                      2 * sector_size, sector_size,
239                      EXTENT_TYPE_BOOT);
240	fs_add_extent(fs, &fs->fat_extent,
241                      reserved_sectors * sector_size, fs->fat_size,
242                      EXTENT_TYPE_FAT);
243
244	*total_size_out = (offset_t)total_sectors * sector_size;
245
246	return 0;
247}
248
249void fs_set_rootdir_start(struct fs *fs, cluster_t rootdir_start)
250{
251	assert(fs);
252
253	fs->boot.rootdir_start = htole32(rootdir_start);
254}
255
256void fs_update_free_clusters(struct fs *fs)
257{
258	assert(fs);
259
260	fs->info.free_clusters = htole32(fs->num_clusters - fs->next_cluster);
261}
262