diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/common/dir.c | 3 | ||||
-rw-r--r-- | firmware/common/file.c | 178 | ||||
-rw-r--r-- | firmware/common/file.h | 16 | ||||
-rw-r--r-- | firmware/debug.c | 11 | ||||
-rw-r--r-- | firmware/debug.h | 6 | ||||
-rw-r--r-- | firmware/drivers/fat.c | 585 | ||||
-rw-r--r-- | firmware/drivers/fat.h | 19 | ||||
-rw-r--r-- | firmware/test/fat/README | 25 | ||||
-rw-r--r-- | firmware/test/fat/ata-sim.c | 7 | ||||
-rw-r--r-- | firmware/test/fat/main.c | 52 |
10 files changed, 610 insertions, 292 deletions
diff --git a/firmware/common/dir.c b/firmware/common/dir.c index 70aa4946dc..6bf9a53cad 100644 --- a/firmware/common/dir.c +++ b/firmware/common/dir.c | |||
@@ -105,8 +105,7 @@ struct dirent* readdir(DIR* dir) | |||
105 | return NULL; | 105 | return NULL; |
106 | 106 | ||
107 | if ( !entry.name[0] ) | 107 | if ( !entry.name[0] ) |
108 | return NULL; | 108 | return NULL; |
109 | |||
110 | 109 | ||
111 | strncpy(theent->d_name, entry.name, sizeof( theent->d_name ) ); | 110 | strncpy(theent->d_name, entry.name, sizeof( theent->d_name ) ); |
112 | theent->attribute = entry.attr; | 111 | theent->attribute = entry.attr; |
diff --git a/firmware/common/file.c b/firmware/common/file.c index 2c00c3e3f6..27258e4603 100644 --- a/firmware/common/file.c +++ b/firmware/common/file.c | |||
@@ -42,23 +42,25 @@ struct filedesc { | |||
42 | int size; | 42 | int size; |
43 | struct fat_file fatfile; | 43 | struct fat_file fatfile; |
44 | bool busy; | 44 | bool busy; |
45 | bool write; | ||
45 | }; | 46 | }; |
46 | 47 | ||
47 | static struct filedesc openfiles[MAX_OPEN_FILES]; | 48 | static struct filedesc openfiles[MAX_OPEN_FILES]; |
48 | 49 | ||
49 | int open(char* pathname, int flags) | 50 | int creat(const char *pathname, int mode) |
51 | { | ||
52 | (void)mode; | ||
53 | return open(pathname, O_WRONLY); | ||
54 | } | ||
55 | |||
56 | int open(const char* pathname, int flags) | ||
50 | { | 57 | { |
51 | DIR* dir; | 58 | DIR* dir; |
52 | struct dirent* entry; | 59 | struct dirent* entry; |
53 | int fd; | 60 | int fd; |
54 | char* name; | 61 | char* name; |
55 | 62 | ||
56 | /* For now, we don't support writing */ | 63 | LDEBUGF("open(\"%s\",%d)\n",pathname,flags); |
57 | if(flags & (O_WRONLY | O_RDWR)) | ||
58 | { | ||
59 | errno = EROFS; | ||
60 | return -1; | ||
61 | } | ||
62 | 64 | ||
63 | if ( pathname[0] != '/' ) { | 65 | if ( pathname[0] != '/' ) { |
64 | DEBUGF("'%s' is not an absolute path.\n",pathname); | 66 | DEBUGF("'%s' is not an absolute path.\n",pathname); |
@@ -75,44 +77,74 @@ int open(char* pathname, int flags) | |||
75 | if ( fd == MAX_OPEN_FILES ) { | 77 | if ( fd == MAX_OPEN_FILES ) { |
76 | DEBUGF("Too many files open\n"); | 78 | DEBUGF("Too many files open\n"); |
77 | errno = EMFILE; | 79 | errno = EMFILE; |
78 | return -1; | 80 | return -2; |
79 | } | 81 | } |
80 | 82 | ||
83 | switch ( flags ) { | ||
84 | case O_RDONLY: | ||
85 | openfiles[fd].write = false; | ||
86 | break; | ||
87 | |||
88 | case O_WRONLY: | ||
89 | openfiles[fd].write = true; | ||
90 | break; | ||
91 | |||
92 | default: | ||
93 | DEBUGF("Only O_RDONLY and O_WRONLY is supported\n"); | ||
94 | errno = EROFS; | ||
95 | return -3; | ||
96 | } | ||
81 | openfiles[fd].busy = true; | 97 | openfiles[fd].busy = true; |
82 | 98 | ||
83 | /* locate filename */ | 99 | /* locate filename */ |
84 | name=strrchr(pathname+1,'/'); | 100 | name=strrchr(pathname+1,'/'); |
85 | if ( name ) { | 101 | if ( name ) { |
86 | *name = 0; | 102 | *name = 0; |
87 | dir = opendir(pathname); | 103 | dir = opendir((char*)pathname); |
88 | *name = '/'; | 104 | *name = '/'; |
89 | name++; | 105 | name++; |
90 | } | 106 | } |
91 | else { | 107 | else { |
92 | dir = opendir("/"); | 108 | dir = opendir("/"); |
93 | name = pathname+1; | 109 | name = (char*)pathname+1; |
94 | } | 110 | } |
95 | if (!dir) { | 111 | if (!dir) { |
96 | DEBUGF("Failed opening dir\n"); | 112 | DEBUGF("Failed opening dir\n"); |
97 | errno = EIO; | 113 | errno = EIO; |
98 | openfiles[fd].busy = false; | 114 | openfiles[fd].busy = false; |
99 | return -1; | 115 | return -4; |
100 | } | 116 | } |
101 | 117 | ||
102 | /* scan dir for name */ | 118 | /* scan dir for name */ |
103 | while ((entry = readdir(dir))) { | 119 | while ((entry = readdir(dir))) { |
104 | if ( !strcasecmp(name, entry->d_name) ) { | 120 | if ( !strcasecmp(name, entry->d_name) ) { |
105 | fat_open(entry->startcluster, &(openfiles[fd].fatfile)); | 121 | fat_open(entry->startcluster, |
122 | &(openfiles[fd].fatfile), | ||
123 | &(dir->fatdir)); | ||
106 | openfiles[fd].size = entry->size; | 124 | openfiles[fd].size = entry->size; |
107 | break; | 125 | break; |
108 | } | 126 | } |
109 | } | 127 | } |
110 | closedir(dir); | 128 | closedir(dir); |
111 | if ( !entry ) { | 129 | if ( !entry ) { |
112 | DEBUGF("Couldn't find %s in %s\n",name,pathname); | 130 | LDEBUGF("Didn't find file %s\n",name); |
113 | errno = ENOENT; | 131 | if ( openfiles[fd].write ) { |
114 | openfiles[fd].busy = false; | 132 | if (fat_create_file(name, |
115 | return -1; | 133 | &(openfiles[fd].fatfile), |
134 | &(dir->fatdir)) < 0) { | ||
135 | DEBUGF("Couldn't create %s in %s\n",name,pathname); | ||
136 | errno = EIO; | ||
137 | openfiles[fd].busy = false; | ||
138 | return -5; | ||
139 | } | ||
140 | openfiles[fd].size = 0; | ||
141 | } | ||
142 | else { | ||
143 | DEBUGF("Couldn't find %s in %s\n",name,pathname); | ||
144 | errno = ENOENT; | ||
145 | openfiles[fd].busy = false; | ||
146 | return -6; | ||
147 | } | ||
116 | } | 148 | } |
117 | 149 | ||
118 | openfiles[fd].cacheoffset = -1; | 150 | openfiles[fd].cacheoffset = -1; |
@@ -122,19 +154,37 @@ int open(char* pathname, int flags) | |||
122 | 154 | ||
123 | int close(int fd) | 155 | int close(int fd) |
124 | { | 156 | { |
157 | int rc = 0; | ||
158 | |||
159 | LDEBUGF("close(%d)\n",fd); | ||
160 | |||
125 | if (fd < 0 || fd > MAX_OPEN_FILES-1) { | 161 | if (fd < 0 || fd > MAX_OPEN_FILES-1) { |
126 | errno = EINVAL; | 162 | errno = EINVAL; |
127 | return -1; | 163 | return -1; |
128 | } | 164 | } |
129 | if (!openfiles[fd].busy) { | 165 | if (!openfiles[fd].busy) { |
130 | errno = EBADF; | 166 | errno = EBADF; |
131 | return -1; | 167 | return -2; |
168 | } | ||
169 | if (openfiles[fd].write) { | ||
170 | /* flush sector cache */ | ||
171 | if ( openfiles[fd].cacheoffset != -1 ) { | ||
172 | if ( fat_readwrite(&(openfiles[fd].fatfile), 1, | ||
173 | &(openfiles[fd].cache),true) < 0 ) { | ||
174 | DEBUGF("Failed flushing cache\n"); | ||
175 | errno = EIO; | ||
176 | rc = -1; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /* tie up all loose ends */ | ||
181 | fat_closewrite(&(openfiles[fd].fatfile), openfiles[fd].size); | ||
132 | } | 182 | } |
133 | openfiles[fd].busy = false; | 183 | openfiles[fd].busy = false; |
134 | return 0; | 184 | return rc; |
135 | } | 185 | } |
136 | 186 | ||
137 | int read(int fd, void* buf, int count) | 187 | static int readwrite(int fd, void* buf, int count, bool write) |
138 | { | 188 | { |
139 | int sectors; | 189 | int sectors; |
140 | int nread=0; | 190 | int nread=0; |
@@ -144,9 +194,16 @@ int read(int fd, void* buf, int count) | |||
144 | return -1; | 194 | return -1; |
145 | } | 195 | } |
146 | 196 | ||
147 | /* attempt to read past EOF? */ | 197 | LDEBUGF( "readwrite(%d,%x,%d,%s)\n", |
148 | if ( count > openfiles[fd].size - openfiles[fd].fileoffset ) | 198 | fd,buf,count,write?"write":"read"); |
149 | count = openfiles[fd].size - openfiles[fd].fileoffset; | 199 | |
200 | /* attempt to access past EOF? */ | ||
201 | if (count > openfiles[fd].size - openfiles[fd].fileoffset) { | ||
202 | if ( write ) | ||
203 | openfiles[fd].size = openfiles[fd].fileoffset + count; | ||
204 | else | ||
205 | count = openfiles[fd].size - openfiles[fd].fileoffset; | ||
206 | } | ||
150 | 207 | ||
151 | /* any head bytes? */ | 208 | /* any head bytes? */ |
152 | if ( openfiles[fd].cacheoffset != -1 ) { | 209 | if ( openfiles[fd].cacheoffset != -1 ) { |
@@ -163,23 +220,38 @@ int read(int fd, void* buf, int count) | |||
163 | openfiles[fd].cacheoffset = -1; | 220 | openfiles[fd].cacheoffset = -1; |
164 | } | 221 | } |
165 | 222 | ||
166 | /* eof? */ | 223 | if (write) { |
167 | if ( openfiles[fd].fileoffset + headbytes > openfiles[fd].size ) | 224 | memcpy( openfiles[fd].cache + offs, buf, headbytes ); |
168 | headbytes = openfiles[fd].size - openfiles[fd].fileoffset; | 225 | if (offs+headbytes == SECTOR_SIZE) { |
226 | int rc = fat_readwrite(&(openfiles[fd].fatfile), 1, | ||
227 | openfiles[fd].cache, true ); | ||
228 | if ( rc < 0 ) { | ||
229 | DEBUGF("Failed read/writing %d sectors\n",sectors); | ||
230 | errno = EIO; | ||
231 | return -2; | ||
232 | } | ||
233 | openfiles[fd].cacheoffset = -1; | ||
234 | } | ||
235 | } | ||
236 | else { | ||
237 | memcpy( buf, openfiles[fd].cache + offs, headbytes ); | ||
238 | } | ||
169 | 239 | ||
170 | memcpy( buf, openfiles[fd].cache + offs, headbytes ); | ||
171 | nread = headbytes; | 240 | nread = headbytes; |
172 | count -= headbytes; | 241 | count -= headbytes; |
242 | |||
243 | LDEBUGF("readwrite incache: offs=%d\n",openfiles[fd].cacheoffset); | ||
173 | } | 244 | } |
174 | 245 | ||
175 | /* read whole sectors right into the supplied buffer */ | 246 | /* read whole sectors right into the supplied buffer */ |
176 | sectors = count / SECTOR_SIZE; | 247 | sectors = count / SECTOR_SIZE; |
177 | if ( sectors ) { | 248 | if ( sectors ) { |
178 | int rc = fat_read(&(openfiles[fd].fatfile), sectors, buf+nread ); | 249 | int rc = fat_readwrite(&(openfiles[fd].fatfile), sectors, |
250 | buf+nread, write ); | ||
179 | if ( rc < 0 ) { | 251 | if ( rc < 0 ) { |
180 | DEBUGF("Failed reading %d sectors\n",sectors); | 252 | DEBUGF("Failed read/writing %d sectors\n",sectors); |
181 | errno = EIO; | 253 | errno = EIO; |
182 | return -1; | 254 | return -2; |
183 | } | 255 | } |
184 | else { | 256 | else { |
185 | if ( rc > 0 ) { | 257 | if ( rc > 0 ) { |
@@ -197,18 +269,19 @@ int read(int fd, void* buf, int count) | |||
197 | 269 | ||
198 | /* any tail bytes? */ | 270 | /* any tail bytes? */ |
199 | if ( count ) { | 271 | if ( count ) { |
200 | if ( fat_read(&(openfiles[fd].fatfile), 1, | 272 | if (write) { |
201 | &(openfiles[fd].cache)) < 0 ) { | 273 | memcpy( openfiles[fd].cache, buf + nread, count ); |
202 | DEBUGF("Failed caching sector\n"); | ||
203 | errno = EIO; | ||
204 | return -1; | ||
205 | } | 274 | } |
206 | 275 | else { | |
207 | /* eof? */ | 276 | if ( fat_readwrite(&(openfiles[fd].fatfile), 1, |
208 | if ( openfiles[fd].fileoffset + count > openfiles[fd].size ) | 277 | &(openfiles[fd].cache),false) < 0 ) { |
209 | count = openfiles[fd].size - openfiles[fd].fileoffset; | 278 | DEBUGF("Failed caching sector\n"); |
210 | 279 | errno = EIO; | |
211 | memcpy( buf + nread, openfiles[fd].cache, count ); | 280 | return -1; |
281 | } | ||
282 | memcpy( buf + nread, openfiles[fd].cache, count ); | ||
283 | } | ||
284 | |||
212 | nread += count; | 285 | nread += count; |
213 | openfiles[fd].cacheoffset = count; | 286 | openfiles[fd].cacheoffset = count; |
214 | } | 287 | } |
@@ -217,6 +290,17 @@ int read(int fd, void* buf, int count) | |||
217 | return nread; | 290 | return nread; |
218 | } | 291 | } |
219 | 292 | ||
293 | int write(int fd, void* buf, int count) | ||
294 | { | ||
295 | return readwrite(fd, buf, count, true); | ||
296 | } | ||
297 | |||
298 | int read(int fd, void* buf, int count) | ||
299 | { | ||
300 | return readwrite(fd, buf, count, false); | ||
301 | } | ||
302 | |||
303 | |||
220 | int lseek(int fd, int offset, int whence) | 304 | int lseek(int fd, int offset, int whence) |
221 | { | 305 | { |
222 | int pos; | 306 | int pos; |
@@ -225,6 +309,8 @@ int lseek(int fd, int offset, int whence) | |||
225 | int sectoroffset; | 309 | int sectoroffset; |
226 | int rc; | 310 | int rc; |
227 | 311 | ||
312 | LDEBUGF("lseek(%d,%d,%d)\n",fd,offset,whence); | ||
313 | |||
228 | if ( !openfiles[fd].busy ) { | 314 | if ( !openfiles[fd].busy ) { |
229 | errno = EBADF; | 315 | errno = EBADF; |
230 | return -1; | 316 | return -1; |
@@ -245,11 +331,11 @@ int lseek(int fd, int offset, int whence) | |||
245 | 331 | ||
246 | default: | 332 | default: |
247 | errno = EINVAL; | 333 | errno = EINVAL; |
248 | return -1; | 334 | return -2; |
249 | } | 335 | } |
250 | if ((pos < 0) || (pos > openfiles[fd].size)) { | 336 | if ((pos < 0) || (pos > openfiles[fd].size)) { |
251 | errno = EINVAL; | 337 | errno = EINVAL; |
252 | return -1; | 338 | return -3; |
253 | } | 339 | } |
254 | 340 | ||
255 | /* new sector? */ | 341 | /* new sector? */ |
@@ -263,14 +349,14 @@ int lseek(int fd, int offset, int whence) | |||
263 | rc = fat_seek(&(openfiles[fd].fatfile), newsector); | 349 | rc = fat_seek(&(openfiles[fd].fatfile), newsector); |
264 | if ( rc < 0 ) { | 350 | if ( rc < 0 ) { |
265 | errno = EIO; | 351 | errno = EIO; |
266 | return -1; | 352 | return -4; |
267 | } | 353 | } |
268 | } | 354 | } |
269 | rc = fat_read(&(openfiles[fd].fatfile), 1, | 355 | rc = fat_readwrite(&(openfiles[fd].fatfile), 1, |
270 | &(openfiles[fd].cache)); | 356 | &(openfiles[fd].cache),false); |
271 | if ( rc < 0 ) { | 357 | if ( rc < 0 ) { |
272 | errno = EIO; | 358 | errno = EIO; |
273 | return -1; | 359 | return -5; |
274 | } | 360 | } |
275 | openfiles[fd].cacheoffset = sectoroffset; | 361 | openfiles[fd].cacheoffset = sectoroffset; |
276 | } | 362 | } |
diff --git a/firmware/common/file.h b/firmware/common/file.h index c95811fc55..7a7c63d665 100644 --- a/firmware/common/file.h +++ b/firmware/common/file.h | |||
@@ -40,24 +40,22 @@ | |||
40 | #endif | 40 | #endif |
41 | 41 | ||
42 | #if defined(__MINGW32__) && defined(SIMULATOR) | 42 | #if defined(__MINGW32__) && defined(SIMULATOR) |
43 | int open (const char*, int, ...); | 43 | extern int open(const char*, int, ...); |
44 | extern int close(int fd); | 44 | extern int close(int fd); |
45 | int read (int, void*, unsigned int); | 45 | extern int read(int, void*, unsigned int); |
46 | long lseek (int, long, int); | 46 | extern long lseek(int, long, int); |
47 | 47 | ||
48 | #else | 48 | #else |
49 | 49 | ||
50 | #ifndef SIMULATOR | 50 | #ifndef SIMULATOR |
51 | extern int open(char* pathname, int flags); | 51 | extern int open(const char* pathname, int flags); |
52 | extern int close(int fd); | 52 | extern int close(int fd); |
53 | extern int read(int fd, void* buf, int count); | 53 | extern int read(int fd, void* buf, int count); |
54 | extern int lseek(int fd, int offset, int whence); | 54 | extern int lseek(int fd, int offset, int whence); |
55 | 55 | extern int creat(const char *pathname, int mode); | |
56 | #ifdef DISK_WRITE | ||
57 | extern int write(int fd, void* buf, int count); | 56 | extern int write(int fd, void* buf, int count); |
58 | extern int remove(char* pathname); | 57 | extern int remove(const char* pathname); |
59 | extern int rename(char* oldname, char* newname); | 58 | extern int rename(const char* oldname, const char* newname); |
60 | #endif | ||
61 | 59 | ||
62 | #else | 60 | #else |
63 | #ifdef WIN32 | 61 | #ifdef WIN32 |
diff --git a/firmware/debug.c b/firmware/debug.c index 83eb149706..2ebcd86778 100644 --- a/firmware/debug.c +++ b/firmware/debug.c | |||
@@ -195,7 +195,9 @@ static void debug(char *msg) | |||
195 | } | 195 | } |
196 | #endif /* end of DEBUG section */ | 196 | #endif /* end of DEBUG section */ |
197 | 197 | ||
198 | #ifdef __GNUC__ | ||
198 | void debugf(char *fmt, ...) | 199 | void debugf(char *fmt, ...) |
200 | #endif | ||
199 | { | 201 | { |
200 | #ifdef DEBUG | 202 | #ifdef DEBUG |
201 | va_list ap; | 203 | va_list ap; |
@@ -223,4 +225,13 @@ void debugf(char *fmt, ...) | |||
223 | vfprintf( stderr, fmt, ap ); | 225 | vfprintf( stderr, fmt, ap ); |
224 | va_end( ap ); | 226 | va_end( ap ); |
225 | } | 227 | } |
228 | |||
229 | void ldebugf(char* file, int line, char *fmt, ...) | ||
230 | { | ||
231 | va_list ap; | ||
232 | va_start( ap, fmt ); | ||
233 | fprintf( stderr, "%s:%d ", file, line ); | ||
234 | vfprintf( stderr, fmt, ap ); | ||
235 | va_end( ap ); | ||
236 | } | ||
226 | #endif | 237 | #endif |
diff --git a/firmware/debug.h b/firmware/debug.h index e9eec27e86..878da295bc 100644 --- a/firmware/debug.h +++ b/firmware/debug.h | |||
@@ -21,20 +21,24 @@ | |||
21 | 21 | ||
22 | extern void debug_init(void); | 22 | extern void debug_init(void); |
23 | extern void debugf(char* fmt,...); | 23 | extern void debugf(char* fmt,...); |
24 | extern void ldebugf(char* file, int line, char *fmt, ...); | ||
24 | 25 | ||
25 | #ifdef __GNUC__ | 26 | #ifdef __GNUC__ |
26 | 27 | ||
27 | /* */ | 28 | /* */ |
28 | #if defined(DEBUG) || defined(SIMULATOR) | 29 | #if defined(DEBUG) || defined(SIMULATOR) |
29 | //#define DEBUGF(...) debugf(__VA_ARGS__) | ||
30 | #define DEBUGF debugf | 30 | #define DEBUGF debugf |
31 | #define LDEBUGF(...) ldebugf(__FILE__, __LINE__, __VA_ARGS__) | ||
31 | #else | 32 | #else |
32 | #define DEBUGF(...) | 33 | #define DEBUGF(...) |
34 | #define LDEBUGF(...) | ||
33 | #endif | 35 | #endif |
34 | 36 | ||
37 | |||
35 | #else | 38 | #else |
36 | 39 | ||
37 | #define DEBUGF debugf | 40 | #define DEBUGF debugf |
41 | #define LDEBUGF debugf | ||
38 | 42 | ||
39 | #endif /* GCC */ | 43 | #endif /* GCC */ |
40 | 44 | ||
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c index 7bed896748..322ae76a2d 100644 --- a/firmware/drivers/fat.c +++ b/firmware/drivers/fat.c | |||
@@ -22,14 +22,11 @@ | |||
22 | #include <math.h> | 22 | #include <math.h> |
23 | #include <stdlib.h> | 23 | #include <stdlib.h> |
24 | #include <ctype.h> | 24 | #include <ctype.h> |
25 | #ifdef DISK_WRITE | ||
26 | #include <time.h> | ||
27 | #include <sys/timeb.h> | ||
28 | #endif | ||
29 | #include <stdbool.h> | 25 | #include <stdbool.h> |
30 | #include "fat.h" | 26 | #include "fat.h" |
31 | #include "ata.h" | 27 | #include "ata.h" |
32 | #include "debug.h" | 28 | #include "debug.h" |
29 | #include "panic.h" | ||
33 | #include "system.h" | 30 | #include "system.h" |
34 | 31 | ||
35 | #define BYTES2INT16(array,pos) \ | 32 | #define BYTES2INT16(array,pos) \ |
@@ -38,11 +35,6 @@ | |||
38 | (array[pos] | (array[pos+1] << 8 ) | \ | 35 | (array[pos] | (array[pos+1] << 8 ) | \ |
39 | (array[pos+2] << 16 ) | (array[pos+3] << 24 )) | 36 | (array[pos+2] << 16 ) | (array[pos+3] << 24 )) |
40 | 37 | ||
41 | #define NUM_ROOT_DIR_ENTRIES 512 | ||
42 | #define NUM_FATS 2 | ||
43 | #define NUM_RESERVED_SECTORS 1 | ||
44 | #define NUM_BLOCKS 10000 | ||
45 | |||
46 | #define FATTYPE_FAT12 0 | 38 | #define FATTYPE_FAT12 0 |
47 | #define FATTYPE_FAT16 1 | 39 | #define FATTYPE_FAT16 1 |
48 | #define FATTYPE_FAT32 2 | 40 | #define FATTYPE_FAT32 2 |
@@ -107,6 +99,12 @@ | |||
107 | #define FATDIR_FSTCLUSLO 26 | 99 | #define FATDIR_FSTCLUSLO 26 |
108 | #define FATDIR_FILESIZE 28 | 100 | #define FATDIR_FILESIZE 28 |
109 | 101 | ||
102 | #define CLUSTERS_PER_FAT_SECTOR (SECTOR_SIZE / 4) | ||
103 | #define DIR_ENTRIES_PER_SECTOR (SECTOR_SIZE / 32) | ||
104 | #define DIR_ENTRY_SIZE 32 | ||
105 | #define FAT_BAD_MARK 0x0ffffff7 | ||
106 | #define FAT_EOF_MARK 0x0ffffff8 | ||
107 | |||
110 | struct fsinfo { | 108 | struct fsinfo { |
111 | int freecount; /* last known free cluster count */ | 109 | int freecount; /* last known free cluster count */ |
112 | int nextfree; /* first cluster to start looking for free clusters, | 110 | int nextfree; /* first cluster to start looking for free clusters, |
@@ -155,6 +153,7 @@ struct bpb | |||
155 | int rootdirsector; | 153 | int rootdirsector; |
156 | int firstdatasector; | 154 | int firstdatasector; |
157 | int startsector; | 155 | int startsector; |
156 | struct fsinfo fsinfo; | ||
158 | }; | 157 | }; |
159 | 158 | ||
160 | static struct bpb fat_bpb; | 159 | static struct bpb fat_bpb; |
@@ -167,6 +166,7 @@ static unsigned int getcurrdostime(unsigned short *dosdate, | |||
167 | unsigned short *dostime, | 166 | unsigned short *dostime, |
168 | unsigned char *dostenth); | 167 | unsigned char *dostenth); |
169 | static int create_dos_name(unsigned char *name, unsigned char *newname); | 168 | static int create_dos_name(unsigned char *name, unsigned char *newname); |
169 | static int find_free_cluster(int start); | ||
170 | #endif | 170 | #endif |
171 | 171 | ||
172 | #define FAT_CACHE_SIZE 0x20 | 172 | #define FAT_CACHE_SIZE 0x20 |
@@ -256,7 +256,6 @@ int fat_mount(int startsector) | |||
256 | fat_bpb.bpb_secperclus = buf[BPB_SECPERCLUS]; | 256 | fat_bpb.bpb_secperclus = buf[BPB_SECPERCLUS]; |
257 | fat_bpb.bpb_rsvdseccnt = BYTES2INT16(buf,BPB_RSVDSECCNT); | 257 | fat_bpb.bpb_rsvdseccnt = BYTES2INT16(buf,BPB_RSVDSECCNT); |
258 | fat_bpb.bpb_numfats = buf[BPB_NUMFATS]; | 258 | fat_bpb.bpb_numfats = buf[BPB_NUMFATS]; |
259 | fat_bpb.bpb_rootentcnt = BYTES2INT16(buf,BPB_ROOTENTCNT); | ||
260 | fat_bpb.bpb_totsec16 = BYTES2INT16(buf,BPB_TOTSEC16); | 259 | fat_bpb.bpb_totsec16 = BYTES2INT16(buf,BPB_TOTSEC16); |
261 | fat_bpb.bpb_media = buf[BPB_MEDIA]; | 260 | fat_bpb.bpb_media = buf[BPB_MEDIA]; |
262 | fat_bpb.bpb_fatsz16 = BYTES2INT16(buf,BPB_FATSZ16); | 261 | fat_bpb.bpb_fatsz16 = BYTES2INT16(buf,BPB_FATSZ16); |
@@ -295,7 +294,7 @@ int fat_mount(int startsector) | |||
295 | #endif | 294 | #endif |
296 | { | 295 | { |
297 | DEBUGF("This is not FAT32. Go away!\n"); | 296 | DEBUGF("This is not FAT32. Go away!\n"); |
298 | return -1; | 297 | return -2; |
299 | } | 298 | } |
300 | 299 | ||
301 | fat_bpb.bpb_extflags = BYTES2INT16(buf,BPB_EXTFLAGS); | 300 | fat_bpb.bpb_extflags = BYTES2INT16(buf,BPB_EXTFLAGS); |
@@ -316,11 +315,23 @@ int fat_mount(int startsector) | |||
316 | if (bpb_is_sane() < 0) | 315 | if (bpb_is_sane() < 0) |
317 | { | 316 | { |
318 | DEBUGF( "fat_mount() - BPB is not sane\n"); | 317 | DEBUGF( "fat_mount() - BPB is not sane\n"); |
319 | return -1; | 318 | return -3; |
320 | } | 319 | } |
321 | 320 | ||
322 | fat_bpb.rootdirsector = cluster2sec(fat_bpb.bpb_rootclus); | 321 | fat_bpb.rootdirsector = cluster2sec(fat_bpb.bpb_rootclus); |
323 | 322 | ||
323 | /* Read the fsinfo sector */ | ||
324 | err = ata_read_sectors(startsector + fat_bpb.bpb_fsinfo, 1, buf); | ||
325 | if (err) | ||
326 | { | ||
327 | DEBUGF( "fat_mount() - Couldn't read FSInfo (error code %d)\n", err); | ||
328 | return -1; | ||
329 | } | ||
330 | fat_bpb.fsinfo.freecount = BYTES2INT32(buf, FSINFO_FREECOUNT); | ||
331 | fat_bpb.fsinfo.nextfree = BYTES2INT32(buf, FSINFO_NEXTFREE); | ||
332 | LDEBUGF("Freecount: %x\n",fat_bpb.fsinfo.freecount); | ||
333 | LDEBUGF("Nextfree: %x\n",fat_bpb.fsinfo.nextfree); | ||
334 | |||
324 | return 0; | 335 | return 0; |
325 | } | 336 | } |
326 | 337 | ||
@@ -339,9 +350,9 @@ static int bpb_is_sane(void) | |||
339 | fat_bpb.bpb_bytspersec, fat_bpb.bpb_secperclus, | 350 | fat_bpb.bpb_bytspersec, fat_bpb.bpb_secperclus, |
340 | fat_bpb.bpb_bytspersec * fat_bpb.bpb_secperclus); | 351 | fat_bpb.bpb_bytspersec * fat_bpb.bpb_secperclus); |
341 | } | 352 | } |
342 | if(fat_bpb.bpb_rsvdseccnt != 1) | 353 | if (fat_bpb.bpb_rsvdseccnt != 32) |
343 | { | 354 | { |
344 | DEBUGF( "bpb_is_sane() - Warning: Reserved sectors is not 1 (%d)\n", | 355 | DEBUGF( "bpb_is_sane() - Warning: Reserved sectors is not 32 (%d)\n", |
345 | fat_bpb.bpb_rsvdseccnt); | 356 | fat_bpb.bpb_rsvdseccnt); |
346 | } | 357 | } |
347 | if(fat_bpb.bpb_numfats != 2) | 358 | if(fat_bpb.bpb_numfats != 2) |
@@ -349,11 +360,6 @@ static int bpb_is_sane(void) | |||
349 | DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n", | 360 | DEBUGF( "bpb_is_sane() - Warning: NumFATS is not 2 (%d)\n", |
350 | fat_bpb.bpb_numfats); | 361 | fat_bpb.bpb_numfats); |
351 | } | 362 | } |
352 | if(fat_bpb.bpb_rootentcnt != 512) | ||
353 | { | ||
354 | DEBUGF( "bpb_is_sane() - Warning: RootEntCnt is not 512 (%d)\n", | ||
355 | fat_bpb.bpb_rootentcnt); | ||
356 | } | ||
357 | if(fat_bpb.bpb_media != 0xf0 && fat_bpb.bpb_media < 0xf8) | 363 | if(fat_bpb.bpb_media != 0xf0 && fat_bpb.bpb_media < 0xf8) |
358 | { | 364 | { |
359 | DEBUGF( "bpb_is_sane() - Warning: Non-standard " | 365 | DEBUGF( "bpb_is_sane() - Warning: Non-standard " |
@@ -364,33 +370,42 @@ static int bpb_is_sane(void) | |||
364 | { | 370 | { |
365 | DEBUGF( "bpb_is_sane() - Error: Last word is not " | 371 | DEBUGF( "bpb_is_sane() - Error: Last word is not " |
366 | "0xaa55 (0x%04x)\n", fat_bpb.last_word); | 372 | "0xaa55 (0x%04x)\n", fat_bpb.last_word); |
367 | return -1; | 373 | return -4; |
374 | } | ||
375 | |||
376 | if (fat_bpb.fsinfo.freecount > | ||
377 | (fat_bpb.totalsectors - fat_bpb.firstdatasector)/ | ||
378 | fat_bpb.bpb_secperclus) | ||
379 | { | ||
380 | DEBUGF( "bpb_is_sane() - Error: FSInfo.Freecount > disk size " | ||
381 | "(0x%04x)\n", fat_bpb.fsinfo.freecount); | ||
382 | return -5; | ||
368 | } | 383 | } |
384 | |||
369 | return 0; | 385 | return 0; |
370 | } | 386 | } |
371 | 387 | ||
372 | static void *cache_fat_sector(int secnum) | 388 | static void *cache_fat_sector(int fatsector) |
373 | { | 389 | { |
390 | int secnum = fatsector + fat_bpb.bpb_rsvdseccnt; | ||
374 | int cache_index = secnum & FAT_CACHE_MASK; | 391 | int cache_index = secnum & FAT_CACHE_MASK; |
375 | 392 | ||
376 | /* Delete the cache entry if it isn't the sector we want */ | 393 | /* Delete the cache entry if it isn't the sector we want */ |
377 | if(fat_cache[cache_index].inuse && | 394 | if(fat_cache[cache_index].inuse && |
378 | fat_cache[cache_index].secnum != secnum) | 395 | fat_cache[cache_index].secnum != secnum) |
379 | { | 396 | { |
380 | #ifdef WRITE | ||
381 | /* Write back if it is dirty */ | 397 | /* Write back if it is dirty */ |
382 | if(fat_cache[cache_index].dirty) | 398 | if(fat_cache[cache_index].dirty) |
383 | { | 399 | { |
384 | if(ata_write_sectors(secnum + fat_bpb.startsector, 1, sec)) | 400 | if(ata_write_sectors(secnum + fat_bpb.startsector, 1, |
401 | fat_cache_sectors[cache_index])) | ||
385 | { | 402 | { |
386 | panic("cache_fat_sector() - Could" | 403 | panicf("cache_fat_sector() - Could not write sector %d\n", |
387 | " not write sector %d\n", | 404 | secnum); |
388 | secnum); | ||
389 | } | 405 | } |
390 | } | 406 | } |
391 | fat_cache[cache_index].secnum = 8; /* Normally an unused sector */ | 407 | fat_cache[cache_index].secnum = 8; /* Normally an unused sector */ |
392 | fat_cache[cache_index].dirty = false; | 408 | fat_cache[cache_index].dirty = false; |
393 | #endif | ||
394 | fat_cache[cache_index].inuse = false; | 409 | fat_cache[cache_index].inuse = false; |
395 | } | 410 | } |
396 | 411 | ||
@@ -409,101 +424,107 @@ static void *cache_fat_sector(int secnum) | |||
409 | return fat_cache_sectors[cache_index]; | 424 | return fat_cache_sectors[cache_index]; |
410 | } | 425 | } |
411 | 426 | ||
412 | #ifdef DISK_WRITE | 427 | static int find_free_cluster(int startcluster) |
413 | static int update_entry(int entry, unsigned int val) | ||
414 | { | 428 | { |
415 | unsigned long *sec; | 429 | int sector = startcluster / CLUSTERS_PER_FAT_SECTOR; |
416 | int fatoffset; | 430 | int offset = startcluster % CLUSTERS_PER_FAT_SECTOR; |
417 | int thisfatsecnum; | 431 | int i; |
418 | int thisfatentoffset; | ||
419 | 432 | ||
420 | fatoffset = entry * 4; | 433 | LDEBUGF("find_free_cluster(%x)\n",startcluster); |
421 | thisfatsecnum = fatoffset / fat_bpb.bpb_bytspersec + fat_bpb.bpb_rsvdseccnt; | ||
422 | thisfatentoffset = fatoffset % fat_bpb.bpb_bytspersec; | ||
423 | 434 | ||
424 | /* Load the sector if it is not cached */ | 435 | for (i = sector; i<fat_bpb.fatsize; i++) { |
425 | sec = cache_fat_sector(thisfatsecnum); | 436 | int j; |
426 | if(!sec) | 437 | unsigned int* fat = cache_fat_sector(i); |
438 | if ( !fat ) | ||
439 | break; | ||
440 | for (j = offset; j < CLUSTERS_PER_FAT_SECTOR; j++) | ||
441 | if (!(SWAB32(fat[j]) & 0x0fffffff)) { | ||
442 | int c = i * CLUSTERS_PER_FAT_SECTOR + j; | ||
443 | LDEBUGF("Found free cluster %x\n",c); | ||
444 | fat_bpb.fsinfo.nextfree = c; | ||
445 | return c; | ||
446 | } | ||
447 | } | ||
448 | return 0; /* 0 is an illegal cluster number */ | ||
449 | } | ||
450 | |||
451 | static int update_fat_entry(int entry, unsigned int val) | ||
452 | { | ||
453 | int sector = entry / CLUSTERS_PER_FAT_SECTOR; | ||
454 | int offset = entry % CLUSTERS_PER_FAT_SECTOR; | ||
455 | unsigned int* sec; | ||
456 | |||
457 | LDEBUGF("update_fat_entry(%x,%x)\n",entry,val); | ||
458 | |||
459 | sec = cache_fat_sector(sector); | ||
460 | if (!sec) | ||
427 | { | 461 | { |
428 | DEBUGF( "update_entry() - Could not cache sector %d\n", | 462 | DEBUGF( "update_entry() - Could not cache sector %d\n", sector); |
429 | thisfatsecnum); | ||
430 | return -1; | 463 | return -1; |
431 | } | 464 | } |
465 | fat_cache[sector & FAT_CACHE_MASK].dirty = true; | ||
432 | 466 | ||
433 | /* We can safely assume that the correct sector is in the cache, | 467 | if ( val ) { |
434 | so we mark it dirty without checking the sector number */ | 468 | if (!(sec[offset] & 0x0fffffff)) |
435 | fat_cache[thisfatsecnum & FAT_CACHE_MASK].dirty = 1; | 469 | fat_bpb.fsinfo.freecount--; |
470 | } | ||
471 | else | ||
472 | fat_bpb.fsinfo.freecount++; | ||
436 | 473 | ||
437 | /* don't change top 4 bits */ | 474 | /* don't change top 4 bits */ |
438 | sec[thisfatentoffset/sizeof(int)] &= 0xf000000; | 475 | sec[offset] &= SWAB32(0xf000000); |
439 | sec[thisfatentoffset/sizeof(int)] |= val & 0x0fffffff; | 476 | sec[offset] |= SWAB32(val & 0x0fffffff); |
440 | 477 | ||
441 | return 0; | 478 | return 0; |
442 | } | 479 | } |
443 | #endif | ||
444 | 480 | ||
445 | static int read_entry(int entry) | 481 | static int read_fat_entry(int entry) |
446 | { | 482 | { |
447 | unsigned long *sec; | 483 | int sector = entry / CLUSTERS_PER_FAT_SECTOR; |
448 | int fatoffset; | 484 | int offset = entry % CLUSTERS_PER_FAT_SECTOR; |
449 | int thisfatsecnum; | 485 | unsigned int* sec; |
450 | int thisfatentoffset; | ||
451 | int val = -1; | ||
452 | |||
453 | fatoffset = entry * 4; | ||
454 | thisfatsecnum = fatoffset / fat_bpb.bpb_bytspersec + fat_bpb.bpb_rsvdseccnt; | ||
455 | thisfatentoffset = fatoffset % fat_bpb.bpb_bytspersec; | ||
456 | 486 | ||
457 | /* Load the sector if it is not cached */ | 487 | sec = cache_fat_sector(sector); |
458 | sec = cache_fat_sector(thisfatsecnum); | 488 | if (!sec) |
459 | if(!sec) | ||
460 | { | 489 | { |
461 | DEBUGF( "read_entry() - Could not cache sector %d\n", | 490 | DEBUGF( "read_fat_entry() - Could not cache sector %d\n", sector); |
462 | thisfatsecnum); | ||
463 | return -1; | 491 | return -1; |
464 | } | 492 | } |
465 | 493 | ||
466 | val = sec[thisfatentoffset/sizeof(int)]; | 494 | return SWAB32(sec[offset]); |
467 | |||
468 | val = SWAB32(val); | ||
469 | |||
470 | return val; | ||
471 | } | 495 | } |
472 | 496 | ||
473 | static int get_next_cluster(unsigned int cluster) | 497 | static int get_next_cluster(unsigned int cluster) |
474 | { | 498 | { |
475 | int next_cluster; | 499 | int next_cluster; |
476 | 500 | ||
477 | next_cluster = read_entry(cluster); | 501 | next_cluster = read_fat_entry(cluster); |
478 | 502 | ||
479 | /* is this last cluster in chain? */ | 503 | /* is this last cluster in chain? */ |
480 | if ( next_cluster >= 0x0ffffff8 ) | 504 | if ( next_cluster >= FAT_EOF_MARK ) |
481 | return 0; | 505 | return 0; |
482 | else | 506 | else |
483 | return next_cluster; | 507 | return next_cluster; |
484 | } | 508 | } |
485 | 509 | ||
486 | #ifdef DISK_WRITE | 510 | static int flush_fat(void) |
487 | static int flush_fat(struct bpb *bpb) | ||
488 | { | 511 | { |
489 | int i; | 512 | int i; |
490 | int err; | 513 | int err; |
491 | unsigned char *sec; | 514 | unsigned char *sec; |
492 | int secnum; | 515 | int secnum; |
493 | int fatsz; | 516 | unsigned char fsinfo[SECTOR_SIZE]; |
494 | unsigned short d, t; | 517 | unsigned int* intptr; |
495 | char m; | ||
496 | 518 | ||
497 | fatsz = fat_bpb.fatsize; | 519 | LDEBUGF("flush_fat()\n"); |
498 | 520 | ||
499 | for(i = 0;i < FAT_CACHE_SIZE;i++) | 521 | for(i = 0;i < FAT_CACHE_SIZE;i++) |
500 | { | 522 | { |
501 | if(fat_cache[i].ptr && fat_cache[i].dirty) | 523 | if(fat_cache[i].inuse && fat_cache[i].dirty) |
502 | { | 524 | { |
503 | secnum = fat_cache[i].secnum + fat_bpb.bpb_rsvdseccnt + | 525 | secnum = fat_cache[i].secnum + fat_bpb.startsector; |
504 | fat_bpb.startsector; | 526 | LDEBUGF("Flushing FAT sector %x\n", secnum); |
505 | DEBUGF("Flushing FAT sector %d\n", secnum); | 527 | sec = fat_cache_sectors[i]; |
506 | sec = fat_cache[i].ptr; | ||
507 | 528 | ||
508 | /* Write to the first FAT */ | 529 | /* Write to the first FAT */ |
509 | err = ata_write_sectors(secnum, 1, sec); | 530 | err = ata_write_sectors(secnum, 1, sec); |
@@ -514,19 +535,41 @@ static int flush_fat(struct bpb *bpb) | |||
514 | return -1; | 535 | return -1; |
515 | } | 536 | } |
516 | 537 | ||
517 | /* Write to the second FAT */ | 538 | if(fat_bpb.bpb_numfats > 1 ) |
518 | err = ata_write_sectors(secnum + fatsz, 1, sec); | ||
519 | if(err) | ||
520 | { | 539 | { |
521 | DEBUGF( "flush_fat() - Couldn't write" | 540 | /* Write to the second FAT */ |
522 | " sector (%d)\n", secnum + fatsz); | 541 | err = ata_write_sectors(secnum + fat_bpb.fatsize, 1, sec); |
523 | return -1; | 542 | if (err) |
543 | { | ||
544 | DEBUGF( "flush_fat() - Couldn't write" | ||
545 | " sector (%d)\n", secnum + fat_bpb.fatsize); | ||
546 | return -2; | ||
547 | } | ||
524 | } | 548 | } |
525 | fat_cache[i].dirty = 0; | 549 | fat_cache[i].dirty = false; |
526 | } | 550 | } |
527 | } | 551 | } |
528 | 552 | ||
529 | getcurrdostime(&d, &t, &m); | 553 | /* update fsinfo */ |
554 | err = ata_read_sectors(fat_bpb.startsector + fat_bpb.bpb_fsinfo, 1,fsinfo); | ||
555 | if (err) | ||
556 | { | ||
557 | DEBUGF( "flush_fat() - Couldn't read FSInfo (error code %d)\n", err); | ||
558 | return -1; | ||
559 | } | ||
560 | intptr = (int*)&(fsinfo[FSINFO_FREECOUNT]); | ||
561 | *intptr = SWAB32(fat_bpb.fsinfo.freecount); | ||
562 | |||
563 | intptr = (int*)&(fsinfo[FSINFO_NEXTFREE]); | ||
564 | *intptr = SWAB32(fat_bpb.fsinfo.nextfree); | ||
565 | |||
566 | err = ata_write_sectors(fat_bpb.startsector + fat_bpb.bpb_fsinfo,1,fsinfo); | ||
567 | if (err) | ||
568 | { | ||
569 | DEBUGF( "flush_fat() - Couldn't write FSInfo (error code %d)\n", err); | ||
570 | return -1; | ||
571 | } | ||
572 | |||
530 | return 0; | 573 | return 0; |
531 | } | 574 | } |
532 | 575 | ||
@@ -534,10 +577,9 @@ static unsigned int getcurrdostime(unsigned short *dosdate, | |||
534 | unsigned short *dostime, | 577 | unsigned short *dostime, |
535 | unsigned char *dostenth) | 578 | unsigned char *dostenth) |
536 | { | 579 | { |
537 | struct timeb tb; | 580 | #if 0 |
538 | struct tm *tm; | 581 | struct tm *tm; |
539 | 582 | unsigned long now = time(); | |
540 | ftime(&tb); | ||
541 | tm = localtime(&tb.time); | 583 | tm = localtime(&tb.time); |
542 | 584 | ||
543 | *dosdate = ((tm->tm_year - 80) << 9) | | 585 | *dosdate = ((tm->tm_year - 80) << 9) | |
@@ -549,102 +591,92 @@ static unsigned int getcurrdostime(unsigned short *dosdate, | |||
549 | (tm->tm_sec >> 1); | 591 | (tm->tm_sec >> 1); |
550 | 592 | ||
551 | *dostenth = (tm->tm_sec & 1) * 100 + tb.millitm / 10; | 593 | *dostenth = (tm->tm_sec & 1) * 100 + tb.millitm / 10; |
594 | #else | ||
595 | *dosdate = 0; | ||
596 | *dostime = 0; | ||
597 | *dostenth = 0; | ||
598 | #endif | ||
552 | return 0; | 599 | return 0; |
553 | } | 600 | } |
554 | 601 | ||
555 | static int add_dir_entry(unsigned int currdir, struct fat_direntry *de) | 602 | static int add_dir_entry(struct fat_dir* dir, |
603 | struct fat_direntry* de, | ||
604 | struct fat_file* file) | ||
556 | { | 605 | { |
557 | unsigned char buf[SECTOR_SIZE]; | 606 | unsigned char buf[SECTOR_SIZE]; |
558 | unsigned char *eptr; | 607 | unsigned char *eptr; |
559 | int i; | 608 | int i; |
560 | int err; | 609 | int err; |
561 | unsigned int sec; | 610 | int sec; |
562 | unsigned int sec_cnt; | 611 | int sec_cnt; |
563 | int need_to_update_last_empty_marker = 0; | 612 | bool need_to_update_last_empty_marker = false; |
564 | int is_rootdir = (currdir == 0); | 613 | bool done = false; |
565 | int done = 0; | ||
566 | unsigned char firstbyte; | 614 | unsigned char firstbyte; |
615 | int currdir = dir->startcluster; | ||
616 | bool is_rootdir = (currdir == 0); | ||
567 | 617 | ||
568 | if(is_rootdir) | 618 | LDEBUGF( "add_dir_entry()\n"); |
569 | { | 619 | |
620 | if (is_rootdir) | ||
570 | sec = fat_bpb.rootdirsector; | 621 | sec = fat_bpb.rootdirsector; |
571 | } | ||
572 | else | 622 | else |
573 | { | ||
574 | sec = first_sector_of_cluster(currdir); | 623 | sec = first_sector_of_cluster(currdir); |
575 | } | ||
576 | 624 | ||
577 | sec_cnt = 0; | 625 | sec_cnt = 0; |
578 | 626 | ||
579 | while(!done) | 627 | while(!done) |
580 | { | 628 | { |
581 | /* The root dir has a fixed size */ | 629 | if (sec_cnt >= fat_bpb.bpb_secperclus) |
582 | if(is_rootdir) | ||
583 | { | ||
584 | if(sec_cnt >= fat_bpb.bpb_rootentcnt * 32 / fat_bpb.bpb_bytspersec) | ||
585 | { | ||
586 | /* We have reached the last sector of the root dir */ | ||
587 | if(need_to_update_last_empty_marker) | ||
588 | { | ||
589 | /* Since the directory is full, there is no room for | ||
590 | a marker, so we just exit */ | ||
591 | return 0; | ||
592 | } | ||
593 | else | ||
594 | { | ||
595 | DEBUGF( "add_dir_entry() -" | ||
596 | " Root dir is full\n"); | ||
597 | return -1; | ||
598 | } | ||
599 | } | ||
600 | } | ||
601 | else | ||
602 | { | 630 | { |
603 | if(sec_cnt >= fat_bpb.bpb_secperclus) | 631 | int oldcluster = currdir; |
632 | /* We have reached the end of this cluster */ | ||
633 | LDEBUGF("Moving to the next cluster..."); | ||
634 | currdir = get_next_cluster(currdir); | ||
635 | LDEBUGF("new cluster is %d\n", currdir); | ||
636 | |||
637 | if (!currdir) | ||
604 | { | 638 | { |
605 | /* We have reached the end of this cluster */ | 639 | currdir = find_free_cluster(fat_bpb.fsinfo.nextfree); |
606 | DEBUGF("Moving to the next cluster..."); | 640 | if (!currdir) { |
607 | currdir = get_next_cluster(currdir); | 641 | currdir = find_free_cluster(0); |
608 | DEBUGF("new cluster is %d\n", currdir); | 642 | if (!currdir) { |
609 | 643 | DEBUGF("add_dir_entry(): Disk full!\n"); | |
610 | if(!currdir) | 644 | return -1; |
611 | { | 645 | } |
612 | /* This was the last in the chain, | ||
613 | we have to allocate a new cluster */ | ||
614 | /* TODO */ | ||
615 | } | 646 | } |
647 | update_fat_entry(oldcluster, currdir); | ||
616 | } | 648 | } |
617 | } | 649 | } |
618 | 650 | ||
619 | DEBUGF("Reading sector %d...\n", sec); | 651 | LDEBUGF("Reading sector %d...\n", sec); |
620 | /* Read the next sector in the current dir */ | 652 | /* Read the next sector in the current dir */ |
621 | err = ata_read_sectors(sec + fat_bpb.startsector,1,buf); | 653 | err = ata_read_sectors(sec + fat_bpb.startsector,1,buf); |
622 | if(err) | 654 | if (err) |
623 | { | 655 | { |
624 | DEBUGF( "add_dir_entry() - Couldn't read dir sector" | 656 | DEBUGF( "add_dir_entry() - Couldn't read dir sector" |
625 | " (error code %d)\n", err); | 657 | " (error code %d)\n", err); |
626 | return -1; | 658 | return -2; |
627 | } | 659 | } |
628 | 660 | ||
629 | if(need_to_update_last_empty_marker) | 661 | if (need_to_update_last_empty_marker) |
630 | { | 662 | { |
631 | /* All we need to do is to set the first entry to 0 */ | 663 | /* All we need to do is to set the first entry to 0 */ |
632 | DEBUGF("Clearing the first entry in sector %d\n", sec); | 664 | LDEBUGF("Clearing the first entry in sector %x\n", sec); |
633 | buf[0] = 0; | 665 | buf[0] = 0; |
634 | done = 1; | 666 | done = true; |
635 | } | 667 | } |
636 | else | 668 | else |
637 | { | 669 | { |
638 | /* Look for a free slot */ | 670 | /* Look for a free slot */ |
639 | for(i = 0;i < SECTOR_SIZE;i+=32) | 671 | for (i = 0; i < SECTOR_SIZE; i += DIR_ENTRY_SIZE) |
640 | { | 672 | { |
641 | firstbyte = buf[i]; | 673 | firstbyte = buf[i]; |
642 | if(firstbyte == 0xe5 || firstbyte == 0) | 674 | if (firstbyte == 0xe5 || firstbyte == 0) |
643 | { | 675 | { |
644 | DEBUGF("Found free slot at entry %d in sector %d\n", | 676 | LDEBUGF("Found free slot at entry %d in sector %x\n", |
645 | i/32, sec); | 677 | i/DIR_ENTRY_SIZE, sec); |
646 | eptr = &buf[i]; | 678 | eptr = &buf[i]; |
647 | memset(eptr, 0, 32); | 679 | memset(eptr, 0, DIR_ENTRY_SIZE); |
648 | strncpy(&eptr[FATDIR_NAME], de->name, 11); | 680 | strncpy(&eptr[FATDIR_NAME], de->name, 11); |
649 | eptr[FATDIR_ATTR] = de->attr; | 681 | eptr[FATDIR_ATTR] = de->attr; |
650 | eptr[FATDIR_NTRES] = 0; | 682 | eptr[FATDIR_NTRES] = 0; |
@@ -665,31 +697,37 @@ static int add_dir_entry(unsigned int currdir, struct fat_direntry *de) | |||
665 | eptr[FATDIR_FILESIZE+2] = (de->filesize >> 16) & 0xff; | 697 | eptr[FATDIR_FILESIZE+2] = (de->filesize >> 16) & 0xff; |
666 | eptr[FATDIR_FILESIZE+3] = (de->filesize >> 24) & 0xff; | 698 | eptr[FATDIR_FILESIZE+3] = (de->filesize >> 24) & 0xff; |
667 | 699 | ||
700 | /* remember where the dir entry is located */ | ||
701 | file->dirsector = sec; | ||
702 | file->direntry = i/DIR_ENTRY_SIZE; | ||
703 | |||
668 | /* Advance the last_empty_entry marker */ | 704 | /* Advance the last_empty_entry marker */ |
669 | if(firstbyte == 0) | 705 | if (firstbyte == 0) |
670 | { | 706 | { |
671 | i += 32; | 707 | i += DIR_ENTRY_SIZE; |
672 | if(i < SECTOR_SIZE) | 708 | if (i < SECTOR_SIZE) |
673 | { | 709 | { |
674 | buf[i] = 0; | 710 | buf[i] = 0; |
675 | /* We are done */ | 711 | /* We are done */ |
676 | done = 1; | 712 | done = true; |
677 | } | 713 | } |
678 | else | 714 | else |
679 | { | 715 | { |
680 | /* We must fill in the first entry | 716 | /* We must fill in the first entry |
681 | in the next sector */ | 717 | in the next sector */ |
682 | need_to_update_last_empty_marker = 1; | 718 | need_to_update_last_empty_marker = true; |
683 | } | 719 | } |
684 | } | 720 | } |
721 | else | ||
722 | done = true; | ||
685 | 723 | ||
686 | err = ata_write_sectors(sec + fat_bpb.startsector,1,buf); | 724 | err = ata_write_sectors(sec + fat_bpb.startsector,1,buf); |
687 | if(err) | 725 | if (err) |
688 | { | 726 | { |
689 | DEBUGF( "add_dir_entry() - " | 727 | DEBUGF( "add_dir_entry() - " |
690 | " Couldn't write dir" | 728 | " Couldn't write dir" |
691 | " sector (error code %d)\n", err); | 729 | " sector (error code %d)\n", err); |
692 | return -1; | 730 | return -3; |
693 | } | 731 | } |
694 | break; | 732 | break; |
695 | } | 733 | } |
@@ -746,11 +784,6 @@ static int create_dos_name(unsigned char *name, unsigned char *newname) | |||
746 | int i; | 784 | int i; |
747 | char *ext; | 785 | char *ext; |
748 | 786 | ||
749 | if(strlen(name) > 12) | ||
750 | { | ||
751 | return -1; | ||
752 | } | ||
753 | |||
754 | strcpy(n, name); | 787 | strcpy(n, name); |
755 | 788 | ||
756 | ext = strchr(n, '.'); | 789 | ext = strchr(n, '.'); |
@@ -763,7 +796,7 @@ static int create_dos_name(unsigned char *name, unsigned char *newname) | |||
763 | In either case it is illegal. */ | 796 | In either case it is illegal. */ |
764 | if(n[0] == 0) | 797 | if(n[0] == 0) |
765 | { | 798 | { |
766 | return -1; | 799 | return -2; |
767 | } | 800 | } |
768 | 801 | ||
769 | /* Name part */ | 802 | /* Name part */ |
@@ -781,10 +814,10 @@ static int create_dos_name(unsigned char *name, unsigned char *newname) | |||
781 | } | 814 | } |
782 | 815 | ||
783 | /* Extension part */ | 816 | /* Extension part */ |
784 | for(i = 0;ext && ext[i] && (i < 3);i++) | 817 | for (i = 0;ext && ext[i] && (i < 3);i++) |
785 | { | 818 | { |
786 | c = char2dos(ext[i]); | 819 | c = char2dos(ext[i]); |
787 | if(c) | 820 | if (c) |
788 | { | 821 | { |
789 | newname[8+i] = toupper(c); | 822 | newname[8+i] = toupper(c); |
790 | } | 823 | } |
@@ -796,50 +829,48 @@ static int create_dos_name(unsigned char *name, unsigned char *newname) | |||
796 | return 0; | 829 | return 0; |
797 | } | 830 | } |
798 | 831 | ||
799 | int fat_create_dir(unsigned int currdir, char *name) | 832 | static void update_dir_entry( struct fat_file* file, int size ) |
800 | { | 833 | { |
801 | struct fat_direntry de; | 834 | unsigned char buf[SECTOR_SIZE]; |
835 | int sector = file->dirsector + fat_bpb.startsector; | ||
836 | unsigned char* entry = buf + file->direntry * DIR_ENTRY_SIZE; | ||
837 | unsigned int* sizeptr; | ||
838 | unsigned short* clusptr; | ||
802 | int err; | 839 | int err; |
803 | 840 | ||
804 | DEBUGF("fat_create_file()\n"); | 841 | LDEBUGF("update_dir_entry(cluster:%x entry:%d size:%d)\n", |
805 | memset(&de, 0, sizeof(struct fat_direntry)); | 842 | file->firstcluster,file->direntry,size); |
806 | if(create_dos_name(name, de.name) < 0) | 843 | |
844 | if ( file->direntry >= (SECTOR_SIZE / DIR_ENTRY_SIZE) ) { | ||
845 | DEBUGF("update_dir_entry(): Illegal entry %d!\n",file->direntry); | ||
846 | return; | ||
847 | } | ||
848 | |||
849 | err = ata_read_sectors(sector, 1, buf); | ||
850 | if (err) | ||
807 | { | 851 | { |
808 | DEBUGF( "fat_create_file() - Illegal file name (%s)\n", name); | 852 | DEBUGF( "update_dir_entry() - Couldn't read dir sector %d" |
809 | return -1; | 853 | " (error code %d)\n", sector, err); |
854 | return; | ||
810 | } | 855 | } |
856 | |||
857 | clusptr = (short*)(entry + FATDIR_FSTCLUSHI); | ||
858 | *clusptr = SWAB16(file->firstcluster >> 16); | ||
811 | 859 | ||
812 | getcurrdostime(&de.crtdate, &de.crttime, &de.crttimetenth); | 860 | clusptr = (short*)(entry + FATDIR_FSTCLUSLO); |
813 | de.wrtdate = de.crtdate; | 861 | *clusptr = SWAB16(file->firstcluster & 0xffff); |
814 | de.wrttime = de.crttime; | ||
815 | de.filesize = 0; | ||
816 | de.attr = FAT_ATTR_DIRECTORY; | ||
817 | |||
818 | err = add_dir_entry(currdir, &de); | ||
819 | return 0; | ||
820 | } | ||
821 | 862 | ||
822 | int fat_create_file(unsigned int currdir, char *name) | 863 | sizeptr = (int*)(entry + FATDIR_FILESIZE); |
823 | { | 864 | *sizeptr = SWAB32(size); |
824 | struct fat_direntry de; | ||
825 | int err; | ||
826 | 865 | ||
827 | DEBUGF("fat_create_file()\n"); | 866 | err = ata_write_sectors(sector, 1, buf); |
828 | memset(&de, 0, sizeof(struct fat_direntry)); | 867 | if (err) |
829 | if(create_dos_name(name, de.name) < 0) | ||
830 | { | 868 | { |
831 | DEBUGF( "fat_create_file() - Illegal file name (%s)\n", name); | 869 | DEBUGF( "update_file_size() - Couldn't write dir sector %d" |
832 | return -1; | 870 | " (error code %d)\n", sector, err); |
871 | return; | ||
833 | } | 872 | } |
834 | getcurrdostime(&de.crtdate, &de.crttime, &de.crttimetenth); | ||
835 | de.wrtdate = de.crtdate; | ||
836 | de.wrttime = de.crttime; | ||
837 | de.filesize = 0; | ||
838 | |||
839 | err = add_dir_entry(currdir, &de); | ||
840 | return err; | ||
841 | } | 873 | } |
842 | #endif | ||
843 | 874 | ||
844 | static int parse_direntry(struct fat_direntry *de, unsigned char *buf) | 875 | static int parse_direntry(struct fat_direntry *de, unsigned char *buf) |
845 | { | 876 | { |
@@ -866,37 +897,138 @@ static int parse_direntry(struct fat_direntry *de, unsigned char *buf) | |||
866 | return 1; | 897 | return 1; |
867 | } | 898 | } |
868 | 899 | ||
869 | int fat_open( unsigned int startcluster, struct fat_file *file) | 900 | int fat_open(unsigned int startcluster, |
901 | struct fat_file *file, | ||
902 | struct fat_dir* dir) | ||
870 | { | 903 | { |
871 | file->firstcluster = startcluster; | 904 | file->firstcluster = startcluster; |
872 | file->nextcluster = startcluster; | 905 | file->nextcluster = startcluster; |
873 | file->nextsector = cluster2sec(startcluster); | 906 | file->nextsector = cluster2sec(startcluster); |
874 | file->sectornum = 0; | 907 | file->sectornum = 0; |
908 | |||
909 | /* remember where the file's dir entry is located */ | ||
910 | file->dirsector = dir->cached_sec; | ||
911 | file->direntry = (dir->entry % DIR_ENTRIES_PER_SECTOR) - 1; | ||
912 | LDEBUGF("fat_open: entry %d\n",file->direntry); | ||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | int fat_create_file(char* name, | ||
917 | struct fat_file* file, | ||
918 | struct fat_dir* dir) | ||
919 | { | ||
920 | struct fat_direntry de; | ||
921 | int err; | ||
922 | |||
923 | LDEBUGF("fat_create_file(\"%s\",%x,%x)\n",name,file,dir); | ||
924 | memset(&de, 0, sizeof(struct fat_direntry)); | ||
925 | if (create_dos_name(name, de.name) < 0) | ||
926 | { | ||
927 | DEBUGF( "fat_create_file() - Illegal file name (%s)\n", name); | ||
928 | return -1; | ||
929 | } | ||
930 | getcurrdostime(&de.crtdate, &de.crttime, &de.crttimetenth); | ||
931 | de.wrtdate = de.crtdate; | ||
932 | de.wrttime = de.crttime; | ||
933 | de.filesize = 0; | ||
934 | |||
935 | err = add_dir_entry(dir, &de, file); | ||
936 | if (!err) { | ||
937 | file->firstcluster = 0; | ||
938 | file->nextcluster = 0; | ||
939 | file->nextsector = 0; | ||
940 | file->sectornum = 0; | ||
941 | } | ||
942 | |||
943 | return err; | ||
944 | } | ||
945 | |||
946 | int fat_closewrite(struct fat_file *file, int size) | ||
947 | { | ||
948 | int endcluster = file->nextcluster; | ||
949 | int next, last = endcluster; | ||
950 | |||
951 | /* free unused clusters, if any */ | ||
952 | for ( next = get_next_cluster(last); next; last = next ) { | ||
953 | LDEBUGF("Clearing cluster %x\n",last); | ||
954 | update_fat_entry(last,0); | ||
955 | } | ||
956 | |||
957 | /* mark last used cluster as last in chain */ | ||
958 | update_fat_entry(endcluster, FAT_EOF_MARK); | ||
959 | |||
960 | flush_fat(); | ||
961 | |||
962 | update_dir_entry(file, size); | ||
963 | |||
875 | return 0; | 964 | return 0; |
876 | } | 965 | } |
877 | 966 | ||
878 | int fat_read( struct fat_file *file, int sectorcount, void* buf ) | 967 | int fat_readwrite( struct fat_file *file, int sectorcount, |
968 | void* buf, bool write ) | ||
879 | { | 969 | { |
880 | int cluster = file->nextcluster; | 970 | int cluster = file->nextcluster; |
881 | int sector = file->nextsector; | 971 | int sector = file->nextsector; |
882 | int numsec = file->sectornum; | 972 | int numsec = file->sectornum; |
883 | int first = sector, last = sector; | 973 | int first, last; |
884 | int err, i; | 974 | int err, i; |
885 | 975 | ||
976 | LDEBUGF( "fat_readwrite(file:%x,count:%d,buf:%x,%s)\n", | ||
977 | cluster,sectorcount,buf,write?"write":"read"); | ||
978 | |||
886 | if ( sector == -1 ) | 979 | if ( sector == -1 ) |
887 | return 0; | 980 | return 0; |
888 | 981 | ||
889 | /* find sequential sectors and read them all at once */ | 982 | if ( write && !cluster) { |
983 | /* new file */ | ||
984 | cluster = find_free_cluster(fat_bpb.fsinfo.nextfree); | ||
985 | if (!cluster) { | ||
986 | cluster = find_free_cluster(0); | ||
987 | if (!cluster) { | ||
988 | DEBUGF("fat_readwrite(): Disk full!\n"); | ||
989 | return -3; | ||
990 | } | ||
991 | } | ||
992 | file->firstcluster = cluster; | ||
993 | sector = cluster2sec(cluster); | ||
994 | if (sector<0) | ||
995 | return -1; | ||
996 | } | ||
997 | |||
998 | first = sector; | ||
999 | last = sector; | ||
1000 | |||
1001 | /* find sequential sectors and read/write them all at once */ | ||
890 | for (i=0; i<sectorcount && sector>=0; i++ ) { | 1002 | for (i=0; i<sectorcount && sector>=0; i++ ) { |
891 | numsec++; | 1003 | numsec++; |
892 | if ( numsec >= fat_bpb.bpb_secperclus ) { | 1004 | if ( numsec >= fat_bpb.bpb_secperclus ) { |
1005 | int oldcluster = cluster; | ||
893 | cluster = get_next_cluster(cluster); | 1006 | cluster = get_next_cluster(cluster); |
894 | if (!cluster) { | 1007 | if (!cluster) { |
895 | /* end of file */ | 1008 | if ( write ) { |
896 | sector = -1; | 1009 | /* writing past end-of-file, |
1010 | find a new free cluster to use. */ | ||
1011 | cluster = find_free_cluster(cluster); | ||
1012 | if (!cluster) { | ||
1013 | /* no cluster found after last, | ||
1014 | search from beginning */ | ||
1015 | cluster = find_free_cluster(0); | ||
1016 | if (!cluster) { | ||
1017 | /* no free clusters. disk is full. */ | ||
1018 | sector = -1; | ||
1019 | DEBUGF("fat_readwrite(): Disk full!\n"); | ||
1020 | } | ||
1021 | } | ||
1022 | if ( cluster ) | ||
1023 | update_fat_entry(oldcluster, cluster); | ||
1024 | } | ||
1025 | else { | ||
1026 | /* reading past end-of-file */ | ||
1027 | sector = -1; | ||
1028 | } | ||
897 | } | 1029 | } |
898 | else | 1030 | |
899 | { | 1031 | if (cluster) { |
900 | sector = cluster2sec(cluster); | 1032 | sector = cluster2sec(cluster); |
901 | if (sector<0) | 1033 | if (sector<0) |
902 | return -1; | 1034 | return -1; |
@@ -910,11 +1042,14 @@ int fat_read( struct fat_file *file, int sectorcount, void* buf ) | |||
910 | (i == sectorcount-1) || /* last sector requested? */ | 1042 | (i == sectorcount-1) || /* last sector requested? */ |
911 | (last-first+1 == 256) ) { /* max 256 sectors per ata request */ | 1043 | (last-first+1 == 256) ) { /* max 256 sectors per ata request */ |
912 | int count = last-first+1; | 1044 | int count = last-first+1; |
913 | err = ata_read_sectors(first + fat_bpb.startsector, count, buf); | 1045 | if (write) |
914 | if(err) { | 1046 | err = ata_write_sectors(first + fat_bpb.startsector, count, buf); |
915 | DEBUGF( "fat_read() - Couldn't read sector %d" | 1047 | else |
1048 | err = ata_read_sectors(first + fat_bpb.startsector, count, buf); | ||
1049 | if (err) { | ||
1050 | DEBUGF( "fat_readwrite() - Couldn't read sector %d" | ||
916 | " (error code %d)\n", sector,err); | 1051 | " (error code %d)\n", sector,err); |
917 | return -1; | 1052 | return -2; |
918 | } | 1053 | } |
919 | ((char*)buf) += count * SECTOR_SIZE; | 1054 | ((char*)buf) += count * SECTOR_SIZE; |
920 | first = sector; | 1055 | first = sector; |
@@ -970,9 +1105,9 @@ int fat_seek(struct fat_file *file, int seeksector ) | |||
970 | return 0; | 1105 | return 0; |
971 | } | 1106 | } |
972 | 1107 | ||
973 | int fat_opendir(struct fat_dir *dir, unsigned int currdir) | 1108 | int fat_opendir(struct fat_dir *dir, unsigned int startcluster) |
974 | { | 1109 | { |
975 | int is_rootdir = (currdir == 0); | 1110 | int is_rootdir = (startcluster == 0); |
976 | unsigned int sec; | 1111 | unsigned int sec; |
977 | int err; | 1112 | int err; |
978 | 1113 | ||
@@ -982,7 +1117,7 @@ int fat_opendir(struct fat_dir *dir, unsigned int currdir) | |||
982 | } | 1117 | } |
983 | else | 1118 | else |
984 | { | 1119 | { |
985 | sec = first_sector_of_cluster(currdir); | 1120 | sec = first_sector_of_cluster(startcluster); |
986 | } | 1121 | } |
987 | 1122 | ||
988 | /* Read the first sector in the current dir */ | 1123 | /* Read the first sector in the current dir */ |
@@ -997,13 +1132,14 @@ int fat_opendir(struct fat_dir *dir, unsigned int currdir) | |||
997 | dir->entry = 0; | 1132 | dir->entry = 0; |
998 | dir->cached_sec = sec; | 1133 | dir->cached_sec = sec; |
999 | dir->num_sec = 0; | 1134 | dir->num_sec = 0; |
1135 | dir->startcluster = startcluster; | ||
1000 | 1136 | ||
1001 | return 0; | 1137 | return 0; |
1002 | } | 1138 | } |
1003 | 1139 | ||
1004 | int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | 1140 | int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) |
1005 | { | 1141 | { |
1006 | int done = 0; | 1142 | bool done = false; |
1007 | int i; | 1143 | int i; |
1008 | int err; | 1144 | int err; |
1009 | unsigned char firstbyte; | 1145 | unsigned char firstbyte; |
@@ -1013,29 +1149,30 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
1013 | 1149 | ||
1014 | while(!done) | 1150 | while(!done) |
1015 | { | 1151 | { |
1016 | for(i = dir->entry;i < SECTOR_SIZE/32;i++) | 1152 | for (i = dir->entry; i < SECTOR_SIZE/DIR_ENTRY_SIZE; i++) |
1017 | { | 1153 | { |
1018 | firstbyte = dir->cached_buf[i*32]; | 1154 | firstbyte = dir->cached_buf[i*DIR_ENTRY_SIZE]; |
1019 | 1155 | ||
1020 | if(firstbyte == 0xe5) { | 1156 | if (firstbyte == 0xe5) { |
1021 | /* free entry */ | 1157 | /* free entry */ |
1022 | sectoridx = 0; | 1158 | sectoridx = 0; |
1023 | continue; | 1159 | continue; |
1024 | } | 1160 | } |
1025 | 1161 | ||
1026 | if(firstbyte == 0) { | 1162 | if (firstbyte == 0) { |
1027 | /* last entry */ | 1163 | /* last entry */ |
1028 | entry->name[0] = 0; | 1164 | entry->name[0] = 0; |
1029 | return 0; | 1165 | return 0; |
1030 | } | 1166 | } |
1031 | 1167 | ||
1032 | /* longname entry? */ | 1168 | /* longname entry? */ |
1033 | if ( ( dir->cached_buf[i*32 + FATDIR_ATTR] & | 1169 | if ( ( dir->cached_buf[i*DIR_ENTRY_SIZE + FATDIR_ATTR] & |
1034 | FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) { | 1170 | FAT_ATTR_LONG_NAME_MASK ) == FAT_ATTR_LONG_NAME ) { |
1035 | longarray[longs++] = i*32 + sectoridx; | 1171 | longarray[longs++] = i*DIR_ENTRY_SIZE + sectoridx; |
1036 | } | 1172 | } |
1037 | else { | 1173 | else { |
1038 | if ( parse_direntry(entry, &dir->cached_buf[i*32]) ) { | 1174 | if ( parse_direntry(entry, |
1175 | &dir->cached_buf[i*DIR_ENTRY_SIZE]) ) { | ||
1039 | 1176 | ||
1040 | /* don't return volume id entry */ | 1177 | /* don't return volume id entry */ |
1041 | if ( entry->attr == FAT_ATTR_VOLUME_ID ) | 1178 | if ( entry->attr == FAT_ATTR_VOLUME_ID ) |
@@ -1076,7 +1213,7 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
1076 | } | 1213 | } |
1077 | entry->name[l]=0; | 1214 | entry->name[l]=0; |
1078 | } | 1215 | } |
1079 | done = 1; | 1216 | done = true; |
1080 | sectoridx = 0; | 1217 | sectoridx = 0; |
1081 | break; | 1218 | break; |
1082 | } | 1219 | } |
@@ -1091,7 +1228,7 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
1091 | sectoridx += SECTOR_SIZE; | 1228 | sectoridx += SECTOR_SIZE; |
1092 | 1229 | ||
1093 | /* Next sector? */ | 1230 | /* Next sector? */ |
1094 | if(i < SECTOR_SIZE/32) | 1231 | if (i < SECTOR_SIZE / DIR_ENTRY_SIZE) |
1095 | { | 1232 | { |
1096 | i++; | 1233 | i++; |
1097 | } | 1234 | } |
@@ -1100,7 +1237,7 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
1100 | dir->num_sec++; | 1237 | dir->num_sec++; |
1101 | 1238 | ||
1102 | /* Do we need to advance one cluster? */ | 1239 | /* Do we need to advance one cluster? */ |
1103 | if(dir->num_sec < fat_bpb.bpb_secperclus) | 1240 | if (dir->num_sec < fat_bpb.bpb_secperclus) |
1104 | { | 1241 | { |
1105 | dir->cached_sec++; | 1242 | dir->cached_sec++; |
1106 | } | 1243 | } |
@@ -1113,16 +1250,16 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
1113 | } | 1250 | } |
1114 | dir->num_sec = 0; | 1251 | dir->num_sec = 0; |
1115 | cluster = get_next_cluster( cluster ); | 1252 | cluster = get_next_cluster( cluster ); |
1116 | if(!cluster) | 1253 | if (!cluster) |
1117 | { | 1254 | { |
1118 | DEBUGF("End of cluster chain.\n"); | 1255 | DEBUGF("End of cluster chain.\n"); |
1119 | return -1; | 1256 | return -2; |
1120 | } | 1257 | } |
1121 | dir->cached_sec = cluster2sec(cluster); | 1258 | dir->cached_sec = cluster2sec(cluster); |
1122 | if ( dir->cached_sec < 0 ) | 1259 | if ( dir->cached_sec < 0 ) |
1123 | { | 1260 | { |
1124 | DEBUGF("Invalid cluster: %d\n",cluster); | 1261 | DEBUGF("Invalid cluster: %d\n",cluster); |
1125 | return -1; | 1262 | return -3; |
1126 | } | 1263 | } |
1127 | 1264 | ||
1128 | } | 1265 | } |
@@ -1130,11 +1267,11 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) | |||
1130 | /* Read the next sector */ | 1267 | /* Read the next sector */ |
1131 | err = ata_read_sectors(dir->cached_sec + fat_bpb.startsector, 1, | 1268 | err = ata_read_sectors(dir->cached_sec + fat_bpb.startsector, 1, |
1132 | dir->cached_buf); | 1269 | dir->cached_buf); |
1133 | if(err) | 1270 | if (err) |
1134 | { | 1271 | { |
1135 | DEBUGF( "fat_getnext() - Couldn't read dir sector" | 1272 | DEBUGF( "fat_getnext() - Couldn't read dir sector" |
1136 | " (error code %d)\n", err); | 1273 | " (error code %d)\n", err); |
1137 | return -1; | 1274 | return -4; |
1138 | } | 1275 | } |
1139 | 1276 | ||
1140 | i = 0; | 1277 | i = 0; |
diff --git a/firmware/drivers/fat.h b/firmware/drivers/fat.h index 836d5c6866..3052488c5a 100644 --- a/firmware/drivers/fat.h +++ b/firmware/drivers/fat.h | |||
@@ -20,6 +20,8 @@ | |||
20 | #ifndef FAT_H | 20 | #ifndef FAT_H |
21 | #define FAT_H | 21 | #define FAT_H |
22 | 22 | ||
23 | #include <stdbool.h> | ||
24 | |||
23 | #define SECTOR_SIZE 512 | 25 | #define SECTOR_SIZE 512 |
24 | 26 | ||
25 | struct fat_direntry | 27 | struct fat_direntry |
@@ -50,6 +52,7 @@ struct fat_dir | |||
50 | int cached_sec; | 52 | int cached_sec; |
51 | int num_sec; | 53 | int num_sec; |
52 | unsigned char cached_buf[SECTOR_SIZE]; | 54 | unsigned char cached_buf[SECTOR_SIZE]; |
55 | int startcluster; | ||
53 | }; | 56 | }; |
54 | 57 | ||
55 | struct fat_file | 58 | struct fat_file |
@@ -58,17 +61,23 @@ struct fat_file | |||
58 | int nextcluster; /* cluster of last access */ | 61 | int nextcluster; /* cluster of last access */ |
59 | int nextsector; /* sector of last access */ | 62 | int nextsector; /* sector of last access */ |
60 | int sectornum; /* sector number in this cluster */ | 63 | int sectornum; /* sector number in this cluster */ |
64 | int dirsector; /* sector where the dir entry is located */ | ||
65 | int direntry; /* dir entry index in sector */ | ||
61 | }; | 66 | }; |
62 | 67 | ||
63 | extern int fat_mount(int startsector); | 68 | extern int fat_mount(int startsector); |
64 | 69 | ||
65 | #ifdef DISK_WRITE | ||
66 | extern int fat_create_file(unsigned int currdir, char *name); | ||
67 | extern int fat_create_dir(unsigned int currdir, char *name); | 70 | extern int fat_create_dir(unsigned int currdir, char *name); |
68 | #endif | ||
69 | extern int fat_startsector(void); | 71 | extern int fat_startsector(void); |
70 | extern int fat_open(unsigned int cluster, struct fat_file *ent); | 72 | extern int fat_open(unsigned int cluster, |
71 | extern int fat_read(struct fat_file *ent, int sectorcount, void* buf ); | 73 | struct fat_file* ent, |
74 | struct fat_dir* dir); | ||
75 | extern int fat_create_file(char* name, | ||
76 | struct fat_file* ent, | ||
77 | struct fat_dir* dir); | ||
78 | extern int fat_readwrite(struct fat_file *ent, int sectorcount, | ||
79 | void* buf, bool write ); | ||
80 | extern int fat_closewrite(struct fat_file *ent, int size); | ||
72 | extern int fat_seek(struct fat_file *ent, int sector ); | 81 | extern int fat_seek(struct fat_file *ent, int sector ); |
73 | 82 | ||
74 | extern int fat_opendir(struct fat_dir *ent, unsigned int currdir); | 83 | extern int fat_opendir(struct fat_dir *ent, unsigned int currdir); |
diff --git a/firmware/test/fat/README b/firmware/test/fat/README new file mode 100644 index 0000000000..76141c0044 --- /dev/null +++ b/firmware/test/fat/README | |||
@@ -0,0 +1,25 @@ | |||
1 | This code is for testing the Rockbox fat code on a dummy drive image file. | ||
2 | |||
3 | Dummy image | ||
4 | ----------- | ||
5 | Here's how to create a 1 gig dummy drive image in linux: | ||
6 | |||
7 | # dd if=/dev/hda of=disk.img bs=1M count=1024 | ||
8 | |||
9 | You can then format disk.img as a FAT32 partition: | ||
10 | |||
11 | # mkdosfs -F 32 disk.img | ||
12 | |||
13 | To mount the image, your linux kernel must include the loopback device: | ||
14 | |||
15 | # mount -o loop disk.img /mnt/image | ||
16 | |||
17 | Now copy some test data to the disk, umount it and start testing. | ||
18 | |||
19 | |||
20 | Test code | ||
21 | --------- | ||
22 | The files in this dir build the 'fat' program. It will read 'disk.img' and | ||
23 | treat is as a real disk, thanks to the ata-sim.c module. | ||
24 | |||
25 | Modify the main.c source code to make it perform the tests you want. | ||
diff --git a/firmware/test/fat/ata-sim.c b/firmware/test/fat/ata-sim.c index ab7266d6a0..a37fabcfc0 100644 --- a/firmware/test/fat/ata-sim.c +++ b/firmware/test/fat/ata-sim.c | |||
@@ -24,6 +24,13 @@ int ata_read_sectors(unsigned long start, unsigned char count, void* buf) | |||
24 | 24 | ||
25 | int ata_write_sectors(unsigned long start, unsigned char count, void* buf) | 25 | int ata_write_sectors(unsigned long start, unsigned char count, void* buf) |
26 | { | 26 | { |
27 | DEBUGF("Writing block 0x%lx\n",start); | ||
28 | |||
29 | if (start == 0) { | ||
30 | DEBUGF("Holy crap! You're writing on sector 0!\n"); | ||
31 | exit(0); | ||
32 | } | ||
33 | |||
27 | if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) { | 34 | if(fseek(file,start*BLOCK_SIZE,SEEK_SET)) { |
28 | perror("fseek"); | 35 | perror("fseek"); |
29 | return -1; | 36 | return -1; |
diff --git a/firmware/test/fat/main.c b/firmware/test/fat/main.c index 4a11e0a08a..1b9fd22183 100644 --- a/firmware/test/fat/main.c +++ b/firmware/test/fat/main.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <stdio.h> | 1 | #include <stdio.h> |
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <string.h> | 3 | #include <string.h> |
4 | #include <stdarg.h> | ||
4 | #include "fat.h" | 5 | #include "fat.h" |
5 | #include "debug.h" | 6 | #include "debug.h" |
6 | #include "disk.h" | 7 | #include "disk.h" |
@@ -14,6 +15,15 @@ void dbg_dump_sector(int sec); | |||
14 | void dbg_dump_buffer(unsigned char *buf); | 15 | void dbg_dump_buffer(unsigned char *buf); |
15 | void dbg_console(void); | 16 | void dbg_console(void); |
16 | 17 | ||
18 | void panicf( char *fmt, ...) | ||
19 | { | ||
20 | va_list ap; | ||
21 | va_start( ap, fmt ); | ||
22 | vprintf( fmt, ap ); | ||
23 | va_end( ap ); | ||
24 | exit(0); | ||
25 | } | ||
26 | |||
17 | void dbg_dump_sector(int sec) | 27 | void dbg_dump_sector(int sec) |
18 | { | 28 | { |
19 | unsigned char buf[512]; | 29 | unsigned char buf[512]; |
@@ -75,14 +85,16 @@ void dbg_dir(char* currdir) | |||
75 | void dbg_mkfile(char* name) | 85 | void dbg_mkfile(char* name) |
76 | { | 86 | { |
77 | char* text = "Detta är en dummy-text\n"; | 87 | char* text = "Detta är en dummy-text\n"; |
88 | int i; | ||
78 | int fd = open(name,O_WRONLY); | 89 | int fd = open(name,O_WRONLY); |
79 | if (fd<0) { | 90 | if (fd<0) { |
80 | DEBUGF("Failed creating file\n"); | 91 | DEBUGF("Failed creating file\n"); |
81 | return; | 92 | return; |
82 | } | 93 | } |
83 | if (write(fd, text, strlen(text)) < 0) | 94 | for (i=0;i<200;i++) |
84 | DEBUGF("Failed writing data\n"); | 95 | if (write(fd, text, strlen(text)) < 0) |
85 | 96 | DEBUGF("Failed writing data\n"); | |
97 | |||
86 | close(fd); | 98 | close(fd); |
87 | } | 99 | } |
88 | 100 | ||
@@ -168,6 +180,33 @@ void dbg_tail(char* name) | |||
168 | close(fd); | 180 | close(fd); |
169 | } | 181 | } |
170 | 182 | ||
183 | void dbg_head(char* name) | ||
184 | { | ||
185 | unsigned char buf[SECTOR_SIZE*5]; | ||
186 | int fd,rc; | ||
187 | |||
188 | fd = open(name,O_RDONLY); | ||
189 | if (fd<0) | ||
190 | return; | ||
191 | DEBUGF("Got file descriptor %d\n",fd); | ||
192 | |||
193 | rc = read(fd, buf, SECTOR_SIZE); | ||
194 | if( rc > 0 ) | ||
195 | { | ||
196 | buf[rc]=0; | ||
197 | printf("%d: %s\n", strlen(buf), buf); | ||
198 | } | ||
199 | else if ( rc == 0 ) { | ||
200 | DEBUGF("EOF\n"); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | DEBUGF("Failed reading file: %d\n",rc); | ||
205 | } | ||
206 | |||
207 | close(fd); | ||
208 | } | ||
209 | |||
171 | char current_directory[256] = "\\"; | 210 | char current_directory[256] = "\\"; |
172 | int last_secnum = 0; | 211 | int last_secnum = 0; |
173 | 212 | ||
@@ -284,9 +323,12 @@ int main(int argc, char *argv[]) | |||
284 | } | 323 | } |
285 | 324 | ||
286 | //dbg_console(); | 325 | //dbg_console(); |
287 | //dbg_tail("/fat.h"); | ||
288 | //dbg_dir("/"); | 326 | //dbg_dir("/"); |
289 | dbg_mkfile("/apa.txt"); | 327 | #if 1 |
328 | dbg_head("/bepa.txt"); | ||
329 | #else | ||
330 | dbg_mkfile("/bepa.txt"); | ||
331 | #endif | ||
290 | dbg_dir("/"); | 332 | dbg_dir("/"); |
291 | 333 | ||
292 | return 0; | 334 | return 0; |