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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [io/] [fileio/] [current/] [tests/] [testfs.c] - Blame information for rev 825

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

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      testfs.c
4
//
5
//      Test 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 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):           nickg
43
// Contributors:        nickg
44
// Date:                2000-05-25
45
// Purpose:             Test file system
46
// Description:         This is a very simple implementation of a RAM file system.
47
//                      This implementation is not "industrial strength" or suitable
48
//                      for production use, it is too wasteful of both memory and time.
49
//                      Its primary purpose is to support testing of the fileio
50
//                      infrastructure and API. It can, however, serve as a model
51
//                      and source of code fragments for the implementation
52
//                      of further filesystems.
53
//              
54
//
55
//####DESCRIPTIONEND####
56
//
57
//==========================================================================
58
 
59
#include <pkgconf/hal.h>
60
#include <pkgconf/io_fileio.h>
61
 
62
#include <cyg/infra/cyg_trac.h>        // tracing macros
63
#include <cyg/infra/cyg_ass.h>         // assertion macros
64
 
65
#include <unistd.h>
66
#include <fcntl.h>
67
#include <sys/stat.h>
68
#include <errno.h>
69
#include <dirent.h>
70
 
71
#include <cyg/fileio/fileio.h>
72
 
73
#include <cyg/infra/diag.h>
74
 
75
//==========================================================================
76
// Configuration  parameters
77
 
78
#define TESTFS_NFILE            10      // Max number of files/directories
79
#define TESTFS_NBLOCK           20      // Number of data blocks available
80
#define TESTFS_BLOCKSIZE        128     // Bytes stored per block
81
#define TESTFS_FILEBLOCKS       8       // Max blocks per file
82
#define TESTFS_NAMESIZE         32      // Length of file names in bytes
83
 
84
 
85
// Maximum file size is blocksize*blocks
86
#define TESTFS_FILESIZE_MAX     (TESTFS_BLOCKSIZE*TESTFS_FILEBLOCKS)
87
 
88
//==========================================================================
89
// Data structures
90
 
91
struct testfs_node;
92
typedef struct testfs_node testfs_node;
93
 
94
struct testfs_block;
95
typedef struct testfs_block testfs_block;
96
 
97
 
98
struct testfs_node
99
{
100
    testfs_node         *next;          // next node in list
101
    testfs_node         *parent;        // Back pointer to parent
102
    int                 refcnt;         // reference count
103
    char                name[TESTFS_NAMESIZE]; // file name
104
    struct stat         status;         // status data
105
    union
106
    {
107
        struct
108
        {
109
            testfs_block        *data[TESTFS_FILEBLOCKS];  // array of blocks
110
        } file;
111
 
112
        struct
113
        {
114
            testfs_node         *nodes[TESTFS_FILEBLOCKS]; // array of nodes
115
        } dir;
116
    } u;
117
};
118
 
119
struct testfs_block
120
{
121
    union
122
    {
123
        testfs_block    *next;          // next block in free list
124
        testfs_node     *file;          // back pointer to file
125
    } u;
126
    off_t               pos;            // position in file of first byte
127
    size_t              size;           // number of bytes in buffer
128
    char                data[TESTFS_BLOCKSIZE]; // the data
129
};
130
 
131
//==========================================================================
132
// Local data
133
 
134
// Array of nodes
135
static testfs_node node[TESTFS_NFILE];
136
 
137
// node free list.
138
static testfs_node *free_node = NULL;
139
 
140
// Array of data blocks
141
static testfs_block block[TESTFS_NBLOCK];
142
 
143
// block free list.
144
static testfs_block *free_block = NULL;
145
 
146
// Init flag
147
cyg_bool testfs_initialized = false;
148
 
149
//==========================================================================
150
// Forward definitions
151
 
152
// Filesystem operations
153
static int testfs_mount    ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
154
static int testfs_umount   ( cyg_mtab_entry *mte );
155
static int testfs_open     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
156
                             int mode,  cyg_file *fte );
157
static int testfs_unlink   ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
158
static int testfs_mkdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
159
static int testfs_rmdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
160
static int testfs_rename   ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
161
                             cyg_dir dir2, const char *name2 );
162
static int testfs_link     ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
163
                             cyg_dir dir2, const char *name2, int type );
164
static int testfs_opendir  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
165
                             cyg_file *fte );
166
static int testfs_chdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
167
                             cyg_dir *dir_out );
168
static int testfs_stat     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
169
                             struct stat *buf);
170
static int testfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
171
                             int key, void *buf, int len );
172
static int testfs_setinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
173
                             int key, void *buf, int len );
174
 
175
// File operations
176
static int testfs_fo_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
177
static int testfs_fo_write     (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
178
static int testfs_fo_lseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
179
static int testfs_fo_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
180
                                CYG_ADDRWORD data);
