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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [fs/] [rom/] [current/] [support/] [mk_romfs.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
//      mk_romfs.c
4
//
5
//      Create ROM file system image
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, 2010 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):           richard.panton@3glab.com
43
// Contributors:        richard.panton@3glab.com
44
// Date:                2000-07-25
45
// Purpose:             ROM file system
46
// Description:         This program creates a ROM file system image, suitable
47
//                      for use with the sample ROM file system implemented by
48
//                      this package.
49
//                      * CAUTION! * This is host code and can only be built
50
//                      in a host, e.g. Linux, environment.
51
//
52
//####DESCRIPTIONEND####
53
//==========================================================================
54
 
55
#include <stdlib.h>
56
#include <string.h>
57
#include <stdio.h>
58
#include <stdarg.h>
59
#include <sys/stat.h>
60
#include <sys/types.h>
61
#include <dirent.h>
62
#include <fcntl.h>
63
#include <unistd.h>
64
#include <errno.h>
65
#include <stdint.h>
66
 
67
//==========================================================================
68
//
69
// CONFIGURABLE ITEMS HERE
70
//
71
//==========================================================================
72
 
73
// define LONG to be a four byte unsigned integer on the host
74
#define LONG    uint32_t
75
 
76
// define SHORT to be a two byte unsigned integer on the host
77
#define SHORT   uint16_t
78
 
79
// All data files should be aligned to this sized boundary (minimum probably 32)
80
#define DATA_ALIGN      32
81
 
82
// The data stored in a directory should be aligned to this size boundary
83
#define DIRECTORY_ALIGN 32
84
 
85
// All executable files should be aligned to this sized boundary (minimum probably 32)
86
#define EXEC_ALIGN      32
87
 
88
// Undefine this if the host filesystem does not support lstat()
89
#define HAS_LSTAT
90
 
91
// Win32 definitions
92
#ifdef _WIN32
93
#undef HAS_LSTAT
94
#define S_ISLNK(m) (0)
95
typedef unsigned int uid_t;
96
typedef unsigned int gid_t;
97
#endif
98
 
99
//==========================================================================
100
 
101
// Return (n) aligned to the next (b) byte boundary
102
#define ALIGN_TO( n, b ) (( (n) + (b)-1 ) & ~((b)-1))
103
 
104
// Set the stat call to use
105
#ifdef HAS_LSTAT
106
#define get_status( p, b )      lstat( (p), (b) )
107
#else
108
#define get_status( p, b )      stat( (p), (b) )
109
#endif
110
 
111
// This is how we identify a directory from its mode
112
#define IS_DIRECTORY( m )       (S_ISDIR(m))
113
 
114
// This is how we identify a data file from its mode
115
#define IS_DATAFILE( m )        (S_ISREG(m) && ((m)&S_IXUSR) == 0 )
116
 
117
// This is how we identify an executable from its mode
118
#define IS_EXECUTABLE( m )      (S_ISREG(m) && ((m)&S_IXUSR) != 0 )
119
 
120
// This is how we identify a symbolic link from its mode
121
#define IS_SYMLINK( m )         (S_ISLNK(m))
122
 
123
#define ROMFS_MAGIC     0x526f6d2e
124
 
125
//=========================================================================
126
// EXIT CODES
127
#define EXIT_SUCCESS    0
128
#define EXIT_ARGS       1
129
#define EXIT_MALLOC     2
130
#define EXIT_FILESYS    3
131
#define EXIT_WRITE      4
132
#define EXIT_SEEK       5
133
#define EXIT_COMPILE    6
134
#define EXIT_BUG        7
135
 
136
 
137
 
138
// These are the structures we will build into the ROMFS image.
139
// The sizes of these structures should be fixed for all architectures
140
typedef struct romfs_dirent {
141
    LONG        node;           // 4
142
    LONG        next;           // 8
143
    char        name[0]; // 8 + strlen(name) + 1
144
} romfs_dirent;                 // Aligns to next 32 byte boundary
145
 
