Commit 24fa50961451b7b21081e4d16836952b17eb5fb3

Authored by Luciano Rocha
Committed by Linus Torvalds
1 parent 67d38229df

[PATCH] usr/gen_init_cpio.c: support for hard links

Extend usr/gen_init_cpio.c "file" entry, adding support for hard links.

Previous format:
file <name> <location> <mode> <uid> <gid>

New format:
file <name> <location> <mode> <uid> <gid> [<hard links>]

The hard links specification is optional, keeping the previous
behaviour.

All hard links are defined sequentially in the resulting cpio and the
file data is present only in the last link. This is the behaviour of
GNU's cpio and is supported by the kernel initramfs extractor.

Signed-off-by: Luciano Rocha <strange@nsk.no-ip.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 86 additions and 36 deletions Side-by-side Diff

... ... @@ -14,6 +14,7 @@
14 14 * Original work by Jeff Garzik
15 15 *
16 16 * External file lists, symlink, pipe and fifo support by Thayne Harbaugh
  17 + * Hard link support by Luciano Rocha
17 18 */
18 19  
19 20 #define xstr(s) #s
20 21  
21 22  
22 23  
... ... @@ -286,16 +287,19 @@
286 287 return rc;
287 288 }
288 289  
289   -/* Not marked static to keep the compiler quiet, as no one uses this yet... */
290 290 static int cpio_mkfile(const char *name, const char *location,
291   - unsigned int mode, uid_t uid, gid_t gid)
  291 + unsigned int mode, uid_t uid, gid_t gid,
  292 + unsigned int nlinks)
292 293 {
293 294 char s[256];
294 295 char *filebuf = NULL;
295 296 struct stat buf;
  297 + long size;
296 298 int file = -1;
297 299 int retval;
298 300 int rc = -1;
  301 + int namesize;
  302 + int i;
299 303  
300 304 mode |= S_IFREG;
301 305  
302 306  
... ... @@ -323,29 +327,41 @@
323 327 goto error;
324 328 }
325 329  
326   - sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
327   - "%08X%08X%08X%08X%08X%08X%08X",
328   - "070701", /* magic */
329   - ino++, /* ino */
330   - mode, /* mode */
331   - (long) uid, /* uid */
332   - (long) gid, /* gid */
333   - 1, /* nlink */
334   - (long) buf.st_mtime, /* mtime */
335   - (int) buf.st_size, /* filesize */
336   - 3, /* major */
337   - 1, /* minor */
338   - 0, /* rmajor */
339   - 0, /* rminor */
340   - (unsigned)strlen(name) + 1,/* namesize */
341   - 0); /* chksum */
342   - push_hdr(s);
343   - push_string(name);
344   - push_pad();
  330 + size = 0;
  331 + for (i = 1; i <= nlinks; i++) {
  332 + /* data goes on last link */
  333 + if (i == nlinks) size = buf.st_size;
345 334  
346   - fwrite(filebuf, buf.st_size, 1, stdout);
347   - offset += buf.st_size;
348   - push_pad();
  335 + namesize = strlen(name) + 1;
  336 + sprintf(s,"%s%08X%08X%08lX%08lX%08X%08lX"
  337 + "%08lX%08X%08X%08X%08X%08X%08X",
  338 + "070701", /* magic */
  339 + ino, /* ino */
  340 + mode, /* mode */
  341 + (long) uid, /* uid */
  342 + (long) gid, /* gid */
  343 + nlinks, /* nlink */
  344 + (long) buf.st_mtime, /* mtime */
  345 + size, /* filesize */
  346 + 3, /* major */
  347 + 1, /* minor */
  348 + 0, /* rmajor */
  349 + 0, /* rminor */
  350 + namesize, /* namesize */
  351 + 0); /* chksum */
  352 + push_hdr(s);
  353 + push_string(name);
  354 + push_pad();
  355 +
  356 + if (size) {
  357 + fwrite(filebuf, size, 1, stdout);
  358 + offset += size;
  359 + push_pad();
  360 + }
  361 +
  362 + name += namesize;
  363 + }
  364 + ino++;
