1 /* febootstrap-supermin-helper reimplementation in C.
2 * Copyright (C) 2009-2010 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34 #include "ext2internal.h"
36 /* This function must unpack the cpio file and add the files it
37 * contains to the ext2 filesystem. Essentially this is doing the
38 * same thing as the kernel init/initramfs.c code. Note that we
39 * assume that the cpio is uncompressed newc format and can't/won't
40 * deal with anything else. All this cpio parsing code is copied to
41 * some extent from init/initramfs.c in the kernel.
43 #define N_ALIGN(len) ((((len) + 1) & ~3) + 2)
45 static unsigned long cpio_ino, nlink;
47 static unsigned long body_len, name_len;
51 static int dev_major, dev_minor, rdev_major, rdev_minor;
52 static loff_t curr, next_header;
55 static void parse_header (char *s);
56 static int parse_next_entry (void);
57 static void skip_to_next_header (void);
58 static void read_file (void);
59 static char *read_whole_body (void);
60 static ext2_ino_t maybe_link (void);
61 static void add_link (ext2_ino_t real_ino);
62 static void clear_links (void);
65 ext2_cpio_file (const char *cpio_file)
67 fp = fopen (cpio_file, "r");
69 error (EXIT_FAILURE, errno, "open: %s", cpio_file);
72 while (parse_next_entry ())
79 parse_next_entry (void)
85 /* Skip padding and synchronize with the next header. */
87 if (fread (&header[0], 4, 1, fp) != 1) {
90 error (EXIT_FAILURE, errno, "read failure reading cpio file");
93 if (memcmp (header, "\0\0\0\0", 4) == 0)
96 /* Read the rest of the header field. */
97 if (fread (&header[4], sizeof header - 4, 1, fp) != 1)
98 error (EXIT_FAILURE, errno, "read failure reading cpio file");
99 curr += sizeof header - 4;
102 fprintf (stderr, "cpio header %s\n", header);
104 if (memcmp (header, "070707", 6) == 0)
105 error (EXIT_FAILURE, 0, "incorrect cpio method: use -H newc option");
106 if (memcmp (header, "070701", 6) != 0)
107 error (EXIT_FAILURE, 0, "input is not a cpio file");
109 parse_header (header);
111 next_header = curr + N_ALIGN(name_len) + body_len;
112 next_header = (next_header + 3) & ~3;
113 if (name_len <= 0 || name_len > PATH_MAX)
114 skip_to_next_header ();
115 else if (S_ISLNK (mode)) {
116 if (body_len <= 0 || body_len > PATH_MAX)
117 skip_to_next_header ();
121 else if (!S_ISREG (mode) && body_len > 0)
122 skip_to_next_header (); /* only regular files have bodies */
124 read_file (); /* could be file, directory, block special, ... */
130 parse_header (char *s)
132 unsigned long parsed[12];
137 for (i = 0, s += 6; i < 12; i++, s += 8) {
139 parsed[i] = strtoul (buf, NULL, 16);
141 cpio_ino = parsed[0]; /* fake inode number from cpio file */
147 body_len = parsed[6];
148 dev_major = parsed[7];
149 dev_minor = parsed[8];
150 rdev_major = parsed[9];
151 rdev_minor = parsed[10];
152 name_len = parsed[11];
156 skip_to_next_header (void)
160 while (curr < next_header) {
161 size_t bytes = (size_t) (next_header - curr);
162 if (bytes > sizeof buf)
164 size_t r = fread (buf, 1, bytes, fp);
166 error (EXIT_FAILURE, errno, "error or unexpected end of cpio file");
171 /* Read any sort of file. The body will only be present for
172 * regular files and symlinks.
179 char name[N_ALIGN(name_len)+1]; /* asserted above this is <= PATH_MAX */
181 if (fread (name, N_ALIGN(name_len), 1, fp) != 1)
182 error (EXIT_FAILURE, errno, "read failure reading name field in cpio file");
183 curr += N_ALIGN(name_len);
185 name[name_len] = '\0';
188 fprintf (stderr, "ext2 read_file %s %o\n", name, mode);
190 if (strcmp (name, "TRAILER!!!") == 0) {
195 /* The name will be something like "bin/ls" or "./bin/ls". It won't
196 * (ever?) be an absolute path. Skip leading parts, and if it refers
197 * to the root directory just skip it entirely.
199 char *dirname = name, *basename;
204 if (*dirname == '\0')
208 basename = strrchr (dirname, '/');
209 if (basename == NULL) {
211 dir_ino = EXT2_ROOT_INO;
215 /* Look up the parent directory. */
216 err = ext2fs_namei (fs, EXT2_ROOT_INO, EXT2_ROOT_INO, dirname, &dir_ino);
218 error (EXIT_FAILURE, 0, "ext2: parent directory not found: %s: %s",
219 dirname, error_message (err));
223 fprintf (stderr, "ext2 read_file dirname %s basename %s\n",
226 ext2_clean_path (dir_ino, dirname, basename, S_ISDIR (mode));
228 /* Create a regular file. */
229 if (S_ISREG (mode)) {
230 ext2_ino_t ml = maybe_link ();
233 ext2_empty_inode (dir_ino, dirname, basename,
234 mode, uid, gid, mtime, mtime, mtime,
235 0, 0, EXT2_FT_REG_FILE, &ino);
240 /* It's a hard link back to a previous file. */
242 ext2_link (dir_ino, basename, ino, EXT2_FT_REG_FILE);
246 char *buf = read_whole_body ();
247 ext2_write_file (ino, buf, body_len, name);
251 /* Create a symlink. */
252 else if (S_ISLNK (mode)) {
254 ext2_empty_inode (dir_ino, dirname, basename,
255 mode, uid, gid, mtime, mtime, mtime,
256 0, 0, EXT2_FT_SYMLINK, &ino);
258 char *buf = read_whole_body ();
259 ext2_write_file (ino, buf, body_len, name);
262 /* Create a directory. */
263 else if (S_ISDIR (mode)) {
264 ext2_mkdir (dir_ino, dirname, basename,
265 mode, uid, gid, mtime, mtime, mtime);
267 /* Create a special file. */
268 else if (S_ISBLK (mode)) {
269 dir_ft = EXT2_FT_BLKDEV;
272 else if (S_ISCHR (mode)) {
273 dir_ft = EXT2_FT_CHRDEV;
275 } else if (S_ISFIFO (mode)) {
276 dir_ft = EXT2_FT_FIFO;
278 } else if (S_ISSOCK (mode)) {
279 dir_ft = EXT2_FT_SOCK;
281 /* Just like the kernel, we ignore special files with nlink > 1. */
282 if (maybe_link () == 0)
283 ext2_empty_inode (dir_ino, dirname, basename,
284 mode, uid, gid, mtime, mtime, mtime,
285 rdev_major, rdev_minor, dir_ft, NULL);
289 skip_to_next_header ();
293 read_whole_body (void)
295 char *buf = malloc (body_len);
297 error (EXIT_FAILURE, errno, "malloc");
299 size_t r = fread (buf, body_len, 1, fp);
301 error (EXIT_FAILURE, errno, "read failure reading body in cpio file");
309 unsigned long cpio_ino; /* fake ino from cpio file */
312 ext2_ino_t real_ino; /* real inode number on ext2 filesystem */
314 static struct links *links_head = NULL;
316 /* If it's a hard link, return the linked inode number in the real
319 * Returns: 0 = not a hard link
320 * 1 = possible unresolved hard link
321 * inode number = resolved hard link to this inode
328 for (p = links_head; p; p = p->next) {
329 if (p->cpio_ino != cpio_ino)
331 if (p->minor != dev_minor)
333 if (p->major != dev_major)
344 add_link (ext2_ino_t real_ino)
346 struct links *p = malloc (sizeof (*p));
347 p->cpio_ino = cpio_ino;
348 p->minor = dev_minor;
349 p->major = dev_major;
350 p->real_ino = real_ino;
356 /* Don't bother to free the linked list in this short-lived program. */