Codebase list genext2fs / 7e34802
New upstream version 1.5.0 Johannes 'josch' Schauer 3 years ago
14 changed file(s) with 850 addition(s) and 178 deletion(s). Raw diff Collapse all Expand all
0 name: C/C++ CI
1
2 on:
3 push:
4 branches: [ master ]
5 pull_request:
6 branches: [ master ]
7
8 jobs:
9 build:
10
11 runs-on: ubuntu-latest
12
13 steps:
14 - uses: actions/checkout@v2
15 - name: autogen
16 run: ./autogen.sh
17 - name: configure
18 run: ./configure
19 - name: make
20 run: make
21 - name: make distcheck
22 run: make distcheck
0 Xavier Bestel <xavier.bestel@free.fr>
0 Xavier Bestel <xav@bes.tel>
00 bin_PROGRAMS = genext2fs
11 genext2fs_SOURCES = genext2fs.c
2 genext2fs_LDADD = $(ARCHIVE_LIBS)
23 man_MANS = genext2fs.8
3 EXTRA_DIST = $(man_MANS) test-gen.lib test-mount.sh test.sh device_table.txt m4/ac_func_scanf_can_malloc.m4 m4/ac_func_snprintf.m4
4 EXTRA_DIST = $(man_MANS) test-gen.lib test-mount.sh test.sh device_table.txt device_table_link.txt cache.h list.h m4/ac_func_scanf_can_malloc.m4 m4/ac_func_snprintf.m4
45 TESTS = test.sh
1515 does it require that you become the superuser to make device nodes.
1616
1717 The filesystem image is created in the file *output-image*. If not
18 specified, it is sent to stdout.
18 specified, it is sent to stdout. The `-d` and `-a` options support reading
19 from stdin if a single hyphen is given as an argument. Thus, genext2fs
20 can be used as part of a pipeline without any temporary files.
1921
2022 By default, the maximum number of inodes in the filesystem is the
2123 minimum number required to accommodate the initial contents. In this
4749 create many devices with a range of minor numbers (see examples below).
4850 All specified inodes receive the mtime of **spec-file** itself.
4951
52 **-a, --tarball file[:path]**
53
54 Add the given archive (tarball) contents at a particular path (by default
55 the root). If **file** is a hyphen, then the tarball will be read from
56 standard input.
57 Note: if not compiled with `libarchive`, genext2fs will use a builtin
58 tarball parser with very primitive capabilities (e.g. no sparse file
59 support, generally no support other than for modern GNU tar without
60 fancy options).
61
5062 **-b, --size-in-blocks blocks**
5163
5264 Size of the image in blocks.
5769
5870 **-N, --number-of-inodes inodes**
5971
60 Maximum number of inodes.
72 Minimum number of inodes. The required inode number will be computed
73 automatically for all input that is not read from stdin. The number given
74 by this option sets the minimum number of inodes. If you add anything
75 from standard input, you should set this value because in that case the
76 required number of inodes cannot be precomputed. The value set by this
77 option will be overwritten by the value computed from the `-i` option,
78 if the resulting number of inodes is larger.
6179
6280 **-L, --volume-label name**
6381
6583
6684 **-i, --bytes-per-inode ratio**
6785
68 Used to calculate the maximum number of inodes from the available
69 blocks.
86 Used to calculate the minimum number of inodes from the available blocks.
87 Inodes are computed by multiplying the number of blocks (`-b`) by the blocksize
88 (1024) and dividing that by the **ratio** given in this option. If the result
89 is larger, then the number of required inodes counted from the input or the
90 minimum number of inodes from the `-N` option, then the value computed by
91 this option is used.
7092
7193 **-m, --reserved-percentage N**
7294
0 #!/bin/sh
0 #!/bin/bash
11
22 die() {
33 echo "*** $0 failed :("
0 # -*- Autoconf -*-
1 # Process this file with autoconf to produce a configure script.
2
3 AC_PREREQ(2.59)
4 AC_INIT([genext2fs], [1.4.2])
5 AC_CONFIG_SRCDIR([genext2fs.c])
6
7 builtin(include, [m4/ac_func_snprintf.m4])dnl
8 builtin(include, [m4/ac_func_scanf_can_malloc.m4])dnl
9
10 AM_INIT_AUTOMAKE([foreign])
11 AC_CONFIG_HEADER([config.h])
12
13 AC_GNU_SOURCE
14
15 # Checks for programs.
16 AC_PROG_CC
17 AC_PROG_INSTALL
18
19 # Checks for header files.
20 AC_HEADER_DIRENT
21 AC_HEADER_STDC
22 AC_HEADER_MAJOR
23 AC_CHECK_HEADERS([fcntl.h inttypes.h limits.h memory.h stddef.h stdint.h stdlib.h string.h strings.h unistd.h])
24 AC_CHECK_HEADERS([libgen.h getopt.h])
25
26 # Checks for typedefs, structures, and compiler characteristics.
27 AC_C_CONST
28 AC_TYPE_UID_T
29 AC_C_INLINE
30 AC_CHECK_TYPE(size_t, unsigned)
31 AC_CHECK_TYPE(ssize_t, signed)
32 AC_CHECK_MEMBERS([struct stat.st_rdev])
33
34 # Checks for library functions.
35 AC_CHECK_FUNCS([getopt_long getline strtof])
36 AC_FUNC_SNPRINTF
37 AC_FUNC_SCANF_CAN_MALLOC
38
39 AC_MSG_CHECKING(--enable-libarchive argument)
40 AC_ARG_ENABLE(libarchive,
41 [ --enable-libarchive Include libarchive support.],
42 [enable_libarchive=$enableval],
43 [enable_libarchive="no"])
44 AC_MSG_RESULT($enable_libarchive)
45 if test "$enable_libarchive" = "yes"; then
46 # Check for libarchive (no pkg-config support)
47 AC_CHECK_LIB([archive], [archive_read_new], [ARCHIVE_LIBS=-larchive],
48 AC_MSG_ERROR([libarchive not found.
49 If libarchive is installed then perhaps you should set
50 the LDFLAGS=-L/nonstandard/lib/dir environment variable]))
51 AC_SUBST([ARCHIVE_LIBS])
52 AC_CHECK_HEADERS([archive.h archive_entry.h],,
53 AC_MSG_ERROR([libarchive headers not found.
54 If the libarchive headers are installed then perhaps you
55 should set the CPPFLAGS=-I/nonstandard/include/dir
56 environment variable]))
57 AC_DEFINE([HAVE_LIBARCHIVE], [], [Description])
58 fi
59
60 AC_OUTPUT([Makefile],[
61 chmod a+x $ac_top_srcdir/test-mount.sh $ac_top_srcdir/test.sh
62 ])
+0
-41
configure.in less more
0 # -*- Autoconf -*-
1 # Process this file with autoconf to produce a configure script.
2
3 AC_PREREQ(2.59)
4 AC_INIT(genext2fs.c)
5
6 builtin(include, [m4/ac_func_snprintf.m4])dnl
7 builtin(include, [m4/ac_func_scanf_can_malloc.m4])dnl
8
9 AM_INIT_AUTOMAKE(genext2fs,1.4.2)
10 AC_CONFIG_HEADER([config.h])
11
12 AC_GNU_SOURCE
13
14 # Checks for programs.
15 AC_PROG_CC
16 AC_PROG_INSTALL
17
18 # Checks for header files.
19 AC_HEADER_DIRENT
20 AC_HEADER_STDC
21 AC_HEADER_MAJOR
22 AC_CHECK_HEADERS([fcntl.h inttypes.h limits.h memory.h stddef.h stdint.h stdlib.h string.h strings.h unistd.h])
23 AC_CHECK_HEADERS([libgen.h getopt.h])
24
25 # Checks for typedefs, structures, and compiler characteristics.
26 AC_C_CONST
27 AC_TYPE_UID_T
28 AC_C_INLINE
29 AC_CHECK_TYPE(size_t, unsigned)
30 AC_CHECK_TYPE(ssize_t, signed)
31 AC_CHECK_MEMBERS([struct stat.st_rdev])
32
33 # Checks for library functions.
34 AC_CHECK_FUNCS([getopt_long getline strtof])
35 AC_FUNC_SNPRINTF
36 AC_FUNC_SCANF_CAN_MALLOC
37
38 AC_OUTPUT([Makefile],[
39 chmod a+x $ac_top_srcdir/test-mount.sh $ac_top_srcdir/test.sh
40 ])
33 It was downloaded from http://freshmeat.net/projects/genext2fs/
44 Upstream Author(s): Xavier Bestel <xbestel@aplio.fr>
55
6 Copyright (C) 2000 Xavier Bestel <xavier.bestel@free.fr>
6 Copyright (C) 2000 Xavier Bestel <xav@bes.tel>
77
88 This program is free software; you can redistribute it and/or
99 modify it under the terms of the GNU General Public License
0 # do a chown on a symlink
1 /symlink l 777 77 7 - - - - -
2424 as a normal (non-root) user. It does not require you to mount
2525 the image file to copy files on it, nor does it require that
2626 you become the superuser to make device nodes.
27
28 The filesystem is created either from scratch, or from an already existing
29 one if specified by the \fB-x\fP option. Then each \fB-d\fP and \fB-D\fP
30 option successively adds a "layer" to the image.
2731
2832 The filesystem image is created in the file \fIoutput-image\fP. If not
2933 specified, it is sent to stdout.
5357 Furthermore, you can use a single table entry to create many devices
5458 with a range of minor numbers (see examples below).
5559 All specified inodes receive the mtime of \fBspec-file\fP itself.
60 .TP
61 .BI "\-a, \-\-tarball file[:path]"
62 Add the given archive (tarball) contents at a particular path (by default
63 the root).
64 Note: if not compiled with `libarchive`, genext2fs will use a builtin
65 tarball parser with very primitive capabilities (e.g. no sparse file
66 support, generally no support other than for modern GNU tar without
67 fancy options).
5668 .TP
5769 .BI "\-b, \-\-size\-in\-blocks blocks"
5870 Size of the image in blocks.
8597 Make files with holes.
8698 .TP
8799 .BI "\-f, \-\-faketime"
88 Use a timestamp of 0 for inode and filesystem creation, instead of the present. Useful for testing.
100 Use a timestamp of 0 for inode and filesystem creation, instead of the present. Useful for testing. See also SOURCE_DATE_EPOCH.
89101 .TP
90102 .BI "\-q, \-\-squash"
91103 Squash permissions and owners (same as -P -U).
106118 .TP
107119 .BI "\-h, \-\-help"
108120 Display help.
121 .SH ENVIRONMENT
122 .TP
123 .BI SOURCE_DATE_EPOCH
124 Standardized date for reproducible builds, see https://reproducible-builds.org/docs/source-date-epoch/ for more information.
109125 .SH EXAMPLES
110126
111127 .EX
141157 c Character special device file
142158 b Block special device file
143159 p Fifo (named pipe)
160 l Symbolic link
144161 .fi
145162 .RE
146163 uid is the user id for the target file, gid is the group id for the
11 // genext2fs.c
22 //
33 // ext2 filesystem generator for embedded systems
4 // Copyright (C) 2000 Xavier Bestel <xavier.bestel@free.fr>
4 // Copyright (C) 2000 Xavier Bestel <xav@bes.tel>
55 //
66 // Please direct support requests to https://github.com/bestouff/genext2fs/issues
77 //
147147 # include <limits.h>
148148 #endif
149149
150 #ifdef HAVE_LIBARCHIVE
151 #include <archive.h>
152 #include <archive_entry.h>
153 #endif
154
150155 #include "cache.h"
156
157 #define MIN(a, b) ((a) > (b) ? (b) : (a))
158
159 #define FSLAYER_DIR 0
160 #define FSLAYER_TABLE 1
161 #define FSLAYER_TAR 2
162
163 struct fslayer {
164 int type;
165 char * path;
166 };
167
168 #define TAR_BLOCKSIZE 512
169 #define TAR_FULLFILENAME (100 + 155 + 1)
170
171 struct tar_header {
172 char filename[100];
173 char filemode[8];
174 char uid[8];
175 char gid[8];
176 char filesize[12];
177 char mtime[12];
178 char checksum[8];
179 char filetype;
180 char linkedname[100];
181 char ustar[8];
182 char owner[32];
183 char group[32];
184 char major[8];
185 char minor[8];
186 char prefix[155];
187 };
151188
152189 struct stats {
153190 unsigned long nblocks;
154191 unsigned long ninodes;
155192 };
156193
194
195 // used types
196
197 typedef signed char int8;
198 typedef unsigned char uint8;
199 typedef signed short int16;
200 typedef unsigned short uint16;
201 typedef signed int int32;
202 typedef unsigned int uint32;
203
157204 // block size
158205
159 static int blocksize = 1024;
206 static uint32 blocksize = 1024;
160207
161208 #define SUPERBLOCK_OFFSET 1024
162209 #define SUPERBLOCK_SIZE 1024
309356 //Given a block number find its offset within the block bitmap that covers it
310357 #define GRP_BBM_OFFSET(fs,blk) \
311358 ( (blk) - GRP_GROUP_OF_BLOCK((fs),(blk))*(fs)->sb->s_blocks_per_group )
312
313
314 // used types
315
316 typedef signed char int8;
317 typedef unsigned char uint8;
318 typedef signed short int16;
319 typedef unsigned short uint16;
320 typedef signed int int32;
321 typedef unsigned int uint32;
322359
323360
324361 // the GNU C library has a wonderful scanf("%as", string) which will
724761 static void
725762 swap_block(block b)
726763 {
727 int i;
764 uint32 i;
728765 uint32 *blk = (uint32*)b;
729766 for(i = 0; i < BLOCKSIZE/4; i++)
730767 blk[i] = swab32(blk[i]);
13381375 {
13391376 if(!item)
13401377 {
1341 int i;
1378 uint32 i;
13421379 uint8 bits;
13431380 for(i = 0; i < BLOCKSIZE; i++)
13441381 if((bits = b[i]) != (uint8)-1)
17991836 static void
18001837 inode_pos_finish(filesystem *fs, inode_pos *ipos)
18011838 {
1839 fs = fs; // unused
18021840 put_nod(ipos->ni);
18031841 }
18041842
18371875 uint32 bk;
18381876 directory *d;
18391877 dirwalker dw;
1840 int reclen, nlen;
1878 uint32 reclen, nlen;
18411879 inode *node;
18421880 inode *pnode;
18431881 nod_info *dni, *ni;
20622100 #define COPY_BLOCKS 16
20632101 #define CB_SIZE (COPY_BLOCKS * BLOCKSIZE)
20642102
2103 typedef off_t (*file_read_cb)(filesystem *fs, inode_pos *ipos, off_t size, void *data);
2104
2105 off_t fh_read(filesystem *fs, inode_pos *ipos, off_t size, void *data)
2106 {
2107 size_t readbytes;
2108 off_t remaining_size = size;
2109 int fullsize;
2110
2111 uint8 * b = malloc(CB_SIZE);
2112 if (!b)
2113 error_msg_and_die("mkfile_fs: out of memory");
2114
2115 readbytes = fread(b, 1, MIN(remaining_size, CB_SIZE), (FILE *)data);
2116 while (readbytes) {
2117 remaining_size -= readbytes;
2118 fullsize = rndup(readbytes, BLOCKSIZE);
2119 // Fill to end of block with zeros.
2120 memset(b + readbytes, 0, fullsize - readbytes);
2121 extend_inode_blk(fs, ipos, b, fullsize / BLOCKSIZE);
2122 readbytes = fread(b, 1, MIN(remaining_size, CB_SIZE), (FILE *)data);
2123 }
2124
2125 free(b);
2126
2127 return size;
2128 }
2129
2130 #ifdef HAVE_LIBARCHIVE
2131 off_t la_read(filesystem *fs, inode_pos *ipos, off_t s /* ignored */, void *data)
2132 {
2133 size_t readbytes;
2134 off_t actual_size = 0;
2135 int fullsize;
2136
2137 uint8 * b = malloc(CB_SIZE);
2138 if (!b)
2139 error_msg_and_die("mkfile_fs: out of memory");
2140
2141 readbytes = archive_read_data((struct archive *)data, b, CB_SIZE);
2142 while (readbytes) {
2143 actual_size += readbytes;
2144 fullsize = rndup(readbytes, BLOCKSIZE);
2145 // Fill to end of block with zeros.
2146 memset(b + readbytes, 0, fullsize - readbytes);
2147 extend_inode_blk(fs, ipos, b, fullsize / BLOCKSIZE);
2148 readbytes = archive_read_data((struct archive *)data, b, CB_SIZE);
2149 }
2150
2151 free(b);
2152
2153 return actual_size;
2154
2155
2156 }
2157 #endif
2158
20652159 // make a file from a FILE*
20662160 static uint32
2067 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, FILE *f, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
2068 {
2069 uint8 * b;
2161 mkfile_fs(filesystem *fs, uint32 parent_nod, const char *name, uint32 mode, file_read_cb read_cb, void *data, off_t size, uid_t uid, gid_t gid, uint32 ctime, uint32 mtime)
2162 {
20702163 uint32 nod = mknod_fs(fs, parent_nod, name, mode|FM_IFREG, uid, gid, 0, 0, ctime, mtime);
20712164 nod_info *ni;
20722165 inode *node = get_nod(fs, nod, &ni);
2073 off_t size = 0;
2074 size_t readbytes;
2166 off_t actual_size;
20752167 inode_pos ipos;
2076 int fullsize;
2077
2078 b = malloc(CB_SIZE);
2079 if (!b)
2080 error_msg_and_die("mkfile_fs: out of memory");
2168
20812169 inode_pos_init(fs, &ipos, nod, INODE_POS_TRUNCATE, NULL);
2082 readbytes = fread(b, 1, CB_SIZE, f);
2083 while (readbytes) {
2084 fullsize = rndup(readbytes, BLOCKSIZE);
2085 // Fill to end of block with zeros.
2086 memset(b + readbytes, 0, fullsize - readbytes);
2087 extend_inode_blk(fs, &ipos, b, fullsize / BLOCKSIZE);
2088 size += readbytes;
2089 readbytes = fread(b, 1, CB_SIZE, f);
2090 }
2091 if (size > 0x7fffffff) {
2170
2171 actual_size = read_cb(fs, &ipos, size, data);
2172
2173 if (actual_size > 0x7fffffff) {
20922174 if (fs->sb->s_rev_level < 1)
20932175 fs_upgrade_rev1_largefile(fs);
20942176 fs->sb->s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
20952177 }
2096 node->i_dir_acl = size >> 32;
2097 node->i_size = size;
2178 node->i_dir_acl = actual_size >> 32;
2179 node->i_size = actual_size;
20982180 inode_pos_finish(fs, &ipos);
20992181 put_nod(ni);
2100 free(b);
21012182 return nod;
21022183 }
21032184
21342215 return mode;
21352216 }
21362217
2218 #define OCTAL_READ(field) tar_numeric_field_read((unsigned char*)field, sizeof field)
2219
2220 long long tar_numeric_field_read(unsigned char *field, size_t size)
2221 {
2222 size_t i;
2223 unsigned long long res = 0;
2224 // this is the 256-based GNU extension
2225 if(*field == 0x80 || *field == 0xff)
2226 {
2227 if(*field == 0xff)
2228 res = -1;
2229 for(i = 1; i < size; i++)
2230 res = (res << 8) + field[i];
2231 } else
2232 for(i = 0; i < size; i++)
2233 {
2234 char c = field[i];
2235 if(c == ' ')
2236 continue;
2237 if(c < '0' || c > '7')
2238 break;
2239 res = 8 * res + c - '0';
2240 }
2241 return res;
2242 }
2243
2244 int is_zero(char *block, size_t size)
2245 {
2246 size_t i;
2247 for(i = 0; i < size; i++)
2248 if(block[i])
2249 return 0;
2250 return 1;
2251 }
2252
2253 static void
2254 add2fs_from_tarball(filesystem *fs, uint32 this_nod, FILE * fh, int squash_uids, int squash_perms, uint32 fs_timestamp, struct stats *stats)
2255 {
2256 #ifndef HAVE_LIBARCHIVE
2257 uint32 nod, hlnod, oldnod;
2258 uint32 uid, gid, mode, major, minor, ctime, mtime;
2259 char buffer[TAR_BLOCKSIZE];
2260 char pathbuf[TAR_FULLFILENAME], *path, *path2 = NULL, *dir, *name;
2261 char type;
2262 struct tar_header *tarhead = (void*)buffer;
2263 size_t filesize, padding;
2264 int nbnull = 0;
2265 int i, checksum, signed_checksum, unsigned_checksum;
2266 int has_longname = 0;
2267 char *longname = NULL;
2268 size_t longname_size = 0;
2269 int has_longlink = 0;
2270 char *longlink = NULL;
2271 size_t longlink_size = 0;
2272
2273 size_t readbytes;
2274 while(1)
2275 {
2276 if (path2) {
2277 free(path2);
2278 path2 = NULL;
2279 }
2280 readbytes = fread(buffer, 1, TAR_BLOCKSIZE, fh);
2281 if (!readbytes)
2282 break;
2283 if (readbytes != TAR_BLOCKSIZE)
2284 error_msg_and_die("tarball has wrong size");
2285 if (is_zero(buffer, sizeof buffer))
2286 {
2287 if (nbnull++)
2288 break;
2289 continue;
2290 } else
2291 nbnull = 0;
2292 if (*(long *)tarhead->ustar != *(long *)"ustar\00000" && strcmp(tarhead->ustar, "ustar "))
2293 error_msg_and_die("not a tarball");
2294 signed_checksum = unsigned_checksum = 0;
2295 checksum = OCTAL_READ(tarhead->checksum);
2296 memset(tarhead->checksum, ' ', sizeof tarhead->checksum);
2297 for(i = 0; i < TAR_BLOCKSIZE; i++)
2298 {
2299 signed_checksum += (signed char)buffer[i];
2300 unsigned_checksum += (unsigned char)buffer[i];
2301 }
2302 if(checksum != signed_checksum && checksum != unsigned_checksum)
2303 error_msg_and_die("tarball corrupted");
2304 filesize = OCTAL_READ(tarhead->filesize);
2305 padding = rndup(filesize, TAR_BLOCKSIZE) - filesize;
2306 mtime = OCTAL_READ(tarhead->mtime);
2307 ctime = fs_timestamp;
2308 uid = OCTAL_READ(tarhead->uid);
2309 gid = OCTAL_READ(tarhead->gid);
2310 mode = OCTAL_READ(tarhead->filemode) & FM_IMASK;
2311 major = OCTAL_READ(tarhead->major);
2312 minor = OCTAL_READ(tarhead->minor);
2313 type = tarhead->filetype;
2314 if (squash_uids)
2315 uid = gid = 0;
2316 if (squash_perms)
2317 mode &= ~(FM_IRWXG | FM_IRWXO);
2318 if(has_longname)
2319 {
2320 path = longname;
2321 has_longname = 0;
2322 } else {
2323 strncpy(pathbuf, tarhead->prefix, sizeof tarhead->prefix);
2324 strncpy(pathbuf+strnlen(pathbuf, sizeof pathbuf), tarhead->filename, sizeof tarhead->filename);
2325 pathbuf[strnlen(pathbuf, sizeof pathbuf - 1)] = '\0';
2326 path = pathbuf;
2327 }
2328 if (stats)
2329 {
2330 switch (type)
2331 {
2332 case '2':
2333 if (strlen(tarhead->linkedname) >= 4 * (EXT2_TIND_BLOCK+1))
2334 stats->nblocks += (filesize + BLOCKSIZE - 1) / BLOCKSIZE;
2335 stats->ninodes++;
2336 break;
2337 case '0':
2338 case 0:
2339 case '7':
2340 stats->nblocks += (filesize + BLOCKSIZE - 1) / BLOCKSIZE;
2341 case '1':
2342 case '6':
2343 case '3':
2344 case '4':
2345 stats->ninodes++;
2346 break;
2347 default:
2348 break;
2349 }
2350 fseek(fh, filesize + padding, SEEK_CUR);
2351 } else {
2352 if (fs && strcmp(path, "/") == 0) {
2353 // if the entry modifies the root node, don't call
2354 // basename and dirname but chmod the root node
2355 // directly
2356 fseek(fh, filesize + padding, SEEK_CUR);
2357 if (type != '5') {
2358 error_msg("tarball entry \"%s\" skipped: root node must be a directory", path);
2359 continue;
2360 }
2361 mode |= FM_IFDIR;
2362 chmod_fs(fs, this_nod, mode, uid, gid);
2363 continue;
2364 }
2365 path2 = strdup(path);
2366 name = basename(path);
2367 dir = dirname(path2);
2368 if((!strcmp(name, ".")) || (!strcmp(name, "..")))
2369 {
2370 error_msg("tarball entry %s skipped", path);
2371 fseek(fh, filesize + padding, SEEK_CUR);
2372 continue;
2373 }
2374 if(fs)
2375 {
2376 if(!(nod = find_path(fs, this_nod, dir)))
2377 {
2378 error_msg("tarball entry %s skipped: can't find directory '%s' to create '%s''", path, dir, name);
2379 fseek(fh, filesize + padding, SEEK_CUR);
2380 continue;
2381 }
2382 }
2383 else
2384 nod = 0;
2385 switch (type)
2386 {
2387 case '5':
2388 if((oldnod = find_path(fs, nod, name)))
2389 chmod_fs(fs, nod = oldnod, mode, uid, gid);
2390 else
2391 nod = mkdir_fs(fs, nod, name, mode, uid, gid, ctime, mtime);
2392 fseek(fh, filesize + padding, SEEK_CUR);
2393 break;
2394 case '0':
2395 case 0:
2396 case '7':
2397 nod = mkfile_fs(fs, nod, name, mode, fh_read, fh, filesize, uid, gid, ctime, mtime);
2398 fseek(fh, padding, SEEK_CUR);
2399 break;
2400 case '1':
2401 if(!(hlnod = find_path(fs, this_nod, tarhead->linkedname)))
2402 {
2403 error_msg("tarball entry %s skipped: can't find hardlink destination '%s' to create '%s''", path, dir, name);
2404 fseek(fh, filesize + padding, SEEK_CUR);
2405 continue;
2406 }
2407 add2dir(fs, nod, hlnod, name);
2408 fseek(fh, filesize + padding, SEEK_CUR);
2409 break;
2410 case '2':
2411 if(has_longlink)
2412 mklink_fs(fs, nod, name, strlen(longlink), (uint8*)longlink, uid, gid, ctime, mtime);
2413 else
2414 mklink_fs(fs, nod, name, strlen(tarhead->linkedname), (uint8*)tarhead->linkedname, uid, gid, ctime, mtime);
2415 has_longlink = 0;
2416 fseek(fh, filesize + padding, SEEK_CUR);
2417 break;
2418 case '6':
2419 nod = mknod_fs(fs, nod, name, mode|FM_IFIFO, uid, gid, 0, 0, ctime, mtime);
2420 fseek(fh, filesize + padding, SEEK_CUR);
2421 break;
2422 case '3':
2423 nod = mknod_fs(fs, nod, name, mode|FM_IFCHR, uid, gid, major, minor, ctime, mtime);
2424 fseek(fh, filesize + padding, SEEK_CUR);
2425 break;
2426 case '4':
2427 nod = mknod_fs(fs, nod, name, mode|FM_IFBLK, uid, gid, major, minor, ctime, mtime);
2428 fseek(fh, filesize + padding, SEEK_CUR);
2429 break;
2430 case 'L':
2431 if(has_longname)
2432 error_msg("tarball longname to '%s' hasn't been consumed", longname);
2433 if(filesize + padding > longname_size)
2434 {
2435 if(longname)
2436 free(longname);
2437 longname = malloc(longname_size = filesize + padding);
2438 }
2439 fread(longname, longname_size, 1, fh);
2440 has_longname = 1;
2441 break;
2442 case 'K':
2443 if(has_longlink)
2444 error_msg("tarball longlink to '%s' hasn't been consumed", longlink);
2445 if(filesize + padding > longlink_size)
2446 {
2447 if(longlink)
2448 free(longlink);
2449 longlink = malloc(longlink_size = filesize + padding);
2450 }
2451 fread(longlink, longlink_size, 1, fh);
2452 has_longlink = 1;
2453 break;
2454 default:
2455 error_msg("tarball entry %s skipped: bad type '%c' for entry '%s'", path, type, name);
2456 fseek(fh, filesize + padding, SEEK_CUR);
2457 continue;
2458 }
2459 }
2460 }
2461 if (path2)
2462 free(path2);
2463 if (nbnull != 2)
2464 error_msg_and_die("tarball has wrong size");
2465 if(longname)
2466 free(longname);
2467 if(longlink)
2468 free(longlink);
2469 #else
2470 int r;
2471 uint32 nod, lnknod;
2472 struct archive *a;
2473 struct archive_entry *entry;
2474 char *path2, *path3, *dir, *name, *lnk;
2475 size_t filesize;
2476 uint32 uid, gid, mode, ctime, mtime;
2477 a = archive_read_new();
2478 if (a == NULL)
2479 error_msg_and_die("Couldn't create archive reader.");
2480 if (archive_read_support_filter_all(a) != ARCHIVE_OK)
2481 error_msg_and_die("Couldn't enable decompression");
2482 if (archive_read_support_format_all(a) != ARCHIVE_OK)
2483 error_msg_and_die("Couldn't enable read formats");
2484
2485 if ((r = archive_read_open_FILE(a, fh)))
2486 error_msg_and_die("archive_read_open_FILE(): %s", archive_error_string(a));
2487
2488 for (;;) {
2489 r = archive_read_next_header(a, &entry);
2490 if (r == ARCHIVE_EOF)
2491 break;
2492 if (r != ARCHIVE_OK)
2493 error_msg_and_die("archive_read_next_header(): %s",
2494 archive_error_string(a));
2495 mode = archive_entry_mode(entry);
2496 if (stats)
2497 {
2498 // depending on the archive, the entry size might not
2499 // be set in the first place in which case the
2500 // estimate might be totally off
2501 filesize = archive_entry_size(entry);
2502 switch(mode & S_IFMT)
2503 {
2504 case S_IFLNK:
2505 if(filesize >= 4 * (EXT2_TIND_BLOCK+1))
2506 stats->nblocks += (filesize + BLOCKSIZE - 1) / BLOCKSIZE;
2507 stats->ninodes++;
2508 break;
2509 case S_IFREG:
2510 stats->nblocks += (filesize + BLOCKSIZE - 1) / BLOCKSIZE;
2511 case S_IFCHR:
2512 case S_IFBLK:
2513 case S_IFIFO:
2514 case S_IFSOCK:
2515 stats->ninodes++;
2516 break;
2517 case S_IFDIR:
2518 stats->ninodes++;
2519 break;
2520 default:
2521 break;
2522 }
2523 continue;
2524 }
2525 path2 = strdup(archive_entry_pathname(entry));
2526 path3 = strdup(archive_entry_pathname(entry));
2527 name = basename(path2);
2528 dir = dirname(path3);
2529 if(!(nod = find_path(fs, this_nod, dir)))
2530 {
2531 error_msg("can't find directory '%s' to create '%s''", dir, name);
2532 continue;
2533 }
2534 uid = archive_entry_uid(entry);
2535 gid = archive_entry_gid(entry);
2536 if (squash_uids)
2537 uid = gid = 0;
2538 if (squash_perms)
2539 mode &= ~(FM_IRWXG | FM_IRWXO);
2540 if(find_dir(fs, nod, name))
2541 chmod_fs(fs, nod, mode, uid, gid);
2542 // FIXME: if the entry is a regular file, update
2543 // content
2544 else {
2545 ctime = archive_entry_ctime(entry);
2546 mtime = archive_entry_mtime(entry);
2547 switch(mode & S_IFMT)
2548 {
2549 #if HAVE_STRUCT_STAT_ST_RDEV
2550 case S_IFCHR:
2551 mknod_fs(fs, nod, name, mode|FM_IFCHR, uid, gid, major(archive_entry_rdev(entry)), minor(archive_entry_rdev(entry)), ctime, mtime);
2552 break;
2553 case S_IFBLK:
2554 mknod_fs(fs, nod, name, mode|FM_IFBLK, uid, gid, major(archive_entry_rdev(entry)), minor(archive_entry_rdev(entry)), ctime, mtime);
2555 break;
2556 #endif
2557 case S_IFIFO:
2558 mknod_fs(fs, nod, name, mode|FM_IFIFO, uid, gid, 0, 0, ctime, mtime);
2559 break;
2560 case S_IFSOCK:
2561 mknod_fs(fs, nod, name, mode|FM_IFSOCK, uid, gid, 0, 0, ctime, mtime);
2562 break;
2563 case S_IFLNK:
2564 lnk = calloc(1, rndup(strlen(archive_entry_symlink(entry)), BLOCKSIZE));
2565 strcpy(lnk, archive_entry_symlink(entry));
2566 if (lnk == NULL)
2567 error_msg_and_die(memory_exhausted);
2568 mklink_fs(fs, nod, name, strlen(archive_entry_symlink(entry)), (uint8*)lnk, uid, gid, ctime, mtime);
2569 free(lnk);
2570 break;
2571 case S_IFREG:
2572 // we pass a filesize of zero because
2573 // libarchive will take care of it for
2574 // us and the archive does not
2575 // necessarily contain the file size
2576 // in the first place
2577 mkfile_fs(fs, nod, name, mode, la_read, a, 0, uid, gid, ctime, mtime);
2578 break;
2579 case S_IFDIR:
2580 mkdir_fs(fs, nod, name, mode, uid, gid, ctime, mtime);
2581 break;
2582 default:
2583 // probably a hardlink
2584 if (archive_entry_hardlink(entry) != NULL) {
2585 if(!(lnknod = find_path(fs, this_nod, archive_entry_hardlink(entry))))
2586 error_msg_and_die("path %s not found in filesystem", archive_entry_hardlink(entry));
2587 add2dir(fs, nod, lnknod, name);
2588 } else {
2589 error_msg("ignoring entry %s with mode %d", archive_entry_pathname(entry), mode & S_IFMT);
2590 }
2591 }
2592 }
2593 free(path2);
2594 free(path3);
2595 }
2596 archive_read_close(a);
2597 archive_read_free(a);
2598 #endif
2599 }
2600
21372601 // add or fixup entries to the filesystem from a text file
21382602 /* device table entries take the form of:
21392603 <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>
21452609 c Character special device file
21462610 b Block special device file
21472611 p Fifo (named pipe)
2148
2149 I don't bother with symlinks (permissions are irrelevant), hard
2150 links (special cases of regular files), or sockets (why bother).
2612 l Symbolic link
2613
2614 I don't bother with hard links (special cases of regular files),
2615 or sockets.
21512616
21522617 Regular files must exist in the target root directory. If a char,
21532618 block, fifo, or directory does not exist, it will be created.
21922657 continue;
21932658 }
21942659 mode &= FM_IMASK;
2660 if (fs && strcmp(path, "/") == 0) {
2661 // if the entry modifies the root node, don't call
2662 // basename and dirname but chmod the root node
2663 // directly
2664 if (type != 'd') {
2665 error_msg("device table line %d skipped: root node must be a directory", lineno);
2666 continue;
2667 }
2668 mode |= FM_IFDIR;
2669 chmod_fs(fs, this_nod, mode, uid, gid);
2670 continue;
2671 }
21952672 path2 = strdup(path);
21962673 name = basename(path);
21972674 dir = dirname(path2);
22172694 break;
22182695 case 'f':
22192696 mode |= FM_IFREG;
2697 break;
2698 case 'l':
2699 mode |= FM_IFLNK;
22202700 break;
22212701 case 'p':
22222702 mode |= FM_IFIFO;
22902770 struct stat st;
22912771 char *lnk;
22922772 uint32 save_nod;
2773 off_t filesize;
22932774
22942775 if(!(dh = opendir(".")))
22952776 perror_msg_and_die(".");
23122793 switch(st.st_mode & S_IFMT)
23132794 {
23142795 case S_IFLNK:
2315 if((st.st_mode & S_IFMT) == S_IFREG || st.st_size >= 4 * (EXT2_TIND_BLOCK+1))
2796 if(st.st_size >= 4 * (EXT2_TIND_BLOCK+1))
23162797 stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
23172798 stats->ninodes++;
23182799 break;
23192800 case S_IFREG:
2320 if((st.st_mode & S_IFMT) == S_IFREG || st.st_size > 4 * (EXT2_TIND_BLOCK+1))
2321 stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
2801 stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
23222802 case S_IFCHR:
23232803 case S_IFBLK:
23242804 case S_IFIFO:
23902870 break;
23912871 case S_IFREG:
23922872 fh = fopen(dent->d_name, "rb");
2873 fseek(fh, 0, SEEK_END);
2874 filesize = ftell(fh);
2875 rewind(fh);
23932876 if (!fh) {
23942877 error_msg("Unable to open file %s", dent->d_name);
23952878 break;
23962879 }
2397 nod = mkfile_fs(fs, this_nod, name, mode, fh, uid, gid, ctime, mtime);
2880 nod = mkfile_fs(fs, this_nod, name, mode, fh_read, fh, filesize, uid, gid, ctime, mtime);
23982881 fclose(fh);
23992882 break;
24002883 case S_IFDIR:
24282911
24292912 // Copy size blocks from src to dst, putting holes in the output
24302913 // file (if possible) if the input block is all zeros.
2431 // Copy size blocks from src to dst, putting holes in the output
2432 // file (if possible) if the input block is all zeros.
24332914 static void
24342915 copy_file(filesystem *fs, FILE *dst, FILE *src, size_t size)
24352916 {
28073288 if(fsize <= 0)
28083289 error_msg_and_die("wrong size while saving inode %d", nod);
28093290 if(fwrite(get_blk(fs, bk, &bi),
2810 (fsize > BLOCKSIZE) ? BLOCKSIZE : fsize, 1, f) != 1)
3291 ((uint32)fsize > BLOCKSIZE) ? BLOCKSIZE : (uint32)fsize, 1, f) != 1)
28113292 error_msg_and_die("error while saving inode %d", nod);
28123293 put_blk(bi);
28133294 fsize -= BLOCKSIZE;
30873568 }
30883569
30893570 static void
3090 populate_fs(filesystem *fs, char **dopt, int didx, int squash_uids, int squash_perms, uint32 fs_timestamp, struct stats *stats)
3571 populate_fs(filesystem *fs, struct fslayer *fslayers, int nlayers, int squash_uids, int squash_perms, uint32 fs_timestamp, struct stats *stats)
30913572 {
30923573 int i;
3093 for(i = 0; i < didx; i++)
3574 for(i = 0; i < nlayers; i++)
30943575 {
30953576 struct stat st;
30963577 FILE *fh;
30973578 int pdir;
30983579 char *pdest;
30993580 uint32 nod = EXT2_ROOT_INO;
3100 if(fs)
3101 if((pdest = strchr(dopt[i], ':')))
3102 {
3103 *(pdest++) = 0;
3104 if(!(nod = find_path(fs, EXT2_ROOT_INO, pdest)))
3105 error_msg_and_die("path %s not found in filesystem", pdest);
3106 }
3107 stat(dopt[i], &st);
3108 switch(st.st_mode & S_IFMT)
3581 if((pdest = strchr(fslayers[i].path, ':')))
31093582 {
3110 case S_IFREG:
3111 fh = xfopen(dopt[i], "rb");
3583 *(pdest++) = 0;
3584 if(fs && !(nod = find_path(fs, EXT2_ROOT_INO, pdest)))
3585 error_msg_and_die("path %s not found in filesystem", pdest);
3586 }
3587 /* do not compute stats when input is to be read from stdin */
3588 if (stats != NULL && strcmp(fslayers[i].path, "-") == 0) {
3589 continue;
3590 }
3591 stat(fslayers[i].path, &st);
3592 switch(fslayers[i].type)
3593 {
3594 case FSLAYER_TABLE:
3595 if(strcmp(fslayers[i].path, "-") == 0)
3596 fh = stdin;
3597 else if((st.st_mode & S_IFMT) != S_IFREG)
3598 error_msg_and_die("%s should be a file", fslayers[i].path);
3599 else
3600 fh = xfopen(fslayers[i].path, "rb");
3601 if(fs)
3602 fprintf(stderr, "nodes fixup and creation from device table %s\n", fslayers[i].path);
31123603 add2fs_from_file(fs, nod, fh, fs_timestamp, stats);
3113 fclose(fh);
3604 if(strcmp(fslayers[i].path, "-") != 0)
3605 fclose(fh);
31143606 break;
3115 case S_IFDIR:
3607 case FSLAYER_DIR:
3608 if((st.st_mode & S_IFMT) != S_IFDIR)
3609 error_msg_and_die("%s should be a directory", fslayers[i].path);
3610 if(fs)
3611 fprintf(stderr, "copying from directory %s\n", fslayers[i].path);
31163612 if((pdir = open(".", O_RDONLY)) < 0)
31173613 perror_msg_and_die(".");
3118 if(chdir(dopt[i]) < 0)
3119 perror_msg_and_die(dopt[i]);
3614 if(chdir(fslayers[i].path) < 0)
3615 perror_msg_and_die(fslayers[i].path);
31203616 add2fs_from_dir(fs, nod, squash_uids, squash_perms, fs_timestamp, stats);
31213617 if(fchdir(pdir) < 0)
31223618 perror_msg_and_die("fchdir");
31233619 if(close(pdir) < 0)
31243620 perror_msg_and_die("close");
31253621 break;
3126 default:
3127 error_msg_and_die("%s is neither a file nor a directory", dopt[i]);
3622 case FSLAYER_TAR:
3623 if(strcmp(fslayers[i].path, "-") == 0)
3624 fh = stdin;
3625 else if((st.st_mode & S_IFMT) != S_IFREG)
3626 error_msg_and_die("%s should be a file", fslayers[i].path);
3627 else
3628 fh = xfopen(fslayers[i].path, "rb");
3629 if(fs)
3630 fprintf(stderr, "copying from tar archive %s\n", fslayers[i].path);
3631 add2fs_from_tarball(fs, nod, fh, squash_uids, squash_perms, fs_timestamp, stats);
3632 if(strcmp(fslayers[i].path, "-") != 0)
3633 fclose(fh);
3634 break;
31283635 }
31293636 }
31303637 }
31413648 fprintf(stderr, "Usage: %s [options] image\n"
31423649 "Create an ext2 filesystem image from directories/files\n\n"
31433650 " -x, --starting-image <image>\n"
3144 " -d, --root <directory>\n"
3145 " -D, --devtable <file>\n"
3651 " -d, --root <directory>[:path] Copy from a local directory into path (or root)\n"
3652 " -D, --devtable <file>[:path] Add or fixup nodes from a device table into path (or root)\n"
3653 " -a, --tarball <file>[:path] Copy from a tar archive into path (or root)\n"
31463654 " -B, --block-size <bytes>\n"
31473655 " -b, --size-in-blocks <blocks>\n"
31483656 " -i, --bytes-per-inode <bytes per inode>\n"
31493657 " -N, --number-of-inodes <number of inodes>\n"
31503658 " -L, --volume-label <string>\n"
31513659 " -m, --reserved-percentage <percentage of blocks to reserve>\n"
3152 " -o, --creator-os <os> 'linux' (default), 'hurd', 'freebsd' or number.\n"
3153 " -g, --block-map <path> Generate a block map file for this path.\n"
3154 " -e, --fill-value <value> Fill unallocated blocks with value.\n"
3155 " -z, --allow-holes Allow files with holes.\n"
3156 " -f, --faketime Set filesystem timestamps to 0 (for testing).\n"
3157 " -q, --squash Same as \"-U -P\".\n"
3158 " -U, --squash-uids Squash owners making all files be owned by root.\n"
3159 " -P, --squash-perms Squash permissions on all files.\n"
3660 " -o, --creator-os <os> 'linux' (default), 'hurd', 'freebsd' or number.\n"
3661 " -g, --block-map <path> Generate a block map file for this path.\n"
3662 " -e, --fill-value <value> Fill unallocated blocks with value.\n"
3663 " -z, --allow-holes Allow files with holes.\n"
3664 " -f, --faketime Set filesystem timestamps to 0 (for testing).\n"
3665 " -q, --squash Same as \"-U -P\".\n"
3666 " -U, --squash-uids Squash owners making all files be owned by root.\n"
3667 " -P, --squash-perms Squash permissions on all files.\n"
31603668 " -h, --help\n"
31613669 " -V, --version\n"
31623670 " -v, --verbose\n\n"
32013709 int creator_os = CREATOR_OS;
32023710 char * fsout = "-";
32033711 char * fsin = 0;
3204 char * dopt[MAX_DOPT];
3205 int didx = 0;
3712 struct fslayer layers[MAX_DOPT];
3713 int nlayers = 0;
32063714 char * gopt[MAX_GOPT];
32073715 int gidx = 0;
32083716 int verbose = 0;
32233731 { "starting-image", required_argument, NULL, 'x' },
32243732 { "root", required_argument, NULL, 'd' },
32253733 { "devtable", required_argument, NULL, 'D' },
3734 { "tarball", required_argument, NULL, 'a' },
32263735 { "block-size", required_argument, NULL, 'B' },
32273736 { "size-in-blocks", required_argument, NULL, 'b' },
32283737 { "bytes-per-inode", required_argument, NULL, 'i' },
32453754
32463755 app_name = argv[0];
32473756
3248 while((c = getopt_long(argc, argv, "x:d:D:B:b:i:N:L:m:o:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
3757 while((c = getopt_long(argc, argv, "x:d:D:a:B:b:i:N:L:m:o:g:e:zfqUPhVv", longopts, NULL)) != EOF) {
32493758 #else
32503759 app_name = argv[0];
32513760
3252 while((c = getopt(argc, argv, "x:d:D:B:b:i:N:L:m:o:g:e:zfqUPhVv")) != EOF) {
3761 while((c = getopt(argc, argv, "x:d:D:a:B:b:i:N:L:m:o:g:e:zfqUPhVv")) != EOF) {
32533762 #endif /* HAVE_GETOPT_LONG */
32543763 switch(c)
32553764 {
32573766 fsin = optarg;
32583767 break;
32593768 case 'd':
3769 layers[nlayers].type = FSLAYER_DIR;
3770 layers[nlayers++].path = optarg;
3771 break;
32603772 case 'D':
3261 dopt[didx++] = optarg;
3773 layers[nlayers].type = FSLAYER_TABLE;
3774 layers[nlayers++].path = optarg;
3775 break;
3776 case 'a':
3777 layers[nlayers].type = FSLAYER_TAR;
3778 layers[nlayers++].path = optarg;
32623779 break;
32633780 case 'B':
32643781 blocksize = SI_atof(optarg);
33293846 if(creator_os < 0)
33303847 error_msg_and_die("Creator OS unknown.");
33313848
3849 int numstdin = 0;
3850 for(i = 0; i < nlayers; i++)
3851 if (strcmp(layers[i].path, "-") == 0)
3852 numstdin++;
3853 if (numstdin == 1 && nbinodes == -1 && bytes_per_inode == -1)
3854 fprintf(stderr, "Cannot count the required inodes for input from stdin -- use the -N or -i options to set the number of inodes or work with temporary files.");
3855 if (numstdin > 1)
3856 error_msg_and_die("only one input can come from stdin");
3857
33323858 if(fsin)
33333859 {
3860 fprintf(stderr, "starting from existing image %s", fsin);
33343861 if(strcmp(fsin, "-"))
33353862 {
33363863 FILE * fh = xfopen(fsin, "rb");
33503877 stats.ninodes = EXT2_FIRST_INO - 1 + (nbresrvd ? 1 : 0);
33513878 stats.nblocks = 0;
33523879
3353 populate_fs(NULL, dopt, didx, squash_uids, squash_perms, fs_timestamp, &stats);
3880 populate_fs(NULL, layers, nlayers, squash_uids, squash_perms, fs_timestamp, &stats);
33543881
33553882 if(nbinodes == -1)
33563883 nbinodes = stats.ninodes;
33663893 if(tmp_nbinodes > nbinodes)
33673894 nbinodes = tmp_nbinodes;
33683895 }
3369 if(fs_timestamp == -1)
3370 fs_timestamp = time(NULL);
3896 if(fs_timestamp == -1) {
3897 char *source_date_epoch = getenv("SOURCE_DATE_EPOCH");
3898 if (source_date_epoch == NULL) {
3899 fs_timestamp = time(NULL);
3900 } else {
3901 fs_timestamp = strtoll(source_date_epoch, NULL, 10);
3902 }
3903 }
33713904 fs = init_fs(nbblocks, nbinodes, nbresrvd, holes,
33723905 fs_timestamp, creator_os, bigendian, fsout);
3906 fs_upgrade_rev1_largefile(fs);
33733907 }
33743908 if (volumelabel != NULL)
33753909 strncpy((char *)fs->sb->s_volume_name, volumelabel,
33763910 sizeof(fs->sb->s_volume_name));
33773911
3378 populate_fs(fs, dopt, didx, squash_uids, squash_perms, fs_timestamp, NULL);
3912 populate_fs(fs, layers, nlayers, squash_uids, squash_perms, fs_timestamp, NULL);
33793913
33803914 if(emptyval) {
33813915 uint32 b;
66 LC_ALL=C
77 export LC_ALL
88
9 origin_dir="$(dirname "$(realpath "$0")")"
910 test_dir=t_tmp_dir
1011 test_img=t_tmp_ext2.img
1112
1213 gen_cleanup () {
13 rm -r $test_dir $test_img
14 rm -rf $test_dir $test_img
15 }
16
17 gen_setup () {
18 gen_cleanup
19 mkdir $test_dir || exit 1
1420 }
1521
1622 calc_digest () {
2834 dgen () {
2935 blocks=$1; blocksz=$2; size=$3
3036 echo Testing $blocks blocks of $blocksz bytes with file of size $size
31 mkdir $test_dir || exit 1
37 gen_setup
3238 cd $test_dir
3339 if [ x$size = x0 ]; then
3440 > file.$size
4450 # fgen - Exercises the -D option of genext2fs.
4551 # Creates an image with the devices listed in the given spec file.
4652 fgen () {
47 blocks=$1; fname=$3
53 stdin=$1; blocks=$2; fname=$4
4854 echo Testing $blocks blocks with with devices file $fname
49 mkdir $test_dir || exit 1
50 cp $fname $test_dir
55 gen_setup
56 cp $origin_dir/$fname $test_dir
5157 TZ=UTC-11 touch -t 200502070321.43 $test_dir/$fname
52 ./genext2fs -N 92 -b $blocks -D $test_dir/$fname -f -o Linux $test_img
58 if [ "$stdin" = "y" ]; then
59 ./genext2fs -N 92 -b $blocks -D - -f -o Linux $test_img < $test_dir/$fname
60 else
61 ./genext2fs -N 92 -b $blocks -D $test_dir/$fname -f -o Linux $test_img
62 fi
5363 }
5464
55 # lgen - Exercises the -d option of genext2fs, with symlink.
56 # Creates an image with a symlink of variable length.
65 # lgen - Exercises the -d option of genext2fs, with symlink
66 # and a device table
67 # Creates an image with a symlink of variable length, then
68 # uses a device table to change its uid/gid
5769 # NB: some systems including early versions of Mac OS X cannot
5870 # change symlink timestamps; this test will fail on those systems.
5971 lgen () {
60 blocks=$1; blocksz=$2; appendage=$3
61 echo Testing $blocks blocks of $blocksz bytes with symlink ...$appendage
62 mkdir $test_dir || exit 1
72 stdin=$1; blocks=$2; blocksz=$3; appendage=$4; devtable=$5
73 echo Testing $blocks blocks of $blocksz bytes with symlink ...$appendage and devices file $devtable
74 gen_setup
6375 cd $test_dir
6476 target=12345678901234567890123456789012345678901234567890$appendage
6577 ln -s $target symlink
6678 TZ=UTC-11 touch -h -t 201309241353.59 symlink .
6779 cd ..
68 ./genext2fs -B $blocksz -N 234 -b $blocks -d $test_dir -f -o Linux -q $test_img
80 if [ "$stdin" = "y" ]; then
81 ./genext2fs -B $blocksz -N 234 -b $blocks -d $test_dir -D - -f -o Linux -q $test_img < $origin_dir/$devtable
82 else
83 ./genext2fs -B $blocksz -N 234 -b $blocks -d $test_dir -D $origin_dir/$devtable -f -o Linux -q $test_img
84 fi
6985 }
86
87 # agen - Exercises the -a option of genext2fs.
88 # Creates an image with a file of given size.
89 agen () {
90 stdin=$1; blocks=$2; blocksz=$3; tarball=$4
91 echo Testing $blocks blocks of $blocksz bytes with tarball
92 gen_setup
93 echo $tarball | base64 -d | gzip -dc > "$test_dir/input.tar"
94 if [ "$stdin" = "y" ]; then
95 ./genext2fs -B $blocksz -N 17 -b $blocks -a - -f -o Linux $test_img < "$test_dir/input.tar"
96 else
97 ./genext2fs -B $blocksz -N 17 -b $blocks -a "$test_dir/input.tar" -f -o Linux $test_img
98 fi
99 }
88
99 set -e
1010
11 . ./test-gen.lib
11 origin_dir="$(dirname "$(realpath "$0")")"
12 . $origin_dir/test-gen.lib
1213
1314 test_mnt=t_mnt
1415
1516 test_common () {
1617 /sbin/e2fsck -fn $test_img || fail
18 rm -rf $test_mnt
1719 mkdir $test_mnt
1820 mount -t ext2 -o ro,loop $test_img $test_mnt || fail
1921 }
2123 test_cleanup () {
2224 umount $test_mnt
2325 rmdir $test_mnt
24 rm -f fout lsout
26 rm -f fout lsout stout esout
2527 }
2628
2729 fail () {
6567 grep '^[^ #]* [bc]' | \
6668 awk '{print $1,$4,$5,$6","$7}'| \
6769 sort -d -k3.6 > fout
68 ls -aln $test_mnt/dev | \
70 ls -aln $test_mnt/dev | \
6971 egrep -v "(hda|hdb|tty|loop|ram|ubda)" | \
7072 grep ^[bc] | \
7173 awk '{ print "/dev/"$10,$3,$4,$5$6}' | \
7476 pass ftest $@
7577 }
7678
77 # ltest_mount - Exercise the -d option of genext2fs, with symlink.
79 # ltest_mount - Exercise the -d option of genext2fs, with symlink and device table.
7880 ltest_mount () {
7981 appendage=$3
8082 lgen $@
8183 test_common
8284 cd $test_mnt
8385 readlink symlink > ../lsout
86 stat -c "%u %g" symlink > ../stout
8487 cd ..
8588 test -s lsout || fail
8689 echo 12345678901234567890123456789012345678901234567890$appendage > fout
8790 diff fout lsout || fail
91 echo "77 7" > esout
92 diff stout esout || fail
8893 pass ltest $@
8994 }
9095
105110 dtest_mount 20000 1024 16777216
106111 dtest_mount 10000 2048 16777216
107112 ftest_mount 4096 default device_table.txt
108 ltest_mount 200 1024 123456789
109 ltest_mount 200 1024 1234567890
110 ltest_mount 200 4096 12345678901
113 ltest_mount 200 1024 123456789 device_table_link.txt
114 ltest_mount 200 1024 1234567890 device_table_link.txt
115 ltest_mount 200 4096 12345678901 device_table_link.txt
1010
1111 set -e
1212
13 . ./test-gen.lib
13 origin_dir="$(dirname "$(realpath "$0")")"
14 . $origin_dir/test-gen.lib
1415
1516 md5cmp () {
1617 md5=`calc_digest`
3334 ftest () {
3435 expected_digest=$1
3536 shift
36 fgen $@
37 fgen y $@
38 md5cmp $expected_digest
39 fgen n $@
3740 md5cmp $expected_digest
3841 gen_cleanup
3942 }
4144 ltest () {
4245 expected_digest=$1
4346 shift
44 lgen $@
47 lgen y $@
48 md5cmp $expected_digest
49 lgen n $@
50 md5cmp $expected_digest
51 gen_cleanup
52 }
53
54 atest() {
55 expected_digest=$1
56 shift
57 agen y $@
58 md5cmp $expected_digest
59 agen n $@
4560 md5cmp $expected_digest
4661 gen_cleanup
4762 }
5065 # replace the following lines with the output of
5166 # sudo sh test-mount.sh|grep test
5267
53 dtest 4a25d1109fa03f8519e89a5fc365580f 4096 1024 0
54 dtest a2c5c3b014510456320373e72a7d4b3f 2048 2048 0
55 dtest 4af8e2915523207f780e22ff1de29633 1024 4096 0
56 dtest 537400c0b8f868895ced27af64dc703b 8193 1024 0
57 dtest f6f6a6124104c8ff5ca2e3cfd8b3f396 8194 1024 0
58 dtest 63f60f06d4a4858404a09d071b688a7d 8193 4096 0
59 dtest 851d7cac136b44e1bf461fef27180a1b 8194 2048 0
60 dtest 518b75cd6651ae864babf3b12a70866b 4096 1024 1
61 dtest 87b13fb5e0f31e2f13faea02f829730b 1024 4096 1
62 dtest 548ce3a3bf7d57e350a11c0c274b7795 4096 1024 12288
63 dtest d6041295c924de32af49ad35a3b37c0d 4096 1024 274432
64 dtest 2dcd1c07084e616433b43043c1309cc6 9000 1024 8388608
65 dtest 227d38c05d5860dc039812eed603f20f 4500 2048 8388608
66 dtest 627c09439a5ed6194900f12f5591d28e 2250 4096 8388608
67 dtest 84dbb9949b3c1c9d7f3237d3cdaa86b5 20000 1024 16777216
68 dtest a4ab80a62c0fd09a3be023c77e0307b1 10000 2048 16777216
69 ftest 9108433a817035cb5306e8217d5e634b 4096 default device_table.txt
70 ltest 25a6bbe241965e71c077b47dab4172db 200 1024 123456789
71 ltest fcf5cd1344bbe3787418fb857f66b131 200 1024 1234567890
72 ltest 9b70d483ee1b3447c63a32096154fa05 200 4096 12345678901
68 dtest d28c461a408de69eef908045a11207ec 4096 1024 0
69 dtest 8501cc97857245d16aaf4b8a06345fc2 2048 2048 0
70 dtest 1fc39a40fa808aa974aa3065f1862067 1024 4096 0
71 dtest a6bc1b4937db12944a9ae496da1ba65c 8193 1024 0
72 dtest 21d8675cb8b8873540fa3d911dddca7e 8194 1024 0
73 dtest 346ecb90c1ca7a1d6e5fbe57383e1055 8193 4096 0
74 dtest b2672c5deb9cdf598db2c11118b5c91a 8194 2048 0
75 dtest 1e950ef4f2719cd2d4f70de504c88244 4096 1024 1
76 dtest 4a47abd795e5282a1762e1fa8b22a432 1024 4096 1
77 dtest 3e229c70850d2388c172124b05e93ddc 4096 1024 12288
78 dtest 495cda3636eb0f42aceb9d63bc34690b 4096 1024 274432
79 dtest fe792a70e336ed1e7a29aee7ecdeb0ab 9000 1024 8388608
80 dtest 2375e7344dfa1550583ea25d30bc02bf 4500 2048 8388608
81 dtest 4dedea56398027fe3267ebc602b9a6b6 2250 4096 8388608
82 dtest c41835904c45320731aab685436ba8f6 20000 1024 16777216
83 dtest 662529e81e6106288aec9516bcefe109 10000 2048 16777216
84 ftest 3db16dd57bd15c1c80dd6bc900411c58 4096 default device_table.txt
85 ltest c21b5a3cad405197e821ba7143b0ea9b 200 1024 123456789 device_table_link.txt
86 ltest 18b04b4bea2f7ebf315a116be5b92589 200 1024 1234567890 device_table_link.txt
87 ltest 8aaed693b75dbdf77607f376d661027a 200 4096 12345678901 device_table_link.txt
88 atest 994ca42d3179c88263af777bedec0c55 200 1024 H4sIAAAAAAAAA+3WTW6DMBAF4Fn3FD6B8fj3PKAqahQSSwSk9vY1uKssGiJliFretzECJAYeY1s3JM4UKYRlLG7H5ZhdTIHZGevK+ZTYkgrypRFN17EdlKIh5/G3++5d/6N004qbA47er8/fWVduV2aLD7D7/A85C88Ba/ufA/sQIhk25VdA/2+h5t+1gx4/pd7vfv+Hm/ytmfNH/8vr+ql7e3UR8DK6uUx9L/uMtev/3P8p+KX/oyHlZMuqntX/9T34Z9yk9Gco8//xkGWf8Uj+Mbpl/Y+JVJQtq9r5/K+bj3Z474+Xk9wG4JH86/rvyzxAirfYnOw+/+vXWTb+uv9PaV3+JfiSv/WOlJVPf/f5AwAAAAAAAAAAAMD/9A0cPbO/ACgAAA==