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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [fs/] [ram/] [v2_0/] [src/] [ramfs.c] - Blame information for rev 174

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      ramfs.c
4
//
5
//      RAM 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-07-25
46
// Purpose:             RAM file system
47
// Description:         This is a RAM filesystem for eCos. It attempts to
48
//                      provide full POSIX-compatible filesystem behaviour
49
//                      while at the same time being efficient in terms of
50
//                      time and space used.
51
//                      
52
//
53
//####DESCRIPTIONEND####
54
//
55
//==========================================================================
56
// 
57
// General Description
58
// ===================
59
// 
60
// This is an implementation of a RAM filesystem for eCos. Its goal is
61
// to provide a working example of a filesystem that provides most of
62
// the required POSIX functionality. And obviously it may also be
63
// useful in its own right.
64
//
65
//
66
// Nodes
67
// -----
68
//
69
// All files and directories are represented by node objects. Each
70
// ramfs_node structure contains the following fields:
71
//
72
// mode   - Node type, file or directory.
73
// refcnt - Number of references to this node. For files each open counts as
74
//          a reference and for directories a node is referenced when it is made
75
//          current directory, or is opened for reading.
76
// nlink  - Number of links to this node. Each directory entry that references
77
//          this node is a link. 
78
// size   - Size of the data in this node in bytes.
79
// atime  - Last time this node was accessed.
80
// mtime  - Last time the data in this node was modified.
81
// ctime  - Last time the status information in this node was changed.
82
//
83
// The data storage in a node is controlled by the configuration and
84
// can take two forms. These will be described later.
85
//          
86
// Directories
87
// -----------
88
//
89
// A directory is a node whose data is a list of directory entries. To
90
// simplify management of these, long directory entries are split into
91
// a chain of fixed size ramfs_dirent structures. These contain the
92
// following fields:
93
//
94
// node    - Pointer to node referenced by this entry. This is present in
95
//           every directory entry fragment
96
// inuse   - Set to 1 if this entry is in use, zero if it is free.
97
// first   - Set to 1 if this is the first fragment of a directory entry.
98
// last    - Set to 1 if this is the last fragment of a directory entry.
99
// namelen - The size of the whole file name.
100
// fraglen - The number of bytes of the file name that are stored in this
101
//           fragment.
102
// next    - The offset of the next fragment of this directory entry.
103
// name    - The characters of the fragment of the file name stored in this
104
//           entry.
105
//
106
// Small file names are stored in a single fragment. Longer names are
107
// stored in a chain of fragments.
108
//
109
// Data Storage
110
// ------------
111
//
112
// Two data storage mechanisms may be configured, the SIMPLE and the
113
// BLOCKS mechanisms.
114
//
115
// SIMPLE Data Storage
116
// ~~~~~~~~~~~~~~~~~~~
117
//
118
// This mechanism simply uses malloc() and free() to allocate the
119
// memory for both nodes and file data. File data is stored in a
120
// single malloced vector that is realloced as necessary to acquire
121
// more space. 
122
//
123
// The advantage of this approach is that the RAM filesystem only uses
124
// as much memory as it needs, the rest is available for use by other
125
// components. It also requires much simpler data structures and code
126
// in the filesystem to manage. However, if any files get to be a
127
// significant proportion of the size of the heap, there is the danger
128
// that fragmentation will prevent any further extension of some
129
// files, even if there is enough memory in total. It also requires an
130
// implementation of malloc() to be present. If this needs to be
131
// present for other components,then this is not a significant
132
// overhead, but including it just for use by this filesystem
133
// represents a major addition of code and data structures.
134
//
135
//
136
// BLOCKS Data Storage
137
// ~~~~~~~~~~~~~~~~~~~
138
//
139
// This mechanism divides the memory used for file storage into fixed
140
// sized blocks. These blocks may either be allocated using
141
// malloc()/free(), or may be obtained from a array of blocks reserved
142
// for the purpose. Configuration allows the block size to be
143
// selected, as well as the allocation mechanism, and in the case of a
144
// block array, whether it is defined here or by an external
145
// component.
146
// 
147
// Data storage in nodes is arranges in three arrays of pointers to
148
// blocks. The first array points directly to data blocks, the second
149
// to blocks which themselves contain pointers to data blocks, and the
150
// third to blocks which contain pointers to blocks which contain
151
// pointers to data blocks. In the default configuration These last
152
// two arrays have only one element each.
153
// 
154
// The following shows how the data is arranged in a fully populated
155
// file with a 256 byte block size using the default configuration.
156
// 
157
//      Node
158
// ~            ~
159
// |            |
160
// |            |
161
// +------------+
162
// |     *------+--------> data block 0
163
// +------------+
164
// |     *------+--------> data block 1
165
// +------------+
166
// |     *------+--------> data block 2
167
// +------------+
168
// |     *------+--------> data block 3
169
// +------------+
170
// |     *------+--------> data block 4
171
// +------------+
172
// |     *------+--------> data block 5
173
// +------------+
174
// |     *------+--------> data block 6
175
// +------------+
176
// |     *------+--------> data block 7
177
// +------------+
178
// |     *------+--------> +------------+
179
// +------------+          |     *------+--------> data block 8
180
// |     *------+----+     +------------+
181
// +------------+    |     |            |
182
//                   |     ~            ~
183
//                   |     |            |
184
//                   |     +------------+
185
//                   |     |     *------+--------> data block 71
186
//                   |     +------------+
187
//                   |     
188
//                   +---->+------------+         +------------+
189
//                         |     *------+-------->|     *------+---->data block 72
190
//                         +------------+         +------------+
191
//                         |            |         |            |
192
//                         ~            ~         ~            ~
193
//                         |            |         |            |
194
//                         +------------+         +------------+
195
//                         |     *------+---+     |     *------+----> data block 135
196
//                         +------------+   |     +------------+
197
//                                          |
198
//                                          |     +------------+
199
//                                          +---->|     *------+----> data block 4104
200
//                                                +------------+
201
//                                                |            |
202
//                                                ~            ~
203
//                                                |            |
204
//                                                +------------+
205
//                                                |     *------+----> data block 4167
206
//                                                +------------+
207
// 
208
// 
209
//
210
// The advantages of this approach are that, first, memory usage is
211
// divided into discreet fixed size blocks which are easier to
212
// manage. When using malloc() to allocate them, they will fit into
213
// any free memory of at least the right size. Using the block array
214
// option removes the need to have a malloc() implementation at all.
215
//
216
// The disadvantages of this mechanism are that, first, when using
217
// malloc() to allocate blocks, the per-block memory allocator
218
// overhead is paid for each block, rather than per file. This may
219
// result in less memory overall being available for data
220
// storage. When using the block array, it is permanently reserved for
221
// use by the ram filesystem, and is not available for use by other
222
// components.
223
//
224
//==========================================================================
225
 
226
#include <pkgconf/system.h>
227
#include <pkgconf/hal.h>
228
#include <pkgconf/kernel.h>
229
#include <pkgconf/io_fileio.h>
230
#include <pkgconf/fs_ram.h>
231
 
232
#include <cyg/kernel/ktypes.h>         // base kernel types
233
#include <cyg/infra/cyg_trac.h>        // tracing macros
234
#include <cyg/infra/cyg_ass.h>         // assertion macros
235
 
236
#include <unistd.h>
237
#include <sys/types.h>
238
#include <fcntl.h>
239
#include <sys/stat.h>
240
#include <errno.h>
241
#include <dirent.h>
242
 
243
#include <stdlib.h>
244
#include <string.h>
245
 
246
#include <cyg/fileio/fileio.h>
247
 
248
#include <cyg/kernel/kapi.h>
249
#include <cyg/infra/diag.h>
250
 
251
//==========================================================================
252
// Sizes derived from configuration
253
 
254
// -------------------------------------------------------------------------
255
// Simple malloc based allocator parameters
256
 
257
#ifdef CYGPKG_FS_RAM_SIMPLE
258
 
259
#define RAMFS_FILESIZE_MAX      UINT_MAX
260
 
261
#else
262
 
263
// -------------------------------------------------------------------------
264
// Block allocator parameters
265
 
266
// The number of nodes per block
267
#define RAMFS_NODES_PER_BLOCK (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_node))
268
 
269
// The number of indirect pointers that can be stored in a single data block
270
#define RAMFS_INDIRECT_PER_BLOCK (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_block *))
271
 
272
// The number of directory entries that can be stored in a single data block
273
#define RAMFS_DIRENT_PER_BLOCK  (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_dirent))
274
 
275
// Number of bytes contained in a one level indirect block
276
#define RAMFS_INDIRECT1_BLOCK_EXTENT (RAMFS_INDIRECT_PER_BLOCK* \
277
                                      CYGNUM_RAMFS_BLOCK_SIZE)
278
 
279
// number of bytes contained in a two level indirect block
280
#define RAMFS_INDIRECT2_BLOCK_EXTENT (RAMFS_INDIRECT_PER_BLOCK* \
281
                                      RAMFS_INDIRECT_PER_BLOCK* \
282
                                      CYGNUM_RAMFS_BLOCK_SIZE)
283
 
284
// The maximum data offset for data directly accessed from the node
285
#define RAMFS_DIRECT_MAX        (CYGNUM_RAMFS_BLOCKS_DIRECT*CYGNUM_RAMFS_BLOCK_SIZE)
286
 
287
// The maximum data offset for data accessed from the single level indirect blocks
288
#define RAMFS_INDIRECT1_MAX     (RAMFS_DIRECT_MAX+                      \
289
                                 (CYGNUM_RAMFS_BLOCKS_INDIRECT1*        \
290
                                  RAMFS_INDIRECT1_BLOCK_EXTENT))
291
 
