freemyipod r69 - Code Review

Jump to: navigation, search
Repository:freemyipod
Revision:r68‎ | r69 | r70 >
Date:23:52, 9 August 2010
Author:theseven
Status:new
Tags:
Comment:
Make sure that storage accesses through the FAT32 layer are aligned properly
Modified paths:
  • /embios/trunk/file.c (modified) (history)
  • /embios/trunk/target/ipodnano2g/ftl.c (modified) (history)
  • /embios/trunk/target/ipodnano2g/nand.c (modified) (history)

Diff [purge]

Index: embios/trunk/target/ipodnano2g/nand.c
@@ -377,11 +377,11 @@
378378 uint8_t* data = (uint8_t*)databuffer;
379379 uint8_t* spare = nand_spare;
380380 if (sparebuffer) spare = (uint8_t*)sparebuffer;
381 - if ((uint32_t)databuffer & 0xf)
 381+ if ((uint32_t)databuffer & (CACHEALIGN_SIZE - 1))
382382 panicf(PANIC_KILLUSERTHREADS,
383383 "nand_read_page: Misaligned data buffer at %08X (bank %lu, page %lu)",
384384 (unsigned int)databuffer, bank, page);
385 - if ((uint32_t)sparebuffer & 0xf)
 385+ if ((uint32_t)sparebuffer & (CACHEALIGN_SIZE - 1))
386386 panicf(PANIC_KILLUSERTHREADS,
387387 "nand_read_page: Misaligned spare buffer at %08X (bank %lu, page %lu)",
388388 (unsigned int)sparebuffer, bank, page);
Index: embios/trunk/target/ipodnano2g/ftl.c
@@ -1287,7 +1287,7 @@
12881288 DEBUGF("FTL: Reading %d sectors starting at %d", count, sector);
12891289 #endif
12901290
1291 - if ((uint32_t)buffer & 0xf)
 1291+ if ((uint32_t)buffer & (CACHEALIGN_SIZE - 1))
12921292 panicf(PANIC_KILLTHREAD,
12931293 "ftl_read: Misaligned data buffer at %08X (sector %lu, count %lu)",
12941294 (unsigned int)buffer, sector, count);
@@ -1947,7 +1947,7 @@
19481948 DEBUGF("FTL: Writing %d sectors starting at %d", count, sector);
19491949 #endif
19501950
1951 - if ((uint32_t)buffer & 0xf)
 1951+ if ((uint32_t)buffer & (CACHEALIGN_SIZE - 1))
19521952 panicf(PANIC_KILLTHREAD,
19531953 "ftl_write: Misaligned data buffer at %08X (sector %lu, count %lu)",
19541954 (unsigned int)buffer, sector, count);
Index: embios/trunk/file.c
@@ -1,767 +1,772 @@
2 -/***************************************************************************
3 - * __________ __ ___.
4 - * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 - * \/ \/ \/ \/ \/
9 - * $Id: file.c 26191 2010-05-20 12:59:12Z funman $
10 - *
11 - * Copyright (C) 2002 by Björn Stenberg
12 - *
13 - * This program is free software; you can redistribute it and/or
14 - * modify it under the terms of the GNU General Public License
15 - * as published by the Free Software Foundation; either version 2
16 - * of the License, or (at your option) any later version.
17 - *
18 - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 - * KIND, either express or implied.
20 - *
21 - ****************************************************************************/
22 -#include "global.h"
23 -#include <string.h>
24 -#include <errno.h>
25 -#include "file.h"
26 -#include "fat.h"
27 -#include "dir.h"
28 -#include "util.h"
29 -
30 -/*
31 - These functions provide a roughly POSIX-compatible file IO API.
32 -
33 - Since the fat32 driver only manages sectors, we maintain a one-sector
34 - cache for each open file. This way we can provide byte access without
35 - having to re-read the sector each time.
36 - The penalty is the RAM used for the cache and slightly more complex code.
37 -*/
38 -
 2+/***************************************************************************
 3+ * __________ __ ___.
 4+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
 5+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
 6+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
 7+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
 8+ * \/ \/ \/ \/ \/
 9+ * $Id: file.c 26191 2010-05-20 12:59:12Z funman $
 10+ *
 11+ * Copyright (C) 2002 by Björn Stenberg
 12+ *
 13+ * This program is free software; you can redistribute it and/or
 14+ * modify it under the terms of the GNU General Public License
 15+ * as published by the Free Software Foundation; either version 2
 16+ * of the License, or (at your option) any later version.
 17+ *
 18+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 19+ * KIND, either express or implied.
 20+ *
 21+ ****************************************************************************/
 22+#include "global.h"
 23+#include <string.h>
 24+#include <errno.h>
 25+#include "file.h"
 26+#include "fat.h"
 27+#include "dir.h"
 28+#include "util.h"
 29+
 30+/*
 31+ These functions provide a roughly POSIX-compatible file IO API.
 32+
 33+ Since the fat32 driver only manages sectors, we maintain a one-sector
 34+ cache for each open file. This way we can provide byte access without
 35+ having to re-read the sector each time.
 36+ The penalty is the RAM used for the cache and slightly more complex code.
 37+*/
 38+