146
typedef struct romfs_node {
147
    LONG        mode;           // 4
148
    LONG        nlink;          // 8
149
    SHORT       uid;            // 10
150
    SHORT       gid;            // 12
151
    LONG        size;           // 16
152
    LONG        ctime;          // 20
153
    LONG        data_offset;    // 24
154
    char        pad[8];         // 32
155
} romfs_node;                   // Next node begins here
156
 
157
typedef struct romfs_disk {
158
    LONG        magic;          // 4
159
    LONG        nodecount;      // 8
160
    LONG        disksize;       // 12
161
    LONG        dev_id;         // 16
162
    char        name[16];       // 32
163
} romfs_disk;                   // Nodes start here
164
 
165
// This is the holding structure for a node
166
typedef struct node {
167
    const char *path;           // Filename (inc. path) of a link to this node
168
    size_t size;                // Size of file/directory/link
169
    mode_t st_mode;             // Type and permissions
170
    uid_t uid;                  // Owner id
171
    gid_t gid;                  // Group id
172
    time_t ctime;               // File creation time
173
    int nodenum;                // Nodenumber of this node in the ROMFS image
174
    dev_t device;               // Device (for hardlink check)
175
    ino_t inode;                // Inode (for hardlink check)
176
    int nlink;                  // [DIRECTORIES] Number of sub-directories [FILES] hard links
177
    romfs_dirent *entry;        // [DIRECTORIES] Points to an array of directory entries
178
    int entry_size;             // Size to be allocated to file (includes alignment bytes)
179
    unsigned long offset;       // Offset within ROMFS image of data
180
    struct node *sibling;       // Points to the next entry in this directory
181
    struct node *child;         // [DIRECTORIES] Points to any subdirectories
182
    struct node *next_in_rom;   // Next in ROMFS write order
183
    struct node *next_multilink;// Next node that is multilinked
184
} node;
185
 
186
static int nodes = 0;
187
static char *prog;
188
static int verbose = 1;
189
static int dowrite = 1;
190
static int bigendian = 0;
191
static int hardlinks = 0;
192
static unsigned long coffset = 0;
193
static node * first = NULL;
194
static node ** last_p = &first;
195
static node * first_multilink = NULL;
196
static node ** last_multilink_p = &first_multilink;
197
static int fd = -1;
198
 
199
#define VERB_NONE       0
200
#define VERB_MINIMUM    1
201
#define VERB_SUB        2
202
#define VERB_MAX        3
203
#define VERB_EXCESSIVE  4
204
 
205
// Use gcc format argument checking on this function, which cannot return
206
static void fatal_error( int exitcode, const char *fmt, ... ) \
207
        __attribute__ (( noreturn,format (printf, 2, 3) ));
208
 
209
// Use gcc format argument checking on this function
210
static void verb_printf( int level, const char *fmt, ... ) \
211
        __attribute__ ((format (printf, 2, 3) ));
212
 
213
static void fatal_error( int exitcode, const char *fmt, ... ) {
214
    va_list v;
215
 
216
    va_start( v, fmt );
217
    vfprintf( stderr, fmt, v );
218
 
219
    exit(exitcode);
220
}
221
 
222
static void verb_printf( int level, const char *fmt, ... ){
223
    if ( level <= verbose ) {
224
        va_list v;
225
        va_start( v,fmt );
226
        vprintf(fmt, v);
227
    }
228
}
229
 
230
static void *mymalloc( size_t size ) {
231
    void *p = malloc(size);
232
    if ( !p ) {
233
        fatal_error( EXIT_MALLOC, "Out of memory allocating %d bytes\n", size );
234
    }
235
    return p;
236
}
237
 
238
static void myrealloc( void **o, size_t newsize ) {
239
    if ( *o == NULL )
240
        *o = mymalloc( newsize );
241
    else if ( !(*o = realloc( *o, newsize )) ) {
242
        fatal_error( EXIT_MALLOC, "Out of memory re-allocating %d bytes\n", newsize );
243
    }
244
}
245
 
