OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [fs/] [fat/] [current/] [src/] [fatfs.c] - Blame information for rev 856

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      fatfs.c
4
//
5
//      FAT file system
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):           Savin Zlobec <savin@elatec.si> (based on ramfs.c)
43
// Original data:       nickg
44
// Date:                2003-06-29
45
// Purpose:             FAT file system
46
// Description:         This is a FAT filesystem for eCos. 
47
//
48
//####DESCRIPTIONEND####
49
//
50
//==========================================================================
51
 
52
#include <pkgconf/system.h>
53
#include <pkgconf/hal.h>
54
#include <pkgconf/io_fileio.h>
55
#include <pkgconf/fs_fat.h>
56
 
57
#include <cyg/infra/cyg_type.h>   
58
#include <cyg/infra/cyg_trac.h>        // tracing macros
59
#include <cyg/infra/cyg_ass.h>         // assertion macros
60
 
61
#include <unistd.h>
62
#include <sys/types.h>
63
#include <fcntl.h>
64
#include <sys/stat.h>
65
#include <errno.h>
66
#include <dirent.h>
67
 
68
#include <stdlib.h>
69
#include <string.h>
70
 
71
#include <cyg/infra/diag.h>
72
#include <cyg/fileio/fileio.h>
73
#include <cyg/io/io.h>
74
#include <blib/blib.h>
75
#include <cyg/fs/fatfs.h>
76
 
77
#include "fatfs.h"
78
 
79
//==========================================================================
80
// Tracing support defines 
81
 
82
#ifdef FATFS_TRACE_FS_OP
83
# define TFS 1
84
#else
85
# define TFS 0
86
#endif
87
 
88
#ifdef FATFS_TRACE_FILE_OP
89
# define TFO 1
90
#else
91
# define TFO 0
92
#endif
93
 
94
//==========================================================================
95
// Forward definitions
96
 
97
// Filesystem operations
98
static int fatfs_mount  (cyg_fstab_entry *fste, cyg_mtab_entry *mte);
99
static int fatfs_umount (cyg_mtab_entry *mte);
100
static int fatfs_open   (cyg_mtab_entry *mte, cyg_dir dir, const char *name,
101
                         int mode, cyg_file *fte);
102
static int fatfs_unlink (cyg_mtab_entry *mte, cyg_dir dir, const char *name);
103
static int fatfs_mkdir  (cyg_mtab_entry *mte, cyg_dir dir, const char *name);
104
static int fatfs_rmdir  (cyg_mtab_entry *mte, cyg_dir dir, const char *name);
105
static int fatfs_rename (cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
106
                         cyg_dir dir2, const char *name2 );
107
static int fatfs_link   (cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
108
                         cyg_dir dir2, const char *name2, int type );
109
static int fatfs_opendir(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
110
                         cyg_file *fte );
111
static int fatfs_chdir  (cyg_mtab_entry *mte, cyg_dir dir, const char *name,
112
                         cyg_dir *dir_out );
113
static int fatfs_stat   (cyg_mtab_entry *mte, cyg_dir dir, const char *name,
114
                         struct stat *buf);
115
static int fatfs_getinfo(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
116
                         int key, void *buf, int len );
117
static int fatfs_setinfo(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
118
                         int key, void *buf, int len );
119
 
