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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [io/] [fileio/] [v2_0/] [tests/] [testfs.c] - Blame information for rev 307

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

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

powered by: WebSVN 2.1.0

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