246
static void outputlong( unsigned char *b, LONG w ) {
247
    if ( bigendian ) {
248
        b[0] = (w>>24) & 0xff;
249
        b[1] = (w>>16) & 0xff;
250
        b[2] = (w>> 8) & 0xff;
251
        b[3] = (w    ) & 0xff;
252
    } else {
253
        b[3] = (w>>24) & 0xff;
254
        b[2] = (w>>16) & 0xff;
255
        b[1] = (w>> 8) & 0xff;
256
        b[0] = (w    ) & 0xff;
257
    }
258
}
259
 
260
static void outputshort( unsigned char *b, SHORT w ) {
261
    if ( bigendian ) {
262
        b[0] = (w>> 8) & 0xff;
263
        b[1] = (w    ) & 0xff;
264
    } else {
265
        b[1] = (w>> 8) & 0xff;
266
        b[0] = (w    ) & 0xff;
267
    }
268
}
269
 
270
static unsigned long ConvertMode( unsigned long posix_mode ) {
271
    unsigned long result = 0;
272
    if ( S_ISDIR( posix_mode ) ) result |= 1<<0;
273
    if ( S_ISCHR( posix_mode ) ) result |= 1<<1;
274
    if ( S_ISBLK( posix_mode ) ) result |= 1<<2;
275
    if ( S_ISREG( posix_mode ) ) result |= 1<<3;
276
    if ( S_ISFIFO(posix_mode ) ) result |= 1<<4;
277
    // We cannot create MQ, SEM, or SHM entries here
278
    if ( posix_mode & S_IRUSR )  result |= 1<<16;
279
    if ( posix_mode & S_IWUSR )  result |= 1<<17;
280
    if ( posix_mode & S_IXUSR )  result |= 1<<18;
281
#ifndef _WIN32
282
    if ( posix_mode & S_IRGRP )  result |= 1<<19;
283
    if ( posix_mode & S_IWGRP )  result |= 1<<20;
284
    if ( posix_mode & S_IXGRP )  result |= 1<<21;
285
    if ( posix_mode & S_IROTH )  result |= 1<<22;
286
    if ( posix_mode & S_IWOTH )  result |= 1<<23;
287
    if ( posix_mode & S_IXOTH )  result |= 1<<24;
288
    if ( posix_mode & S_ISUID )  result |= 1<<25;
289
    if ( posix_mode & S_ISGID )  result |= 1<<26;
290
#endif
291
    return result;
292
}
293
 
294
static const char *AddDirEntry( const char *name, node *parent_node, int node_num ) {
295
    int this_size = ((strlen(name) + 4 + 4 + 1) + 31) & ~31;
296
    int start = parent_node->size;
297
    romfs_dirent *g;
298
    myrealloc( (void**)&parent_node->entry, (parent_node->size += this_size) );
299
    g = (romfs_dirent *)((unsigned char *)parent_node->entry + start);
300
    memset( (void*)g, '\0', this_size );
301
    outputlong( (unsigned char*)&g->node, node_num);
302
    outputlong( (unsigned char*)&g->next, parent_node->size);
303
    strcpy(g->name,name);
304
    verb_printf( VERB_MAX, "\t%s --> node %d\n", name, node_num );
305
    return (const char *)g->name;
306
}
307
 
308
extern int errno;
309
 
310
static node * FindLink( dev_t d, ino_t i ) {
311
    // See if the node has been previously included by checking the device/inode
312
    // combinations of all known multi-linked nodes
313
    node *np = first_multilink;
314
 
315
    for ( ; np ; np = np->next_multilink ) {
316
        if ( np->device == d && np->inode == i )
317
            return np;
318
    }
319
    return NULL;
320
}
321
 
