Subversion Repositories freemyipod

Rev

Rev 935 | Details | Compare with Previous | 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
 
935 theseven 63
static int open_internal(const char* pathname, int flags, bool ignoredir)
69 theseven 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;
935 theseven 78
        return 0;
69 theseven 79
    }
80
 
433 theseven 81
    file = (struct filedesc*)memalign(0x10, sizeof(struct filedesc));
82
    if (!file)
83
    {
69 theseven 84
        errno = EMFILE;
935 theseven 85
        return 0;
69 theseven 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);
935 theseven 115
        return 0;
69 theseven 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);
935 theseven 123
        return 0;
69 theseven 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
        if ( file->write && (flags & O_CREAT) ) {
141
            rc = fat_create_file(name,
142
                                 &(file->fatfile),
143
                                 &(dir->fatdir));
144
            if (rc < 0) {
935 theseven 145
                DEBUGF("Couldn't create %s", pathnamecopy);
69 theseven 146
                errno = EIO;
433 theseven 147
                free(file);
69 theseven 148
                closedir(dir);
935 theseven 149
                return 0;
69 theseven 150
            }
935 theseven 151
            DEBUGF("File %s doesn't exist, creating it", pathnamecopy);
69 theseven 152
            file->size = 0;
153
            file->attr = 0;
154
        }
155
        else {
935 theseven 156
            DEBUGF("Couldn't find %s", pathnamecopy);
69 theseven 157
            errno = ENOENT;
433 theseven 158
            free(file);
69 theseven 159
            closedir(dir);
935 theseven 160
            return 0;
69 theseven 161
        }
162
    } else {
935 theseven 163
        if (file->attr & FAT_ATTR_DIRECTORY && !ignoredir) {
69 theseven 164
            errno = EISDIR;
433 theseven 165
            free(file);
69 theseven 166
            closedir(dir);
935 theseven 167
            return 0;
69 theseven 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);
935 theseven 180
            errno = EIO;
181
            return 0;
433 theseven 182
        }
69 theseven 183
    }
184
 
433 theseven 185
    mutex_lock(&file_mutex, TIMEOUT_BLOCK);
186
    file->next = openfiles;
187
    openfiles = file;
188
    mutex_unlock(&file_mutex);
189
 
190
    return (int)file;
69 theseven 191
}
192
 
193
int file_open(const char* pathname, int flags)
194
{
935 theseven 195
    return open_internal(pathname, flags, false);
69 theseven 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
    int fd = open_internal(name, O_WRONLY, false);
935 theseven 303
    if (!fd) return - 1;
69 theseven 304
 
481 theseven 305
    struct filedesc* file = (struct filedesc*)fd;
69 theseven 306
    rc = fat_remove(&(file->fatfile));
307
    if ( rc < 0 ) {
308
        DEBUGF("Failed removing file: %d", rc);
309
        errno = EIO;
310
        return rc * 10 - 3;
311
    }
312
 
313
    file->size = 0;
314
 
315
    rc = close(fd);
316
    if (rc<0)
317
        return rc * 10 - 4;
318
 
319
    return 0;
320
}
321
 
322
int rename(const char* path, const char* newpath)
323
{
324
    int rc, fd;
325
    DIR* dir;
326
    char* nameptr;
327
    char* dirptr;
328
    struct filedesc* file;
329
    char newpath2[MAX_PATH];
330
 
331
    /* verify new path does not already exist */
332
    /* If it is a directory, errno == EISDIR if the name exists */
935 theseven 333
    fd = open_internal(newpath, O_RDONLY, true);
334
    if (fd) {
69 theseven 335
        close(fd);
336
        errno = EBUSY;
337
        return -1;
338
    }
339
 
935 theseven 340
    fd = open_internal(path, O_RDONLY, true);
341
    if (!fd) {
69 theseven 342
        errno = EIO;
935 theseven 343
        return -2;
69 theseven 344
    }
345
 
346
    /* extract new file name */
347
    nameptr = strrchr(newpath,'/');
348
    if (nameptr)
349
        nameptr++;
350
    else {
351
        close(fd);
352
        return - 3;
353
    }
354
 
355
    /* Extract new path */
356
    strcpy(newpath2, newpath);
357
 
358
    dirptr = strrchr(newpath2,'/');
359
    if(dirptr)
360
        *dirptr = 0;
361
    else {
362
        close(fd);
363
        return - 4;
364
    }
365
 
366
    dirptr = newpath2;
367
 
368
    if(strlen(dirptr) == 0) {
369
        dirptr = "/";
370
    }
371
 
372
    dir = opendir(dirptr);
373
    if(!dir) {
374
        close(fd);
375
        return - 5;
376
    }
377
 
433 theseven 378
    file = (struct filedesc*)fd;
69 theseven 379
 
380
    rc = fat_rename(&file->fatfile, &dir->fatdir, nameptr,
381
                    file->size, file->attr);
382
#ifdef HAVE_MULTIVOLUME
383
    if ( rc == -1) {
384
        close(fd);
385
        closedir(dir);
386
        DEBUGF("Failed renaming file across volumnes: %d", rc);
387
        errno = EXDEV;
388
        return -6;
389
    }
390
#endif
391
    if ( rc < 0 ) {
392
        close(fd);
393
        closedir(dir);
394
        DEBUGF("Failed renaming file: %d", rc);
395
        errno = EIO;
396
        return rc * 10 - 7;
397
    }
398
 
399
    rc = close(fd);
400
    if (rc<0) {
401
        closedir(dir);
402
        errno = EIO;
403
        return rc * 10 - 8;
404
    }
405
 
406
    rc = closedir(dir);
407
    if (rc<0) {
408
        errno = EIO;
409
        return rc * 10 - 9;
410
    }
411
 
412
    return 0;
413
}
414
 
