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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [fs/] [ram/] [current/] [src/] [ramfs.c] - Blame information for rev 817

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

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

powered by: WebSVN 2.1.0

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