322
static node * GetNodeInfo( const char *path, const char *name, int *hlink ) {
323
    char newpath[1024];
324
    node *node, *lnode;
325
    struct stat stbuff;
326
 
327
    sprintf(newpath,"%s/%s",path,name);
328
    if ( (get_status(newpath,&stbuff)) < 0 ) {
329
        fatal_error(EXIT_FILESYS, "stat(%s) failed: %s\n", newpath, strerror(errno));
330
    }
331
    if ( !(stbuff.st_mode & S_IRUSR) ) {
332
        fatal_error(EXIT_FILESYS, "\"%s\" is not readable\n", newpath );
333
    }
334
    if ( hardlinks && S_ISREG( stbuff.st_mode ) && stbuff.st_nlink > 1 ) {
335
 
336
        // See if this node has already been loaded
337
        lnode = FindLink( stbuff.st_dev, stbuff.st_ino );
338
 
339
        if ( lnode ) {
340
            lnode->nlink++;
341
            *hlink = 1;
342
            return lnode; // Return the found link instead
343
        }
344
 
345
        // Create a new node
346
        node = mymalloc( sizeof(struct node) );
347
 
348
        // Incorporate the new link into the 'multi-linked' node list
349
        *last_multilink_p = node;
350
        last_multilink_p = &node->next_multilink;
351
    } else {
352
        // Create a new node
353
        node = mymalloc( sizeof(struct node) );
354
    }
355
    node->path = strdup( newpath );
356
    // We re-calculate the size for directories
357
    node->size = IS_DIRECTORY( stbuff.st_mode ) ? 0 : stbuff.st_size;
358
    node->st_mode = stbuff.st_mode;
359
    node->uid = stbuff.st_uid;
360
    node->gid = stbuff.st_gid;
361
    node->ctime = stbuff.st_ctime;
362
    node->nodenum = nodes++;
363
    node->device = stbuff.st_dev;
364
    node->inode = stbuff.st_ino;
365
    // We always re-calculate the number of links
366
    node->nlink = IS_DIRECTORY( stbuff.st_mode ) ? 2 : 1;
367
    node->entry = NULL;
368
    node->entry_size = 0;
369
    node->offset = 0;
370
    node->sibling = NULL;
371
    node->child = NULL;
372
    node->next_in_rom = NULL;
373
    node->next_multilink = NULL;
374
    *hlink = 0;
375
    return node;
376
}
377
 
378
static void ScanDirectory(node *mynode, int p_node) {
379
 
380
    DIR *dh;
381
    struct dirent *e;
382
    node **last_p = &mynode->child;
383
    node *th;
384
    int was_hardlinked;
385
 
386
    if ( (dh  = opendir( mynode->path )) == NULL ) {
387
        perror(mynode->path);
388
        return;
389
    }
390
 
391
    verb_printf(VERB_EXCESSIVE, "Construct directory '%s'(%d):\n",
392
            mynode->path, mynode->nodenum );
393
 
394
    // Add . & .. here because they MUST be present in the image
395
    AddDirEntry( ".", mynode, mynode->nodenum );
396
    AddDirEntry( "..", mynode, p_node );
397
 
398
    while ( (e = readdir( dh )) ) {
399
        // Ignore . & .. here because they MAY NOT be in the host filesystem
400
        if ( strcmp(e->d_name,".") && strcmp(e->d_name,"..") ) {
401
 
402
 
403
            th = GetNodeInfo( mynode->path, e->d_name, &was_hardlinked );
404
            AddDirEntry( e->d_name, mynode, th->nodenum );
405
 
406
            if ( !was_hardlinked ) {
407
                verb_printf( VERB_EXCESSIVE, "\t\tNew node %d for entry '%s'\n", th->nodenum, e->d_name);
408
                *last_p = th;
409
                last_p = &th->sibling;
410
            } else {
411
                verb_printf( VERB_EXCESSIVE, "\t\tRe-used node %d for entry '%s'\n", th->nodenum, e->d_name);
412
            }
413
        }
414
    }
415
    closedir( dh );
416
    verb_printf(VERB_EXCESSIVE,"Completed '%s'. Checking for child directories...\n", mynode->path);
417
 
418
    for ( th = mynode->child ; th ; th = th->sibling ) {
419
        if ( IS_DIRECTORY( th->st_mode ) ) {
420
            mynode->nlink++;
421
            ScanDirectory( th, mynode->nodenum );
422
        }
423
    }
424
}
425
 