349 365 rc = 0;
350 366  
351 367 error:
352 368  
353 369  
354 370  
355 371  
... ... @@ -357,18 +373,51 @@
357 373 static int cpio_mkfile_line(const char *line)
358 374 {
359 375 char name[PATH_MAX + 1];
  376 + char *dname = NULL; /* malloc'ed buffer for hard links */
360 377 char location[PATH_MAX + 1];
361 378 unsigned int mode;
362 379 int uid;
363 380 int gid;
  381 + int nlinks = 1;
  382 + int end = 0, dname_len = 0;
364 383 int rc = -1;
365 384  
366   - if (5 != sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX) "s %o %d %d", name, location, &mode, &uid, &gid)) {
  385 + if (5 > sscanf(line, "%" str(PATH_MAX) "s %" str(PATH_MAX)
  386 + "s %o %d %d %n",
  387 + name, location, &mode, &uid, &gid, &end)) {
367 388 fprintf(stderr, "Unrecognized file format '%s'", line);
368 389 goto fail;
369 390 }
370   - rc = cpio_mkfile(name, location, mode, uid, gid);
  391 + if (end && isgraph(line[end])) {
  392 + int len;
  393 + int nend;
  394 +
  395 + dname = malloc(strlen(line));
  396 + if (!dname) {
  397 + fprintf (stderr, "out of memory (%d)\n", dname_len);
  398 + goto fail;
  399 + }
  400 +
  401 + dname_len = strlen(name) + 1;
  402 + memcpy(dname, name, dname_len);
  403 +
  404 + do {
  405 + nend = 0;
  406 + if (sscanf(line + end, "%" str(PATH_MAX) "s %n",
  407 + name, &nend) < 1)
  408 + break;
  409 + len = strlen(name) + 1;
  410 + memcpy(dname + dname_len, name, len);
  411 + dname_len += len;
  412 + nlinks++;
  413 + end += nend;
  414 + } while (isgraph(line[end]));
  415 + } else {
  416 + dname = name;
  417 + }
  418 + rc = cpio_mkfile(dname, location, mode, uid, gid, nlinks);
371 419 fail:
  420 + if (dname_len) free(dname);
372 421 return rc;
373 422 }
374 423  
375 424  
... ... @@ -381,22 +430,23 @@
381 430 "describe the files to be included in the initramfs archive:\n"
382 431 "\n"
383 432 "# a comment\n"
384   - "file <name> <location> <mode> <uid> <gid>\n"
  433 + "file <name> <location> <mode> <uid> <gid> [<hard links>]\n"
385 434 "dir <name> <mode> <uid> <gid>\n"
386 435 "nod <name> <mode> <uid> <gid> <dev_type> <maj> <min>\n"
387 436 "slink <name> <target> <mode> <uid> <gid>\n"
388 437 "pipe <name> <mode> <uid> <gid>\n"
389 438 "sock <name> <mode> <uid> <gid>\n"
390 439 "\n"
391   - "<name> name of the file/dir/nod/etc in the archive\n"
392   - "<location> location of the file in the current filesystem\n"
393   - "<target> link target\n"
394   - "<mode> mode/permissions of the file\n"
395   - "<uid> user id (0=root)\n"
396   - "<gid> group id (0=root)\n"
397   - "<dev_type> device type (b=block, c=character)\n"
398   - "<maj> major number of nod\n"
399   - "<min> minor number of nod\n"
  440 + "<name> name of the file/dir/nod/etc in the archive\n"
  441 + "<location> location of the file in the current filesystem\n"
  442 + "<target> link target\n"
  443 + "<mode> mode/permissions of the file\n"
  444 + "<uid> user id (0=root)\n"
  445 + "<gid> group id (0=root)\n"
  446 + "<dev_type> device type (b=block, c=character)\n"
  447 + "<maj> major number of nod\n"
  448 + "<min> minor number of nod\n"
  449 + "<hard links> space separated list of other links to file\n"
400 450 "\n"
401 451 "example:\n"
402 452 "# A simple initramfs\n"