292
// The maximum data offset for data accessed from the two level indirect blocks
293
#define RAMFS_INDIRECT2_MAX     (RAMFS_INDIRECT1_MAX+                   \
294
                                 (CYGNUM_RAMFS_BLOCKS_INDIRECT2*        \
295
                                  RAMFS_INDIRECT2_BLOCK_EXTENT))
296
 
297
// The maximum size of a file
298
#define RAMFS_FILESIZE_MAX      RAMFS_INDIRECT2_MAX
299
 
300
#endif
301
 
302
//==========================================================================
303
// Forward definitions
304
 
305
// Filesystem operations
306
static int ramfs_mount    ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
307
static int ramfs_umount   ( cyg_mtab_entry *mte );
308
static int ramfs_open     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
309
                             int mode,  cyg_file *fte );
310
static int ramfs_unlink   ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
311
static int ramfs_mkdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
312
static int ramfs_rmdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
313
static int ramfs_rename   ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
314
                             cyg_dir dir2, const char *name2 );
315
static int ramfs_link     ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
316
                             cyg_dir dir2, const char *name2, int type );
317
static int ramfs_opendir  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
318
                             cyg_file *fte );
319
static int ramfs_chdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
320
                             cyg_dir *dir_out );
321
static int ramfs_stat     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
322
                             struct stat *buf);
323
static int ramfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
324
                             int key, void *buf, int len );
325
static int ramfs_setinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
326
                             int key, void *buf, int len );
327
 
328
// File operations
329
static int ramfs_fo_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
330
static int ramfs_fo_write     (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
331
static int ramfs_fo_lseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
332
static int ramfs_fo_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
333
                                CYG_ADDRWORD data);
334
static int ramfs_fo_fsync     (struct CYG_FILE_TAG *fp, int mode );
335
static int ramfs_fo_close     (struct CYG_FILE_TAG *fp);
336
static int ramfs_fo_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf );
337
static int ramfs_fo_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
338
static int ramfs_fo_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
339
 
340
// Directory operations
341
static int ramfs_fo_dirread      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
342
static int ramfs_fo_dirlseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
343
 
344
 
345
//==========================================================================
346
// Filesystem table entries
347
 
348
// -------------------------------------------------------------------------
349
// Fstab entry.
350
// This defines the entry in the filesystem table.
351
// For simplicity we use _FILESYSTEM synchronization for all accesses since
352
// we should never block in any filesystem operations.
353
 
354
FSTAB_ENTRY( ramfs_fste, "ramfs", 0,
355
             CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
356
             ramfs_mount,
357
             ramfs_umount,
358
             ramfs_open,
359
             ramfs_unlink,
360
             ramfs_mkdir,
361
             ramfs_rmdir,
362
             ramfs_rename,
363
             ramfs_link,
364
             ramfs_opendir,
365
             ramfs_chdir,
366
             ramfs_stat,
367
             ramfs_getinfo,
368
             ramfs_setinfo);
369
 
370
// -------------------------------------------------------------------------
371
// File operations.
372
// This set of file operations are used for normal open files.
373
 
374
static cyg_fileops ramfs_fileops =
375
{
376
    ramfs_fo_read,
377
    ramfs_fo_write,
378
    ramfs_fo_lseek,
379
    ramfs_fo_ioctl,
380
    cyg_fileio_seltrue,
381
    ramfs_fo_fsync,
382
    ramfs_fo_close,
383
    ramfs_fo_fstat,
384
    ramfs_fo_getinfo,
385
    ramfs_fo_setinfo
386
};
387
 
388
// -------------------------------------------------------------------------
389
// Directory file operations.
390
// This set of operations are used for open directories. Most entries
391
// point to error-returning stub functions. Only the read, lseek and
392
// close entries are functional.
393
 
394
static cyg_fileops ramfs_dirops =
395
{
396
    ramfs_fo_dirread,
397
    (cyg_fileop_write *)cyg_fileio_enosys,
398
    ramfs_fo_dirlseek,
399
    (cyg_fileop_ioctl *)cyg_fileio_enosys,
400
    cyg_fileio_seltrue,
401
    (cyg_fileop_fsync *)cyg_fileio_enosys,
402
    ramfs_fo_close,
403
    (cyg_fileop_fstat *)cyg_fileio_enosys,
404
    (cyg_fileop_getinfo *)cyg_fileio_enosys,
405
    (cyg_fileop_setinfo *)cyg_fileio_enosys
406
};
407
 
408
//==========================================================================
409
// Data typedefs
410
// Some forward typedefs for the main data structures.
411
 
412
struct ramfs_node;
413
typedef struct ramfs_node ramfs_node;
414
 
415
struct ramfs_dirent;
416
typedef struct ramfs_dirent ramfs_dirent;
417
 
418
#ifndef CYGPKG_FS_RAM_SIMPLE
419
 
420
typedef cyg_uint8 ramfs_block[CYGNUM_RAMFS_BLOCK_SIZE];
421
 
422
#endif
423
 
424
//==========================================================================
425
// File and directory node
426
// This data structure represents a file or directory.
427
 
428
struct ramfs_node
429
{
430
    mode_t              mode;           // node type
431
    cyg_ucount32        refcnt;         // open file/current dir references
432
    nlink_t             nlink;          // number of links to this node
433
    size_t              size;           // size of file in bytes
434
    time_t              atime;          // last access time
435
    time_t              mtime;          // last modified time
436
    time_t              ctime;          // last changed status time
437
 
438
#ifdef CYGPKG_FS_RAM_SIMPLE
439
 
440
    // The data storage in this case consists of a single
441
    // malloced memory block, together with its size.
442
 
443
    size_t              datasize;       // size of data block
444
    cyg_uint8           *data;          // malloced data buffer
445
 
446
#else
447
 
448
    // The data storage in this case consists of arrays of pointers
449
    // to data blocks. 
450
 
451
#if CYGNUM_RAMFS_BLOCKS_DIRECT > 0
452
    // Directly accessible blocks from the inode.
453
    ramfs_block         *direct[CYGNUM_RAMFS_BLOCKS_DIRECT];
454
#endif
455
#if  CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
456
    // Single level indirection
457
    ramfs_block         **indirect1[CYGNUM_RAMFS_BLOCKS_INDIRECT1];
458
#endif
459
#if  CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
460
    // Two level indirection
461
    ramfs_block         ***indirect2[CYGNUM_RAMFS_BLOCKS_INDIRECT2];
462
#endif
463
 
464
#endif
465
 
466
};
467
 
468
//==========================================================================
469
// Directory entry.
470
// Fixed sized entry containing a fragment of the name of a file/directory.
471
 
472
struct ramfs_dirent
473
{
474
    ramfs_node          *node;          // pointer to node
475
    unsigned int        inuse:1,        // entry in use?
476
                        first:1,        // first directory entry fragment?
477
                        last:1,         // last directory entry fragment?
478
                        namelen:8,      // bytes in whole name
479
                        fraglen:8;      // bytes in name fragment
480
    off_t               next;           // offset of next dirent
481
 
482
    // Name fragment, fills rest of entry.
483
    char                name[CYGNUM_RAMFS_DIRENT_SIZE-
484
                             sizeof(ramfs_node *)-
485
                             sizeof( cyg_uint32)-
486
                             sizeof(off_t)];
487
};
488
 
489
//==========================================================================
490
// Directory search data
491
// Parameters for a directory search. The fields of this structure are
492
// updated as we follow a pathname through the directory tree.
493
 
494
struct ramfs_dirsearch
495
{
496
    ramfs_node          *dir;           // directory to search
497
    const char          *path;          // path to follow
498
    ramfs_node          *node;          // Node found
499
    const char          *name;          // last name fragment used
500
    int                 namelen;        // name fragment length
501
    cyg_bool            last;           // last name in path?
502
};
503
 
504
typedef struct ramfs_dirsearch ramfs_dirsearch;
505
 
506
//==========================================================================
507
// Forward defs
508
 
509
static int del_direntry( ramfs_node *dir, const char *name, int namelen );
510
 
511
 
512
//==========================================================================
513
// Block array
514
// This is used for block allocation when malloc is not being used.
515
 
516
#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
517
 
518
# ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY_EXTERN
519
 
520
// Array is defined externally with a user-supplied name
521
 
522
__externC ramfs_block CYGPKG_FS_RAM_BLOCKS_ARRAY_NAME[CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE];
523
 
524
// Translate into a usable common name
525
#define ramfs_block_array CYGPKG_FS_RAM_BLOCKS_ARRAY_NAME
526
 
527
# else
528
 
529
// Array is defined here
530
 
531
static ramfs_block cyg_ramfs_block_array[CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE];
532
 
533
#define ramfs_block_array cyg_ramfs_block_array
534
 
535
# endif
536
 
537
// Pointer to list of free blocks
538
static ramfs_block *block_free_list = NULL;
539
 
540
#endif
541
 
542
//==========================================================================
543
// Block allocation
544
 
545
#ifndef CYGPKG_FS_RAM_SIMPLE
546
 
547
// -------------------------------------------------------------------------
548
// block_init()
549
// Initialize the block allocator by chaining them all together on
550
// block_free_list.
551
 
552
#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
553
 
554
static void block_init()
555
{
556
    static cyg_bool initialized = false;
557
    int i;
558
 
559
    if( !initialized )
560
    {
561
        for( i = 0; i < CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE; i++ )
562
        {
563
            ramfs_block *b = &ramfs_block_array[i];
564
            *(ramfs_block **)b = block_free_list;
565
            block_free_list = b;
566
        }
567
        initialized = true;
568
    }
569
}
570
 
571
#endif
572
 