426
static void AllocateSpaceToDirectories( node *first ) {
427
    node *np;
428
 
429
    for ( np = first ; np ; np = np->sibling ) {
430
        if ( IS_DIRECTORY( np->st_mode ) ) {
431
            // The first node is a directory. Add its data
432
            np->offset = coffset;
433
            np->entry_size = ALIGN_TO( np->size, DIRECTORY_ALIGN );
434
            coffset += np->entry_size;
435
 
436
            verb_printf( VERB_MAX, "\t\tnode %5d : 0x%06lX (+0x%05X)\n",
437
                        np->nodenum, np->offset, np->entry_size );
438
 
439
            // Link this node into the write order chain.
440
            // For node 0 (the root), this will overwrite the first pointer with itself
441
            *last_p = np;
442
            last_p = &np->next_in_rom;
443
        }
444
    }
445
 
446
    // Now add any child directories
447
    for ( np = first ; np ; np = np->sibling ) {
448
        if ( IS_DIRECTORY( np->st_mode ) && np->child )
449
            AllocateSpaceToDirectories( np->child );
450
    }
451
}
452
 
453
static void AllocateSpaceToDataFiles( node *first ) {
454
    node *np;
455
 
456
    // There are two loops below. It CAN be done in just one, but this re-orders
457
    // the file positions in relation to their inode numbers. To keep it simple
458
    // to check, allocation takes place in the first loop, recursion in the second
459
 
460
    // Search for child data files
461
    for ( np = first->child ; np ; np = np->sibling ) {
462
        if ( IS_DATAFILE( np->st_mode ) || IS_SYMLINK( np->st_mode ) ) {
463
            np->offset = coffset;
464
            np->entry_size = ALIGN_TO( np->size, DATA_ALIGN );
465
            coffset += np->entry_size;
466
 
467
            // Link in to the rom write order list
468
            *last_p = np;
469
            last_p = &np->next_in_rom;
470
 
471
            verb_printf( VERB_MAX, "\t\tnode %5d : 0x%06lX (+0x%05X)\n",
472
                        np->nodenum, np->offset, np->entry_size );
473
        }
474
    }
475
 
476
    // Recurse into sub-directories
477
    for ( np = first->child ; np ; np = np->sibling ) {
478
        if ( IS_DIRECTORY( np->st_mode ) ) {
479
            AllocateSpaceToDataFiles( np );
480
        }
481
    }
482
}
483
 
484
static void AllocateSpaceToExecutables( node *first ) {
485
    node *np;
486
 
487
    // The first node is a directory. Don't bother with that...
488
 
489
    // Search for child executables
490
    for ( np = first->child ; np ; np = np->sibling ) {
491
        if ( IS_EXECUTABLE( np->st_mode ) ) {
492
            np->offset = coffset;
493
            np->entry_size = ALIGN_TO( np->size, EXEC_ALIGN );
494
            coffset += np->entry_size;
495
 
496
            // Link in to the rom write order list
497
            *last_p = np;
498
            last_p = &np->next_in_rom;
499
 
500
            verb_printf( VERB_MAX, "\t\tnode %5d : 0x%06lX (+0x%05X)\n",
501
                        np->nodenum, np->offset, np->entry_size );
502
        }
503
    }
504
 
505
    // Recurse into sub-directories
506
    for ( np = first->child ; np ; np = np->sibling ) {
507
        if ( IS_DIRECTORY( np->st_mode ) ) {
508
            AllocateSpaceToExecutables( np );
509
        }
510
    }
511
}
512
 