415
int ftruncate(int fd, off_t size)
416
{
417
    int rc, sector;
433 theseven 418
    struct filedesc* file = (struct filedesc*)fd;
69 theseven 419
 
420
    sector = size / SECTOR_SIZE;
421
    if (size % SECTOR_SIZE)
422
        sector++;
423
 
424
    rc = fat_seek(&(file->fatfile), sector);
425
    if (rc < 0) {
426
        errno = EIO;
427
        return rc * 10 - 1;
428
    }
429
 
430
    rc = fat_truncate(&(file->fatfile));
431
    if (rc < 0) {
432
        errno = EIO;
433
        return rc * 10 - 2;
434
    }
435
 
436
    file->size = size;
437
 
438
    return 0;
439
}
440
 
441
static int flush_cache(int fd)
442
{
443
    int rc;
433 theseven 444
    struct filedesc* file = (struct filedesc*)fd;
69 theseven 445
    long sector = file->fileoffset / SECTOR_SIZE;
446
 
447
    DEBUGF("Flushing dirty sector cache");
448
 
449
    /* make sure we are on correct sector */
450
    rc = fat_seek(&(file->fatfile), sector);
451
    if ( rc < 0 )
452
        return rc * 10 - 3;
453
 
454
    rc = fat_readwrite(&(file->fatfile), 1, file->cache, true );
455
 
456
    if ( rc < 0 ) {
457
        if(file->fatfile.eof)
458
            errno = ENOSPC;
459
 
460
        return rc * 10 - 2;
461
    }
462
 
463
    file->dirty = false;
464
 
465
    return 0;
466
}
467
 
