earlycpio.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /* ----------------------------------------------------------------------- *
  2. *
  3. * Copyright 2012 Intel Corporation; author H. Peter Anvin
  4. *
  5. * This file is part of the Linux kernel, and is made available
  6. * under the terms of the GNU General Public License version 2, as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * ----------------------------------------------------------------------- */
  15. /*
  16. * earlycpio.c
  17. *
  18. * Find a specific cpio member; must precede any compressed content.
  19. * This is used to locate data items in the initramfs used by the
  20. * kernel itself during early boot (before the main initramfs is
  21. * decompressed.) It is the responsibility of the initramfs creator
  22. * to ensure that these items are uncompressed at the head of the
  23. * blob. Depending on the boot loader or package tool that may be a
  24. * separate file or part of the same file.
  25. */
  26. #include <linux/earlycpio.h>
  27. #include <linux/kernel.h>
  28. #include <linux/string.h>
  29. enum cpio_fields {
  30. C_MAGIC,
  31. C_INO,
  32. C_MODE,
  33. C_UID,
  34. C_GID,
  35. C_NLINK,
  36. C_MTIME,
  37. C_FILESIZE,
  38. C_MAJ,
  39. C_MIN,
  40. C_RMAJ,
  41. C_RMIN,
  42. C_NAMESIZE,
  43. C_CHKSUM,
  44. C_NFIELDS
  45. };
  46. /**
  47. * cpio_data find_cpio_data - Search for files in an uncompressed cpio
  48. * @path: The directory to search for, including a slash at the end
  49. * @data: Pointer to the the cpio archive or a header inside
  50. * @len: Remaining length of the cpio based on data pointer
  51. * @offset: When a matching file is found, this is the offset to the
  52. * beginning of the cpio. It can be used to iterate through
  53. * the cpio to find all files inside of a directory path
  54. *
  55. * @return: struct cpio_data containing the address, length and
  56. * filename (with the directory path cut off) of the found file.
  57. * If you search for a filename and not for files in a directory,
  58. * pass the absolute path of the filename in the cpio and make sure
  59. * the match returned an empty filename string.
  60. */
  61. struct cpio_data __cpuinit find_cpio_data(const char *path, void *data,
  62. size_t len, long *offset)
  63. {
  64. const size_t cpio_header_len = 8*C_NFIELDS - 2;
  65. struct cpio_data cd = { NULL, 0, "" };
  66. const char *p, *dptr, *nptr;
  67. unsigned int ch[C_NFIELDS], *chp, v;
  68. unsigned char c, x;
  69. size_t mypathsize = strlen(path);
  70. int i, j;
  71. p = data;
  72. while (len > cpio_header_len) {
  73. if (!*p) {
  74. /* All cpio headers need to be 4-byte aligned */
  75. p += 4;
  76. len -= 4;
  77. continue;
  78. }
  79. j = 6; /* The magic field is only 6 characters */
  80. chp = ch;
  81. for (i = C_NFIELDS; i; i--) {
  82. v = 0;
  83. while (j--) {
  84. v <<= 4;
  85. c = *p++;
  86. x = c - '0';
  87. if (x < 10) {
  88. v += x;
  89. continue;
  90. }
  91. x = (c | 0x20) - 'a';
  92. if (x < 6) {
  93. v += x + 10;
  94. continue;
  95. }
  96. goto quit; /* Invalid hexadecimal */
  97. }
  98. *chp++ = v;
  99. j = 8; /* All other fields are 8 characters */
  100. }
  101. if ((ch[C_MAGIC] - 0x070701) > 1)
  102. goto quit; /* Invalid magic */
  103. len -= cpio_header_len;
  104. dptr = PTR_ALIGN(p + ch[C_NAMESIZE], 4);
  105. nptr = PTR_ALIGN(dptr + ch[C_FILESIZE], 4);
  106. if (nptr > p + len || dptr < p || nptr < dptr)
  107. goto quit; /* Buffer overrun */
  108. if ((ch[C_MODE] & 0170000) == 0100000 &&
  109. ch[C_NAMESIZE] >= mypathsize &&
  110. !memcmp(p, path, mypathsize)) {
  111. *offset = (long)nptr - (long)data;
  112. if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) {
  113. pr_warn(
  114. "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n",
  115. p, MAX_CPIO_FILE_NAME);
  116. }
  117. strlcpy(cd.name, p + mypathsize, MAX_CPIO_FILE_NAME);
  118. cd.data = (void *)dptr;
  119. cd.size = ch[C_FILESIZE];
  120. return cd; /* Found it! */
  121. }
  122. len -= (nptr - p);
  123. p = nptr;
  124. }
  125. quit:
  126. return cd;
  127. }