573
// -------------------------------------------------------------------------
574
// block_alloc()
575
// Allocate a block for data storage.
576
// If we have a block array, just pick the first off the free list.
577
// If we are mallocing, call malloc() to get it.
578
 
579
static ramfs_block *block_alloc(void)
580
{
581
    ramfs_block *b;
582
 
583
#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
584
 
585
    block_init();       // Check blocks are initialized
586
 
587
    // pick first block off free list.
588
    b = block_free_list;
589
 
590
    // and advance list
591
    if( b != NULL )
592
        block_free_list = *(ramfs_block **)b;
593
 
594
#else
595
 
596
    b = malloc(CYGNUM_RAMFS_BLOCK_SIZE);
597
 
598
#endif
599
 
600
    // Clear the block to zero if it was allocated
601
    if( b != NULL )
602
        memset( b, 0, CYGNUM_RAMFS_BLOCK_SIZE );
603
 
604
    return b;
605
 
606
}
607
 
608
// -------------------------------------------------------------------------
609
// block_free()
610
// Free a block. Depending on the configuration send it back to the
611
// heap or put it back on free list.
612
 
613
static void block_free( ramfs_block *b )
614
{
615
#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
616
 
617
    // Put the block back on the free list
618
 
619
    *(ramfs_block **)b = block_free_list;
620
    block_free_list = b;
621
 
622
#else    
623
 
624
    // Call free() to return it to the memory pool
625
 
626
    free( b );
627
 
628
#endif
629
}
630
 
631
#endif
632
 
633
//==========================================================================
634
// Node buffer management
635
// There are two versions of this, one for the _SIMPLE variant and one for
636
// the _BLOCKS variant. In both cases the interface to this code is via the
637
// findbuffer_node() and freebuffer_node() functions.
638
 
639
#ifdef CYGPKG_FS_RAM_SIMPLE
640
 
641
//==========================================================================
642
// SIMPLE buffer management.
643
// Each node has a data buffer pointer and a size. This buffer is
644
// realloc()ed as needed.
645
 
646
// -------------------------------------------------------------------------
647
// findbuffer_node()
648
// return a pointer to the data at the indicated file position, extending
649
// the buffer if required.
650
 
651
static int findbuffer_node( ramfs_node  *node,  // node pointer
652
                            off_t pos,          // data position to get
653
                            cyg_uint8 **buffer, // returned buffer pointer
654
                            size_t *size,       // returned buffer size
655
                            cyg_bool alloc)     // extend allocation?
656
{
657
    if( alloc && (pos == node->datasize || node->datasize == 0) )
658
    {
659
        // If we are allowed to alloc new data, and we are at the end of the
660
        // current data allocation, or there is no data present, allocate or
661
        // extend the data buffer.
662
 
663
        cyg_uint8 *newdata;
664
 
665
        if( node->data == NULL )
666
            newdata = malloc( CYGNUM_RAMFS_REALLOC_INCREMENT );
667
        else
668
            newdata = realloc( node->data, pos+CYGNUM_RAMFS_REALLOC_INCREMENT );
669
 
670
        if( newdata == NULL ) return ENOSPC;
671
        else memset( newdata+pos, 0, CYGNUM_RAMFS_REALLOC_INCREMENT );
672
 
673
        node->data = newdata;
674
        node->datasize = pos+CYGNUM_RAMFS_REALLOC_INCREMENT;
675
    }
676
    else if( pos > node->datasize )
677
    {
678
        // Indicate end of data.
679
        *size = 0;
680
        return ENOERR;
681
    }
682
 
683
    *buffer = node->data+pos;
684
    *size = node->datasize-pos;
685
 
686
    return ENOERR;
687
}
688
 
689
// -------------------------------------------------------------------------
690
// freebuffer_node()
691
// Empty out the data storage from the node.
692
 
693
static int freebuffer_node( ramfs_node *node )
694
{
695
    if( node->data != NULL )
696
    {
697
        free( node->data );
698
    }
699
 
700
    node->data = NULL;
701
    node->datasize = 0;
702
 
703
    return ENOERR;
704
}
705
 
706
//==========================================================================
707
 
708
#else
709
 
710
//==========================================================================
711
// _BLOCKS storage management.
712
// Data storage in the node is by means of a set of arrays of pointers to
713
// blocks. The first array points directly to the data blocks. Subsequent
714
// arrays point to single and double indirect blocks respectively. 
715
 
716
// -------------------------------------------------------------------------
717
// findbuffer_direct()
718
// Indexes into an array of block pointers and extracts a pointer to the
719
// data at offset _pos_, allocating new blocks if required.
720
 
721
static int findbuffer_direct( off_t pos,
722
                              ramfs_block **blocks,
723
                              int nblocks,
724
                              cyg_uint8 **buffer,
725
                              size_t *size,
726
                              cyg_bool alloc)
727
{
728
    int bi = pos / CYGNUM_RAMFS_BLOCK_SIZE;
729
    int bpos = pos % CYGNUM_RAMFS_BLOCK_SIZE;
730
    ramfs_block *b;
731
 
732
    *buffer = NULL;
733
    *size = 0;
734
 
735
    if( bi >= nblocks )
736
        return ENOERR;
737
 
738
    b = blocks[bi];
739
 
740
    if( b == NULL )
741
    {
742
        // There is no block there. If _alloc_ is true we can fill the
743
        // slot in with a new block. If it is false, we indicate end of
744
        // data with a zero size result.
745
        if( alloc )
746
        {
747
            b = block_alloc();
748
            if( b == NULL )
749
                return ENOSPC;
750
            blocks[bi] = b;
751
        }
752
        else return ENOERR;
753
    }
754
 
755
    *buffer = &((*b)[bpos]);
756
    *size = CYGNUM_RAMFS_BLOCK_SIZE - bpos;
757
 
758
    return ENOERR;
759
}
760
 
761
// -------------------------------------------------------------------------
762
// findbuffer_indirect1()
763
// Indexes into an array of pointers to blocks containing pointers to
764
// blocks and extracts a pointer to the data at offset _pos_,
765
// allocating new blocks if required.
766
 
767
#if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
768
 
769
static int findbuffer_indirect1( off_t pos,
770
                                 ramfs_block ***blocks,
771
                                 int nblocks,
772
                                 cyg_uint8 **buffer,
773
                                 size_t *size,
774
                                 cyg_bool alloc)
775
{
776
 
777
    int bi = pos / RAMFS_INDIRECT1_BLOCK_EXTENT;
778
    int bpos = pos % RAMFS_INDIRECT1_BLOCK_EXTENT;
779
    int err;
780
    cyg_uint8 *b;
781
    size_t sz;
782
 
783
    // Use findbuffer_direct() to index and allocate
784
    // the first level indirect block.
785
 
786
    err = findbuffer_direct( bi*CYGNUM_RAMFS_BLOCK_SIZE,
787
                             (ramfs_block **)blocks,
788
                             nblocks,
789
                             &b,
790
                             &sz,
791
                             alloc);
792
 
793
    if( err != ENOERR )
794
        return err;
795
 
796
    if( sz == 0 )
797
    {
798
        *size = 0;
799
        return ENOERR;
800
    }
801
 
802
    // Use findbuffer_direct() on the first level indirect
803
    // block to allocate and return the data pointer.
804
 
805
    return findbuffer_direct( bpos,
806
                              blocks[bi],
807
                              RAMFS_INDIRECT_PER_BLOCK,
808
                              buffer,
809
                              size,
810
                              alloc);
811
}
812
 
813
#endif
814
 
815
// -------------------------------------------------------------------------
816
// findbuffer_indirect1()
817
// Indexes into an array of pointers to blocks containing pointers to
818
// blocks containing pointers to blocks (!) and extracts a pointer to
819
// the data at offset _pos_, allocating new blocks if required.
820
 
821
#if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
822
 
823
static int findbuffer_indirect2( off_t pos,
824
                                 ramfs_block ****blocks,
825
                                 int nblocks,
826
                                 cyg_uint8 **buffer,
827
                                 size_t *size,
828
                                 cyg_bool alloc)
829
{
830
    int bi = pos / RAMFS_INDIRECT2_BLOCK_EXTENT;
831
    int bpos = pos % RAMFS_INDIRECT2_BLOCK_EXTENT;
832
    int err;
833
    cyg_uint8 *b;
834
    size_t sz;
835
 
836
    // Use findbuffer_direct() to index and allocate
837
    // the first level indirect block.
838
 
839
    err = findbuffer_direct( bi*CYGNUM_RAMFS_BLOCK_SIZE,
840
                             (ramfs_block **)blocks,
841
                             nblocks,
842
                             &b,
843
                             &sz,
844
                             alloc);
845
 
846
    if( err != ENOERR )
847
        return err;
848
 
849
    if( sz == 0 )
850
    {
851
        *size = 0;
852
        return ENOERR;
853
    }
854
 
855
    // Use findbuffer_indirect1() on the first level indirect block to
856
    // index and allocate the next level indirect block and the data
857
    // block.
858
 
859
    return findbuffer_indirect1( bpos,
860
                                 blocks[bi],
861
                                 RAMFS_INDIRECT_PER_BLOCK,
862
                                 buffer,
863
                                 size,
864
                                 alloc);
865
}
866
 
867
#endif
868
 
869
// -------------------------------------------------------------------------
870
// findbuffer_node()
871
// Depending on the offset and configuration, call the appropriate
872
// function to get the buffer pointer.
873
 
874
static int findbuffer_node( ramfs_node  *node,
875
                            off_t pos,
876
                            cyg_uint8 **buffer,
877
                            size_t *size,
878
                            cyg_bool alloc)