468
static int readwrite(int fd, void* buf, long count, bool write)
469
{
470
    long sectors;
120 theseven 471
    long i;
69 theseven 472
    long nread=0;
473
    struct filedesc* file;
120 theseven 474
    int rc, rc2;
69 theseven 475
 
433 theseven 476
    file = (struct filedesc*)fd;
69 theseven 477
 
433 theseven 478
    if (!file) {
69 theseven 479
        errno = EBADF;
480
        return -1;
481
    }
482
 
483
    if(file->attr & FAT_ATTR_DIRECTORY) {
484
        errno = EISDIR;
485
        return -1;
486
    }
487
 
488
    DEBUGF( "readwrite(%d,%lx,%ld,%s)",
489
             fd,(long)buf,count,write?"write":"read");
490
 
491
    /* attempt to read past EOF? */
492
    if (!write && count > file->size - file->fileoffset)
493
        count = file->size - file->fileoffset;
494
 
495
    /* any head bytes? */
496
    if ( file->cacheoffset != -1 ) {
497
        int offs = file->cacheoffset;
498
        int headbytes = MIN(count, SECTOR_SIZE - offs);
499
 
500
        if (write) {
501
            memcpy( file->cache + offs, buf, headbytes );
502
            file->dirty = true;
503
        }
504
        else {
505
            memcpy( buf, file->cache + offs, headbytes );
506
        }
507
 
508
        if (offs + headbytes == SECTOR_SIZE) {
509
            if (file->dirty) {
510
                rc = flush_cache(fd);
511
                if ( rc < 0 ) {
512
                    errno = EIO;
513
                    return rc * 10 - 2;
514
                }
515
            }
516
            file->cacheoffset = -1;
517
        }
518
        else {
519
            file->cacheoffset += headbytes;
520
        }
521
 
522
        nread = headbytes;
523
        count -= headbytes;
524
    }
525
 
526
    /* If the buffer has been modified, either it has been flushed already
527
     * (if (offs+headbytes == SECTOR_SIZE)...) or does not need to be (no
528
     * more data to follow in this call). Do NOT flush here. */
529
 
530
    /* read/write whole sectors right into/from the supplied buffer */
531
    sectors = count / SECTOR_SIZE;
120 theseven 532
    rc = 0;
69 theseven 533
    if ( sectors ) {
70 theseven 534
        if (((uint32_t)buf + nread) & (CACHEALIGN_SIZE - 1))
120 theseven 535
            for (i = 0; i < sectors; i++)
536
            {
537
                if (write) memcpy(file->cache, buf+nread+i*SECTOR_SIZE, SECTOR_SIZE);
538
                rc2 = fat_readwrite(&(file->fatfile), 1, file->cache, write );
539
                if (rc2 < 0)
540
                {
541
                    rc = rc2;
542
                    break;
543
                }
544
                else rc += rc2;
545
                if (!write) memcpy(buf+nread+i*SECTOR_SIZE, file->cache, SECTOR_SIZE);
546
            }
69 theseven 547
        else rc = fat_readwrite(&(file->fatfile), sectors, (unsigned char*)buf+nread, write );
548
        if ( rc < 0 ) {
549
            DEBUGF("Failed read/writing %ld sectors",sectors);
550
            errno = EIO;
551
            if(write && file->fatfile.eof) {
552
                DEBUGF("No space left on device");
553
                errno = ENOSPC;
554
            } else {
555
                file->fileoffset += nread;
556
            }
557
            file->cacheoffset = -1;
558
            /* adjust file size to length written */
559
            if ( write && file->fileoffset > file->size )
560
            {
561
                file->size = file->fileoffset;
562
            }
563
            return nread ? nread : rc * 10 - 4;
564
        }
565
        else {
566
            if ( rc > 0 ) {
567
                nread += rc * SECTOR_SIZE;
568
                count -= sectors * SECTOR_SIZE;
569
 
570
                /* if eof, skip tail bytes */
571
                if ( rc < sectors )
572
                    count = 0;
573
            }
574
            else {
575
                /* eof */
576
                count=0;
577
            }
578
 
579
            file->cacheoffset = -1;
580
        }
581
    }
582
 
583
    /* any tail bytes? */
584
    if ( count ) {
585
        if (write) {
586
            if ( file->fileoffset + nread < file->size ) {
587
                /* sector is only partially filled. copy-back from disk */
588
                DEBUGF("Copy-back tail cache");
589
                rc = fat_readwrite(&(file->fatfile), 1, file->cache, false );
590
                if ( rc < 0 ) {
591
                    DEBUGF("Failed writing");
592
                    errno = EIO;
593
                    file->fileoffset += nread;
594
                    file->cacheoffset = -1;
595
                    /* adjust file size to length written */
596
                    if ( file->fileoffset > file->size )
597
                    {
598
                        file->size = file->fileoffset;
599
                    }
600
                    return nread ? nread : rc * 10 - 5;
601
                }
602
                /* seek back one sector to put file position right */
603
                rc = fat_seek(&(file->fatfile), 
604
                              (file->fileoffset + nread) /
605
                              SECTOR_SIZE);
606
                if ( rc < 0 ) {
607
                    DEBUGF("fat_seek() failed");
608
                    errno = EIO;
609
                    file->fileoffset += nread;
610
                    file->cacheoffset = -1;
611
                    /* adjust file size to length written */
612
                    if ( file->fileoffset > file->size )
613
                    {
614
                        file->size = file->fileoffset;
615
                    }
616
                    return nread ? nread : rc * 10 - 6;
617
                }
618
            }
619
            memcpy( file->cache, (unsigned char*)buf + nread, count );
620
            file->dirty = true;
621
        }
622
        else {
623
            rc = fat_readwrite(&(file->fatfile), 1, file->cache,false);
624
            if (rc < 1 ) {
625
                DEBUGF("Failed caching sector");
626
                errno = EIO;
627
                file->fileoffset += nread;
628
                file->cacheoffset = -1;
629
                return nread ? nread : rc * 10 - 7;
630
            }
631
            memcpy( (unsigned char*)buf + nread, file->cache, count );
632
        }
633
 
634
        nread += count;
635
        file->cacheoffset = count;
636
    }
637
 
638
    file->fileoffset += nread;
639
    DEBUGF("fileoffset: %ld", file->fileoffset);
640
 
641
    /* adjust file size to length written */
642
    if ( write && file->fileoffset > file->size )
643
    {
644
        file->size = file->fileoffset;
645
    }
646
 
647
    return nread;
648
}
649
 
