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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [fs/] [rom/] [v2_0/] [support/] [mk_romfs.c] - Blame information for rev 757

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

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

powered by: WebSVN 2.1.0

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