3939 extern struct scheduler_thread* current_thread;
40 -
41 -struct filedesc {
42 - unsigned char cache[SECTOR_SIZE] CACHEALIGN_ATTR;
43 - int cacheoffset; /* invariant: 0 <= cacheoffset <= SECTOR_SIZE */
44 - long fileoffset;
45 - long size;
46 - int attr;
47 - struct fat_file fatfile;
48 - bool busy;
49 - bool write;
50 - bool dirty;
51 - bool trunc;
52 - struct scheduler_thread* process;
53 -} CACHEALIGN_ATTR;
54 -
55 -static struct filedesc openfiles[MAX_OPEN_FILES] CACHEALIGN_ATTR;
56 -
57 -static int flush_cache(int fd);
58 -
59 -int file_creat(const char *pathname)
60 -{
61 - return open(pathname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
62 -}
63 -
64 -static int open_internal(const char* pathname, int flags, bool use_cache)
65 -{
66 - DIR* dir;
67 - struct dirent* entry;
68 - int fd;
69 - char pathnamecopy[MAX_PATH];
70 - char* name;
71 - struct filedesc* file = NULL;
72 - int rc;
73 -
74 - DEBUGF("open(\"%s\",%d)",pathname,flags);
75 -
76 - if ( pathname[0] != '/' ) {
77 - DEBUGF("'%s' is not an absolute path.",pathname);
78 - DEBUGF("Only absolute pathnames supported at the moment");
79 - errno = EINVAL;
80 - return -1;
81 - }
82 -
83 - /* find a free file descriptor */
84 - for ( fd=0; fd<MAX_OPEN_FILES; fd++ )
85 - if ( !openfiles[fd].busy )
86 - break;
87 -
88 - if ( fd == MAX_OPEN_FILES ) {
89 - DEBUGF("Too many files open");
90 - errno = EMFILE;
91 - return -2;
92 - }
93 -
94 - file = &openfiles[fd];
95 - memset(file, 0, sizeof(struct filedesc));
96 -
97 - if (flags & (O_RDWR | O_WRONLY)) {
98 - file->write = true;
99 -
100 - if (flags & O_TRUNC)
101 - file->trunc = true;
102 - }
103 - file->busy = true;
104 - file->process = current_thread;
105 -
106 - strlcpy(pathnamecopy, pathname, sizeof(pathnamecopy));
107 -
108 - /* locate filename */
109 - name=strrchr(pathnamecopy+1,'/');
110 - if ( name ) {
111 - *name = 0;
112 - dir = opendir(pathnamecopy);
113 - *name = '/';
114 - name++;
115 - }
116 - else {
117 - dir = opendir("/");
118 - name = pathnamecopy+1;
119 - }
120 - if (!dir) {
121 - DEBUGF("Failed opening dir");
122 - errno = EIO;
123 - file->busy = false;
124 - return -4;
125 - }
126 -
127 - if(name[0] == 0) {
128 - DEBUGF("Empty file name");
129 - errno = EINVAL;
130 - file->busy = false;
131 - closedir(dir);
132 - return -5;
133 - }
134 -
135 - /* scan dir for name */
136 - while ((entry = readdir(dir))) {
137 - if ( !strcasecmp(name, entry->d_name) ) {
138 - fat_open(IF_MV2(dir->fatdir.file.volume,)
139 - entry->startcluster,
140 - &(file->fatfile),
141 - &(dir->fatdir));
142 - file->size = file->trunc ? 0 : entry->size;
143 - file->attr = entry->attribute;
144 - break;
145 - }
146 - }
147 -
148 - if ( !entry ) {
149 - DEBUGF("Didn't find file %s",name);
150 - if ( file->write && (flags & O_CREAT) ) {
151 - rc = fat_create_file(name,
152 - &(file->fatfile),
153 - &(dir->fatdir));
154 - if (rc < 0) {
155 - DEBUGF("Couldn't create %s in %s",name,pathnamecopy);
156 - errno = EIO;
157 - file->busy = false;
158 - closedir(dir);
159 - return rc * 10 - 6;
160 - }
161 - file->size = 0;
162 - file->attr = 0;
163 - }
164 - else {
165 - DEBUGF("Couldn't find %s in %s",name,pathnamecopy);
166 - errno = ENOENT;
167 - file->busy = false;
168 - closedir(dir);
169 - return -7;
170 - }
171 - } else {
172 - if(file->write && (file->attr & FAT_ATTR_DIRECTORY)) {
173 - errno = EISDIR;
174 - file->busy = false;
175 - closedir(dir);
176 - return -8;
177 - }
178 - }
179 - closedir(dir);
180 -
181 - file->cacheoffset = -1;
182 - file->fileoffset = 0;
183 -
184 - if (file->write && (flags & O_APPEND)) {
185 - rc = lseek(fd,0,SEEK_END);
186 - if (rc < 0 )
187 - return rc * 10 - 9;
188 - }
189 -
190 - return fd;
191 -}
192 -
193 -int file_open(const char* pathname, int flags)
194 -{
195 - /* By default, use the dircache if available. */
196 - return open_internal(pathname, flags, true);
197 -}
198 -
199 -int close(int fd)
200 -{
201 - struct filedesc* file = &openfiles[fd];
202 - int rc = 0;
203 -
204 - DEBUGF("close(%d)", fd);
205 -
206 - if (fd < 0 || fd > MAX_OPEN_FILES-1) {
207 - errno = EINVAL;
208 - return -1;
209 - }
210 - if (!file->busy) {
211 - errno = EBADF;
212 - return -2;
213 - }
214 - if (file->write) {
215 - rc = fsync(fd);
216 - if (rc < 0)
217 - return rc * 10 - 3;
218 - }
219 -
220 - file->busy = false;
221 - return 0;
222 -}
223 -
224 -int close_all_of_process(struct scheduler_thread* process)
225 -{
226 - struct filedesc* pfile = openfiles;
227 - int fd;
228 - int closed = 0;
229 - for ( fd=0; fd<MAX_OPEN_FILES; fd++, pfile++)
230 - {
231 - if (pfile->process == process)
232 - {
233 - pfile->busy = false; /* mark as available, no further action */
234 - closed++;
235 - }
236 - }
237 - return closed; /* return how many we did */
238 -}
239 -
240 -int fsync(int fd)
241 -{
242 - struct filedesc* file = &openfiles[fd];
243 - int rc = 0;
244 -
245 - DEBUGF("fsync(%d)", fd);
246 -
247 - if (fd < 0 || fd > MAX_OPEN_FILES-1) {
248 - errno = EINVAL;
249 - return -1;
250 - }
251 - if (!file->busy) {
252 - errno = EBADF;
253 - return -2;
254 - }
255 - if (file->write) {
256 - /* flush sector cache */
257 - if ( file->dirty ) {
258 - rc = flush_cache(fd);
259 - if (rc < 0)
260 - {
261 - /* when failing, try to close the file anyway */
262 - fat_closewrite(&(file->fatfile), file->size, file->attr);
263 - return rc * 10 - 3;
264 - }
265 - }
266 -
267 - /* truncate? */
268 - if (file->trunc) {
269 - rc = ftruncate(fd, file->size);
270 - if (rc < 0)
271 - {
272 - /* when failing, try to close the file anyway */
273 - fat_closewrite(&(file->fatfile), file->size, file->attr);
274 - return rc * 10 - 4;
275 - }
276 - }
277 -
278 - /* tie up all loose ends */
279 - rc = fat_closewrite(&(file->fatfile), file->size, file->attr);
280 - if (rc < 0)
281 - return rc * 10 - 5;
282 - }
283 - return 0;
284 -}
285 -
286 -int remove(const char* name)
287 -{
288 - int rc;
289 - struct filedesc* file;
290 - /* Can't use dircache now, because we need to access the fat structures. */
291 - int fd = open_internal(name, O_WRONLY, false);
292 - if ( fd < 0 )
293 - return fd * 10 - 1;
294 -
295 - file = &openfiles[fd];
296 - rc = fat_remove(&(file->fatfile));
297 - if ( rc < 0 ) {
298 - DEBUGF("Failed removing file: %d", rc);
299 - errno = EIO;
300 - return rc * 10 - 3;
301 - }
302 -
303 - file->size = 0;
304 -
305 - rc = close(fd);
306 - if (rc<0)
307 - return rc * 10 - 4;
308 -
309 - return 0;
310 -}
311 -
312 -int rename(const char* path, const char* newpath)
313 -{
314 - int rc, fd;
315 - DIR* dir;
316 - char* nameptr;
317 - char* dirptr;
318 - struct filedesc* file;
319 - char newpath2[MAX_PATH];
320 -
321 - /* verify new path does not already exist */
322 - /* If it is a directory, errno == EISDIR if the name exists */
323 - fd = open(newpath, O_RDONLY);
324 - if ( fd >= 0 || errno == EISDIR) {
325 - close(fd);
326 - errno = EBUSY;
327 - return -1;
328 - }
329 - close(fd);
330 -
331 - fd = open_internal(path, O_RDONLY, false);
332 - if ( fd < 0 ) {
333 - errno = EIO;
334 - return fd * 10 - 2;
335 - }
336 -
337 - /* extract new file name */
338 - nameptr = strrchr(newpath,'/');
339 - if (nameptr)
340 - nameptr++;
341 - else {
342 - close(fd);
343 - return - 3;
344 - }
345 -
346 - /* Extract new path */
347 - strcpy(newpath2, newpath);
348 -
349 - dirptr = strrchr(newpath2,'/');
350 - if(dirptr)
351 - *dirptr = 0;
352 - else {
353 - close(fd);
354 - return - 4;
355 - }
356 -
357 - dirptr = newpath2;
358 -
359 - if(strlen(dirptr) == 0) {
360 - dirptr = "/";
361 - }
362 -
363 - dir = opendir(dirptr);
364 - if(!dir) {
365 - close(fd);
366 - return - 5;
367 - }
368 -
369 - file = &openfiles[fd];
370 -
371 - rc = fat_rename(&file->fatfile, &dir->fatdir, nameptr,
372 - file->size, file->attr);
373 -#ifdef HAVE_MULTIVOLUME
374 - if ( rc == -1) {
375 - close(fd);
376 - closedir(dir);
377 - DEBUGF("Failed renaming file across volumnes: %d", rc);
378 - errno = EXDEV;
379 - return -6;
380 - }
381 -#endif
382 - if ( rc < 0 ) {
383 - close(fd);
384 - closedir(dir);
385 - DEBUGF("Failed renaming file: %d", rc);
386 - errno = EIO;
387 - return rc * 10 - 7;
388 - }
389 -
390 - rc = close(fd);
391 - if (rc<0) {
392 - closedir(dir);
393 - errno = EIO;
394 - return rc * 10 - 8;
395 - }
396 -
397 - rc = closedir(dir);
398 - if (rc<0) {
399 - errno = EIO;
400 - return rc * 10 - 9;
401 - }
402 -
403 - return 0;
404 -}
405 -
406 -int ftruncate(int fd, off_t size)
407 -{
408 - int rc, sector;
409 - struct filedesc* file = &openfiles[fd];
410 -
411 - sector = size / SECTOR_SIZE;
412 - if (size % SECTOR_SIZE)
413 - sector++;
414 -
415 - rc = fat_seek(&(file->fatfile), sector);
416 - if (rc < 0) {
417 - errno = EIO;
418 - return rc * 10 - 1;
419 - }
420 -
421 - rc = fat_truncate(&(file->fatfile));
422 - if (rc < 0) {
423 - errno = EIO;
424 - return rc * 10 - 2;
425 - }
426 -
427 - file->size = size;
428 -
429 - return 0;
430 -}
431 -
432 -static int flush_cache(int fd)
433 -{
434 - int rc;
435 - struct filedesc* file = &openfiles[fd];
436 - long sector = file->fileoffset / SECTOR_SIZE;
437 -
438 - DEBUGF("Flushing dirty sector cache");
439 -
440 - /* make sure we are on correct sector */
441 - rc = fat_seek(&(file->fatfile), sector);
442 - if ( rc < 0 )
443 - return rc * 10 - 3;
444 -
445 - rc = fat_readwrite(&(file->fatfile), 1, file->cache, true );
446 -
447 - if ( rc < 0 ) {
448 - if(file->fatfile.eof)
449 - errno = ENOSPC;
450 -
451 - return rc * 10 - 2;
452 - }
453 -
454 - file->dirty = false;
455 -
456 - return 0;
457 -}
458 -
459 -static int readwrite(int fd, void* buf, long count, bool write)
460 -{
461 - long sectors;
462 - long nread=0;
463 - struct filedesc* file;
464 - int rc;
465 -
466 - if (fd < 0 || fd > MAX_OPEN_FILES-1) {
467 - errno = EINVAL;
468 - return -1;
469 - }
470 -
471 - file = &openfiles[fd];
472 -
473 - if ( !file->busy ) {
474 - errno = EBADF;
475 - return -1;
476 - }
477 -
478 - if(file->attr & FAT_ATTR_DIRECTORY) {
479 - errno = EISDIR;
480 - return -1;
481 - }
482 -
483 - DEBUGF( "readwrite(%d,%lx,%ld,%s)",
484 - fd,(long)buf,count,write?"write":"read");
485 -
486 - /* attempt to read past EOF? */
487 - if (!write && count > file->size - file->fileoffset)
488 - count = file->size - file->fileoffset;
489 -
490 - /* any head bytes? */
491 - if ( file->cacheoffset != -1 ) {
492 - int offs = file->cacheoffset;
493 - int headbytes = MIN(count, SECTOR_SIZE - offs);
494 -
495 - if (write) {
496 - memcpy( file->cache + offs, buf, headbytes );
497 - file->dirty = true;
498 - }
499 - else {
500 - memcpy( buf, file->cache + offs, headbytes );
501 - }
502 -
503 - if (offs + headbytes == SECTOR_SIZE) {
504 - if (file->dirty) {
505 - rc = flush_cache(fd);
506 - if ( rc < 0 ) {
507 - errno = EIO;
508 - return rc * 10 - 2;
509 - }
510 - }
511 - file->cacheoffset = -1;
512 - }
513 - else {
514 - file->cacheoffset += headbytes;
515 - }
516 -
517 - nread = headbytes;
518 - count -= headbytes;
519 - }
520 -
521 - /* If the buffer has been modified, either it has been flushed already
522 - * (if (offs+headbytes == SECTOR_SIZE)...) or does not need to be (no
523 - * more data to follow in this call). Do NOT flush here. */
524 -
525 - /* read/write whole sectors right into/from the supplied buffer */
526 - sectors = count / SECTOR_SIZE;
527 - if ( sectors ) {
528 - rc = fat_readwrite(&(file->fatfile), sectors,
529 - (unsigned char*)buf+nread, write );
530 - if ( rc < 0 ) {
531 - DEBUGF("Failed read/writing %ld sectors",sectors);
532 - errno = EIO;
533 - if(write && file->fatfile.eof) {
534 - DEBUGF("No space left on device");
535 - errno = ENOSPC;
536 - } else {
537 - file->fileoffset += nread;
538 - }
539 - file->cacheoffset = -1;
540 - /* adjust file size to length written */
541 - if ( write && file->fileoffset > file->size )
542 - {
543 - file->size = file->fileoffset;
544 - }
545 - return nread ? nread : rc * 10 - 4;
546 - }
547 - else {
548 - if ( rc > 0 ) {
549 - nread += rc * SECTOR_SIZE;
550 - count -= sectors * SECTOR_SIZE;
551 -
552 - /* if eof, skip tail bytes */
553 - if ( rc < sectors )
554 - count = 0;
555 - }
556 - else {
557 - /* eof */
558 - count=0;
559 - }
560 -
561 - file->cacheoffset = -1;
562 - }
563 - }
564 -
565 - /* any tail bytes? */
566 - if ( count ) {
567 - if (write) {
568 - if ( file->fileoffset + nread < file->size ) {
569 - /* sector is only partially filled. copy-back from disk */
570 - DEBUGF("Copy-back tail cache");
571 - rc = fat_readwrite(&(file->fatfile), 1, file->cache, false );
572 - if ( rc < 0 ) {
573 - DEBUGF("Failed writing");
574 - errno = EIO;
575 - file->fileoffset += nread;
576 - file->cacheoffset = -1;
577 - /* adjust file size to length written */
578 - if ( file->fileoffset > file->size )
579 - {
580 - file->size = file->fileoffset;
581 - }
582 - return nread ? nread : rc * 10 - 5;
583 - }
584 - /* seek back one sector to put file position right */
585 - rc = fat_seek(&(file->fatfile),
586 - (file->fileoffset + nread) /
587 - SECTOR_SIZE);
588 - if ( rc < 0 ) {
589 - DEBUGF("fat_seek() failed");
590 - errno = EIO;
591 - file->fileoffset += nread;
592 - file->cacheoffset = -1;
593 - /* adjust file size to length written */
594 - if ( file->fileoffset > file->size )
595 - {
596 - file->size = file->fileoffset;
597 - }
598 - return nread ? nread : rc * 10 - 6;
599 - }
600 - }
601 - memcpy( file->cache, (unsigned char*)buf + nread, count );
602 - file->dirty = true;
603 - }
604 - else {
605 - rc = fat_readwrite(&(file->fatfile), 1, file->cache,false);
606 - if (rc < 1 ) {
607 - DEBUGF("Failed caching sector");
608 - errno = EIO;
609 - file->fileoffset += nread;
610 - file->cacheoffset = -1;
611 - return nread ? nread : rc * 10 - 7;
612 - }
613 - memcpy( (unsigned char*)buf + nread, file->cache, count );
614 - }
615 -
616 - nread += count;
617 - file->cacheoffset = count;
618 - }
619 -
620 - file->fileoffset += nread;
621 - DEBUGF("fileoffset: %ld", file->fileoffset);
622 -
623 - /* adjust file size to length written */
624 - if ( write && file->fileoffset > file->size )
625 - {
626 - file->size = file->fileoffset;
627 - }
628 -
629 - return nread;
630 -}
631 -
632 -ssize_t write(int fd, const void* buf, size_t count)
633 -{
634 - if (!openfiles[fd].write) {
635 - errno = EACCES;
636 - return -1;
637 - }
638 - return readwrite(fd, (void *)buf, count, true);
639 -}
640 -
641 -ssize_t read(int fd, void* buf, size_t count)
642 -{
643 - return readwrite(fd, buf, count, false);
644 -}
645 -
646 -
647 -off_t lseek(int fd, off_t offset, int whence)
648 -{
649 - off_t pos;
650 - long newsector;
651 - long oldsector;
652 - int sectoroffset;
653 - int rc;
654 - struct filedesc* file = &openfiles[fd];
655 -
656 - DEBUGF("lseek(%d,%ld,%d)",fd,offset,whence);
657 -
658 - if (fd < 0 || fd > MAX_OPEN_FILES-1) {
659 - errno = EINVAL;
660 - return -1;
661 - }
662 - if ( !file->busy ) {
663 - errno = EBADF;
664 - return -1;
665 - }
666 -
667 - switch ( whence ) {
668 - case SEEK_SET:
669 - pos = offset;
670 - break;
671 -
672 - case SEEK_CUR:
673 - pos = file->fileoffset + offset;
674 - break;
675 -
676 - case SEEK_END:
677 - pos = file->size + offset;
678 - break;
679 -
680 - default:
681 - errno = EINVAL;
682 - return -2;
683 - }
684 - if ((pos < 0) || (pos > file->size)) {
685 - errno = EINVAL;
686 - return -3;
687 - }
688 -
689 - /* new sector? */
690 - newsector = pos / SECTOR_SIZE;
691 - oldsector = file->fileoffset / SECTOR_SIZE;
692 - sectoroffset = pos % SECTOR_SIZE;
693 -
694 - if ( (newsector != oldsector) ||
695 - ((file->cacheoffset==-1) && sectoroffset) ) {
696 -
697 - if ( newsector != oldsector ) {
698 - if (file->dirty) {
699 - rc = flush_cache(fd);
700 - if (rc < 0)
701 - return rc * 10 - 5;
702 - }
703 -
704 - rc = fat_seek(&(file->fatfile), newsector);
705 - if ( rc < 0 ) {
706 - errno = EIO;
707 - return rc * 10 - 4;
708 - }
709 - }
710 - if ( sectoroffset ) {
711 - rc = fat_readwrite(&(file->fatfile), 1, file->cache ,false);
712 - if ( rc < 0 ) {
713 - errno = EIO;
714 - return rc * 10 - 6;
715 - }
716 - file->cacheoffset = sectoroffset;
717 - }
718 - else
719 - file->cacheoffset = -1;
720 - }
721 - else
722 - if ( file->cacheoffset != -1 )
723 - file->cacheoffset = sectoroffset;
724 -
725 - file->fileoffset = pos;
726 -
727 - return pos;
728 -}
729 -
730 -off_t filesize(int fd)
731 -{
732 - struct filedesc* file = &openfiles[fd];
733 -
734 - if (fd < 0 || fd > MAX_OPEN_FILES-1) {
735 - errno = EINVAL;
736 - return -1;
737 - }
738 - if ( !file->busy ) {
739 - errno = EBADF;
740 - return -1;
741 - }
742 -
743 - return file->size;
744 -}
745 -
746 -
747 -#ifdef HAVE_HOTSWAP
748 -/* release all file handles on a given volume "by force", to avoid leaks */
749 -int release_files(int volume)
750 -{
751 - struct filedesc* pfile = openfiles;
752 - int fd;
753 - int closed = 0;
754 - for ( fd=0; fd<MAX_OPEN_FILES; fd++, pfile++)
755 - {
756 -#ifdef HAVE_MULTIVOLUME
757 - if (pfile->fatfile.volume == volume)
758 -#else
759 - (void)volume;
760 -#endif
761 - {
762 - pfile->busy = false; /* mark as available, no further action */
763 - closed++;
764 - }
765 - }
766 - return closed; /* return how many we did */
767 -}
768 -#endif /* #ifdef HAVE_HOTSWAP */
 40+
 41+struct filedesc {
 42+ unsigned char cache[SECTOR_SIZE] CACHEALIGN_ATTR;
 43+ int cacheoffset; /* invariant: 0 <= cacheoffset <= SECTOR_SIZE */
 44+ long fileoffset;
 45+ long size;
 46+ int attr;
 47+ struct fat_file fatfile;
 48+ bool busy;
 49+ bool write;
 50+ bool dirty;
 51+ bool trunc;
 52+ struct scheduler_thread* process;
 53+} CACHEALIGN_ATTR;
 54+
 55+static struct filedesc openfiles[MAX_OPEN_FILES] CACHEALIGN_ATTR;
 56+
 57+static int flush_cache(int fd);
 58+
 59+int file_creat(const char *pathname)
 60+{
 61+ return open(pathname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
 62+}
 63+
 64+static int open_internal(const char* pathname, int flags, bool use_cache)
 65+{
 66+ DIR* dir;
 67+ struct dirent* entry;
 68+ int fd;
 69+ char pathnamecopy[MAX_PATH];
 70+ char* name;
 71+ struct filedesc* file = NULL;
 72+ int rc;
 73+
 74+ DEBUGF("open(\"%s\",%d)",pathname,flags);
 75+
 76+ if ( pathname[0] != '/' ) {
 77+ DEBUGF("'%s' is not an absolute path.", pathname);
 78+ DEBUGF("Only absolute pathnames supported at the moment");
 79+ errno = EINVAL;
 80+ return -1;
 81+ }
 82+
 83+ /* find a free file descriptor */
 84+ for ( fd=0; fd<MAX_OPEN_FILES; fd++ )
 85+ if ( !openfiles[fd].busy )
 86+ break;
 87+
 88+ if ( fd == MAX_OPEN_FILES ) {
 89+ DEBUGF("Too many files open");
 90+ errno = EMFILE;
 91+ return -2;
 92+ }
 93+
 94+ file = &openfiles[fd];
 95+ memset(file, 0, sizeof(struct filedesc));
 96+
 97+ if (flags & (O_RDWR | O_WRONLY)) {
 98+ file->write = true;
 99+
 100+ if (flags & O_TRUNC)
 101+ file->trunc = true;
 102+ }
 103+ file->busy = true;
 104+ file->process = current_thread;
 105+
 106+ strlcpy(pathnamecopy, pathname, sizeof(pathnamecopy));
 107+
 108+ /* locate filename */
 109+ name=strrchr(pathnamecopy+1,'/');
 110+ if ( name ) {
 111+ *name = 0;
 112+ dir = opendir(pathnamecopy);
 113+ *name = '/';
 114+ name++;
 115+ }
 116+ else {
 117+ dir = opendir("/");
 118+ name = pathnamecopy+1;
 119+ }
 120+ if (!dir) {
 121+ DEBUGF("Failed opening dir");
 122+ errno = EIO;
 123+ file->busy = false;
 124+ return -4;
 125+ }
 126+
 127+ if(name[0] == 0) {
 128+ DEBUGF("Empty file name");
 129+ errno = EINVAL;
 130+ file->busy = false;
 131+ closedir(dir);
 132+ return -5;
 133+ }
 134+
 135+ /* scan dir for name */
 136+ while ((entry = readdir(dir))) {
 137+ if ( !strcasecmp(name, entry->d_name) ) {
 138+ fat_open(IF_MV2(dir->fatdir.file.volume,)
 139+ entry->startcluster,
 140+ &(file->fatfile),
 141+ &(dir->fatdir));
 142+ file->size = file->trunc ? 0 : entry->size;
 143+ file->attr = entry->attribute;
 144+ break;
 145+ }
 146+ }
 147+
 148+ if ( !entry ) {
 149+ DEBUGF("Didn't find file %s",name);
 150+ if ( file->write && (flags & O_CREAT) ) {
 151+ rc = fat_create_file(name,
 152+ &(file->fatfile),
 153+ &(dir->fatdir));
 154+ if (rc < 0) {
 155+ DEBUGF("Couldn't create %s in %s",name,pathnamecopy);
 156+ errno = EIO;
 157+ file->busy = false;
 158+ closedir(dir);
 159+ return rc * 10 - 6;
 160+ }
 161+ file->size = 0;
 162+ file->attr = 0;
 163+ }
 164+ else {
 165+ DEBUGF("Couldn't find %s in %s",name,pathnamecopy);
 166+ errno = ENOENT;
 167+ file->busy = false;
 168+ closedir(dir);
 169+ return -7;
 170+ }
 171+ } else {
 172+ if(file->write && (file->attr & FAT_ATTR_DIRECTORY)) {
 173+ errno = EISDIR;
 174+ file->busy = false;
 175+ closedir(dir);
 176+ return -8;
 177+ }
 178+ }
 179+ closedir(dir);
 180+
 181+ file->cacheoffset = -1;
 182+ file->fileoffset = 0;
 183+
 184+ if (file->write && (flags & O_APPEND)) {
 185+ rc = lseek(fd,0,SEEK_END);
 186+ if (rc < 0 )
 187+ return rc * 10 - 9;
 188+ }
 189+
 190+ return fd;
 191+}
 192+
 193+int file_open(const char* pathname, int flags)
 194+{
 195+ /* By default, use the dircache if available. */
 196+ return open_internal(pathname, flags, true);
 197+}
 198+
 199+int close(int fd)
 200+{
 201+ struct filedesc* file = &openfiles[fd];
 202+ int rc = 0;
 203+
 204+ DEBUGF("close(%d)", fd);
 205+
 206+ if (fd < 0 || fd > MAX_OPEN_FILES-1) {
 207+ errno = EINVAL;
 208+ return -1;
 209+ }
 210+ if (!file->busy) {
 211+ errno = EBADF;
 212+ return -2;
 213+ }
 214+ if (file->write) {
 215+ rc = fsync(fd);
 216+ if (rc < 0)
 217+ return rc * 10 - 3;
 218+ }
 219+
 220+ file->busy = false;
 221+ return 0;
 222+}
 223+
 224+int close_all_of_process(struct scheduler_thread* process)
 225+{
 226+ struct filedesc* pfile = openfiles;
 227+ int fd;
 228+ int closed = 0;
 229+ for ( fd=0; fd<MAX_OPEN_FILES; fd++, pfile++)
 230+ {
 231+ if (pfile->process == process)
 232+ {
 233+ pfile->busy = false; /* mark as available, no further action */
 234+ closed++;
 235+ }
 236+ }
 237+ return closed; /* return how many we did */
 238+}
 239+
 240+int fsync(int fd)
 241+{
 242+ struct filedesc* file = &openfiles[fd];
 243+ int rc = 0;
 244+
 245+ DEBUGF("fsync(%d)", fd);
 246+
 247+ if (fd < 0 || fd > MAX_OPEN_FILES-1) {
 248+ errno = EINVAL;
 249+ return -1;
 250+ }
 251+ if (!file->busy) {
 252+ errno = EBADF;
 253+ return -2;
 254+ }
 255+ if (file->write) {
 256+ /* flush sector cache */
 257+ if ( file->dirty ) {
 258+ rc = flush_cache(fd);
 259+ if (rc < 0)
 260+ {
 261+ /* when failing, try to close the file anyway */
 262+ fat_closewrite(&(file->fatfile), file->size, file->attr);
 263+ return rc * 10 - 3;
 264+ }
 265+ }
 266+
 267+ /* truncate? */
 268+ if (file->trunc) {
 269+ rc = ftruncate(fd, file->size);
 270+ if (rc < 0)
 271+ {
 272+ /* when failing, try to close the file anyway */
 273+ fat_closewrite(&(file->fatfile), file->size, file->attr);
 274+ return rc * 10 - 4;
 275+ }
 276+ }
 277+
 278+ /* tie up all loose ends */
 279+ rc = fat_closewrite(&(file->fatfile), file->size, file->attr);
 280+ if (rc < 0)
 281+ return rc * 10 - 5;
 282+ }
 283+ return 0;
 284+}
 285+
 286+int remove(const char* name)
 287+{
 288+ int rc;
 289+ struct filedesc* file;
 290+ /* Can't use dircache now, because we need to access the fat structures. */
 291+ int fd = open_internal(name, O_WRONLY, false);
 292+ if ( fd < 0 )
 293+ return fd * 10 - 1;
 294+
 295+ file = &openfiles[fd];
 296+ rc = fat_remove(&(file->fatfile));
 297+ if ( rc < 0 ) {
 298+ DEBUGF("Failed removing file: %d", rc);
 299+ errno = EIO;
 300+ return rc * 10 - 3;
 301+ }
 302+
 303+ file->size = 0;
 304+
 305+ rc = close(fd);
 306+ if (rc<0)
 307+ return rc * 10 - 4;
 308+
 309+ return 0;
 310+}
 311+
 312+int rename(const char* path, const char* newpath)
 313+{
 314+ int rc, fd;
 315+ DIR* dir;
 316+ char* nameptr;
 317+ char* dirptr;
 318+ struct filedesc* file;
 319+ char newpath2[MAX_PATH];
 320+
 321+ /* verify new path does not already exist */
 322+ /* If it is a directory, errno == EISDIR if the name exists */
 323+ fd = open(newpath, O_RDONLY);
 324+ if ( fd >= 0 || errno == EISDIR) {
 325+ close(fd);
 326+ errno = EBUSY;
 327+ return -1;
 328+ }
 329+ close(fd);
 330+
 331+ fd = open_internal(path, O_RDONLY, false);
 332+ if ( fd < 0 ) {
 333+ errno = EIO;
 334+ return fd * 10 - 2;
 335+ }
 336+
 337+ /* extract new file name */
 338+ nameptr = strrchr(newpath,'/');
 339+ if (nameptr)
 340+ nameptr++;
 341+ else {
 342+ close(fd);
 343+ return - 3;
 344+ }
 345+
 346+ /* Extract new path */
 347+ strcpy(newpath2, newpath);
 348+
 349+ dirptr = strrchr(newpath2,'/');
 350+ if(dirptr)
 351+ *dirptr = 0;
 352+ else {
 353+ close(fd);
 354+ return - 4;
 355+ }
 356+
 357+ dirptr = newpath2;
 358+
 359+ if(strlen(dirptr) == 0) {
 360+ dirptr = "/";
 361+ }
 362+
 363+ dir = opendir(dirptr);
 364+ if(!dir) {
 365+ close(fd);
 366+ return - 5;
 367+ }
 368+
 369+ file = &openfiles[fd];
 370+
 371+ rc = fat_rename(&file->fatfile, &dir->fatdir, nameptr,
 372+ file->size, file->attr);
 373+#ifdef HAVE_MULTIVOLUME
 374+ if ( rc == -1) {
 375+ close(fd);
 376+ closedir(dir);
 377+ DEBUGF("Failed renaming file across volumnes: %d", rc);
 378+ errno = EXDEV;
 379+ return -6;
 380+ }
 381+#endif
 382+ if ( rc < 0 ) {
 383+ close(fd);
 384+ closedir(dir);
 385+ DEBUGF("Failed renaming file: %d", rc);
 386+ errno = EIO;
 387+ return rc * 10 - 7;
 388+ }
 389+
 390+ rc = close(fd);
 391+ if (rc<0) {
 392+ closedir(dir);
 393+ errno = EIO;
 394+ return rc * 10 - 8;
 395+ }
 396+
 397+ rc = closedir(dir);
 398+ if (rc<0) {
 399+ errno = EIO;
 400+ return rc * 10 - 9;
 401+ }
 402+
 403+ return 0;
 404+}
 405+
 406+int ftruncate(int fd, off_t size)
 407+{
 408+ int rc, sector;
 409+ struct filedesc* file = &openfiles[fd];
 410+
 411+ sector = size / SECTOR_SIZE;
 412+ if (size % SECTOR_SIZE)
 413+ sector++;
 414+
 415+ rc = fat_seek(&(file->fatfile), sector);
 416+ if (rc < 0) {
 417+ errno = EIO;
 418+ return rc * 10 - 1;
 419+ }
 420+
 421+ rc = fat_truncate(&(file->fatfile));
 422+ if (rc < 0) {
 423+ errno = EIO;
 424+ return rc * 10 - 2;
 425+ }
 426+
 427+ file->size = size;
 428+
 429+ return 0;
 430+}
 431+
 432+static int flush_cache(int fd)
 433+{
 434+ int rc;
 435+ struct filedesc* file = &openfiles[fd];
 436+ long sector = file->fileoffset / SECTOR_SIZE;
 437+
 438+ DEBUGF("Flushing dirty sector cache");
 439+
 440+ /* make sure we are on correct sector */
 441+ rc = fat_seek(&(file->fatfile), sector);
 442+ if ( rc < 0 )
 443+ return rc * 10 - 3;
 444+
 445+ rc = fat_readwrite(&(file->fatfile), 1, file->cache, true );
 446+
 447+ if ( rc < 0 ) {
 448+ if(file->fatfile.eof)
 449+ errno = ENOSPC;
 450+
 451+ return rc * 10 - 2;
 452+ }
 453+
 454+ file->dirty = false;
 455+
 456+ return 0;
 457+}
 458+
 459+static int readwrite(int fd, void* buf, long count, bool write)
 460+{
 461+ long sectors;
 462+ long nread=0;
 463+ struct filedesc* file;
 464+ int rc;
 465+
 466+ if (fd < 0 || fd > MAX_OPEN_FILES-1) {
 467+ errno = EINVAL;
 468+ return -1;
 469+ }
 470+
 471+ file = &openfiles[fd];
 472+
 473+ if ( !file->busy ) {
 474+ errno = EBADF;
 475+ return -1;
 476+ }
 477+
 478+ if(file->attr & FAT_ATTR_DIRECTORY) {
 479+ errno = EISDIR;
 480+ return -1;
 481+ }
 482+
 483+ DEBUGF( "readwrite(%d,%lx,%ld,%s)",
 484+ fd,(long)buf,count,write?"write":"read");
 485+
 486+ /* attempt to read past EOF? */
 487+ if (!write && count > file->size - file->fileoffset)
 488+ count = file->size - file->fileoffset;
 489+
 490+ /* any head bytes? */
 491+ if ( file->cacheoffset != -1 ) {
 492+ int offs = file->cacheoffset;
 493+ int headbytes = MIN(count, SECTOR_SIZE - offs);
 494+
 495+ if (write) {
 496+ memcpy( file->cache + offs, buf, headbytes );
 497+ file->dirty = true;
 498+ }
 499+ else {
 500+ memcpy( buf, file->cache + offs, headbytes );
 501+ }
 502+
 503+ if (offs + headbytes == SECTOR_SIZE) {
 504+ if (file->dirty) {
 505+ rc = flush_cache(fd);
 506+ if ( rc < 0 ) {
 507+ errno = EIO;
 508+ return rc * 10 - 2;
 509+ }
 510+ }
 511+ file->cacheoffset = -1;
 512+ }
 513+ else {
 514+ file->cacheoffset += headbytes;
 515+ }
 516+
 517+ nread = headbytes;
 518+ count -= headbytes;
 519+ }
 520+
 521+ /* If the buffer has been modified, either it has been flushed already
 522+ * (if (offs+headbytes == SECTOR_SIZE)...) or does not need to be (no
 523+ * more data to follow in this call). Do NOT flush here. */
 524+
 525+ /* read/write whole sectors right into/from the supplied buffer */
 526+ sectors = count / SECTOR_SIZE;
 527+ if ( sectors ) {
 528+ if (buf+nread & (CACHEALIGN_SIZE - 1))
 529+ {
 530+ if (write) memcpy(file->cache, buf+nread, SECTOR_SIZE);
 531+ rc = fat_readwrite(&(file->fatfile), sectors, file->cache, write );
 532+ if (!write) memcpy(buf+nread, file->cache, SECTOR_SIZE);
 533+ }
 534+ else rc = fat_readwrite(&(file->fatfile), sectors, (unsigned char*)buf+nread, write );
 535+ if ( rc < 0 ) {
 536+ DEBUGF("Failed read/writing %ld sectors",sectors);
 537+ errno = EIO;
 538+ if(write && file->fatfile.eof) {
 539+ DEBUGF("No space left on device");
 540+ errno = ENOSPC;
 541+ } else {
 542+ file->fileoffset += nread;
 543+ }
 544+ file->cacheoffset = -1;
 545+ /* adjust file size to length written */
 546+ if ( write && file->fileoffset > file->size )
 547+ {
 548+ file->size = file->fileoffset;
 549+ }
 550+ return nread ? nread : rc * 10 - 4;
 551+ }
 552+ else {
 553+ if ( rc > 0 ) {
 554+ nread += rc * SECTOR_SIZE;
 555+ count -= sectors * SECTOR_SIZE;
 556+
 557+ /* if eof, skip tail bytes */
 558+ if ( rc < sectors )
 559+ count = 0;
 560+ }
 561+ else {
 562+ /* eof */
 563+ count=0;
 564+ }
 565+
 566+ file->cacheoffset = -1;
 567+ }
 568+ }
 569+
 570+ /* any tail bytes? */
 571+ if ( count ) {
 572+ if (write) {
 573+ if ( file->fileoffset + nread < file->size ) {
 574+ /* sector is only partially filled. copy-back from disk */
 575+ DEBUGF("Copy-back tail cache");
 576+ rc = fat_readwrite(&(file->fatfile), 1, file->cache, false );
 577+ if ( rc < 0 ) {
 578+ DEBUGF("Failed writing");
 579+ errno = EIO;
 580+ file->fileoffset += nread;
 581+ file->cacheoffset = -1;
 582+ /* adjust file size to length written */
 583+ if ( file->fileoffset > file->size )
 584+ {
 585+ file->size = file->fileoffset;
 586+ }
 587+ return nread ? nread : rc * 10 - 5;
 588+ }
 589+ /* seek back one sector to put file position right */
 590+ rc = fat_seek(&(file->fatfile),
 591+ (file->fileoffset + nread) /
 592+ SECTOR_SIZE);
 593+ if ( rc < 0 ) {
 594+ DEBUGF("fat_seek() failed");
 595+ errno = EIO;
 596+ file->fileoffset += nread;
 597+ file->cacheoffset = -1;
 598+ /* adjust file size to length written */
 599+ if ( file->fileoffset > file->size )
 600+ {
 601+ file->size = file->fileoffset;
 602+ }
 603+ return nread ? nread : rc * 10 - 6;
 604+ }
 605+ }
 606+ memcpy( file->cache, (unsigned char*)buf + nread, count );
 607+ file->dirty = true;
 608+ }
 609+ else {
 610+ rc = fat_readwrite(&(file->fatfile), 1, file->cache,false);
 611+ if (rc < 1 ) {
 612+ DEBUGF("Failed caching sector");
 613+ errno = EIO;
 614+ file->fileoffset += nread;
 615+ file->cacheoffset = -1;
 616+ return nread ? nread : rc * 10 - 7;
 617+ }
 618+ memcpy( (unsigned char*)buf + nread, file->cache, count );
 619+ }
 620+
 621+ nread += count;
 622+ file->cacheoffset = count;
 623+ }
 624+
 625+ file->fileoffset += nread;
 626+ DEBUGF("fileoffset: %ld", file->fileoffset);
 627+
 628+ /* adjust file size to length written */
 629+ if ( write && file->fileoffset > file->size )
 630+ {
 631+ file->size = file->fileoffset;
 632+ }
 633+
 634+ return nread;
 635+}
 636+
 637+ssize_t write(int fd, const void* buf, size_t count)
 638+{
 639+ if (!openfiles[fd].write) {
 640+ errno = EACCES;
 641+ return -1;
 642+ }
 643+ return readwrite(fd, (void *)buf, count, true);
 644+}
 645+
 646+ssize_t read(int fd, void* buf, size_t count)
 647+{
 648+ return readwrite(fd, buf, count, false);
 649+}
 650+
 651+
 652+off_t lseek(int fd, off_t offset, int whence)
 653+{
 654+ off_t pos;
 655+ long newsector;
 656+ long oldsector;
 657+ int sectoroffset;
 658+ int rc;
 659+ struct filedesc* file = &openfiles[fd];
 660+
 661+ DEBUGF("lseek(%d,%ld,%d)",fd,offset,whence);
 662+
 663+ if (fd < 0 || fd > MAX_OPEN_FILES-1) {
 664+ errno = EINVAL;
 665+ return -1;
 666+ }
 667+ if ( !file->busy ) {
 668+ errno = EBADF;
 669+ return -1;
 670+ }
 671+
 672+ switch ( whence ) {
 673+ case SEEK_SET:
 674+ pos = offset;
 675+ break;
 676+
 677+ case SEEK_CUR:
 678+ pos = file->fileoffset + offset;
 679+ break;
 680+
 681+ case SEEK_END:
 682+ pos = file->size + offset;
 683+ break;
 684+
 685+ default:
 686+ errno = EINVAL;
 687+ return -2;
 688+ }
 689+ if ((pos < 0) || (pos > file->size)) {
 690+ errno = EINVAL;
 691+ return -3;
 692+ }
 693+
 694+ /* new sector? */
 695+ newsector = pos / SECTOR_SIZE;
 696+ oldsector = file->fileoffset / SECTOR_SIZE;
 697+ sectoroffset = pos % SECTOR_SIZE;
 698+
 699+ if ( (newsector != oldsector) ||
 700+ ((file->cacheoffset==-1) && sectoroffset) ) {
 701+
 702+ if ( newsector != oldsector ) {
 703+ if (file->dirty) {
 704+ rc = flush_cache(fd);
 705+ if (rc < 0)
 706+ return rc * 10 - 5;
 707+ }
 708+
 709+ rc = fat_seek(&(file->fatfile), newsector);
 710+ if ( rc < 0 ) {
 711+ errno = EIO;
 712+ return rc * 10 - 4;
 713+ }
 714+ }
 715+ if ( sectoroffset ) {
 716+ rc = fat_readwrite(&(file->fatfile), 1, file->cache ,false);
 717+ if ( rc < 0 ) {
 718+ errno = EIO;
 719+ return rc * 10 - 6;
 720+ }
 721+ file->cacheoffset = sectoroffset;
 722+ }
 723+ else
 724+ file->cacheoffset = -1;
 725+ }
 726+ else
 727+ if ( file->cacheoffset != -1 )
 728+ file->cacheoffset = sectoroffset;
 729+
 730+ file->fileoffset = pos;
 731+
 732+ return pos;
 733+}
 734+
 735+off_t filesize(int fd)
 736+{
 737+ struct filedesc* file = &openfiles[fd];
 738+
 739+ if (fd < 0 || fd > MAX_OPEN_FILES-1) {
 740+ errno = EINVAL;
 741+ return -1;
 742+ }
 743+ if ( !file->busy ) {
 744+ errno = EBADF;
 745+ return -1;
 746+ }
 747+
 748+ return file->size;
 749+}
 750+
 751+
 752+#ifdef HAVE_HOTSWAP
 753+/* release all file handles on a given volume "by force", to avoid leaks */
 754+int release_files(int volume)
 755+{
 756+ struct filedesc* pfile = openfiles;
 757+ int fd;
 758+ int closed = 0;
 759+ for ( fd=0; fd<MAX_OPEN_FILES; fd++, pfile++)
 760+ {
 761+#ifdef HAVE_MULTIVOLUME
 762+ if (pfile->fatfile.volume == volume)
 763+#else
 764+ (void)volume;
 765+#endif
 766+ {
 767+ pfile->busy = false; /* mark as available, no further action */
 768+ closed++;
 769+ }
 770+ }
 771+ return closed; /* return how many we did */
 772+}
 773+#endif /* #ifdef HAVE_HOTSWAP */