879
{
880
#if CYGNUM_RAMFS_BLOCKS_DIRECT > 0    
881
    if( pos < RAMFS_DIRECT_MAX )
882
        return findbuffer_direct( pos,
883
                                  node->direct,
884
                                  CYGNUM_RAMFS_BLOCKS_DIRECT,
885
                                  buffer,
886
                                  size,
887
                                  alloc);
888
#endif        
889
#if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0    
890
    if( pos < RAMFS_INDIRECT1_MAX )
891
        return findbuffer_indirect1( pos - RAMFS_DIRECT_MAX,
892
                                     node->indirect1,
893
                                     CYGNUM_RAMFS_BLOCKS_INDIRECT1,
894
                                     buffer,
895
                                     size,
896
                                     alloc);
897
#endif        
898
#if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0    
899
    if( pos < RAMFS_INDIRECT2_MAX )
900
        return findbuffer_indirect2( pos - RAMFS_INDIRECT1_MAX,
901
                                     node->indirect2,
902
                                     CYGNUM_RAMFS_BLOCKS_INDIRECT2,
903
                                     buffer,
904
                                     size,
905
                                     alloc);
906
#endif
907
 
908
    return EINVAL;
909
}
910
 
911
// -------------------------------------------------------------------------
912
// freeblock_list()
913
// Free a list of data blocks.
914
 
915
static void freeblock_list( ramfs_block *blocks[],int nblocks )
916
{
917
    int i;
918
    for( i = 0; i < nblocks ; i++ )
919
    {
920
        if( blocks[i] != NULL )
921
        {
922
            block_free( blocks[i] );
923
            blocks[i] = NULL;
924
        }
925
    }
926
}
927
 
928
// -------------------------------------------------------------------------
929
// freebuffer_node()
930
// Free all the data blocks in the node and clear the pointers.
931
 
932
static int freebuffer_node( ramfs_node *node )
933
{
934
#if CYGNUM_RAMFS_BLOCKS_DIRECT > 0
935
    freeblock_list( node->direct, CYGNUM_RAMFS_BLOCKS_DIRECT );
936
#endif
937
 
938
#if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
939
    {
940
        int i;
941
        for( i = 0; i < CYGNUM_RAMFS_BLOCKS_INDIRECT1 ; i++ )
942
        {
943
            if( node->indirect1[i] != NULL )
944
            {
945
                freeblock_list( (ramfs_block **)node->indirect1[i], RAMFS_INDIRECT_PER_BLOCK );
946
                block_free( (ramfs_block *)node->indirect1[i] );
947
                node->indirect1[i] = NULL;
948
            }
949
        }
950
    }
951
#endif    
952
 
953
#if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
954
    {
955
        int i;
956
        for( i = 0; i < CYGNUM_RAMFS_BLOCKS_INDIRECT2 ; i++ )
957
        {
958
            if( node->indirect2[i] != NULL )
959
            {
960
                ramfs_block ***b = node->indirect2[i];
961
                int j;
962
                for( j = 0; j < RAMFS_INDIRECT_PER_BLOCK ; j++ )
963
                {
964
                    if( b[j] != NULL )
965
                    {
966
                        freeblock_list( (ramfs_block **)b[j], RAMFS_INDIRECT_PER_BLOCK );
967
                        block_free( (ramfs_block *)b[j] );
968
                        b[j] = NULL;
969
                    }
970
                }
971
                block_free( (ramfs_block *)node->indirect2[i] );
972
                node->indirect2[i] = NULL;
973
            }
974
        }
975
    }
976
#endif
977
 
978
    return ENOERR;
979
}
980
 
981
//==========================================================================
982
 
983
#endif
984
 
985
//==========================================================================
986
// Node allocation
987
 
988
// -------------------------------------------------------------------------
989
// alloc_node()
990
// Allocate a node and initialize it.
991
// For the _SIMPLE allocation option, we just malloc it. For the
992
// _BLOCKS option we allocate a block and use that. In theory we could
993
// pack several nodes into a single block, but we don't at present due
994
// to sheer lazyness.
995
 
996
static ramfs_node *alloc_node( mode_t mode )
997
{
998
#ifdef CYGPKG_FS_RAM_SIMPLE
999
    ramfs_node *node = malloc( sizeof( ramfs_node ) );
1000
 
1001
    if( node == NULL )
1002
        return NULL;
1003
 
1004
#else
1005
    ramfs_block *b = block_alloc();
1006
    ramfs_node *node;
1007
 
1008
    if( b == NULL )
1009
        return NULL;
1010
 
1011
    node = (ramfs_node *)b;
1012
 
1013
#endif
1014
 
1015
    memset( node, 0, sizeof(ramfs_node) );
1016
 
1017
    node->mode          = mode;
1018
    node->refcnt        = 0;
1019
    node->nlink         = 0;
1020
    node->size          = 0;
1021
    node->atime         =
1022
    node->mtime         =
1023
    node->ctime         = cyg_timestamp();
1024
 
1025
#ifdef CYGPKG_FS_RAM_SIMPLE    
1026
    node->datasize      = 0;
1027
    node->data          = NULL;
1028
#else
1029
 
1030
    // The node is already all zero
1031
 
1032
#endif    
1033
    return node;
1034
}
1035
 
1036
// -------------------------------------------------------------------------
1037
// free_node()
1038
// Release a node either back to the free pool or back into the block
1039
// pool.
1040
 
1041
static void free_node( ramfs_node *node )
1042
{
1043
#ifdef CYGPKG_FS_RAM_SIMPLE    
1044
 
1045
    free( node );
1046
 
1047
#else
1048
 
1049
    block_free( (ramfs_block *)node );
1050
 
1051
#endif    
1052
 
1053
}
1054
 
1055
 
1056
//==========================================================================
1057
// Ref count and nlink management
1058
 
1059
// -------------------------------------------------------------------------
1060
// dec_refcnt()
1061
// Decrment the reference count on a node. If this makes the ref count
1062
// zero, and the number of links is either zero for a file or one for
1063
// a node, then this node is detached from the directory tree and can
1064
// be freed.
1065
 
1066
static int dec_refcnt( ramfs_node *node )
1067
{
1068
    int err = ENOERR;
1069
    node->refcnt--;
1070
 
1071
    if( node->refcnt == 0 &&
1072
        ((S_ISREG(node->mode) && node->nlink == 0 ) ||
1073
         (S_ISDIR(node->mode) && node->nlink == 1) )
1074
        )
1075
    {
1076
        // This node it now totally detached from the directory tree,
1077
        // so delete it.
1078
 
1079
        if( S_ISDIR(node->mode) )
1080
        {
1081
            del_direntry( node, ".", 1 );
1082
            del_direntry( node, "..", 2 );
1083
        }
1084
 
1085
        err = freebuffer_node( node );
1086
 
1087
        if( err == ENOERR )
1088
            free_node( node );
1089
    }
1090
 
1091
    return err;
1092
}
1093
 
1094
// -------------------------------------------------------------------------
1095
// dec_nlink()
1096
// Decrement a node's link count. Since this has to do all the same
1097
// work as dec_refcnt() we implement this using that function by
1098
// essentially transferring the count to refcnt and then decrement
1099
// that.
1100
 
1101
static int dec_nlink( ramfs_node *node )
1102
{
1103
    node->refcnt++;
1104
 
1105
    node->nlink--;
1106
 
1107
    return dec_refcnt( node );
1108
}
1109
 
1110
//==========================================================================
1111
// Directory operations
1112
 
1113
// -------------------------------------------------------------------------
1114
// add_direntry()
1115
// Add an entry to a directory. This is added as a chain of entry
1116
// fragments until the name is exhausted.
1117
 
1118
static int add_direntry( ramfs_node *dir,       // dir to add to
1119
                         const char *name,      // name to add
1120
                         int namelen,           // length of name
1121
                         ramfs_node *node       // node to reference
1122
                       )
1123
{
1124
    off_t pos = 0;
1125
    ramfs_dirent *d = NULL, *dp = NULL;
1126
    cyg_bool isfirst = true;
1127
 
1128
    // Loop inserting fragments of the name into the directory until we
1129
    // have found a home for them all.
1130
 
1131
    while( namelen > 0 )
1132
    {
1133
        int fraglen = namelen;
1134
 
1135
        if( fraglen > sizeof(d->name) )
1136
            fraglen = sizeof(d->name);
1137
 
1138
        // Find a free fragment
1139
        for(;;)
1140
        {
1141
            cyg_uint8 *buf;
1142
            size_t size;
1143
            int err = findbuffer_node( dir, pos, &buf, &size, true );
1144
            if( err != ENOERR ) return err;
1145
 
1146
            d = (ramfs_dirent *)buf;
1147
 
1148
            if( size < sizeof(ramfs_dirent) || d->inuse )
1149
            {
1150
                pos += sizeof(ramfs_dirent);
1151
                continue;
1152
            }
1153
 
1154
            break;
1155
        }
1156
 
1157
        // d now points to a free dirent structure
1158
 
1159
        d->node         = node;
1160
        d->inuse        = 1;
1161
        d->first        = isfirst;
1162
        d->namelen      = namelen;
1163
        d->fraglen      = fraglen;
1164
        if( dp ) dp->next = pos;
1165
 
1166
        memcpy( d->name, name, fraglen );
1167
 
1168
        name            += fraglen;
1169
        namelen         -= fraglen;
1170
        pos             += sizeof(ramfs_dirent);
1171
        dp              = d;
1172
        isfirst         = false;
1173
 
1174
    }
1175
 
1176
 
1177
    d->last = 1;        // Mark last fragment
1178
 
1179
    // Update directory times
1180
    dir->mtime =
1181
    dir->ctime = cyg_timestamp();
1182
 
1183
    // Extend dir size if necessary
1184
    if( pos > dir->size )
1185
        dir->size = pos;
1186
 
1187
    // Count the new link
1188
    node->nlink++;
1189
 
1190
    return ENOERR;
1191
}
1192
 