120
// File operations
121
static int fatfs_fo_read   (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
122
static int fatfs_fo_write  (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
123
static int fatfs_fo_lseek  (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
124
static int fatfs_fo_ioctl  (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
125
                            CYG_ADDRWORD data);
126
static int fatfs_fo_fsync  (struct CYG_FILE_TAG *fp, int mode );
127
static int fatfs_fo_close  (struct CYG_FILE_TAG *fp);
128
static int fatfs_fo_fstat  (struct CYG_FILE_TAG *fp, struct stat *buf );
129
static int fatfs_fo_getinfo(struct CYG_FILE_TAG *fp, int key,
130
                            void *buf, int len );
131
static int fatfs_fo_setinfo(struct CYG_FILE_TAG *fp, int key,
132
                            void *buf, int len );
133
 
134
// Directory operations
135
static int fatfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
136
static int fatfs_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence);
137
 
138
//==========================================================================
139
// Filesystem table entries
140
 
141
// -------------------------------------------------------------------------
142
// Fstab entry.
143
 
144
FSTAB_ENTRY(fatfs_fste, "fatfs", 0,
145
            CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
146
            fatfs_mount,
147
            fatfs_umount,
148
            fatfs_open,
149
            fatfs_unlink,
150
            fatfs_mkdir,
151
            fatfs_rmdir,
152
            fatfs_rename,
153
            fatfs_link,
154
            fatfs_opendir,
155
            fatfs_chdir,
156
            fatfs_stat,
157
            fatfs_getinfo,
158
            fatfs_setinfo);
159
 
160
// -------------------------------------------------------------------------
161
// File operations.
162
 
163
static cyg_fileops fatfs_fileops =
164
{
165
    fatfs_fo_read,
166
    fatfs_fo_write,
167
    fatfs_fo_lseek,
168
    fatfs_fo_ioctl,
169
    cyg_fileio_seltrue,
170
    fatfs_fo_fsync,
171
    fatfs_fo_close,
172
    fatfs_fo_fstat,
173
    fatfs_fo_getinfo,
174
    fatfs_fo_setinfo
175
};
176
 
177
// -------------------------------------------------------------------------
178
// Directory file operations.
179
 
180
static cyg_fileops fatfs_dirops =
181
{
182
    fatfs_fo_dirread,
183
    (cyg_fileop_write *)cyg_fileio_enosys,
184
    fatfs_fo_dirlseek,
185
    (cyg_fileop_ioctl *)cyg_fileio_enosys,
186
    cyg_fileio_seltrue,
187
    (cyg_fileop_fsync *)cyg_fileio_enosys,
188
    fatfs_fo_close,
189
    (cyg_fileop_fstat *)cyg_fileio_enosys,
190
    (cyg_fileop_getinfo *)cyg_fileio_enosys,
191
    (cyg_fileop_setinfo *)cyg_fileio_enosys
192
};
193
 
194
// -------------------------------------------------------------------------
195
// Directory search data
196
// Parameters for a directory search. The fields of this structure are
197
// updated as we follow a pathname through the directory tree.
198
 
199
typedef struct fatfs_dirsearch_s
200
{
201
    fatfs_disk_t        *disk;     // Disk info 
202
    fatfs_node_t        *dir;      // Directory to search
203
    const char          *path;     // Path to follow
204
    fatfs_node_t        *node;     // Node found
205
    const char          *name;     // Last name fragment used
206
    int                  namelen;  // Name fragment length
207
    cyg_bool             last;     // Last name in path?
208
} fatfs_dirsearch_t;
209
 
210
// -------------------------------------------------------------------------
211
// FATFS file descriptor data
212
 
213
typedef struct fatfs_fd_s
214
{
215
    fatfs_node_t      *node;
216
    fatfs_data_pos_t   pos;
217
} fatfs_fd_t;
218
 
219
static fatfs_fd_t  fatfs_fds_base[CYGNUM_FILEIO_NFD];
220
static fatfs_fd_t *fatfs_fds_pool[CYGNUM_FILEIO_NFD];
221
static cyg_uint32  fatfs_fds_free_cnt;
222
 
223
//==========================================================================
224
 
225
#if TFS
226
static void
227
print_disk_info(fatfs_disk_t *disk)
228
{
229
    diag_printf("FAT: sector size:        %u\n", disk->sector_size);
230
    diag_printf("FAT: cluster size:       %u\n", disk->cluster_size);
231
    diag_printf("FAT: FAT table position: %u\n", disk->fat_tbl_pos);
232
    diag_printf("FAT: FAT table num ent:  %u\n", disk->fat_tbl_nents);
233
    diag_printf("FAT: FAT table size:     %u\n", disk->fat_tbl_size);
234
    diag_printf("FAT: FAT tables num:     %u\n", disk->fat_tbls_num);
235
    diag_printf("FAT: FAT root dir pos:   %u\n", disk->fat_root_dir_pos);
236
    diag_printf("FAT: FAT root dir nents: %u\n", disk->fat_root_dir_nents);
237
    diag_printf("FAT: FAT root dir size:  %u\n", disk->fat_root_dir_size);
238
    diag_printf("FAT: FAT data position:  %u\n", disk->fat_data_pos);
239
}
240
#endif
241
 
242
static void
243
init_fatfs_fds(void)
244
{
245
    static bool initialized = false;
246
 
247
    int i;
248
 
249
    if (initialized)
250
        return;
251
 
252
    initialized = true;
253
 
254
    for (i = 0; i < CYGNUM_FILEIO_NFD; i++)
255
    {
256
        fatfs_fds_pool[i] = &fatfs_fds_base[i];
257
    }
258
    fatfs_fds_free_cnt = i;
259
}
260
 
261
static fatfs_fd_t *
262
alloc_fatfs_fd(fatfs_disk_t *disk, fatfs_node_t *node)
263
{
264
    fatfs_fd_t *fd = NULL;
265
 
266
    if (fatfs_fds_free_cnt > 0)
267
    {
268
        fd = fatfs_fds_pool[--fatfs_fds_free_cnt];
269
 
270
        fd->node = node;
271
        fatfs_initpos(disk, &node->dentry, &fd->pos);
272
    }
273
 
274
    return fd;
275
}
276
 
277
static void
278
free_fatfs_fd(fatfs_fd_t *fd)
279
{
280
    fatfs_fds_pool[fatfs_fds_free_cnt++] = fd;
281
}
282
 
283
static void
284
init_dirsearch(fatfs_dirsearch_t *ds,
285
               fatfs_disk_t      *disk,
286
               fatfs_node_t      *dir,
287
               const char        *name)
288
{
289
    ds->disk = disk;
290
 
291
    if (NULL == dir)
292
        ds->dir = disk->root;
293
    else
294
        ds->dir = dir;
295
 
296
    ds->path    = name;
297
    ds->node    = ds->dir;
298
    ds->namelen = 0;
299
    ds->last    = false;
300
}
301
 
302
static int
303
find_direntry(fatfs_dirsearch_t *ds)
304
{
305
    fatfs_dir_entry_t  dentry;
306
    fatfs_data_pos_t   pos;
307
    int                err;
308
 
309
    CYG_TRACE1(TFS, "searching for dir entry '%s'", ds->name);
310
 
311
    // Check for '.' 
312
 
313
    if (!strncmp(".", ds->name, ds->namelen))
314
    {
315
        ds->node = ds->dir;
316
        return ENOERR;
317
    }
318
 
319
    // Check the cache
320
 
321
    ds->node = fatfs_node_find(ds->disk,
322
                               ds->name,
323
                               ds->namelen,
324
                               ds->dir->dentry.cluster);
325
 
326
    if (ds->node != NULL)
327
    {
328
        // Dir entry found in cache
329
 
330
        CYG_TRACE0(TFS, "dir entry found in cache");
331
 
332
        fatfs_node_touch(ds->disk, ds->node);
333
        return ENOERR;
334
    }
335
 
336
    // Dir entry not in cache - search the current dir
337
 
338
    fatfs_initpos(ds->disk, &ds->dir->dentry, &pos);
339
 
340
    while (true)
341
    {
342
        // Read next dir entry 
343
 
344
        err = fatfs_read_dir_entry(ds->disk, &ds->dir->dentry, &pos, &dentry);
345
        if (err != ENOERR)
346
            return (err == EEOF ? ENOERR : err);
347
 
348
        // Compare filenames
349
 
350
        if ('\0' == dentry.filename[ds->namelen] &&
351
 
352
        {
353
            // Dir entry found - allocate new node and return
354
 
355
            CYG_TRACE0(TFS, "dir entry found");
356
 
357
            if (0 == strncmp(ds->name, "..", ds->namelen))
358
            {
359
                fatfs_dir_entry_t _dentry;
360
                fatfs_data_pos_t  _pos;
361
 
362
                if (0 == dentry.cluster)
363
                {
364
                    ds->node = ds->disk->root;
365
                    return ENOERR;
366
                }
367
 
368
                fatfs_initpos(ds->disk, &dentry, &_pos);
369
                while (true)
370
                {
371
                    err = fatfs_read_dir_entry(ds->disk, &dentry, &_pos, &_dentry);
372
                    if (err != ENOERR)
373
                        return err;
374
                    if (0 == strcmp(".", _dentry.filename))
375
                        break;
376
                }
377
 
378
                ds->node = fatfs_node_find(ds->disk,
379
                                           _dentry.filename,
380
                                           strlen(_dentry.filename),
381
                                           _dentry.parent_cluster);
382
 
383
                if (NULL != ds->node)
384
                    fatfs_node_touch(ds->disk, ds->node);
385
                else
386
                    ds->node = fatfs_node_alloc(ds->disk, &_dentry);
387
 
388
                if (NULL == ds->node)
389
                    return EMFILE;
390
 
391
                return ENOERR;
392
            }
393
            else
394
                ds->node = fatfs_node_alloc(ds->disk, &dentry);
395
 
396
            if (NULL == ds->node)
397
                return EMFILE;
398
 
399
            return ENOERR;
400
        }
401
    }
402
}
403
 
404
static int
405
find_entry(fatfs_dirsearch_t *ds)
406
{
407
    const char  *name     = ds->path;
408
    const char  *n        = name;
409
    char         namelen  = 0;
410
    int          err;
411
 
412
    if( !S_ISDIR(ds->dir->dentry.mode) )
413
    {
414
        CYG_TRACE1(TFS, "entry '%s' not dir", ds->dir->dentry.filename);
415
        return ENOTDIR;
416
    }
417
 
418
    // Isolate the next element of the path name
419
    while (*n != '\0' && *n != '/')
420
        n++, namelen++;
421
 
422
    // If we terminated on a NUL, set last flag
423
    if (*n == '\0')
424
        ds->last = true;
425
 
426
    // Update name in dirsearch object
427
    ds->name    = name;
428
    ds->namelen = namelen;
429
 
430
    err = find_direntry(ds);
431
    if (err != ENOERR)
432
        return err;
433
 
434
    CYG_TRACE2(TFS, "entry '%s' %s", name, (ds->node ? "found" : "not found"));
435
 
436
    if (ds->node != NULL)
437
       return ENOERR;
438
    else
439
       return ENOENT;
440
}
441
 
442
static int
443
fatfs_find(fatfs_dirsearch_t *ds)
444
{
445
    int err;
446
 
447
    CYG_TRACE1(TFS, "find path='%s'", ds->path);
448
 
449
    // Short circuit empty paths
450
    if (*(ds->path) == '\0')
451
        return ENOERR;
452
 
453
    // Iterate down directory tree until we find the object we want
454
    for(;;)
455
    {
456
        err = find_entry(ds);
457
 
458
        if (err != ENOERR)
459
            return err;
460
 
461
        if (ds->last)
462
        {
463
            CYG_TRACE0(TFS, "entry found");
464
            return ENOERR;
465
        }
466
 
467
        // Update dirsearch object to search next directory
468
        ds->dir   = ds->node;
469
        ds->path += ds->namelen;
470
 
471
        // Skip dirname separators
472
        if (*(ds->path) == '/') ds->path++;
473
 
474
        CYG_TRACE1(TFS, "find path to go='%s'", ds->path);
475
    }
476
}
477
 
478
//==========================================================================
479
// Filesystem operations
480
 
481
// -------------------------------------------------------------------------
482
// fatfs_mount()
483
// Process a mount request. This mainly creates a root for the
484
// filesystem.
485
 
486
static int
487
fatfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte)
488
{
489
    cyg_io_handle_t     dev_h;
490
    fatfs_disk_t       *disk;
491
    fatfs_dir_entry_t   root_dentry;
492
    Cyg_ErrNo           err;
493
 
494
    CYG_TRACE2(TFS, "mount fste=%p mte=%p", fste, mte);
495
 
496
    init_fatfs_fds();
497
 
498
    CYG_TRACE1(TFS, "looking up disk device '%s'", mte->devname);
499
 
500
    err = cyg_io_lookup(mte->devname, &dev_h);
501
    if (err != ENOERR)
502
        return err;
503
 
504
    disk = (fatfs_disk_t *)malloc(sizeof(fatfs_disk_t));
505
    if (NULL == disk)
506
        return ENOMEM;
507
 
508
    CYG_TRACE0(TFS, "initializing block cache");
509
 
510
    disk->bcache_mem = (cyg_uint8 *)malloc(CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE);
511
    if (NULL == disk->bcache_mem)
512
    {
513
        free(disk);
514
        return ENOMEM;
515
    }
516
    // FIXME: get block size from disk device
517
    err = cyg_blib_io_create(dev_h, disk->bcache_mem,
518
            CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE, 512, &disk->blib);
519
    if (err != ENOERR)
520
    {
521
        free(disk->bcache_mem);
522
        free(disk);
523
        return err;
524
    }
525
 
526
    disk->dev_h = dev_h;
527
 
528
    CYG_TRACE0(TFS, "initializing disk");
529
 
530
    err = fatfs_init(disk);
531
    if (err != ENOERR)
532
    {
533
        cyg_blib_delete(&disk->blib);
534
        free(disk->bcache_mem);
535
        free(disk);
536
        return err;
537
    }
538
 
539
#if TFS    
540
    print_disk_info(disk);
541
#endif
542
 
543
    CYG_TRACE0(TFS, "initializing node cache");
544
 
545
    fatfs_node_cache_init(disk);
546
 
547
    CYG_TRACE0(TFS, "initializing root node");
548
 
549
    fatfs_get_root_dir_entry(disk, &root_dentry);
550
 
551
    disk->root = fatfs_node_alloc(disk, &root_dentry);
552
 
553
    fatfs_node_ref(disk, disk->root);
554
 
555
    mte->root = (cyg_dir)disk->root;
556
    mte->data = (CYG_ADDRWORD)disk;
557
 
558
    CYG_TRACE0(TFS, "disk mounted");
559
 
560
    return ENOERR;
561
}
562
 
563
// -------------------------------------------------------------------------
564
// fatfs_umount()
565
// Unmount the filesystem. This will currently only succeed if the
566
// filesystem is empty.
567
 
568
static int
569
fatfs_umount(cyg_mtab_entry *mte)
570
{
571
    fatfs_disk_t  *disk  = (fatfs_disk_t *) mte->data;
572
    fatfs_node_t  *root  = (fatfs_node_t *) mte->root;
573
 
574
    CYG_TRACE3(TFS, "umount mte=%p %d live nodes %d dead nodes",
575
                    mte, fatfs_get_live_node_count(disk),
576
                    fatfs_get_dead_node_count(disk));
577
 
578
    if (root->refcnt > 1)
579
        return EBUSY;
580
 
581
    if (fatfs_get_live_node_count(disk) != 1)
582
        return EBUSY;
583
 
584
    fatfs_node_unref(disk, root);
585
    fatfs_node_cache_flush(disk);
586
    // FIXME: cache delete can fail if cache can't be synced
587
    cyg_blib_delete(&disk->blib);
588
    free(disk->bcache_mem);
589
    free(disk);
590
 
591
    mte->root = CYG_DIR_NULL;
592
    mte->data = (CYG_ADDRWORD) NULL;
593
 
594
    CYG_TRACE0(TFS, "disk umounted");
595
 
596
    return ENOERR;
597
}
598
 
599
// -------------------------------------------------------------------------
600
// fatfs_open()
601
// Open a file for reading or writing.
602
 
603
static int
604
fatfs_open(cyg_mtab_entry *mte,
605
           cyg_dir         dir,
606
           const char     *name,
607
           int             mode,
608
           cyg_file       *file)
609
{
610
    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
611
    fatfs_node_t       *node = NULL;
612
    fatfs_fd_t         *fd;
613
    fatfs_dirsearch_t   ds;
614
    int                 err;
615
 
616
    CYG_TRACE5(TFS, "open mte=%p dir=%p name='%s' mode=%d file=%p",
617
                    mte, dir, name, mode, file);
618
 
619
    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
620
 
621
    err = fatfs_find(&ds);
622
 
623
    if (err == ENOENT)
624
    {
625
        if (ds.last && (mode & O_CREAT))
626
        {
627
            fatfs_dir_entry_t new_file_dentry;
628
 
629
            // No node there, if the O_CREAT bit is set then we must
630
            // create a new one. The dir and name fields of the dirsearch
631
            // object will have been updated so we know where to put it.
632
 
633
            CYG_TRACE1(TFS, "creating new file '%s'", name);
634
 
635
            err = fatfs_create_file(disk,
636
                                    &ds.dir->dentry,
637
                                    ds.name,
638
                                    ds.namelen,
639
                                    &new_file_dentry);
640
            if (err != ENOERR)
641
                return err;
642
 
643
            node = fatfs_node_alloc(disk, &new_file_dentry);
644
            if (NULL == node)
645
                return EMFILE;
646
 
647
            // Update directory times
648
            ds.dir->dentry.atime =
649
            ds.dir->dentry.mtime = cyg_timestamp();
650
 
651
            err = ENOERR;
652
        }
653
    }
654
    else if (err == ENOERR)
655
    {
656
        // The node exists. If the O_CREAT and O_EXCL bits are set, we
657
        // must fail the open
658
 
659
        if ((mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
660
            err = EEXIST;
661
        else
662
            node = ds.node;
663
    }
664
 
665
    if (err == ENOERR && (mode & O_TRUNC))
666
    {
667
        // If the O_TRUNC bit is set we must clean out the file data
668
        CYG_TRACE0(TFS, "truncating file");
669
        fatfs_trunc_file(disk, &node->dentry);
670
    }
671
 
672
    if (err != ENOERR)
673
        return err;
674
 
675
    if (S_ISDIR(node->dentry.mode))
676
        return EISDIR;
677
 
678
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
679
    // if the file is read only and is opened for writing
680
    // fail with permission error
681
    if (S_FATFS_ISRDONLY(node->dentry.attrib) && (mode & O_WRONLY))
682
        return EACCES;
683
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
684
 
685
    // Allocate file object private data and
686
    // make a reference to this file node
687
 
688
    fd = alloc_fatfs_fd(disk, node);
689
    if (NULL == fd)
690
        return EMFILE;
691
 
692
    fatfs_node_ref(disk, node);
693
 
694
    // Initialize the file object
695
 
696
    if (mode & O_APPEND)
697
        fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);
698
 
699
    file->f_flag   |= mode & CYG_FILE_MODE_MASK;
700
    file->f_type    = CYG_FILE_TYPE_FILE;
701
    file->f_ops     = &fatfs_fileops;
702
    file->f_offset  = (mode & O_APPEND) ? node->dentry.size : 0;
703
    file->f_data    = (CYG_ADDRWORD) fd;
704
    file->f_xops    = 0;
705
 
706
    return ENOERR;
707
}
708
 
709
// -------------------------------------------------------------------------
710
// fatfs_unlink()
711
// Remove a file link from its directory.
712
 
713
static int
714
fatfs_unlink(cyg_mtab_entry *mte,
715
             cyg_dir         dir,
716
             const char     *name)
717
{
718
    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
719
    fatfs_dirsearch_t   ds;
720
    int                 err;
721
 
722
    CYG_TRACE3(TFS, "unlink mte=%p dir=%p name='%s'", mte, dir, name);
723
 
724
    init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);
725
 
726
    err = fatfs_find(&ds);
727
 
728
    if (err != ENOERR)
729
        return err;
730
 
731
    if (ds.node->refcnt > 0)
732
        return EBUSY;
733
 
734
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
735
    // if the file is read only fail with permission error
736
    if (S_FATFS_ISRDONLY(ds.node->dentry.attrib))
737
        return EPERM;
738
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
739
 
740
    err = fatfs_delete_file(disk, &ds.node->dentry);
741
    if (err == ENOERR)
742
        fatfs_node_free(disk, ds.node);
743
 
744
    return err;
745
}
746
 
747
// -------------------------------------------------------------------------
748
// fatfs_mkdir()
749
// Create a new directory.
750
 
751
static int
752
fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
753
{
754
    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
755
    fatfs_dirsearch_t   ds;
756
    int                 err;
757
 
758
    CYG_TRACE3(TFS, "mkdir mte=%p dir=%p name='%s'", mte, dir, name);
759
 
760
    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
761
 
762
    err = fatfs_find(&ds);
763
 
764
    if (err == ENOENT)
765
    {
766
        if (ds.last)
767
        {
768
            fatfs_dir_entry_t new_dir_dentry;
769
 
770
            // The entry does not exist, and it is the last element in
771
            // the pathname, so we can create it here
772
 
773
            err = fatfs_create_dir(disk,
774
                                   &ds.dir->dentry,
775
                                   ds.name,
776
                                   ds.namelen,
777
                                   &new_dir_dentry);
778
            if (err != ENOERR)
779
                return err;
780
 
781
            fatfs_node_alloc(disk, &new_dir_dentry);
782
 
783
            return ENOERR;
784
        }
785
    }
786
    else if (err == ENOERR)
787
    {
788
        return EEXIST;
789
    }
790
 
791
    return err;
792
}
793
 
794
// -------------------------------------------------------------------------
795
// fatfs_rmdir()
796
// Remove a directory.
797
 
798
static int
799
fatfs_rmdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
800
{
801
    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
802
    fatfs_dirsearch_t  ds;
803
    int                err;
804
    fatfs_node_t      *node;
805
 
806
    CYG_TRACE3(TFS, "rmdir mte=%p dir=%p name='%s'", mte, dir, name);
807
 
808
    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
809
 
810
    err = fatfs_find(&ds);
811
 
812
    if (err != ENOERR)
813
        return err;
814
 
815
    if (!S_ISDIR(ds.node->dentry.mode))
816
        return EPERM;
817
 
818
    if (ds.node->refcnt > 0)
819
        return EBUSY;
820
 
821
    err = fatfs_delete_file(disk, &ds.node->dentry);
822
    if (err == ENOERR)
823
    {
824
        node = fatfs_node_find( disk, ".", 1, ds.node->dentry.cluster );
825
        if (node != NULL)
826
             fatfs_node_free(disk, node);
827
 
828
        node = fatfs_node_find( disk, "..", 2, ds.node->dentry.cluster );
829
        if (node != NULL)
830
            fatfs_node_free(disk, node);
831
 
832
        fatfs_node_free(disk, ds.node);
833
    }
834
    return err;
835
}
836
 
837
// -------------------------------------------------------------------------
838
// fatfs_rename()
839
// Rename a file/dir.
840
 
841
static int
842
fatfs_rename(cyg_mtab_entry *mte,
843
             cyg_dir         dir1,
844
             const char     *name1,
845
             cyg_dir         dir2,
846
             const char     *name2)
847
{
848
    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
849
    fatfs_dirsearch_t   ds1, ds2;
850
    int                 err;
851
 
852
    CYG_TRACE5(TFS, "rename mte=%p dir1=%p name1='%s' dir2=%p name2='%s'",
853
                    mte, dir1, name1, dir2, name2);
854
 
855
    init_dirsearch(&ds1, disk, (fatfs_node_t *)dir1, name1);
856
 
857
    err = fatfs_find(&ds1);
858
    if (err != ENOERR)
859
        return err;
860
 
861
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
862
    // if the file is read only fail with permission error
863
    if (S_FATFS_ISRDONLY(ds1.node->dentry.attrib))
864
        return EPERM;
865
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
866
 
867
    // Protect the found nodes from being reused 
868
    // by the search for the ds2 dir/node pair 
869
    fatfs_node_ref(disk, ds1.dir);
870
    fatfs_node_ref(disk, ds1.node);
871
 
872
    init_dirsearch(&ds2, disk, (fatfs_node_t *) dir2, name2);
873
 
874
    err = fatfs_find(&ds2);
875
 
876
    // Check if the target name already exists
877
    if (err == ENOERR && ds2.last)
878
    {
879
        err = EEXIST;
880
        goto out;
881
    }
882
 
883
    // Check if the target dir doesn't exist
884
    if (err == ENOENT && !ds2.last)
885
        goto out;
886
 
887
    // Check if the target and the source are the same
888
    if (ds1.node == ds2.node)
889
    {
890
        err = ENOERR;
891
        goto out;
892
    }
893
 
894
    err = fatfs_rename_file(disk,
895
                            &ds1.dir->dentry,
896
                            &ds1.node->dentry,
897
                            &ds2.dir->dentry,
898
                            ds2.name,
899
                            ds2.namelen);
900
 
901
    fatfs_node_rehash(disk, ds1.node);
902
 
903
out:
904
    // Unreference previousely protected nodes
905
    fatfs_node_unref(disk, ds1.dir);
906
    fatfs_node_unref(disk, ds1.node);
907
 
908
    if (err == ENOERR)
909
    {
910
        ds1.dir->dentry.atime =
911
        ds1.dir->dentry.mtime =
912
        ds2.dir->dentry.atime =
913
        ds2.dir->dentry.mtime = cyg_timestamp();
914
    }
915
    return err;
916
}
917
 
918
// -------------------------------------------------------------------------
919
// fatfs_link()
920
// Make a new directory entry for a file.
921
 
922
static int
923
fatfs_link(cyg_mtab_entry *mte,
924
           cyg_dir         dir1,
925
           const char     *name1,
926
           cyg_dir         dir2,
927
           const char     *name2,
928
           int             type)
929
{
930
    CYG_TRACE6(TFS, "link mte=%p dir1=%p name1='%s' dir2=%p name2='%s' type=%d",
931
                    mte, dir1, name1, dir2, name2, type);
932
 
933
    // Linking not supported
934
    return EINVAL;
935
}
936
 
937
// -------------------------------------------------------------------------
938
// fatfs_opendir()
939
// Open a directory for reading.
940
 
941
static int
942
fatfs_opendir(cyg_mtab_entry *mte,
943
              cyg_dir         dir,
944
              const char     *name,
945
              cyg_file       *file)
946
{
947
    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
948
    fatfs_fd_t         *fd;
949
    fatfs_dirsearch_t   ds;
950
    int                 err;
951
 
952
    CYG_TRACE4(TFS, "opendir mte=%p dir=%p name='%s' file=%p",
953
                    mte, dir, name, file);
954
 
955
    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
956
 
957
    err = fatfs_find(&ds);
958
    if (err != ENOERR)
959
        return err;
960
 
961
    if (!S_ISDIR(ds.node->dentry.mode))
962
        return ENOTDIR;
963
 
964
    // Allocate file object private data and
965
    // make a reference to this file node
966
 
967
    fd = alloc_fatfs_fd(disk, ds.node);
968
    if (NULL == fd)
969
        return EMFILE;
970
 
971
    fatfs_node_ref(disk, ds.node);
972
 
973
    // Initialize the file object
974
 
975
    file->f_type    = CYG_FILE_TYPE_FILE;
976
    file->f_ops     = &fatfs_dirops;
977
    file->f_data    = (CYG_ADDRWORD) fd;
978
    file->f_xops    = 0;
979
    file->f_offset  = 0;
980
 
981
    return ENOERR;
982
}
983
 
984
// -------------------------------------------------------------------------
985
// fatfs_chdir()
986
// Change directory support.
987
 
988
static int
989
fatfs_chdir(cyg_mtab_entry *mte,
990
            cyg_dir         dir,
991
            const char     *name,
992
            cyg_dir        *dir_out)
993
{
994
    fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
995
 
996
    CYG_TRACE4(TFS, "chdir mte=%p dir=%p dir_out=%p name=%d",
997
                    mte, dir, dir_out, name);
998
 
999
    if (dir_out != NULL)
1000
    {
1001
        // This is a request to get a new directory pointer in *dir_out
1002
 
1003
        fatfs_dirsearch_t ds;
1004
        int               err;
1005
 
1006
        init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1007
 
1008
        err = fatfs_find(&ds);
1009
        if (err != ENOERR)
1010
            return err;
1011
 
1012
        if (!S_ISDIR(ds.node->dentry.mode))
1013
            return ENOTDIR;
1014
 
1015
        if (ds.node != disk->root)
1016
            fatfs_node_ref(disk, ds.node);
1017
 
1018
        *dir_out = (cyg_dir) ds.node;
1019
    }
1020
    else
1021
    {
1022
        // If no output dir is required, this means that the mte and
1023
        // dir arguments are the current cdir setting and we should
1024
        // forget this fact.
1025
 
1026
        fatfs_node_t *node = (fatfs_node_t *) dir;
1027
 
1028
        if (node != disk->root)
1029
            fatfs_node_unref(disk, node);
1030
    }
1031
 
1032
    return ENOERR;
1033
}
1034
 
1035
// -------------------------------------------------------------------------
1036
// fatfs_stat()
1037
// Get struct stat info for named object.
1038
 
1039
static int
1040
fatfs_stat(cyg_mtab_entry *mte,
1041
           cyg_dir         dir,
1042
           const char     *name,
1043
           struct stat    *buf)
1044
{
1045
    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
1046
    fatfs_dirsearch_t  ds;
1047
    int                err;
1048
 
1049
    CYG_TRACE4(TFS, "stat mte=%p dir=%p name='%s' buf=%p",
1050
                    mte, dir, name, buf);
1051
 
1052
    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1053
 
1054
    err = fatfs_find(&ds);
1055
    if (err != ENOERR)
1056
        return err;
1057
 
1058
    // Fill in the status
1059
 
1060
    buf->st_mode   = ds.node->dentry.mode;
1061
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1062
    if (!S_FATFS_ISRDONLY(ds.node->dentry.attrib))
1063
        buf->st_mode |= (S_IWUSR | S_IWGRP | S_IWOTH);
1064
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1065
    buf->st_ino    = (ino_t) ds.node->dentry.cluster;
1066
    buf->st_dev    = 0;
1067
    buf->st_nlink  = 1;
1068
    buf->st_uid    = 0;
1069
    buf->st_gid    = 0;
1070
    buf->st_size   = ds.node->dentry.size;
1071
    buf->st_atime  = ds.node->dentry.atime;
1072
    buf->st_mtime  = ds.node->dentry.mtime;
1073
    buf->st_ctime  = ds.node->dentry.ctime;
1074
 
1075
    return ENOERR;
1076
}
1077
 
1078
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1079
// -------------------------------------------------------------------------
1080
// fatfs_set_attrib()
1081
// Set FAT file system attributes for specified file
1082
 
1083
static int
1084
fatfs_set_attrib(cyg_mtab_entry        *mte,
1085
                 cyg_dir                dir,
1086
                 const char            *name,
1087
                 const cyg_fs_attrib_t  new_attrib)
1088
{
1089
    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
1090
    fatfs_dirsearch_t  ds;
1091
    int                err;
1092
 
1093
    CYG_TRACE4(TFS, "set_attrib mte=%p dir=%p name='%s' buf=%x",
1094
                    mte, dir, name, new_attrib);
1095
 
1096
    // Verify new_mode is valid
1097
    if ((new_attrib & S_FATFS_ATTRIB) != new_attrib)
1098
        return EINVAL;
1099
 
1100
    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1101
 
1102
    err = fatfs_find(&ds);
1103
    if (err != ENOERR)
1104
        return err;
1105
 
1106
    // Change the "changeable" mode bits for the file.
1107
    ds.node->dentry.attrib =
1108
      (ds.node->dentry.attrib & (~S_FATFS_ATTRIB)) | new_attrib;
1109
 
1110
    return fatfs_write_dir_entry(disk,&ds.node->dentry);
1111
}
1112
 
1113
// -------------------------------------------------------------------------
1114
// fatfs_get_attrib()
1115
// Set FAT file system attributes for specified file
1116
 
1117
static int
1118
fatfs_get_attrib(cyg_mtab_entry  *mte,
1119
                 cyg_dir          dir,
1120
                 const char      *name,
1121
                 cyg_fs_attrib_t * const file_attrib)
1122
{
1123
    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
1124
    fatfs_dirsearch_t  ds;
1125
    int                err;
1126
 
1127
    CYG_TRACE4(TFS, "get_attrib mte=%p dir=%p name='%s' buf=%x",
1128
                    mte, dir, name, file_attrib);
1129
 
1130
    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
1131
 
1132
    err = fatfs_find(&ds);
1133
    if (err != ENOERR)
1134
        return err;
1135
 
1136
    // Get the attribute field
1137
    CYG_CHECK_DATA_PTR(file_attrib,"Invalid destination attribute pointer");
1138
    *file_attrib = ds.node->dentry.attrib;
1139
 
1140
    return ENOERR;
1141
}
1142
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1143
 
1144
// -------------------------------------------------------------------------
1145
// fatfs_getinfo()
1146
// Getinfo. Support for attrib
1147
 
1148
static int
1149
fatfs_getinfo(cyg_mtab_entry *mte,
1150
              cyg_dir         dir,
1151
              const char     *name,
1152
              int             key,
1153
              void           *buf,
1154
              int             len)
1155
{
1156
    int err = EINVAL;
1157
 
1158
    CYG_TRACE6(TFS, "getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
1159
                    mte, dir, name, key, buf, len);
1160
    switch( key )
1161
    {
1162
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1163
        case FS_INFO_ATTRIB:
1164
            err = fatfs_get_attrib(mte, dir, name, (cyg_fs_attrib_t*)buf);
1165
            break;
1166
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1167
#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
1168
        case FS_INFO_BLOCK_USAGE: {
1169
          cyg_uint32 total_clusters;
1170
          cyg_uint32 free_clusters;
1171
          struct cyg_fs_block_usage *usage = (struct cyg_fs_block_usage *) buf;
1172
          fatfs_disk_t  *disk   = (fatfs_disk_t *) mte->data;
1173
 
1174
          err = fatfs_get_disk_usage(disk, &total_clusters, &free_clusters);
1175
          if (err)
1176
            return err;
1177
          usage->total_blocks = total_clusters;
1178
          usage->free_blocks = free_clusters;
1179
          usage->block_size = disk->cluster_size;
1180
          break;
1181
        }
1182
#endif
1183
        default:
1184
            err = EINVAL;
1185
            break;
1186
    }
1187
    return err;
1188
}
1189
 
1190
// -------------------------------------------------------------------------
1191
// fatfs_setinfo()
1192
// Setinfo. Support for fssync and attrib
1193
 
1194
static int
1195
fatfs_setinfo(cyg_mtab_entry *mte,
1196
              cyg_dir         dir,
1197
              const char     *name,
1198
              int             key,
1199
              void           *buf,
1200
              int             len)
1201
{
1202
    int err = EINVAL;
1203
 
1204
    CYG_TRACE6(TFS, "setinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
1205
                    mte, dir, name, key, buf, len);
1206
 
1207
    switch( key )
1208
    {
1209
        case FS_INFO_SYNC:
1210
            err = cyg_blib_sync(&(((fatfs_disk_t *) mte->data)->blib));
1211
            break;
1212
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1213
        case FS_INFO_ATTRIB:
1214
            err = fatfs_set_attrib(mte, dir, name, *(cyg_fs_attrib_t *)buf);
1215
            break;
1216
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1217
        default:
1218
            err = EINVAL;
1219
            break;
1220
    }
1221
    return err;
1222
}
1223
 
1224
//==========================================================================
1225
// File operations
1226
 
1227
// -------------------------------------------------------------------------
1228
// fatfs_fo_read()
1229
// Read data from the file.
1230
 
1231
static int
1232
fatfs_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1233
{
1234
    fatfs_disk_t  *disk   = (fatfs_disk_t *) fp->f_mte->data;
1235
    fatfs_fd_t    *fd     = (fatfs_fd_t *)   fp->f_data;
1236
    fatfs_node_t  *node   = fd->node;
1237
    cyg_uint32     pos    = fp->f_offset;
1238
    ssize_t        resid  = uio->uio_resid;
1239
    int            i;
1240
 
1241
    CYG_TRACE3(TFO, "read fp=%p uio=%p pos=%d", fp, uio, pos);
1242
 
1243
    // Loop over the io vectors until there are none left
1244
 
1245
    for (i = 0; i < uio->uio_iovcnt; i++)
1246
    {
1247
        cyg_iovec  *iov  = &uio->uio_iov[i];
1248
        char       *buf  = (char *) iov->iov_base;
1249
        off_t       len  = iov->iov_len;
1250
 
1251
        // Loop over each vector filling it with data from the file
1252
 
1253
        while (len > 0 && pos < node->dentry.size)
1254
        {
1255
            cyg_uint32 l = len;
1256
            int        err;
1257
 
1258
            // Adjust size to end of file if necessary
1259
            if (l > node->dentry.size-pos)
1260
                l = node->dentry.size-pos;
1261
 
1262
            err = fatfs_read_data(disk, &node->dentry, &fd->pos, buf, &l);
1263
            if (err != ENOERR)
1264
                return err;
1265
 
1266
            // Update working vars
1267
 
1268
            len   -= l;
1269
            buf   += l;
1270
            pos   += l;
1271
            resid -= l;
1272
        }
1273
    }
1274
 
1275
    // We successfully read some data, update the access time, 
1276
    // file offset and transfer residue
1277
 
1278
    node->dentry.atime = cyg_timestamp();
1279
    uio->uio_resid     = resid;
1280
    fp->f_offset       = (off_t) pos;
1281
 
1282
    return ENOERR;
1283
}
1284
 
1285
// -------------------------------------------------------------------------
1286
// fatfs_fo_write()
1287
// Write data to file.
1288
 
1289
static int
1290
fatfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1291
{
1292
    fatfs_disk_t  *disk   = (fatfs_disk_t *) fp->f_mte->data;
1293
    fatfs_fd_t    *fd     = (fatfs_fd_t *)   fp->f_data;
1294
    fatfs_node_t  *node   = fd->node;
1295
    cyg_uint32     pos    = fp->f_offset;
1296
    ssize_t        resid  = uio->uio_resid;
1297
    int            err    = ENOERR;
1298
    int            i;
1299
 
1300
    CYG_TRACE3(TFO, "write fp=%p uio=%p pos=%d", fp, uio, pos);
1301
 
1302
    // If the APPEND mode bit was supplied, force all writes to
1303
    // the end of the file
1304
    if (fp->f_flag & CYG_FAPPEND)
1305
    {
1306
        fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);
1307
        pos = fp->f_offset = node->dentry.size;
1308
    }
1309
 
1310
    // Check that pos is within current file size, or at the very end
1311
    if (pos < 0 || pos > node->dentry.size)
1312
        return EINVAL;
1313
 
1314
    // Now loop over the iovecs until they are all done, or we get an error
1315
 
1316
    for (i = 0; i < uio->uio_iovcnt; i++)
1317
    {
1318
        cyg_iovec  *iov  = &uio->uio_iov[i];
1319
        char       *buf  = (char *) iov->iov_base;
1320
        off_t       len  = iov->iov_len;
1321
 
1322
        // Loop over the vector writing it to the file 
1323
        // until it has all been done
1324
 
1325
        while (len > 0)
1326
        {
1327
            cyg_uint32 l = len;
1328
 
1329
            err = fatfs_write_data(disk, &node->dentry, &fd->pos, buf, &l);
1330
 
1331
            // Update working vars
1332
 
1333
            len   -= l;
1334
            buf   += l;
1335
            pos   += l;
1336
            resid -= l;
1337
 
1338
            // Stop writing if there is no more space in the file
1339
            if (err == ENOSPC)
1340
                break;
1341
 
1342
            if (err != ENOERR)
1343
                return err;
1344
        }
1345
    }
1346
 
1347
    // We wrote some data successfully, update the modified and access
1348
    // times of the node, increase its size appropriately, and update
1349
    // the file offset and transfer residue.
1350
 
1351
    node->dentry.mtime =
1352
    node->dentry.atime = cyg_timestamp();
1353
 
1354
    if (pos > node->dentry.size)
1355
        node->dentry.size = pos;
1356
 
1357
    uio->uio_resid = resid;
1358
    fp->f_offset   = (off_t) pos;
1359
 
1360
    return err;
1361
}
1362
 
1363
// -------------------------------------------------------------------------
1364
// fatfs_fo_lseek()
1365
// Seek to a new file position.
1366
 
1367
static int
1368
fatfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence)
1369
{
1370
    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
1371
    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
1372
    off_t          pos   = *apos;
1373
    int            err;
1374
 
1375
    CYG_TRACE3(TFO, "lseek fp=%p pos=%d whence=%d", fp, fp->f_offset, whence);
1376
 
1377
    switch (whence)
1378
    {
1379
        case SEEK_SET:
1380
            // Pos is already where we want to be
1381
            break;
1382
         case SEEK_CUR:
1383
            // Add pos to current offset
1384
            pos += fp->f_offset;
1385
            break;
1386
         case SEEK_END:
1387
            // Add pos to file size
1388
            pos += fd->node->dentry.size;
1389
            break;
1390
         default:
1391
            return EINVAL;
1392
    }
1393
 
1394
    // Check that pos is still within current file size, 
1395
    // or at the very end
1396
    if (pos < 0 || pos > fd->node->dentry.size)
1397
        return EINVAL;
1398
 
1399
    // All OK, set fp offset and return new position
1400
 
1401
    err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, pos);
