net: tcp_client_socket connection state routines
[quarnos.git] / resources / fat.cpp
blob13136d496ed28667912803b534bbb7cb9b5075e3
1 /* Quarn OS
3 * FAT filesystem
5 * Copyright (C) 2008-2009 Pawel Dziepak
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "fat.h"
25 #include "manes/manec.h"
27 using namespace manes;
28 using namespace resources;
30 fat::fat() : mounted(false) {}
32 bool fat::mount(p<block> _dep) {
33 dep = _dep;
35 /* Load MBR */
36 mbr = new unsigned char[512];
37 dep->read_block(0, 1, (void*)mbr);
39 /* Check if filesystem is FAT12 */
40 if (strncmp((char*)&(mbr[mbr_fsid]),"FAT12",5)) {
41 debug("fat: fs is not fat12");
42 return false;
44 if (mbr[mbr_dev_desc] != 0xF0) {
45 debug("fat: fs is not fat12");
46 return false;
49 /* Load FAT */
50 main_fat = new unsigned char[(unsigned short)mbr[mbr_sectors_per_fat] << 9];
51 dep->read_block(mbr[mbr_reserved_sectors], ((unsigned short)mbr[mbr_sectors_per_fat]), (void*)main_fat);
53 /* Load root dir */
54 root_dir = new dir_entry[(unsigned short)mbr[mbr_root_entries] * 32];
55 dep->read_block(mbr[mbr_fat_count] * mbr[mbr_sectors_per_fat] + mbr[mbr_reserved_sectors], ((unsigned short)mbr[mbr_root_entries])* 32 / 512, (void*)root_dir);
57 mounted = true;
59 return true;
61 typedef unsigned int cpu_word;
62 void fat::load_file(const string &filename, buffer &addr) {
63 assert("fat: filesystem is not mounted", !mounted);
65 int index = find_file(filename);
67 unsigned int cluster = root_dir[index].cluster;
68 int count = 0;
70 while (cluster < 0xFF0 && cluster > 1) {
71 index = ((unsigned char)mbr[mbr_fat_count])*((unsigned short)mbr[mbr_sectors_per_fat])+((unsigned short)mbr[mbr_reserved_sectors])+((unsigned short)mbr[mbr_root_entries])*32/512;
73 index += cluster - 2;
75 dep->read_block(index, 1, (void*)((cpu_word)addr.get_address() + count));
77 cluster = get_cluster_val(cluster);
79 count += 512;
83 file::file_meta fat::load_meta(const string &filename) {
84 assert("fat: filesystem is not mounted", !mounted);
86 int index = find_file(filename);
88 file::file_meta meta;
89 meta.creation_d = date(root_dir[index].date & 0x1f, root_dir[index].date & 0x1e0 >> 5, (root_dir[index].date & 0xf800 >> 9) + 1980);
90 meta.creation_t = time(root_dir[index].time & 0x1f, root_dir[index].time & 0x7e0 >> 5, root_dir[index].time & 0xf800 >> 0xb);
92 if ((root_dir[index].attr & fat_hidden) == fat_hidden)
93 meta.attributes = file::attr_hidden;
94 else
95 meta.attributes = (file::attrib)0;
97 meta.directory = (root_dir[index].attr & fat_directory) == fat_directory;
99 if ((root_dir[index].attr & fat_read_only) == fat_read_only)
100 meta.access = prvl(0, 555);
101 else
102 meta.access = prvl(0, 777);
104 meta.size = root_dir[index].size;
106 return meta;
109 short fat::get_cluster_val(int n) {
110 int cluster = n;
111 int index = cluster + (cluster >> 1);
112 cluster = *((unsigned short*)((int)main_fat+index));
114 if (n % 2 == 0)
115 cluster &= 0xFFF;
116 else
117 cluster >>= 4;
119 return cluster;
122 void fat::set_cluster_val(int n, int val) {
123 int cluster = n;
124 int index = cluster + (cluster >> 1);
127 if (n % 2 == 0) {
128 *((unsigned short*)((int)main_fat+index)) &= 0xF000;
129 val &= 0xFFF;
130 *((unsigned short*)((int)main_fat+index)) |= val;
131 } else {
132 *((unsigned short*)((int)main_fat+index)) &= 0x000F;
133 val <<= 4;
134 *((unsigned short*)((int)main_fat+index)) |= val;
138 void fat::filename_to_fatname(const char *filename, char *fatname) {
139 bool dot = false;
140 for (int i = 0, j = 0; i < 11; j++, i++) {
141 if (i > 7 && !dot) {
142 dot = true;
143 for (; filename[j] != '.' && filename[j]; j++);
144 fatname[7] = '1';
145 fatname[6] = '~';
148 if (filename[j] >= 'a' && filename[j] <= 'z') fatname[i] = filename[j] - 'a' + 'A';
149 else if (filename[j] == '.') {
150 dot = true;
151 for (; i < 8; i++)
152 fatname[i] = ' ';
153 i--;
155 else if (!filename[j])
156 for (; i < 11; i++)
157 fatname[i] = ' ';
158 else fatname[i] = filename[j];
162 void fat::fatname_to_filename(const char *fatname, char *filename) {
163 int i, j;
164 for (i = 0, j = 0; i < 11; i++,j++) {
165 if (i == 8 && fatname[9] != ' ') {
166 filename[j] = '.';
167 j++;
170 if (fatname[i] >= 'A' && fatname[i] <= 'Z')
171 filename[j] = fatname[i] - 'A' + 'a';
172 else if (fatname[i] != ' ')
173 filename[j] = fatname[i];
175 if (fatname[i] == ' ') {
176 for (; fatname[i]==' ' && i < 11; i++);
177 if (i == 11) break;
178 /*filename[j] = '.';*/
179 i--;
180 j--;
183 filename[j]=0;
186 bool valid_fatname(const char *fatname) {
187 for (int i = 0; i < 11; i++)
188 if (fatname[i] < ' ' || fatname[i] > '~')
189 return false;
190 return true;
193 void fat::save_file(const string &filename, buffer &addr) {
194 assert("fat: filesystem is not mounted", !mounted);
196 char fatname[11];
197 filename_to_fatname(filename, fatname);
199 int pos = 0;
200 for (int i = 0; i < 50; i++)
201 if (root_dir[i].name[0] == '\0' && root_dir[i].name[1] == '\0')
202 pos = i;
203 assert("fat: no free entry in root dir", pos == 0);
205 strcpy((char*)root_dir[pos].name, fatname);
206 root_dir[pos].size = addr.get_size();
208 int first_cluster = 0, n_cluster, cluster, saved = 0;
210 for (first_cluster = 3; get_cluster_val(first_cluster) != 0; first_cluster++);
212 n_cluster = first_cluster;
213 do {
214 cluster = n_cluster;
216 int index = ((unsigned char)mbr[mbr_fat_count])*((unsigned short)mbr[mbr_sectors_per_fat])+((unsigned short)mbr[mbr_reserved_sectors])+((unsigned short)mbr[mbr_root_entries])*32/512;
217 index += cluster - 2;
219 dep->write_block(index, 1, (void*)((int)addr.get_address() + saved));
221 for (n_cluster = cluster + 1; get_cluster_val(n_cluster) != 0; n_cluster++);
222 set_cluster_val(cluster, n_cluster);
224 saved += 512;
225 } while (saved < addr.get_size());
227 set_cluster_val(cluster, 0xFFF);
229 root_dir[pos].cluster = first_cluster;
231 /* Save FAT */
232 dep->write_block(mbr[mbr_reserved_sectors], ((unsigned short)mbr[mbr_sectors_per_fat]), (void*)main_fat);
234 /* Save root dir */
235 dep->write_block(mbr[mbr_fat_count] * mbr[mbr_sectors_per_fat] + mbr[mbr_reserved_sectors], ((unsigned short)mbr[mbr_root_entries])* 32 / 512, (void*)root_dir);
239 list<p<file> > fat::list_directory(const string &dirname) {
240 list<p<file> > dir;
242 for (int i = 0; i < 50; i++) {
243 if (valid_fatname((char*)root_dir[i].name)) {
244 char filename[20];
245 p<file> fp = new file();
246 fatname_to_filename((char*)root_dir[i].name, filename);
247 fp->set(filename, (fs*)this);
248 dir.add(fp);
252 return dir;
255 int fat::find_file(const char *filename) {
256 char fatname[11];
258 filename_to_fatname(filename, fatname);
260 for (int i = 0; i < 50; i++)
261 if (!strncmp(fatname, (const char*)root_dir[i].name,11))
262 return i;
264 debug((string)"fat: file not found: " + filename);
265 return -1;
268 void fat::register_type() {
269 manec::get()->register_type<fat>("fat", "manec");