1193
// -------------------------------------------------------------------------
1194
// find_direntry()
1195
// Find a directory entry for the name and return a pointer to the first
1196
// entry fragment.
1197
 
1198
static ramfs_dirent *find_direntry( ramfs_node *dir, const char *name, int namelen )
1199
{
1200
    ramfs_dirent *first = NULL;
1201
    off_t pos = 0;
1202
    int err;
1203
 
1204
    // Loop over all the entries until a match is found or we run out
1205
    // of data.
1206
    while( pos < dir->size )
1207
    {
1208
        const char *frag = name;
1209
        ramfs_dirent *d;
1210
        cyg_uint8 *buf;
1211
        size_t size;
1212
 
1213
        // look for a first name fragment
1214
        for(;;)
1215
        {
1216
            err = findbuffer_node( dir, pos, &buf, &size, false );
1217
            if( err != ENOERR || size == 0)
1218
                return NULL;
1219
 
1220
            d = (ramfs_dirent *)buf;
1221
 
1222
            if( size < sizeof(ramfs_dirent) || !d->inuse || !d->first )
1223
            {
1224
                pos += sizeof(ramfs_dirent);
1225
                continue;
1226
            }
1227
 
1228
            break;
1229
        }
1230
 
1231
        // Here we have got a first fragment of a name, check it
1232
        // against the name we are looking for. First check that they
1233
        // are the same length.
1234
 
1235
        if( d->namelen == namelen )
1236
        {
1237
            // We have a potential candidate here...
1238
 
1239
            first = d;      // Save it for later
1240
 
1241
            // Now check that all the name fragments match
1242
            for(;;)
1243
            {
1244
                int fraglen = namelen-(frag-name);
1245
 
1246
                if( fraglen > d->fraglen )
1247
                    fraglen = d->fraglen;
1248
 
1249
                // compare strings, if different, look for another
1250
                if( memcmp( frag, d->name, fraglen ) != 0 )
1251
                    break;
1252
 
1253
                frag        += fraglen;
1254
 
1255
                // If we are at the last fragment, then the whole name string
1256
                // has matched and we have a successful search.
1257
 
1258
                if( d->last )
1259
                        return first;
1260
 
1261
                // Otherwise move on to next entry in chain
1262
                err = findbuffer_node( dir, d->next, &buf, &size, false );
1263
                if( err != ENOERR )
1264
                    return NULL;
1265
 
1266
                d = (ramfs_dirent *)buf;
1267
 
1268
            }
1269
        }
1270
 
1271
        pos += sizeof(ramfs_dirent);
1272
    }
1273
 
1274
    return NULL;
1275
}
1276
 
1277
// -------------------------------------------------------------------------
1278
// del_direntry()
1279
// Delete a named directory entry. Find it and then follow the chain
1280
// deleting the fragments as we go.
1281
 
1282
static int del_direntry( ramfs_node *dir, const char *name, int namelen )
1283
{
1284
    ramfs_dirent *d = find_direntry( dir, name, namelen );
1285
 
1286
    if( d == NULL )
1287
        return ENOENT;
1288
 
1289
    for(;;)
1290
    {
1291
        int err;
1292
        cyg_uint8 *buf;
1293
        size_t size;
1294
 
1295
        d->inuse = 0;
1296
        if( d->last ) break;
1297
 
1298
        err = findbuffer_node( dir, d->next, &buf, &size, false );
1299
        if( err != ENOERR )
1300
            return ENOENT;
1301
 
1302
        d = (ramfs_dirent *)buf;
1303
    }
1304
 
1305
    dec_nlink( d->node );
1306
 
1307
    return ENOERR;
1308
}
1309
 
1310
//==========================================================================
1311
// Directory search
1312
 
1313
// -------------------------------------------------------------------------
1314
// init_dirsearch()
1315
// Initialize a dirsearch object to start a search
1316
 
1317
static void init_dirsearch( ramfs_dirsearch *ds,
1318
                            ramfs_node *dir,
1319
                            const char *name)
1320
{
1321
    ds->dir      = dir;
1322
    ds->path     = name;
1323
    ds->node     = dir;
1324
    ds->name     = name;
1325
    ds->namelen  = 0;
1326
    ds->last     = false;
1327
}
1328
 
1329
// -------------------------------------------------------------------------
1330
// find_entry()
1331
// Search a single directory for the next name in a path and update the
1332
// dirsearch object appropriately.
1333
 
1334
static int find_entry( ramfs_dirsearch *ds )
1335
{
1336
    ramfs_node *dir = ds->dir;
1337
    const char *name = ds->path;
1338
    const char *n = name;
1339
    char namelen = 0;
1340
    ramfs_dirent *d;
1341
 
1342
    // check that we really have a directory
1343
    if( !S_ISDIR(dir->mode) )
1344
        return ENOTDIR;
1345
 
1346
    // Isolate the next element of the path name. 
1347
    while( *n != '\0' && *n != '/' )
1348
        n++, namelen++;
1349
 
1350
    // If we terminated on a NUL, set last flag.
1351
    if( *n == '\0' )
1352
        ds->last = true;
1353
 
1354
    // update name in dirsearch object
1355
    ds->name = name;
1356
    ds->namelen = namelen;
1357
 
1358
    // Here we have the name and its length set up.
1359
    // Search the directory for a matching entry
1360
 
1361
    d = find_direntry( dir, name, namelen );
1362
 
1363
    if( d == NULL )
1364
        return ENOENT;
1365
 
1366
    // pass back the node we have found
1367
    ds->node = d->node;
1368
 
1369
    return ENOERR;
1370
 
1371
}
1372
 
1373
// -------------------------------------------------------------------------
1374
// ramfs_find()
1375
// Main interface to directory search code. This is used in all file
1376
// level operations to locate the object named by the pathname.
1377
 
1378
static int ramfs_find( ramfs_dirsearch *d )
1379
{
1380
    int err;
1381
 
1382
    // Short circuit empty paths
1383
    if( *(d->path) == '\0' )
1384
        return ENOERR;
1385
 
1386
    // iterate down directory tree until we find the object
1387
    // we want.
1388
    for(;;)
1389
    {
1390
        err = find_entry( d );
1391
 
1392
        if( err != ENOERR )
1393
            return err;
1394
 
1395
        if( d->last )
1396
            return ENOERR;
1397
 
1398
        // Update dirsearch object to search next directory.
1399
        d->dir = d->node;
1400
        d->path += d->namelen;
1401
        if( *(d->path) == '/' ) d->path++; // skip dirname separators
1402
    }
1403
}
1404
 
1405
//==========================================================================
1406
// Pathconf support
1407
// This function provides support for pathconf() and fpathconf().
1408
 
1409
static int ramfs_pathconf( ramfs_node *node, struct cyg_pathconf_info *info )
1410
{
1411
    int err = ENOERR;
1412
 
1413
    switch( info->name )
1414
    {
1415
    case _PC_LINK_MAX:
1416
        info->value = LINK_MAX;
1417
        break;
1418
 
1419
    case _PC_MAX_CANON:
1420
        info->value = -1;       // not supported
1421
        err = EINVAL;
1422
        break;
1423
 
1424
    case _PC_MAX_INPUT:
1425
        info->value = -1;       // not supported
1426
        err = EINVAL;
1427
        break;
1428
 
1429
    case _PC_NAME_MAX:
1430
        info->value = NAME_MAX;
1431
        break;
1432
 
1433
    case _PC_PATH_MAX:
1434
        info->value = PATH_MAX;
1435
        break;
1436
 
1437
    case _PC_PIPE_BUF:
1438
        info->value = -1;       // not supported
1439
        err = EINVAL;
1440
        break;
1441
 
1442
 
1443
    case _PC_ASYNC_IO:
1444
        info->value = -1;       // not supported
1445
        err = EINVAL;
1446
        break;
1447
 
1448
    case _PC_CHOWN_RESTRICTED:
1449
        info->value = -1;       // not supported
1450
        err = EINVAL;
1451
        break;
1452
 
1453
    case _PC_NO_TRUNC:
1454
        info->value = 0;
1455
        break;
1456
 
1457
    case _PC_PRIO_IO:
1458
        info->value = 0;
1459
        break;
1460
 
1461
    case _PC_SYNC_IO:
1462
        info->value = 0;
1463
        break;
1464
 
1465
    case _PC_VDISABLE:
1466
        info->value = -1;       // not supported
1467
        err = EINVAL;
1468
        break;
1469
 
1470
    default:
1471
        err = EINVAL;
1472
        break;
1473
    }
1474
 
1475
    return err;
1476
}
1477
 
1478
//==========================================================================
1479
// Filesystem operations
1480
 
1481
// -------------------------------------------------------------------------
1482
// ramfs_mount()
1483
// Process a mount request. This mainly creates a root for the
1484
// filesystem.
1485
 
1486
static int ramfs_mount    ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
1487
{
1488
    ramfs_node *root;
1489
    int err;
1490
 
1491
    // Allocate a node to be the root of this filesystem and initialize it.
1492
 
1493
    root = alloc_node(__stat_mode_DIR);
1494
 
1495
    if( root == NULL )
1496
        return ENOSPC;
1497
 
1498
    // Add . and .. entries back to self.
1499
 
1500
    err = add_direntry( root, ".", 1, root );
1501
    if( err == ENOERR )
1502
        err = add_direntry( root, "..", 2, root );
1503
 
1504
    if( err != ENOERR )
1505
    {
1506
        free_node( root );
1507
        return err;
1508
    }
1509
 
1510
    mte->root = (cyg_dir)root;
1511
 
1512
    return ENOERR;
1513
}
1514
 