1402
 
1403
    if (ENOERR == err)
1404
        *apos = fp->f_offset = pos;
1405
 
1406
    CYG_TRACE2(TFO, "lseek fp=%p new pos=%d", fp, *apos);
1407
 
1408
    return err;
1409
}
1410
 
1411
// -------------------------------------------------------------------------
1412
// fatfs_fo_ioctl()
1413
// Handle ioctls. Currently none are defined.
1414
 
1415
static int
1416
fatfs_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, CYG_ADDRWORD data)
1417
{
1418
    CYG_TRACE3(TFO, "ioctl fp=%p com=%x data=%x", fp, com, data);
1419
    return EINVAL;
1420
}
1421
 
1422
// -------------------------------------------------------------------------
1423
// fatfs_fo_fsync().
1424
// Force the file out to data storage.
1425
 
1426
static int
1427
fatfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
1428
{
1429
    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
1430
    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
1431
    fatfs_node_t  *node  = fd->node;
1432
    int            err;
1433
 
1434
    CYG_TRACE2(TFO, "fsync fp=%p mode=%d", fp, mode);
1435
 
1436
    err = fatfs_write_dir_entry(disk, &node->dentry);
1437
 
1438
    if (ENOERR == err)
1439
        err = cyg_blib_sync(&disk->blib);
1440
 
1441
    return err;
1442
}
1443
 
