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