513
static void WriteNode( int fd, node *np ) {
514
    romfs_node anode;
515
    char padhere[9];
516
    outputlong( (unsigned char*) &anode.mode, ConvertMode( np->st_mode ) );
517
    outputlong( (unsigned char*) &anode.nlink, np->nlink );
518
    outputshort((unsigned char*) &anode.uid, np->uid );
519
    outputshort((unsigned char*) &anode.gid, np->gid );
520
    outputlong( (unsigned char*) &anode.size, np->size );
521
    outputlong( (unsigned char*) &anode.ctime, np->ctime );
522
    outputlong( (unsigned char*) &anode.data_offset, np->offset );
523
    sprintf( padhere, "<%6d>", np->nodenum );
524
    memcpy( anode.pad, padhere, 8 );
525
    if ( dowrite && write( fd, (void*)&anode, sizeof(anode) ) != sizeof(anode) )
526
        fatal_error(EXIT_WRITE, "Error writing node %d (%s): %s\n", np->nodenum, np->path, strerror(errno) );
527
}
528
 
529
static int WriteNodeAndSiblings( int fd, int nodenum, node *first ) {
530
    node *np;
531
 
532
    for ( np = first ; np ; np = np->sibling ) {
533
        if ( np->nodenum != nodenum++ ) {
534
            fatal_error(EXIT_BUG, "BUG: Out of sequence node number; got %d, expected %d\n", np->nodenum, nodenum-1);
535
        }
536
        WriteNode( fd, np );
537
    }
538
 
539
    for ( np = first ; np ; np = np->sibling ) {
540
        if ( IS_DIRECTORY( np->st_mode ) && np->child ) {
541
            nodenum = WriteNodeAndSiblings( fd, nodenum, np->child );
542
        }
543
    }
544
    return nodenum;
545
}
546
 
547
static void WriteNodeTable( int fd ) {
548
    romfs_disk header;
549
    int wnodes;
550
 
551
    outputlong( (unsigned char*) &header.magic, ROMFS_MAGIC );
552
    outputlong( (unsigned char*) &header.nodecount, nodes );
553
    outputlong( (unsigned char*) &header.disksize, coffset );
554
    outputlong( (unsigned char*) &header.dev_id, 0x01020304 );
555
    strcpy( header.name, "ROMFS v1.0" );
556
    if ( dowrite && write( fd, (void*)&header, sizeof(header) ) != sizeof(header) )
557
        fatal_error(EXIT_WRITE, "Error writing ROMFS header: %s\n", strerror(errno) );
558
 
559
    if ( (wnodes = WriteNodeAndSiblings( fd, 0, first )) != nodes ) {
560
        fatal_error(EXIT_BUG, "BUG: Lost/gained some nodes; wrote %d, expected %d\n", wnodes, nodes );
561
    }
562
}
563
 
564
#ifndef O_BINARY
565
#define O_BINARY 0
566
#endif
567
 