181
//static int testfs_fo_select    (struct CYG_FILE_TAG *fp, int which, CYG_ADDRWORD info);
182
static int testfs_fo_fsync     (struct CYG_FILE_TAG *fp, int mode );
183
static int testfs_fo_close     (struct CYG_FILE_TAG *fp);
184
static int testfs_fo_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf );
185
static int testfs_fo_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
186
static int testfs_fo_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
187
 
188
// Directory operations
189
static int testfs_fo_dirread      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
190
static int testfs_fo_dirlseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
191
 
192
//==========================================================================
193
// Filesystem table entries
194
 
195
FSTAB_ENTRY( testfs_fste, "testfs", 0,
196
             CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
197
             testfs_mount,
198
             testfs_umount,
199
             testfs_open,
200
             testfs_unlink,
201
             testfs_mkdir,
202
             testfs_rmdir,
203
             testfs_rename,
204
             testfs_link,
205
             testfs_opendir,
206
             testfs_chdir,
207
             testfs_stat,
208
             testfs_getinfo,
209
             testfs_setinfo);
210
 
211
MTAB_ENTRY( testfs_mte1,
212
                   "/",
213
                   "testfs",
214
                   "",
215
                   0);
216
 
217
#if 0
218
MTAB_ENTRY( testfs_mte2,
219
                   "/ram",
220
                   "testfs",
221
                   "",
222
                   0);
223
#endif
224
 
225
static cyg_fileops testfs_fileops =
226
{
227
    testfs_fo_read,
228
    testfs_fo_write,
229
    testfs_fo_lseek,
230
    testfs_fo_ioctl,
231
    cyg_fileio_seltrue,
232
    testfs_fo_fsync,
233
    testfs_fo_close,
234
    testfs_fo_fstat,
235
    testfs_fo_getinfo,
236
    testfs_fo_setinfo
237
};
238
 
239
static cyg_fileops testfs_dirops =
240
{
241
    testfs_fo_dirread,
242
    (cyg_fileop_write *)cyg_fileio_enosys,
243
    testfs_fo_dirlseek,
244
    (cyg_fileop_ioctl *)cyg_fileio_enosys,
245
    cyg_fileio_seltrue,
246
    (cyg_fileop_fsync *)cyg_fileio_enosys,
247
    testfs_fo_close,
248
    (cyg_fileop_fstat *)cyg_fileio_enosys,
249
    (cyg_fileop_getinfo *)cyg_fileio_enosys,
250
    (cyg_fileop_setinfo *)cyg_fileio_enosys
251
};
252
 
253
//==========================================================================
254
// Support routines
255
 
256
// -------------------------------------------------------------------------
257
// Local strcmp() and strcpy()
258
 
259
static int mystrcmp( const char *s1, const char *s2 )
260
{
261
    while( *s1 == *s2 && *s1 != '\0' && *s2 != '\0' )
262
        s1++, s2++;
263
 
264
    return (*s2)-(*s1);
265
}
266
 
267
static char *mystrcpy( char *s1, const char *s2 )
268
{
269
    char *s = s1;
270
    while( (*s1++ = *s2++) != 0);
271
    return s;
272
}
273
 
274
// -------------------------------------------------------------------------
275
// Follow a path through the directory structure
276
 
277
static int testfs_find( testfs_node *dir,       // dir to start search in
278
                        const char *path,       // path to follow
279
                        testfs_node **found,    // return node found
280
                        testfs_node **parent,   // return last dir searched
281
                        char *name,             // name fragment buffer
282
                        cyg_bool *lastp)        // last name in path ?
283
{
284
    testfs_node *nd = dir;
285
 
286
    *lastp = false;
287
    *found = NULL;
288
 
289
    while( *path != '\0' )
290
    {
291
        const char *p = path;
292
        char *n = name;
293
        testfs_node *nd1;
294
        int i;
295
 
296
        // check nd is a directory
297
        if( !S_ISDIR(nd->status.st_mode) ) return ENOTDIR;
298
 
299
        // Isolate the next element of the path name. 
300
        while( *p != '\0' && *p != '/' && (n-&name[0]) < TESTFS_NAMESIZE)
301
            *n++ = *p++;
302
 
303
        if( (n-&name[0]) >= TESTFS_NAMESIZE )
304
            return ENAMETOOLONG;
305
 
306
        // Step path on past the separator
307
        // If this is the last name element in the path,
308
        // set *lastp to indicate this.
309
        if( *(path=p) == '/' ) path++;
310
        else *lastp = true;
311
 
312
        // teminate name
313
        *n = '\0';
314
 
315
        // name now contains the next path element, search the node
316
        // in nd for it.
317
 
318
        *parent = nd;
319
        nd1 = NULL;
320
 
321
        for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
322
        {
323
            testfs_node *n = nd->u.dir.nodes[i];
324
            if( n == NULL )
325
                continue;
326
 
327
            if( mystrcmp( name, n->name ) == 0 )
328
            {
329
                nd1 = n;
330
                break;
331
            }
332
        }
333
 
334
        if( nd1 == NULL ) return ENOENT;
335
 
336
        nd = nd1;
337
    }
338
 
339
    // Return what we have found
340
    *found = nd;
341
 
342
    return ENOERR;
343
}
344
 