1515
// -------------------------------------------------------------------------
1516
// ramfs_umount()
1517
// Unmount the filesystem. This will currently only succeed if the
1518
// filesystem is empty.
1519
 
1520
static int ramfs_umount   ( cyg_mtab_entry *mte )
1521
{
1522
    ramfs_node *root = (ramfs_node *)mte->root;
1523
 
1524
    // Check for open/inuse root
1525
    if( root->refcnt != 0 )
1526
        return EBUSY;
1527
 
1528
    // Check that root directory is clear of extra links.
1529
    if( root->nlink != 2 )
1530
        return EBUSY;
1531
 
1532
    // Just return it to free pool
1533
    free_node( root );
1534
 
1535
    // Clear root pointer
1536
    mte->root = CYG_DIR_NULL;
1537
 
1538
    // That's all folks.
1539
 
1540
    return ENOERR;
1541
}
1542
 
1543
// -------------------------------------------------------------------------
1544
// ramfs_open()
1545
// Open a file for reading or writing.
1546
 
1547
static int ramfs_open     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1548
                             int mode,  cyg_file *file )
1549
{
1550
 
1551
    ramfs_dirsearch ds;
1552
    ramfs_node *node = NULL;
1553
    int err;
1554
 
1555
    init_dirsearch( &ds, (ramfs_node *)dir, name );
1556
 
1557
    err = ramfs_find( &ds );
1558
 
1559
    if( err == ENOENT )
1560
    {
1561
        if( ds.last && (mode & O_CREAT) )
1562
        {
1563
            // No node there, if the O_CREAT bit is set then we must
1564
            // create a new one. The dir and name fields of the dirsearch
1565
            // object will have been updated so we know where to put it.
1566
 
1567
            node = alloc_node( __stat_mode_REG );
1568
 
1569
            if( node == NULL )
1570
                return ENOSPC;
1571
 
1572
            err = add_direntry( ds.dir, ds.name, ds.namelen, node );
1573
 
1574
            if( err != ENOERR )
1575
            {
1576
                free_node( node );
1577
                return err;
1578
            }
1579
 
1580
            err = ENOERR;
1581
        }
1582
    }
1583
    else if( err == ENOERR )
1584
    {
1585
        // The node exists. If the O_CREAT and O_EXCL bits are set, we
1586
        // must fail the open.
1587
 
1588
        if( (mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) )
1589
            err = EEXIST;
1590
        else node = ds.node;
1591
    }
1592
 
1593
    if( err == ENOERR && (mode & O_TRUNC ) )
1594
    {
1595
        // If the O_TRUNC bit is set we must clean out the file data.
1596
 
1597
        err = freebuffer_node( node );
1598
        node->size = 0;
1599
 
1600
        // Update file times
1601
        node->ctime =
1602
        node->mtime = cyg_timestamp();
1603
    }
1604
 
1605
    if( err != ENOERR ) return err;
1606
 
1607
    // Check that we actually have a file here
1608
    if( S_ISDIR(node->mode) ) return EISDIR;
1609
 
1610
    node->refcnt++;       // Count successful open
1611
 
1612
    // Initialize the file object
1613
 
1614
    file->f_flag        |= mode & CYG_FILE_MODE_MASK;
1615
    file->f_type        = CYG_FILE_TYPE_FILE;
1616
    file->f_ops         = &ramfs_fileops;
1617
    file->f_offset      = (mode&O_APPEND) ? node->size : 0;
1618
    file->f_data        = (CYG_ADDRWORD)node;
1619
    file->f_xops        = 0;
1620
 
1621
    return ENOERR;
1622
}
1623
 
1624
// -------------------------------------------------------------------------
1625
// ramfs_unlink()
1626
// Remove a file link from its directory.
1627
 
1628
static int ramfs_unlink   ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
1629
{
1630
    ramfs_dirsearch ds;
1631
    int err;
1632
 
1633
    init_dirsearch( &ds, (ramfs_node *)dir, name );
1634
 
1635
    err = ramfs_find( &ds );
1636
 
1637
    if( err != ENOERR ) return err;
1638
 
1639
    // Cannot unlink directories, use rmdir() instead
1640
    if( S_ISDIR(ds.node->mode) )
1641
        return EPERM;
1642
 
1643
    // Delete it from its directory
1644
    err = del_direntry( ds.dir, ds.name, ds.namelen );
1645
 
1646
    return err;
1647
}
1648
 
1649
// -------------------------------------------------------------------------
1650
// ramfs_mkdir()
1651
// Create a new directory.
1652
 
1653
static int ramfs_mkdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
1654
{
1655
    ramfs_dirsearch ds;
1656
    ramfs_node *node = NULL;
1657
    int err;
1658
 
1659
    init_dirsearch( &ds, (ramfs_node *)dir, name );
1660
 
1661
    err = ramfs_find( &ds );
1662
 
1663
    if( err == ENOENT )
1664
    {
1665
        if( ds.last )
1666
        {
1667
            // The entry does not exist, and it is the last element in
1668
            // the pathname, so we can create it here.
1669
            int doterr, dotdoterr, direrr;
1670
 
1671
            node = alloc_node( __stat_mode_DIR );
1672
 
1673
            if( node == NULL )
1674
                return ENOSPC;
1675
 
1676
            // Add "." and ".." entries.
1677
            doterr = add_direntry( node, ".", 1, node );
1678
            dotdoterr = add_direntry( node, "..", 2, ds.dir );
1679
 
1680
            // And add to parent directory.
1681
            direrr = add_direntry( ds.dir, ds.name, ds.namelen, node );
1682
 
1683
            // check for any errors in that...
1684
            if( doterr+dotdoterr+direrr != ENOERR )
1685
            {
1686
                // For each of the add_direntry() calls that succeeded,
1687
                // we must now undo it.
1688
 
1689
                if( doterr == ENOERR )
1690
                    del_direntry( node, ".", 1 );
1691
                else err = doterr;
1692
 
1693
                if( dotdoterr == ENOERR )
1694
                    del_direntry( node, "..", 2 );
1695
                else err = dotdoterr;
1696
 
1697
                if( direrr == ENOERR )
1698
                    del_direntry( ds.dir, ds.name, ds.namelen );
1699
                else err = direrr;
1700
 
1701
                // Free the data and the node itself.
1702
                freebuffer_node( node );
1703
                free_node( node );
1704
            }
1705
            else err = ENOERR;
1706
        }
1707
        // If this was not the last element, then and intermediate
1708
        // directory does not exist.
1709
    }
1710
    else
1711
    {
1712
        // If there we no error, something already exists with that
1713
        // name, so we cannot create another one.
1714
 
1715
        if( err == ENOERR )
1716
            err = EEXIST;
1717
    }
1718
 
1719
    return err;
1720
}
1721
 
1722
// -------------------------------------------------------------------------
1723
// ramfs_rmdir()
1724
// Remove a directory.
1725
 
1726
static int ramfs_rmdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
1727
{
1728
    ramfs_dirsearch ds;
1729
    int err;
1730
 
1731
    init_dirsearch( &ds, (ramfs_node *)dir, name );
1732
 
1733
    err = ramfs_find( &ds );
1734
 
1735
    if( err != ENOERR ) return err;
1736
 
1737
    // Check that this is actually a directory.
1738
    if( !S_ISDIR(ds.node->mode) )
1739
        return EPERM;
1740
 
1741
    // Delete the entry. This will adjust the link values
1742
    // accordingly and if the directory is now unreferenced,
1743
    // will cause it to be deleted.
1744
 
1745
    err = del_direntry( ds.dir, ds.name, ds.namelen );
1746
 
1747
    return err;
1748
}
1749
 
1750
// -------------------------------------------------------------------------
1751
// ramfs_rename()
1752
// Rename a file/dir.
1753
 
1754
static int ramfs_rename   ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
1755
                             cyg_dir dir2, const char *name2 )
1756
{
1757
    ramfs_dirsearch ds1, ds2;
1758
    int err;
1759
 
1760
    init_dirsearch( &ds1, (ramfs_node *)dir1, name1 );
1761
 
1762
    err = ramfs_find( &ds1 );
1763
 
1764
    if( err != ENOERR ) return err;
1765
 
1766
    init_dirsearch( &ds2, (ramfs_node *)dir2, name2 );
1767
 
1768
    err = ramfs_find( &ds2 );
1769
 
1770
    // Allow through renames to non-existent objects.
1771
    if( ds2.last && err == ENOENT )
1772
        ds2.node = NULL, err = ENOERR;
1773
 
1774
    if( err != ENOERR ) return err;
1775
 
1776
    // Null rename, just return
1777
    if( ds1.node == ds2.node )
1778
        return ENOERR;
1779
 
1780
    // First deal with any entry that is at the destination
1781
    if( ds2.node )
1782
    {
1783
        // Check that we are renaming like-for-like
1784
 
1785
        if( !S_ISDIR(ds1.node->mode) && S_ISDIR(ds2.node->mode) )
1786
            return EISDIR;
1787
 
1788
        if( S_ISDIR(ds1.node->mode) && !S_ISDIR(ds2.node->mode) )
1789
            return ENOTDIR;
1790
 
1791
        // Now delete the destination directory entry
1792
 
1793
        err = del_direntry( ds2.dir, ds2.name, ds2.namelen );
1794
 
1795
        if( err != ENOERR ) return err;
1796
 
1797
    }
1798
 
1799
    // Now we know that there is no clashing node at the destination,
1800
    // make a new direntry at the destination and delete the old entry
1801
    // at the source.
1802
 
1803
    err = add_direntry( ds2.dir, ds2.name, ds2.namelen, ds1.node );
1804
 
1805
    if( err == ENOERR )
1806
        err = del_direntry( ds1.dir, ds1.name, ds1.namelen );
1807
 
1808
    // Update directory times
1809
    if( err == ENOERR )
1810
        ds1.dir->ctime =
1811
        ds1.dir->mtime =
1812
        ds2.dir->ctime =
1813
        ds2.dir->mtime = cyg_timestamp();
1814
 
1815
    return err;
1816
}
1817
 