650
ssize_t write(int fd, const void* buf, size_t count)
651
{
433 theseven 652
    if (!((struct filedesc*)fd)->write) {
69 theseven 653
        errno = EACCES;
654
        return -1;
655
    }
656
    return readwrite(fd, (void *)buf, count, true);
657
}
658
 
659
ssize_t read(int fd, void* buf, size_t count)
660
{
661
    return readwrite(fd, buf, count, false);
662
}
663
 
664
 
665
off_t lseek(int fd, off_t offset, int whence)
666
{
667
    off_t pos;
668
    long newsector;
669
    long oldsector;
670
    int sectoroffset;
671
    int rc;
433 theseven 672
    struct filedesc* file = (struct filedesc*)fd;
69 theseven 673
 
674
    DEBUGF("lseek(%d,%ld,%d)",fd,offset,whence);
675
 
433 theseven 676
    if (!file) {
69 theseven 677
        errno = EBADF;
678
        return -1;
679
    }
680
 
681
    switch ( whence ) {
682
        case SEEK_SET:
683
            pos = offset;
684
            break;
685
 
686
        case SEEK_CUR:
687
            pos = file->fileoffset + offset;
688
            break;
689
 
690
        case SEEK_END:
691
            pos = file->size + offset;
692
            break;
693
 
694
        default:
695
            errno = EINVAL;
696
            return -2;
697
    }
698
    if ((pos < 0) || (pos > file->size)) {
699
        errno = EINVAL;
700
        return -3;
701
    }
702
 
703
    /* new sector? */
704
    newsector = pos / SECTOR_SIZE;
705
    oldsector = file->fileoffset / SECTOR_SIZE;
706
    sectoroffset = pos % SECTOR_SIZE;
707
 
708
    if ( (newsector != oldsector) ||
709
         ((file->cacheoffset==-1) && sectoroffset) ) {
710
 
711
        if ( newsector != oldsector ) {
712
            if (file->dirty) {
713
                rc = flush_cache(fd);
714
                if (rc < 0)
715
                    return rc * 10 - 5;
716
            }
717
 
718
            rc = fat_seek(&(file->fatfile), newsector);
719
            if ( rc < 0 ) {
720
                errno = EIO;
721
                return rc * 10 - 4;
722
            }
723
        }
724
        if ( sectoroffset ) {
725
            rc = fat_readwrite(&(file->fatfile), 1, file->cache ,false);
726
            if ( rc < 0 ) {
727
                errno = EIO;
728
                return rc * 10 - 6;
729
            }
730
            file->cacheoffset = sectoroffset;
731
        }
732
        else
733
            file->cacheoffset = -1;
734
    }
735
    else
736
        if ( file->cacheoffset != -1 )
737
            file->cacheoffset = sectoroffset;
738
 
739
    file->fileoffset = pos;
740
 
741
    return pos;
742
}
743
 
744
off_t filesize(int fd)
745
{
433 theseven 746
    struct filedesc* file = (struct filedesc*)fd;
69 theseven 747
 
433 theseven 748
    if (!file) {
69 theseven 749
        errno = EBADF;
750
        return -1;
751
    }
752
 
753
    return file->size;
754
}
755
 
756
 
757
#ifdef HAVE_HOTSWAP
758
/* release all file handles on a given volume "by force", to avoid leaks */
759
int release_files(int volume)
760
{
433 theseven 761
    struct filedesc* prev;
69 theseven 762
    int closed = 0;
433 theseven 763
    mutex_lock(&file_mutex, TIMEOUT_BLOCK);
764
#ifdef HAVE_MULTIVOLUME
765
    struct filedesc* f;
766
    while (openfiles && openfiles->fatfile.volume == volume)
69 theseven 767
    {
433 theseven 768
        prev = openfiles;
769
        openfiles = openfiles->next;
770
        free(prev);
771
        closed++;
772
    }
773
    for (f = openfiles; f; f = f->next)
460 theseven 774
        while (f->next && f->next->fatfile.volume == volume)
69 theseven 775
        {
460 theseven 776
            prev = f->next;
777
            f->next = f->next->next;
778
            free(prev);
69 theseven 779
            closed++;
780
        }
433 theseven 781
#else
782
    (void)volume;
783
    while (openfiles)
784
    {
785
        prev = openfiles;
786
        openfiles = openfiles->next;
787
        free(prev);
788
        closed++;
789
    }
790
#endif
791
    mutex_unlock(&file_mutex);
69 theseven 792
    return closed; /* return how many we did */
793
}
794
#endif /* #ifdef HAVE_HOTSWAP */