345
// -------------------------------------------------------------------------
346
// Get current time since epoch
347
 
348
static time_t testfs_time(void)
349
{
350
#ifdef CYGPKG_KERNEL
351
    return cyg_current_time();
352
#else
353
    return 0;
354
#endif
355
}
356
 
357
// -------------------------------------------------------------------------
358
 
359
static int testfs_delnode( testfs_node *nd )
360
{
361
 
362
    testfs_node *parent;
363
    int i;
364
 
365
    // Non-unitary ref count means this node is either open    
366
    // or is a dir with entries in it.
367
    if( nd->refcnt > 1 )
368
        return EBUSY;
369
 
370
    // Remove from parent's node list.
371
 
372
    parent = nd->parent;
373
 
374
    for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
375
        if( parent->u.dir.nodes[i] == nd )
376
        {
377
            parent->u.dir.nodes[i] = NULL;
378
            break;
379
        }
380
 
381
    parent->refcnt--;
382
 
383
    if( S_ISREG(nd->status.st_mode) )
384
    {
385
        // for a file, return blocks to free list
386
        for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
387
        {
388
            testfs_block *b = nd->u.file.data[i];
389
            if( b != NULL )
390
            {
391
                b->u.next = free_block;
392
                b->pos = -1;
393
                free_block = b;
394
            }
395
        }
396
    }
397
 
398
    // and finally return nd to free node list
399
 
400
    nd->next = free_node;
401
    nd->refcnt = -1;
402
    free_node = nd;
403
 
404
    return ENOERR;
405
}
406
 
407
//==========================================================================
408
// Filesystem operations
409
 
410
// -------------------------------------------------------------------------
411
 
412
static int testfs_mount    ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
413
{
414
    testfs_node *root;
415
    int i;
416
 
417
    if( !testfs_initialized )
418
    {
419
        int i;
420
 
421
        for( i = 0; i < TESTFS_NFILE; i++ )
422
        {
423
            node[i].next = free_node;
424
            node[i].refcnt = -1;
425
            free_node = &node[i];
426
        }
427
 
428
        for( i = 0; i < TESTFS_NBLOCK; i++ )
429
        {
430
            block[i].u.next = free_block;
431
            block[i].pos = -1;
432
            free_block = &block[i];
433
        }
434
 
435
        testfs_initialized = true;
436
    }
437
 
438
    // Allocate a node to be the root of this filesystem and
439
    // initialize it.
440
 
441
    root = free_node;
442
 
443
    if( root == NULL ) return ENOSPC;
444
 
445
    free_node = root->next;
446
 
447
    root->next                  = root;  // form circular list
448
    root->parent                = root;  // I'm my own parent!
449
    root->refcnt                = 1;     // don't want to ever lose root
450
    mystrcpy( root->name, "root");
451
    root->status.st_mode        = __stat_mode_DIR;
452
    root->status.st_ino         = root-&node[0];
453
    root->status.st_dev         = 0;
454
    root->status.st_nlink       = 1;
455
    root->status.st_uid         = 0;
456
    root->status.st_gid         = 0;
457
    root->status.st_size        = 0;
458
    root->status.st_atime       = testfs_time();
459
    root->status.st_mtime       = testfs_time();
460
    root->status.st_ctime       = testfs_time();
461
 
462
    for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
463
        root->u.dir.nodes[i]    = NULL;
464
 
465
    mte->root = (cyg_dir)root;
466
 
467
    return 0;
468
}
469
 
470
// -------------------------------------------------------------------------
471
 
472
static int testfs_umount    ( cyg_mtab_entry *mte )
473
{
474
    testfs_node *root = (testfs_node *)mte->root;
475
 
476
    // Non-empty filesystem, do not unmount
477
    if( root->refcnt != 1 )
478
        return EBUSY;
479
 
480
    // Otherwise just return it to the free pool
481
    root->next = free_node;
482
    root->refcnt = -1;
483
    free_node = root;
484
 
485
    // Clear root pointer
486
    mte->root = CYG_DIR_NULL;
487
 
488
    // That's all folks.
489
 
490
    return ENOERR;
491
}
492
// -------------------------------------------------------------------------
493
 
494
static int testfs_open     ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
495
                          int mode,  cyg_file *file )
