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