1444
// -------------------------------------------------------------------------
1445
// fatfs_fo_close()
1446
// Close a file.
1447
 
1448
static int
1449
fatfs_fo_close(struct CYG_FILE_TAG *fp)
1450
{
1451
    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
1452
    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
1453
    fatfs_node_t  *node  = fd->node;
1454
    int            err   = ENOERR;
1455
 
1456
    CYG_TRACE1(TFO, "close fp=%p", fp);
1457
 
1458
    // Write file attributes to disk, unreference 
1459
    // the file node and free its private data
1460
 
1461
    if (node != disk->root)
1462
        err = fatfs_write_dir_entry(disk, &node->dentry);
1463
 
1464
    fatfs_node_unref(disk, node);
1465
 
1466
    free_fatfs_fd(fd);
1467
 
1468
    return err;
1469
}
1470
 
1471
// -------------------------------------------------------------------------
1472
// fatfs_fo_fstat()
1473
// Get file status.
1474
 
1475
static int
1476
fatfs_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
1477
{
1478
    fatfs_fd_t    *fd    = (fatfs_fd_t *) fp->f_data;
1479
    fatfs_node_t  *node  = fd->node;
1480
 
1481
    CYG_TRACE2(TFO, "fstat fp=%p buf=%p", fp, buf);
1482
 
1483
    // Fill in the status
1484
 
1485
    buf->st_mode   = node->dentry.mode;
1486
    buf->st_ino    = (ino_t) node->dentry.cluster;
1487
    buf->st_dev    = 0;
1488
    buf->st_nlink  = 1;
1489
    buf->st_uid    = 0;
1490
    buf->st_gid    = 0;
1491
    buf->st_size   = node->dentry.size;
1492
    buf->st_atime  = node->dentry.atime;
1493
    buf->st_mtime  = node->dentry.mtime;
1494
    buf->st_ctime  = node->dentry.ctime;
1495
 
1496
    return ENOERR;
1497
}
1498
 