496
{
497
    testfs_node *nd, *parent;
498
    int err;
499
    char name[TESTFS_NAMESIZE];
500
    cyg_bool lastp;
501
 
502
    err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
503
 
504
    if( lastp && err == ENOENT && (mode & O_CREAT) )
505
    {
506
        int i;
507
        // No node there, if the O_CREAT bit is set then we must
508
        // create a new one. The parent and name results will have been filled
509
        // in, so we know where to put it.
510
 
511
        // first check that there is space for it
512
        for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
513
            if( parent->u.dir.nodes[i] == NULL )
514
                break;
515
 
516
        if( i == TESTFS_FILEBLOCKS ) return ENOSPC;
517
 
518
        // Allocate a new node
519
        nd = free_node;
520
        if( nd == NULL ) return ENOSPC;
521
        free_node = nd->next;
522
 
523
        // Add to directory list
524
        parent->u.dir.nodes[i] = nd;
525
 
526
        parent->refcnt++;
527
 
528
        // Fill in details
529
        nd->parent              = parent;
530
        nd->refcnt              = 1;    // 1 for directory reference
531
        mystrcpy( nd->name, name);
532
        nd->status.st_mode      = __stat_mode_REG;
533
        nd->status.st_ino       = nd-&node[0];
534
        nd->status.st_dev       = 0;
535
        nd->status.st_nlink     = 1;
536
        nd->status.st_uid       = 0;
537
        nd->status.st_gid       = 0;
538
        nd->status.st_size      = 0;
539
        nd->status.st_atime     = testfs_time();
540
        nd->status.st_mtime     = testfs_time();
541
        nd->status.st_ctime     = testfs_time();
542
 
543
        for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
544
            nd->u.file.data[i]  = NULL;
545
 
546
        err = ENOERR;
547
    }
548
 
549
    if( err == ENOERR && (mode & O_TRUNC ) )
550
    {
551
        // Clean out any blocks in the file...
552
 
553
        int i;
554
 
555
        for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
556
        {
557
            testfs_block *b = nd->u.file.data[i];
558
            if( b != NULL )
559
            {
560
                b->u.next = free_block;
561
                b->pos = -1;
562
                free_block = b;
563
                nd->u.file.data[i] = NULL;
564
            }
565
        }
566
 
567
        nd->status.st_size = 0;
568
    }
569
 
570
    if( err != ENOERR ) return err;
571
 
572
    if( S_ISDIR(nd->status.st_mode) ) return EISDIR;
573
 
574
    nd->refcnt++;       // Count successful open as a ref
575
 
576
    // Initialize the file object
577
 
578
    file->f_flag        |= mode & CYG_FILE_MODE_MASK;
579
    file->f_type        = CYG_FILE_TYPE_FILE;
580
    file->f_ops         = &testfs_fileops;
581
    file->f_offset      = 0;
582
    file->f_data        = (CYG_ADDRWORD)nd;
583
    file->f_xops        = 0;
584
 
585
    return ENOERR;
586
}
587
 
588
// -------------------------------------------------------------------------
589
 
590
static int testfs_unlink   ( cyg_mtab_entry *mte, cyg_dir dir, const char *path )
591
{
592
    testfs_node *nd, *parent;
593
    int err;
594
    char name[TESTFS_NAMESIZE];
595
    cyg_bool lastp;
596
 
597
    err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
598
 
599
    if( err != ENOERR ) return err;
600
 
601
    // Cannot unlink directories, use rmdir() instead
602
    if( S_ISDIR(nd->status.st_mode) )
603
        return EPERM;
604
 
605
    err = testfs_delnode( nd );
606
 
607
    return err;
608
}
609
 
610
// -------------------------------------------------------------------------
611
 
612
static int testfs_mkdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *path )
613
{
614
 
615
    testfs_node *nd, *parent;
616
    int err;
617
    char name[TESTFS_NAMESIZE];
618
    cyg_bool lastp;
619
 
620
    err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
621
 
622
    if( lastp && err == ENOENT )
623
    {
624
        int i;
625
        // No node there, create a new one. The parent and name
626
        // results will have been filled in, so we know where to put
627
        // it.
628
 
629
        // first check that there is space for it
630
        for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
631
            if( parent->u.dir.nodes[i] == NULL )
632
                break;
633
 
634
        if( i == TESTFS_FILEBLOCKS ) return ENOSPC;
635
 
636
        // Allocate a new node
637
        nd = free_node;
638
        if( nd == NULL ) return ENOSPC;
639
        free_node = nd->next;
640
 
641
        // Add to directory list
642
        parent->u.dir.nodes[i] = nd;
643
 
644
        parent->refcnt++;
645
 
646
        // Fill in details
647
        nd->parent              = parent;
648
        nd->refcnt              = 1;    // 1 for directory reference
649
        mystrcpy( nd->name, name);
650
        nd->status.st_mode      = __stat_mode_DIR;
651
        nd->status.st_ino       = nd-&node[0];
652
        nd->status.st_dev       = 0;
653
        nd->status.st_nlink     = 1;
654
        nd->status.st_uid       = 0;
655
        nd->status.st_gid       = 0;
656
        nd->status.st_size      = 0;
657
        nd->status.st_atime     = testfs_time();
658
        nd->status.st_mtime     = testfs_time();
659
        nd->status.st_ctime     = testfs_time();
660
 
661
        for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
662
            nd->u.dir.nodes[i]  = NULL;
663
 
664
        err = ENOERR;
665
    }
666
 
667
    return err;
668
}
669
 