1818
// -------------------------------------------------------------------------
1819
// ramfs_link()
1820
// Make a new directory entry for a file.
1821
 
1822
static int ramfs_link     ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
1823
                             cyg_dir dir2, const char *name2, int type )
1824
{
1825
    ramfs_dirsearch ds1, ds2;
1826
    int err;
1827
 
1828
    // Only do hard links for now in this filesystem
1829
    if( type != CYG_FSLINK_HARD )
1830
        return EINVAL;
1831
 
1832
    init_dirsearch( &ds1, (ramfs_node *)dir1, name1 );
1833
 
1834
    err = ramfs_find( &ds1 );
1835
 
1836
    if( err != ENOERR ) return err;
1837
 
1838
    init_dirsearch( &ds2, (ramfs_node *)dir2, name2 );
1839
 
1840
    err = ramfs_find( &ds2 );
1841
 
1842
    // Don't allow links to existing objects
1843
    if( err == ENOERR ) return EEXIST;
1844
 
1845
    // Allow through links to non-existing terminal objects
1846
    if( ds2.last && err == ENOENT )
1847
        ds2.node = NULL, err = ENOERR;
1848
 
1849
    if( err != ENOERR ) return err;
1850
 
1851
    // Now we know that there is no existing node at the destination,
1852
    // make a new direntry at the destination.
1853
 
1854
    err = add_direntry( ds2.dir, ds2.name, ds2.namelen, ds1.node );
1855
 
1856
    if( err == ENOERR )
1857
        ds1.node->ctime =
1858
        ds2.dir->ctime =
1859
        ds2.dir->mtime = cyg_timestamp();
1860
 
1861
    return err;
1862
}
1863
 
1864
// -------------------------------------------------------------------------
1865
// ramfs_opendir()
1866
// Open a directory for reading.
1867
 
1868
static int ramfs_opendir  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1869
                             cyg_file *file )
1870
{
1871
    ramfs_dirsearch ds;
1872
    int err;
1873
 
1874
    init_dirsearch( &ds, (ramfs_node *)dir, name );
1875
 
1876
    err = ramfs_find( &ds );
1877
 
1878
    if( err != ENOERR ) return err;
1879
 
1880
    // check it is really a directory.
1881
    if( !S_ISDIR(ds.node->mode) ) return ENOTDIR;
1882
 
1883
    ds.node->refcnt++;       // Count successful open
1884
 
1885
    // Initialize the file object, setting the f_ops field to a
1886
    // special set of file ops.
1887
 
1888
    file->f_type        = CYG_FILE_TYPE_FILE;
1889
    file->f_ops         = &ramfs_dirops;
1890
    file->f_offset      = 0;
1891
    file->f_data        = (CYG_ADDRWORD)ds.node;
1892
    file->f_xops        = 0;
1893
 
1894
    return ENOERR;
1895
 
1896
}
1897
 
1898
// -------------------------------------------------------------------------
1899
// ramfs_chdir()
1900
// Change directory support.
1901
 
1902
static int ramfs_chdir    ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1903
                             cyg_dir *dir_out )
1904
{
1905
    if( dir_out != NULL )
1906
    {
1907
        // This is a request to get a new directory pointer in
1908
        // *dir_out.
1909
 
1910
        ramfs_dirsearch ds;
1911
        int err;
1912
 
1913
        init_dirsearch( &ds, (ramfs_node *)dir, name );
1914
 
1915
        err = ramfs_find( &ds );
1916
 
1917
        if( err != ENOERR ) return err;
1918
 
1919
        // check it is a directory
1920
        if( !S_ISDIR(ds.node->mode) )
1921
            return ENOTDIR;
1922
 
1923
        // Increment ref count to keep this directory in existent
1924
        // while it is the current cdir.
1925
        ds.node->refcnt++;
1926
 
1927
        // Pass it out
1928
        *dir_out = (cyg_dir)ds.node;
1929
    }
1930
    else
1931
    {
1932
        // If no output dir is required, this means that the mte and
1933
        // dir arguments are the current cdir setting and we should
1934
        // forget this fact.
1935
 
1936
        ramfs_node *node = (ramfs_node *)dir;
1937
 
1938
        // Just decrement directory reference count.
1939
        dec_refcnt( node );
1940
    }
1941
 
1942
    return ENOERR;
1943
}
1944
 
1945
// -------------------------------------------------------------------------
1946
// ramfs_stat()
1947
// Get struct stat info for named object.
1948
 
1949
static int ramfs_stat     ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1950
                             struct stat *buf)
1951
{
1952
    ramfs_dirsearch ds;
1953
    int err;
1954
 
1955
    init_dirsearch( &ds, (ramfs_node *)dir, name );
1956
 
1957
    err = ramfs_find( &ds );
1958
 
1959
    if( err != ENOERR ) return err;
1960
 
1961
    // Fill in the status
1962
    buf->st_mode        = ds.node->mode;
1963
    buf->st_ino         = (ino_t)ds.node;
1964
    buf->st_dev         = 0;
1965
    buf->st_nlink       = ds.node->nlink;
1966
    buf->st_uid         = 0;
1967
    buf->st_gid         = 0;
1968
    buf->st_size        = ds.node->size;
1969
    buf->st_atime       = ds.node->atime;
1970
    buf->st_mtime       = ds.node->mtime;
1971
    buf->st_ctime       = ds.node->ctime;
1972
 
1973
    return err;
1974
}
1975
 
1976
// -------------------------------------------------------------------------
1977
// ramfs_getinfo()
1978
// Getinfo. Currently only support pathconf().
1979
 
1980
static int ramfs_getinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
1981
                             int key, void *buf, int len )
1982
{
1983
    ramfs_dirsearch ds;
1984
    int err;
1985
 
1986
    init_dirsearch( &ds, (ramfs_node *)dir, name );
1987
 
1988
    err = ramfs_find( &ds );
1989
 
1990
    if( err != ENOERR ) return err;
1991
 
1992
    switch( key )
1993
    {
1994
    case FS_INFO_CONF:
1995
        err = ramfs_pathconf( ds.node, (struct cyg_pathconf_info *)buf );
1996
        break;
1997
 
1998
    default:
1999
        err = EINVAL;
2000
    }
2001
    return err;
2002
}
2003
 
2004
// -------------------------------------------------------------------------
2005
// ramfs_setinfo()
2006
// Setinfo. Nothing to support here at present.
2007
 
2008
static int ramfs_setinfo  ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
2009
                             int key, void *buf, int len )
2010
{
2011
    // No setinfo keys supported at present
2012
 
2013
    return EINVAL;
2014
}
2015
 
2016
 
2017
//==========================================================================
2018
// File operations
2019
 
2020
// -------------------------------------------------------------------------
2021
// ramfs_fo_read()
2022
// Read data from the file.
2023
 
2024
static int ramfs_fo_read      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
2025
{
2026
    ramfs_node *node = (ramfs_node *)fp->f_data;
2027
    int i;
2028
    off_t pos = fp->f_offset;
2029
    ssize_t resid = uio->uio_resid;
2030
 
2031
    // Loop over the io vectors until there are none left
2032
    for( i = 0; i < uio->uio_iovcnt; i++ )
2033
    {
2034
        cyg_iovec *iov = &uio->uio_iov[i];
2035
        char *buf = (char *)iov->iov_base;
2036
        off_t len = iov->iov_len;
2037
 
2038
        // Loop over each vector filling it with data from the file.
2039
        while( len > 0 && pos < node->size )
2040
        {
2041
            cyg_uint8 *fbuf;
2042
            size_t bsize;
2043
            off_t l = len;
2044
            int err;
2045
 
2046
            // Get a pointer to the data at offset _pos_.
2047
            err = findbuffer_node( node, pos, &fbuf, &bsize, false );
2048
 
2049
            if( err != ENOERR )
2050
                return err;
2051
 
2052
            // adjust size to end of file if necessary
2053
            if( l > node->size-pos )
2054
                l = node->size-pos;
2055
 
2056
            // adjust size to the amount of contiguous data we can see
2057
            // at present.
2058
            if( l > bsize )
2059
                l = bsize;
2060
 
2061
            // copy data out
2062
            memcpy( buf, fbuf, l );
2063
 
2064
            // Update working vars
2065
            len -= l;
2066
            buf += l;
2067
            pos += l;
2068
            resid -= l;
2069
        }
2070
    }
2071
 
2072
    // We successfully read some data, update the node's access time
2073
    // and update the file offset and transfer residue.
2074
 
2075
    node->atime = cyg_timestamp();
2076
 
2077
    uio->uio_resid = resid;
2078
    fp->f_offset = pos;
2079
 
2080
    return ENOERR;
2081
}
2082
 
2083
// -------------------------------------------------------------------------
2084
// ramfs_fo_write()
2085
// Write data to file.
2086
 