1499
// -------------------------------------------------------------------------
1500
// fatfs_fo_getinfo()
1501
// Get info.
1502
 
1503
static int
1504
fatfs_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
1505
{
1506
    CYG_TRACE4(TFO, "getinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
1507
    return EINVAL;
1508
}
1509
 
1510
// -------------------------------------------------------------------------
1511
// fatfs_fo_setinfo()
1512
// Set info.
1513
 
1514
static int
1515
fatfs_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
1516
{
1517
    CYG_TRACE4(TFO, "setinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
1518
    return EINVAL;
1519
}
1520
 
1521
//==========================================================================
1522
// Directory operations
1523
 
1524
// -------------------------------------------------------------------------
1525
// fatfs_fo_dirread()
1526
// Read a single directory entry from a file.
1527
 
1528
static int
1529
fatfs_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1530
{
1531
    fatfs_disk_t      *disk    = (fatfs_disk_t *)  fp->f_mte->data;
1532
    fatfs_fd_t        *fd      = (fatfs_fd_t *)    fp->f_data;
1533
    struct dirent     *ent     = (struct dirent *) uio->uio_iov[0].iov_base;
1534
    char              *nbuf    = ent->d_name;
1535
    off_t              len     = uio->uio_iov[0].iov_len;
1536
    fatfs_dir_entry_t  dentry;
1537
    int                err;
1538
 
1539
    CYG_TRACE3(TFO, "dirread fp=%p uio=%p pos=%d", fp, uio, fp->f_offset);
1540
 
1541
    if (len < sizeof(struct dirent))
1542
        return EINVAL;
1543
 
1544
    err = fatfs_read_dir_entry(disk, &fd->node->dentry, &fd->pos, &dentry);
1545
 
1546
    if (err != ENOERR)
1547
        return (err == EEOF ? ENOERR : err);
1548
 
1549
    strcpy(nbuf, dentry.filename);
1550
#ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE
1551
    ent->d_type = dentry.mode;
1552
#endif
1553
    fd->node->dentry.atime  = cyg_timestamp();
1554
    uio->uio_resid         -= sizeof(struct dirent);
1555
    fp->f_offset++;
1556
 
1557
    return ENOERR;
1558
}
1559
 
1560
// -------------------------------------------------------------------------
1561
// fatfs_fo_dirlseek()
1562
// Seek directory to start.
1563
 
1564
static int
1565
fatfs_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence)
1566
{
1567
    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
1568
    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
1569
    int            err;
1570
 
1571
    CYG_TRACE2(TFO, "dirlseek fp=%p whence=%d", fp, whence);
1572
 
1573
    // Only allow SEEK_SET to zero
1574
 
1575
    if (whence != SEEK_SET || *pos != 0)
1576
        return EINVAL;
1577
 
1578
    err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, 0);
1579
 
1580
    if (ENOERR == err)
1581
        *pos = fp->f_offset = 0;
1582
 
1583
    return err;
1584
}
1585
 
1586
// -------------------------------------------------------------------------
1587
// EOF fatfs.c

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.