670
// -------------------------------------------------------------------------
671
 
672
static int testfs_rmdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *path )
673
{
674
    testfs_node *nd, *parent;
675
    int err;
676
    char name[TESTFS_NAMESIZE];
677
    cyg_bool lastp;
678
 
679
    err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
680
 
681
    if( err != ENOERR ) return err;
682
 
683
    // Check that it is a directory
684
    if( !S_ISDIR(nd->status.st_mode) )
685
        return EPERM;
686
 
687
    err = testfs_delnode( nd );
688
 
689
    return err;
690
}
691
 
692
// -------------------------------------------------------------------------
693
 
694
static int testfs_rename   ( cyg_mtab_entry *mte, cyg_dir dir1, const char *path1,
695
                          cyg_dir dir2, const char *path2 )
696
{
697
    testfs_node *nd1, *parent1;
698
    testfs_node *nd2, *parent2;
699
    int err;
700
    char name1[TESTFS_NAMESIZE];
701
    char name2[TESTFS_NAMESIZE];
702
    cyg_bool lastp;
703
    int i,j;
704
 
705
    err = testfs_find( (testfs_node *)dir1, path1, &nd1, &parent1, name1, &lastp );
706
 
707
    if( err != ENOERR ) return err;
708
 
709
    err = testfs_find( (testfs_node *)dir2, path2, &nd2, &parent2, name2, &lastp );
710
 
711
    // Allow through renames to non-existent objects.
712
    if( lastp && err == ENOENT )
713
        err = ENOERR;
714
 
715
    if( err != ENOERR ) return err;
716
 
717
    // Null rename, just return
718
    if( nd1 == nd2 )
719
        return ENOERR;
720
 
721
 
722
    // First deal with any node that is at the destination
723
    if( nd2 )
724
    {
725
        // Check that we are renaming like-for-like
726
 
727
        if( !S_ISDIR(nd1->status.st_mode) && S_ISDIR(nd2->status.st_mode) )
728
            return EISDIR;
729
 
730
        if( S_ISDIR(nd1->status.st_mode) && !S_ISDIR(nd2->status.st_mode) )
731
            return ENOTDIR;
732
 
733
        // Now delete the destination node.
734
        err = testfs_delnode( nd2 );
735
        if( err != ENOERR ) return err;
736
    }
737
 
738
    // Now we know that there is no clashing node at the destination.
739
    // Move the node over and change its name.
740
 
741
    // first check that there is space for it
742
    for( i = 0; i < TESTFS_FILEBLOCKS; i++ )
743
        if( parent2->u.dir.nodes[i] == NULL )
744
            break;
745
 
746
    if( i == TESTFS_FILEBLOCKS ) return ENOSPC;
747
 
748
    // Now remove node from old parent.
749
    for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
750
        if( parent1->u.dir.nodes[j] == nd1 )
751
        {
752
            parent1->u.dir.nodes[j] = NULL;
753
            break;
754
        }
755
 
756
    parent1->refcnt--;
757
 
758
    // Add to directory list
759
    parent2->u.dir.nodes[i] = nd1;
760
    parent2->refcnt++;
761
    nd1->parent = parent2;
762
 
763
    // And give it a new name.
764
    mystrcpy( nd1->name, name2 );
765
 
766
    return err;
767
}
768
 
769
// -------------------------------------------------------------------------
770
 
771
static int testfs_link   ( cyg_mtab_entry *mte, cyg_dir dir1, const char *path1,
772
                          cyg_dir dir2, const char *path2, int type )
773
{
774
    // The data structures of this file system do not support the
775
    // creation of links.
776
 
777
    return ENOSYS;
778
}
779
 
780
// -------------------------------------------------------------------------
781
 
782
static int testfs_opendir  ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
783
                          cyg_file *file )