568
static void WriteData( int fd, node *np ) {
569
    char newpath[1024];
570
    int ffd;
571
    unsigned long todo;
572
 
573
    if ( IS_SYMLINK( np->st_mode ) ) {
574
        if ( (ffd = readlink( np->path, newpath, sizeof(newpath) )) < 0 )
575
            fatal_error(EXIT_FILESYS, "Error reading symlink \"%s\": %s\n", np->path, strerror(errno) );
576
 
577
        if ( !dowrite ) return;
578
 
579
        if ( lseek( fd, np->offset, SEEK_SET ) != np->offset )
580
            fatal_error(EXIT_SEEK, "Error seeking to offset 0x%lX: %s\n", np->offset, strerror(errno) );
581
 
582
        if ( write( fd, newpath, ffd ) != ffd )
583
            fatal_error(EXIT_WRITE, "Write error: %s\n", strerror(errno) );
584
 
585
        return;
586
    }
587
 
588
    if ( (ffd=open(np->path, O_RDONLY | O_BINARY )) < 0 )
589
        fatal_error(EXIT_FILESYS, "Error opening \"%s\": %s\n", np->path, strerror(errno) );
590
 
591
    if ( dowrite && lseek( fd, np->offset, SEEK_SET ) != np->offset )
592
        fatal_error(EXIT_SEEK, "Error seeking to offset 0x%lX: %s\n", np->offset, strerror(errno) );
593
 
594
    todo = np->size;
595
    while ( todo >= 1024 ) {
596
        if ( read( ffd, newpath, 1024 ) != 1024 )
597
            fatal_error(EXIT_FILESYS, "Error reading file \"%s\" at offset 0x%lX: %s\n", np->path, np->size - todo, strerror(errno) );
598
        if ( dowrite && write( fd, newpath, 1024 ) != 1024 )
599
            fatal_error(EXIT_WRITE, "Write error: %s\n", strerror(errno) );
600
        todo -= 1024;
601
    }
602
 
603
    if ( todo ) {
604
        if ( read( ffd, newpath, todo ) != todo )
605
            fatal_error(EXIT_FILESYS, "Error reading file \"%s\" at offset 0x%lX: %s\n", np->path, np->size - todo, strerror(errno) );
606
        if ( dowrite && write( fd, newpath, todo ) != todo )
607
            fatal_error(EXIT_WRITE, "Write error: %s\n", strerror(errno) );
608
    }
609
 
610
    close(ffd);
611
 
612
}
613
 
614
static void WriteDataBlocks( int fd, node *first ) {
615
    for ( ; first ; first = first->next_in_rom ) {
616
        if ( dowrite && lseek( fd, first->offset, SEEK_SET ) != first->offset )
617
            fatal_error(EXIT_SEEK, "Error seeking to offset 0x%lX: %s\n", first->offset, strerror(errno) );
618
        if ( IS_DIRECTORY( first->st_mode ) ) {
619
            if ( dowrite && write( fd, first->entry, first->size ) != first->size )
620
                fatal_error(EXIT_WRITE, "Write error: %s\n", strerror(errno) );
621
        } else {
622
            WriteData( fd, first );
623
        }
624
    }
625
}
626
 
627
static void usage(void) {
628
    fprintf(stderr,"\n%s - Create an eCos ROMFS disk image from the files\n",prog);
629
    fprintf(stderr,"%*s   contained under a specified directory\n\n", strlen(prog), "");
630
    fprintf(stderr,"Usage: %s [options] <fs_root> <fs_file>\n", prog);
631
    fprintf(stderr," fs_root    is the directory containing the files to package into the ROMFS image\n");
632
    fprintf(stderr," fs_file    is the name of the ROMFS image file to create\n");
633
    fprintf(stderr,"          Options include:\n");
634
    fprintf(stderr," -v / -q    increase / decrease verbosity\n");
635
    fprintf(stderr," -n         do everything EXCEPT creating the output file\n");
636
    fprintf(stderr," -b         write a big-endian image (default is little endian)\n");
637
    fprintf(stderr," -l         collapse hard links to a single node\n");
638
    fprintf(stderr,"\n");
639
    exit(EXIT_ARGS);
640
}
641
 
