Subversion Repositories freemyipod

Rev

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

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