784
{
785
    testfs_node *nd, *parent;
786
    int err;
787
    char name[TESTFS_NAMESIZE];
788
    cyg_bool lastp;
789
 
790
    err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
791
 
792
    if( err != ENOERR ) return err;
793
 
794
    if( !S_ISDIR(nd->status.st_mode) )
795
        return ENOTDIR;
796
 
797
    nd->refcnt++;       // Count successful open as a ref
798
 
799
    // Initialize the file object
800
 
801
    file->f_type        = CYG_FILE_TYPE_FILE;
802
    file->f_ops         = &testfs_dirops;
803
    file->f_offset      = 0;
804
    file->f_data        = (CYG_ADDRWORD)nd;
805
    file->f_xops        = 0;
806
 
807
    return ENOERR;
808
}
809
 
810
// -------------------------------------------------------------------------
811
 
812
static int testfs_chdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
813
                             cyg_dir *dir_out )
814
{
815
    if( dir_out != NULL )
816
    {
817
        // This is a request to get a new directory pointer in
818
        // *dir_out.
819
 
820
        testfs_node *nd, *parent;
821
        int err;
822
        char name[TESTFS_NAMESIZE];
823
        cyg_bool lastp;
824
 
825
        err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
826
 
827
        if( err != ENOERR ) return err;
828
 
829
        if( !S_ISDIR(nd->status.st_mode) )
830
            return ENOTDIR;
831
 
832
        // Increment ref count to keep this directory in existent
833
        // while it is the current cdir.
834
        nd->refcnt++;
835
 
836
        // Pass it out
837
        *dir_out = (cyg_dir)nd;
838
    }
839
    else
840
    {
841
        // If no output dir is required, this means that the mte and
842
        // dir arguments are the current cdir setting and we should
843
        // forget this fact.
844
 
845
        testfs_node *nd = (testfs_node *)dir;
846
 
847
        // Just decrement reference count.
848
        nd->refcnt--;
849
    }
850
 
851
    return ENOERR;
852
}
853
 
854
// -------------------------------------------------------------------------
855
 
856
static int testfs_stat     ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
857
                          struct stat *buf)
858
{
859
    testfs_node *nd, *parent;
860
    int err;
861
    char name[TESTFS_NAMESIZE];
862
    cyg_bool lastp;
863
 
864
    err = testfs_find( (testfs_node *)dir, path, &nd, &parent, name, &lastp );
865
 
866
    if( err != ENOERR ) return err;
867
 
868
    *buf = nd->status;
869
 
870
    return err;
871
}
872
 
873
// -------------------------------------------------------------------------
874
 
875
static int testfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
876
                          int key, void *buf, int len )
877
{
878
    return ENOSYS;
879
}
880
 
881
// -------------------------------------------------------------------------
882
 
883
static int testfs_setinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *path,
884
                          int key, void *buf, int len )
885
{
886
    return ENOSYS;
887
}
888
 
889
 
890
//==========================================================================
891
// File operations
892
 
893
 
894
// -------------------------------------------------------------------------
895
 
896
static int testfs_fo_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
897
{
898
    testfs_node *nd = (testfs_node *)fp->f_data;
899
    int i;
900
    off_t pos = fp->f_offset;
901
 
902
    for( i = 0; i < uio->uio_iovcnt; i++ )
903
    {
904
        cyg_iovec *iov = &uio->uio_iov[i];
905
        char *buf = (char *)iov->iov_base;
906
        off_t len = iov->iov_len;
907
 
908
        while( len > 0 && pos < nd->status.st_size )
909
        {
910
            testfs_block *b = nd->u.file.data[pos/TESTFS_BLOCKSIZE];
911
            off_t l = len;
912
            off_t bpos = pos%TESTFS_BLOCKSIZE;
913
 
914
            // If there is no block in that pos, we have reached
915
            // the end of the file.
916
            if( b == NULL ) return ENOERR;
917
 
918
            // adjust size to this block
919
            if( l > (b->size-bpos) )
920
                l = (b->size-bpos);
921
 
922
            // copy data out
923
            memcpy( buf, &b->data[bpos], l );
924
 
925
            uio->uio_resid -= l;
926
            len -= l;
927
            buf += l;
928
            pos += l;
929
 
930
            // keep offset up to date incase of errors
931
            fp->f_offset = pos;
932
        }
933
    }
934
 
935
    return ENOERR;
936
}
937
 
938
// -------------------------------------------------------------------------
939
 