2087
static int ramfs_fo_write     (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
2088
{
2089
    ramfs_node *node = (ramfs_node *)fp->f_data;
2090
    off_t pos = fp->f_offset;
2091
    ssize_t resid = uio->uio_resid;
2092
    int i;
2093
 
2094
    // If the APPEND mode bit was supplied, force all writes to
2095
    // the end of the file.
2096
    if( fp->f_flag & CYG_FAPPEND )
2097
        pos = fp->f_offset = node->size;
2098
 
2099
    // Check that pos is within current file size, or at the very end.
2100
    if( pos < 0 || pos > node->size )
2101
        return EINVAL;
2102
 
2103
    // Now loop over the iovecs until they are all done, or
2104
    // we get an error.
2105
    for( i = 0; i < uio->uio_iovcnt; i++ )
2106
    {
2107
        cyg_iovec *iov = &uio->uio_iov[i];
2108
        char *buf = (char *)iov->iov_base;
2109
        off_t len = iov->iov_len;
2110
 
2111
        // loop over the vector writing it to the file until it has
2112
        // all been done.
2113
        while( len > 0 )
2114
        {
2115
            cyg_uint8 *fbuf;
2116
            size_t bsize;
2117
            off_t l = len;
2118
            int err;
2119
 
2120
            err = findbuffer_node( node, pos, &fbuf, &bsize, true );
2121
 
2122
            // Stop writing if there is no more space in the file and
2123
            // indicate end of data.
2124
            if( err == ENOSPC )
2125
                break;
2126
 
2127
            if( err != ENOERR )
2128
                return err;
2129
 
2130
            // adjust size to this block
2131
            if( l > bsize )
2132
                l = bsize;
2133
 
2134
            // copy data in
2135
            memcpy( fbuf, buf, l );
2136
 
2137
            // Update working vars
2138
            len -= l;
2139
            buf += l;
2140
            pos += l;
2141
            resid -= l;
2142
        }
2143
    }
2144
 
2145
    // We wrote some data successfully, update the modified and access
2146
    // times of the node, increase its size appropriately, and update
2147
    // the file offset and transfer residue.
2148
    node->mtime =
2149
    node->ctime = cyg_timestamp();
2150
    if( pos > node->size )
2151
        node->size = pos;
2152
 
2153
    uio->uio_resid = resid;
2154
    fp->f_offset = pos;
2155
 
2156
    return ENOERR;
2157
}
2158
 
2159
// -------------------------------------------------------------------------
2160
// ramfs_fo_lseek()
2161
// Seek to a new file position.
2162
 
2163
static int ramfs_fo_lseek     (struct CYG_FILE_TAG *fp, off_t *apos, int whence )
2164
{
2165
    ramfs_node *node = (ramfs_node *)fp->f_data;
2166
    off_t pos = *apos;
2167
 
2168
    switch( whence )
2169
    {
2170
    case SEEK_SET:
2171
        // Pos is already where we want to be.
2172
        break;
2173
 
2174
    case SEEK_CUR:
2175
        // Add pos to current offset.
2176
        pos += fp->f_offset;
2177
        break;
2178
 
2179
    case SEEK_END:
2180
        // Add pos to file size.
2181
        pos += node->size;
2182
        break;
2183
 
2184
    default:
2185
        return EINVAL;
2186
    }
2187
 
2188
    // Check that pos is still within current file size, or at the
2189
    // very end.
2190
    if( pos < 0 || pos > node->size )
2191
        return EINVAL;
2192
 
2193
    // All OK, set fp offset and return new position.
2194
    *apos = fp->f_offset = pos;
2195
 
2196
    return ENOERR;
2197
}
2198
 
2199
// -------------------------------------------------------------------------
2200
// ramfs_fo_ioctl()
2201
// Handle ioctls. Currently none are defined.
2202
 
2203
static int ramfs_fo_ioctl     (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
2204
                                CYG_ADDRWORD data)
2205
{
2206
    // No Ioctls currenly defined.
2207
 
2208
    return EINVAL;
2209
}
2210
 
2211
// -------------------------------------------------------------------------
2212
// ramfs_fo_fsync().
2213
// Force the file out to data storage.
2214
 
2215
static int ramfs_fo_fsync     (struct CYG_FILE_TAG *fp, int mode )
2216
{
2217
    // Data is always permanently where it belongs, nothing to do
2218
    // here.
2219
 
2220
    return ENOERR;
2221
}
2222
 
2223
// -------------------------------------------------------------------------
2224
// ramfs_fo_close()
2225
// Close a file. We just decrement the refcnt and let it go away if
2226
// that is all that is keeping it here.
2227
 
2228
static int ramfs_fo_close     (struct CYG_FILE_TAG *fp)
2229
{
2230
    ramfs_node *node = (ramfs_node *)fp->f_data;
2231
 
2232
    dec_refcnt( node );
2233
 
2234
    fp->f_data = 0;     // zero data pointer
2235
 
2236
    return ENOERR;
2237
}
2238
 
2239
// -------------------------------------------------------------------------
2240
//ramfs_fo_fstat()
2241
// Get file status.
2242
 
2243
static int ramfs_fo_fstat     (struct CYG_FILE_TAG *fp, struct stat *buf )
2244
{
2245
    ramfs_node *node = (ramfs_node *)fp->f_data;
2246
 
2247
    // Fill in the status
2248
    buf->st_mode        = node->mode;
2249
    buf->st_ino         = (ino_t)node;
2250
    buf->st_dev         = 0;
2251
    buf->st_nlink       = node->nlink;
2252
    buf->st_uid         = 0;
2253
    buf->st_gid         = 0;
2254
    buf->st_size        = node->size;
2255
    buf->st_atime       = node->atime;
2256
    buf->st_mtime       = node->mtime;
2257
    buf->st_ctime       = node->ctime;
2258
 
2259
    return ENOERR;
2260
}
2261
 
2262
// -------------------------------------------------------------------------
2263
// ramfs_fo_getinfo()
2264
// Get info. Currently only supports fpathconf().
2265
 
2266
static int ramfs_fo_getinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
2267
{
2268
    ramfs_node *node = (ramfs_node *)fp->f_data;
2269
    int err;
2270
 
2271
    switch( key )
2272
    {
2273
    case FS_INFO_CONF:
2274
        err = ramfs_pathconf( node, (struct cyg_pathconf_info *)buf );
2275
        break;
2276
 
2277
    default:
2278
        err = EINVAL;
2279
    }
2280
    return err;
2281
}
2282
 
2283
// -------------------------------------------------------------------------
2284
// ramfs_fo_setinfo()
2285
// Set info. Nothing supported here.
2286
 
2287
static int ramfs_fo_setinfo   (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
2288
{
2289
    // No setinfo key supported at present
2290
 
2291
    return ENOERR;
2292
}
2293
 
2294
 
2295
//==========================================================================
2296
// Directory operations
2297
 
2298
// -------------------------------------------------------------------------
2299
// ramfs_fo_dirread()
2300
// Read a single directory entry from a file.
2301
 
2302
static int ramfs_fo_dirread      (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
2303
{
2304
    ramfs_node *dir = (ramfs_node *)fp->f_data;
2305
    off_t pos = fp->f_offset;
2306
    int err = ENOERR;
2307
    struct dirent *ent = (struct dirent *)uio->uio_iov[0].iov_base;
2308
    char *nbuf = ent->d_name;
2309
    int nlen = sizeof(ent->d_name)-1;
2310
    off_t len = uio->uio_iov[0].iov_len;
2311
    ramfs_dirent *d = NULL;
2312
    cyg_uint8 *buf;
2313
    size_t size;
2314
 
2315
    if( len < sizeof(struct dirent) )
2316
        return EINVAL;
2317
 
2318
    // look for a first name fragment
2319
 
2320
    while( pos < dir->size )
2321
    {
2322
        err = findbuffer_node( dir, pos, &buf, &size, false );
2323
        if( err != ENOERR || size == 0)
2324
            break;
2325
 
2326
        d = (ramfs_dirent *)buf;
2327
 
2328
        if( size < sizeof(ramfs_dirent) || !d->inuse || !d->first )
2329
        {
2330
            pos += sizeof(ramfs_dirent);
2331
            continue;
2332
        }
2333
 
2334
        break;
2335
    }
2336
 
2337
    // Check we have not exceeded the size of the directory.
2338
    if( pos == dir->size )
2339
        return err;
2340
 
2341
    // Here we  have the first fragment of a directory entry.
2342
 
2343
    for(;;)
2344
    {
2345
        int fraglen = d->fraglen;
2346
 
2347
        // adjust to allow for remaining space in dirent struct
2348
        if( fraglen > nlen )
2349
            fraglen = nlen;
2350
 
2351
        memcpy( nbuf, d->name, fraglen);
2352
        nbuf += fraglen;
2353
        nlen -= fraglen;
2354
 
2355
        // if we hit the last entry, we have a successful transfer
2356
        if( d->last || nlen == 0)
2357
            break;
2358
 
2359
        // Otherwise move on to next entry in chain
2360
        err = findbuffer_node( dir, d->next, &buf, &size, false );
2361
        if( err != ENOERR )
2362
            return err;
2363
 
2364
        d = (ramfs_dirent *)buf;
2365
    }
2366
 
2367
    // A successful read. Terminate the entry name with a NUL, set the
2368
    // residue and set the file offset to restart at the next
2369
    // directory entry.
2370
 
2371
    *nbuf = '\0';
2372
    uio->uio_resid -= sizeof(struct dirent);
2373
    fp->f_offset = pos+sizeof(ramfs_dirent);
2374
 
2375
    return ENOERR;
2376
}
2377
 
2378
// -------------------------------------------------------------------------
2379
// ramfs_fo_dirlseek()
2380
// Seek directory to start.
2381
 
2382
static int ramfs_fo_dirlseek     (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
2383
{
2384
    // Only allow SEEK_SET to zero
2385
 
2386
    if( whence != SEEK_SET || *pos != 0)
2387
        return EINVAL;
2388
 
2389
    *pos = fp->f_offset = 0;
2390
 
2391
    return ENOERR;
2392
}
2393
 
2394
// -------------------------------------------------------------------------
2395
// EOF ramfs.c

powered by: WebSVN 2.1.0

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