642
int main(int ac, char *av[]) {
643
    int dummy;
644
 
645
    prog = av[0];
646
 
647
    // Check structure sizes
648
    if (sizeof(romfs_node) != 32) {
649
        fatal_error(EXIT_COMPILE , "Size of romfs_node is %d, NOT 32\n", sizeof(romfs_node) );
650
    } else if (sizeof(romfs_dirent) != 8) {
651
        fatal_error(EXIT_COMPILE , "Size of romfs_dirent is %d, NOT 8\n", sizeof(romfs_dirent) );
652
    } else if (sizeof(romfs_disk) != 32) {
653
        fatal_error(EXIT_COMPILE , "Size of romfs_disk is %d, NOT 32\n", sizeof(romfs_disk) );
654
    }
655
 
656
    // Parse option arguments
657
    while ( ac > 1 && av[1][0] == '-' ) {
658
        char *o = &av[1][1];
659
        for ( ; *o ; o++ ) {
660
            switch ( *o ) {
661
                case 'q' :
662
                    verbose--;
663
                    break;
664
                case 'v' :
665
                    verbose++;
666
                    break;
667
                case 'n' :
668
                    dowrite = 0;
669
                    break;
670
                case 'b' :
671
                    bigendian = 1;
672
                    break;
673
                case 'l' :
674
                    hardlinks = 1;
675
                    break;
676
                default :
677
                    fprintf(stderr,"%s: Invalid flag -%c\n", prog, *o );
678
                    usage();
679
            }
680
        }
681
        av++; ac--;
682
    }
683
 
684
    // Check remaining arguments
685
    if ( ac != 3 ) usage();
686
 
687
 
688
    verb_printf( VERB_MINIMUM, "%s: Verbosity %d %s%s endian\n",
689
                prog, verbose,
690
                dowrite ? "" : "no write, ",
691
                bigendian ? "big" : "little" );
692
 
693
    // Phase 1. Recursively scan the root directory for files and directories.
694
    verb_printf(VERB_MINIMUM, "Phase 1  - Build file list\n");
695
 
696
    first = GetNodeInfo( av[1], ".", &dummy );  // Initialize the root node entry.
697
    ScanDirectory( first, 0 );
698
 
699
    // Phase 2. Work out space allocations for filesystem
700
    verb_printf(VERB_MINIMUM, "Phase 2  - Calculate space allocation\n");
701
    coffset = sizeof(romfs_disk) + nodes * sizeof(romfs_node);
702
    verb_printf(VERB_MAX,"\t\tnode table : 0x000000 (+0x%05lX) %d nodes\n", coffset, nodes );
703
 
704
    // Phase 2a. Work out space allocations for the directories of the filesystem
705
    verb_printf(VERB_SUB,"Phase 2a -     * Directories\n");
706
    coffset = ALIGN_TO( coffset, DIRECTORY_ALIGN );
707
    AllocateSpaceToDirectories( first );
708
 
709
    // Phase 2b. Work out space allocations for the data files of the filesystem
710
    verb_printf(VERB_SUB,"Phase 2b -     * Regular files\n");
711
    coffset = ALIGN_TO( coffset, DATA_ALIGN );
712
    AllocateSpaceToDataFiles( first );
713
 
714
    // Phase 2c. Work out space allocations for the executable files of the filesystem
715
    verb_printf(VERB_SUB,"Phase 2c -     * Executable files\n");
716
    coffset = ALIGN_TO( coffset, EXEC_ALIGN );
717
    AllocateSpaceToExecutables( first );
718
 
719
    // Round off the image size...
720
    coffset = ALIGN_TO( coffset, EXEC_ALIGN );
721
 
722
    // Phase 3. Write out the image file
723
    verb_printf(VERB_MINIMUM, "Phase 3  - Construct ROMFS image file (%ld kb)\n", ALIGN_TO( coffset, 1024 )/1024);
724
 
725
    if ( dowrite ) {
726
        if ( (fd = open( av[2], O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666 )) < 0 ) {
727
            fatal_error(EXIT_WRITE,"Failed to open output file '%s', errno=%d\n", av[2], errno );
728
        }
729
    } else {
730
        verb_printf(VERB_NONE,"           (No image is being written)\n");
731
    }
732
 
733
    verb_printf(VERB_SUB,"Phase 3a -     * Node table\n");
734
    WriteNodeTable( fd );
735
 
736
    verb_printf(VERB_SUB,"Phase 3b -     * Data blocks\n");
737
    WriteDataBlocks( fd, first );
738
 
739
    if ( fd >= 0 ) close(fd);
740
 
741
    verb_printf(VERB_MINIMUM,  "%s completed\n", av[2] );
742
 
743
    return 0;
744
}

powered by: WebSVN 2.1.0

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