940
static int testfs_fo_write     (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
941
{
942
    testfs_node *nd = (testfs_node *)fp->f_data;
943
    int i;
944
    off_t pos = fp->f_offset;
945
 
946
    // Check we are not at end of allowed max file size
947
    if( pos >= TESTFS_FILESIZE_MAX )
948
        return EFBIG;
949
 
950
    // Check that pos is within current file size, or at the very end.
951
    if( pos < 0 || pos > nd->status.st_size )
952
        return EINVAL;
953
 
954
    // Now loop over the iovecs until they are all done, or
955
    // we get an error.
956
    for( i = 0; i < uio->uio_iovcnt; i++ )
957
    {
958
        cyg_iovec *iov = &uio->uio_iov[i];
959
        char *buf = (char *)iov->iov_base;
960
        off_t len = iov->iov_len;
961
 
962
        while( len > 0 )
963
        {
964
            testfs_block *b = nd->u.file.data[pos/TESTFS_BLOCKSIZE];
965
            off_t l = len;
966
            off_t bpos = pos%TESTFS_BLOCKSIZE;
967
 
968
            // If there is no block in that pos, allocate one
969
            // and initialize it
970
            if( b == NULL )
971
            {
972
                b = free_block;
973
                if( b == NULL ) return ENOSPC;
974
                free_block = b->u.next;
975
                nd->u.file.data[pos/TESTFS_BLOCKSIZE] = b;
976
                b->u.file = nd;
977
                b->pos = pos;
978
                b->size = 0;
979
            }
980
 
981
            // adjust size to this block
982
            if( l > (TESTFS_BLOCKSIZE-bpos) )
983
                l = (TESTFS_BLOCKSIZE-bpos);
984
 
985
            // copy data in
986
            memcpy( &b->data[bpos], buf, l );
987
 
988
            // adjust buffer info
989
            if( b->size < bpos+l )
990
                b->size = bpos+l;
991
 
992
            uio->uio_resid -= l;
993
            len -= l;
994
            buf += l;
995
            pos += l;
996
 
997
            // keep node size and file offset up to date
998
            //in case of an error.
999
            if( pos > nd->status.st_size )
1000
                nd->status.st_size = pos;
1001
            fp->f_offset = pos;
1002
 
1003
            if( pos >= TESTFS_FILESIZE_MAX )
1004
                return EFBIG;
1005
        }
1006
    }
1007
 
1008
    return ENOERR;
1009
}
1010
 
1011
// -------------------------------------------------------------------------
1012
 
1013
static int testfs_fo_lseek     (struct CYG_FILE_TAG *fp, off_t *apos, int whence )
1014
{
1015
    testfs_node *nd = (testfs_node *)fp->f_data;
1016
    off_t pos = *apos;
1017
 
1018
    switch( whence )
1019
    {
1020
    case SEEK_SET:
1021
        // we are already where we want to be.
1022
        break;
1023
 
1024
    case SEEK_CUR:
1025
        pos += fp->f_offset;
1026
        break;
1027
 
1028
    case SEEK_END:
1029
        pos += nd->status.st_size;
1030
        break;
1031
 
1032
    default:
1033
        return EINVAL;
1034
    }
1035
 
1036
    // Check that pos is within current file size, or at the very end.
1037
    if( pos < 0 || pos > nd->status.st_size )
1038
        return EINVAL;
1039
 
1040
    // All OK, set fp offset.
1041
    *apos = fp->f_offset = pos;
1042
 
1043
    return ENOERR;
1044
}
1045
 
1046
// -------------------------------------------------------------------------
1047
 
1048
static int testfs_fo_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
1049
                             CYG_ADDRWORD data)
1050
{
1051
    return ENOSYS;
1052
}
1053
 
1054
// -------------------------------------------------------------------------
1055
 
1056
static int testfs_fo_fsync     (struct CYG_FILE_TAG *fp, int mode )
1057
{
1058
    // Nothing to do
1059
    return ENOERR;
1060
}
1061
 
1062
// -------------------------------------------------------------------------
1063
 
1064
static int testfs_fo_close     (struct CYG_FILE_TAG *fp)
1065
{
1066
    testfs_node *nd = (testfs_node *)fp->f_data;
1067
 
1068
    nd->refcnt--;       // remove open count
1069
 
1070
    fp->f_data = 0;     // clear data pointer
1071
 
1072
    return ENOERR;
1073
}
1074
 
1075
// -------------------------------------------------------------------------
1076
 
1077
static int testfs_fo_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf )
1078
{
1079
    testfs_node *nd = (testfs_node *)fp->f_data;
1080
 
1081
    *buf = nd->status;
1082
 
1083
    return ENOERR;
1084
}
1085
 
1086
// -------------------------------------------------------------------------
1087
 
1088
static int testfs_fo_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
1089
{
1090
    return ENOERR;
1091
}
1092
 
1093
// -------------------------------------------------------------------------
1094
 
1095
static int testfs_fo_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
1096
{
1097
    return ENOERR;
1098
}
1099
 
1100
 
1101
//==========================================================================
1102
// Directory operations
1103
 
