Subversion Repositories freemyipod

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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