1104
static int testfs_fo_dirread      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
1105
{
1106
    testfs_node *nd = (testfs_node *)fp->f_data;
1107
    off_t pos = fp->f_offset;
1108
    cyg_iovec *iov = &uio->uio_iov[0];
1109
    char *buf = (char *)iov->iov_base;
1110
    off_t len = iov->iov_len;
1111
 
1112
    // End of directory
1113
    if( pos >= TESTFS_FILEBLOCKS )
1114
        return ENOERR;
1115
 
1116
    if( len < sizeof(struct dirent) )
1117
        return EINVAL;
1118
 
1119
    for( ; pos < TESTFS_FILEBLOCKS; pos++ )
1120
        if( nd->u.dir.nodes[pos] != NULL )
1121
        {
1122
            struct dirent *ent = (struct dirent *)buf;
1123
            mystrcpy( ent->d_name, nd->u.dir.nodes[pos]->name );
1124
            uio->uio_resid -= sizeof(struct dirent);
1125
            break;
1126
        }
1127
 
1128
    fp->f_offset = pos+1;
1129
 
1130
    return ENOERR;
1131
}
1132
 
1133
// -------------------------------------------------------------------------
1134
 
1135
static int testfs_fo_dirlseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
1136
{
1137
    if( whence != SEEK_SET || *pos != 0)
1138
        return EINVAL;
1139
 
1140
    *pos = fp->f_offset = 0;
1141
 
1142
    return ENOERR;
1143
}
1144
 
1145
//==========================================================================
1146
// Filesystem dump
1147
// Dumps out the node and block arrays in a readable format, and does
1148
// a little consistency checking as it goes.
1149
 
1150
void testfs_dump(void)
1151
{
1152
    int errors = 0;
1153
    int i;
1154
    char *indent = "\n                      |";
1155
 
1156
    diag_printf("Nodes:\n");
1157
    for( i = 0; i < TESTFS_NFILE; i++ )
1158
    {
1159
        testfs_node *nd = &node[i];
1160
 
1161
        diag_printf("%3d : ",i);
1162
        if( nd->refcnt < 0 )
1163
            diag_printf("<free>");
1164
        else if( !S_ISDIR(nd->status.st_mode) )
1165
        {
1166
            // Regular file
1167
            int j;
1168
            diag_printf("f %8s %4ld |",nd->name,
1169
                        (unsigned long)nd->status.st_size);
1170
            for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
1171
            {
1172
                testfs_block *b = nd->u.file.data[j];
1173
                if( b != NULL )
1174
                {
1175
                    if( j > 0 && (j%4) == 0 )
1176
                        diag_printf(indent);
1177
                    diag_printf(" %3d[%3ld,%3zd]",(int) (b-block),
1178
                                (unsigned long)b->pos,b->size);
1179
                    if( b->u.file != nd )
1180
                    {
1181
                        errors++;
1182
                        diag_printf("!");
1183
                    }
1184
                }
1185
            }
1186
        }
1187
        else
1188
        {
1189
            // Directory
1190
            int j;
1191
            int rc = 1;
1192
            diag_printf("d %8s      |",nd->name);
1193
 
1194
            for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
1195
            {
1196
                testfs_node *n = nd->u.dir.nodes[j];
1197
                if( n != NULL )
1198
                {
1199
                    if( j > 0 && (j%4) == 0 )
1200
                        diag_printf(indent);
1201
                    diag_printf(" %3d[%7s]",(int) (n-node),n->name);
1202
                    rc++;
1203
                }
1204
            }
1205
 
1206
            if( nd->refcnt != rc )
1207
            {
1208
                diag_printf("%s refcount is %d should be %d",indent,nd->refcnt,rc);
1209
                if( nd->refcnt == rc+1 )
1210
                    diag_printf(" (but may be current dir)");
1211
            }
1212
        }
1213
 
1214
        diag_printf("\n");
1215
    }
1216
 
1217
    diag_printf("Blocks:\n");
1218
 
1219
    for( i = 0; i < TESTFS_NBLOCK; i++ )
1220
    {
1221
        testfs_block *b = &block[i];
1222
 
1223
        diag_printf("%3d :",i);
1224
        if( b->pos == -1 )
1225
            diag_printf(" <free>");
1226
        else
1227
        {
1228
            int j;
1229
            testfs_node *nd = b->u.file;
1230
            diag_printf(" %3ld %3zd %d[%7s]",b->pos,b->size,(int) (nd-node),nd->name);
1231
            for( j = 0; j < TESTFS_FILEBLOCKS; j++ )
1232
            {
1233
                if( nd->u.file.data[j] == b )
1234
                    break;
1235
            }
1236
            if( j == TESTFS_FILEBLOCKS )
1237
            {
1238
                errors++;
1239
                diag_printf(" block not in file!");
1240
            }
1241
        }
1242
        diag_printf("\n");
1243
    }
1244
 
1245
    if( errors != 0 )
1246
        diag_printf("%d errors detected\n",errors);
1247
}
1248
 
1249
// -------------------------------------------------------------------------
1250
// EOF testfs.c

powered by: WebSVN 2.1.0

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