Bug#1107203: unblock: initramfs-tools/0.148.1 (4/5)
From
Ben Hutchings@1:229/2 to
All on Tue Jun 3 00:20:01 2025
[continued from previous message]
+ return true;
+
+ errno = orig_errno;
+ return false;
+}
+
+/* write() with loop in case of partial writes */
+static bool write_all(int fd, const void *buf, size_t len)
+{
+ size_t pos;
+ ssize_t ret;
+
+ pos = 0;
+ do {
+ ret = write(fd, (const char *)buf + pos, len - pos);
+ if (ret < 0)
+ return false;
+ pos += ret;
+ } while (pos < len);
+
+ return true;
+}
+
+/*
+ * Warn about failure of fread. This may be due to a file error
+ * reported in errno, or EOF which is not.
+ */
+static void warn_after_fread_failure(FILE *file, const char *name)
+{
+ if (ferror(file))
+ warn("%s", name);
+ else
+ warnx("%s: unexpected EOF", name);
+}
+
+/*
+ * Parse one of the hexadecimal fields. Don't use strtoul() because
+ * it requires null-termination.
+ */
+static bool cpio_parse_hex(const char *field, uint32_t *value_p)
+{
+ const char digits[] = "0123456789ABCDEF", *p;
+ uint32_t value = 0;
+ unsigned int i;
+ bool found_digit = false;
+
+ /* Skip leading spaces */
+ for (i = 0; i < 8 && field[i] == ' '; ++i)
+ ;
+
+ /* Parse digits up to end of field or null */
+ for (; i < 8 && field[i] != 0; ++i) {
+ p = strchr(digits, field[i]);
+ if (!p)
+ return false;
+ value = (value << 4) | (p - digits);
+ found_digit = true;
+ }
+
+ *value_p = value;
+ return found_digit;
+}
+
+/* Align offset of file contents or header */
+static off_t cpio_align(off_t off)
+{
+ return (off + 3) & ~3;
+}
+
+static struct cpio_handle *cpio_open(FILE *file, const char *name)
+{
+ struct cpio_handle *cpio;
+
+ cpio = calloc(1, sizeof(*cpio));
+ if (!cpio)
+ return NULL;
+
+ cpio->file = file;
+ cpio->name = name;
+ cpio->next_off = ftell(file);
+ return cpio;
+}
+
+/*
+ * Read next cpio header and name.
+ * Return:
+ * -1 on error
+ * 0 if entry is trailer
+ * 1 if entry is anything else
+ */
+static int cpio_get_next(struct cpio_handle *cpio, struct cpio_entry *entry) +{
+ struct cpio_new header;
+ uint32_t file_size, name_size;
+
+ if (fseek(cpio->file, cpio->next_off, SEEK_SET) < 0 ||
+ fread(&header, sizeof(header), 1, cpio->file) != 1) {
+ warn_after_fread_failure(cpio->file, cpio->name);
+ return -1;
+ }
+
+ if ((memcmp(header.c_magic, CPIO_NEW_MAGIC, CPIO_MAGIC_LEN) != 0 &&
+ memcmp(header.c_magic, CPIO_NEW_CRC_MAGIC, CPIO_MAGIC_LEN) != 0) ||
+ !cpio_parse_hex(header.c_filesize, &file_size) ||
+ !cpio_parse_hex(header.c_namesize, &name_size)) {
+ warnx("%s: cpio archive has invalid header", cpio->name);
+ return -1;
+ }
+
+ entry->name = cpio->name_buf;
+ entry->start = cpio->next_off;
+
+ /* Calculate offset of the next header */
+ cpio->next_off = cpio_align(
+ cpio_align(cpio->next_off + sizeof(header) + name_size)
+ + file_size);
+ entry->end = cpio->next_off;
+
+ if (name_size > sizeof(cpio->name_buf)) {
+ warnx("%s: cpio member name is too long", cpio->name);
+ return -1;
+ }
+
+ if (fread(cpio->name_buf, name_size, 1, cpio->file) != 1) {
+ warn_after_fread_failure(cpio->file, cpio->name);
+ return -1;
+ }
+
+ if (name_size == 0 || cpio->name_buf[name_size - 1] != 0) {
+ warnx("%s: cpio member name is invalid", cpio->name);
+ return -1;
+ }
+
+ return strcmp(entry->name, CPIO_NAME_TRAILER) != 0;
+}
+
+static void cpio_close(struct cpio_handle *cpio)
+{
+ free(cpio);
+}
+
+static bool detect_early_initramfs(FILE *in_file, const char *in_filename)
+{
+ struct cpio_handle *cpio;
+ struct cpio_entry entry;
+ bool ret = false;
+ off_t start = ftell(in_file);
+
+ cpio = cpio_open(in_file, in_filename);
+ if (!cpio)
+ return false;
+
+ while (cpio_get_next(cpio, &entry) > 0) {
+ if (strncmp(entry.name, "kernel/", 7) == 0) {
+ ret = true;
+ break;
+ }
+ }
+
+ cpio_close(cpio);
+
+ fseek(in_file, start, SEEK_SET);
+ return ret;
+}
+
+static bool copy_to_pipe(FILE *in_file, const char *in_filename,
+ off_t start, off_t end, int out_pipe)
+{
+ char buf[0x10000];
+ off_t in_pos;
+ size_t want_len, read_len;
+
+ /* Set input position */
+ fseek(in_file, start, SEEK_SET);
+ in_pos = start;
+
+ while (in_pos < end) {
+ /* How much do we want to copy? */
+ want_len = sizeof(buf);
+ if ((ssize_t)want_len > end - in_pos)
+ want_len = end - in_pos;
+
+ /* Read to buffer; update input position */
+ read_len = fread(buf, 1, want_len, in_file);
+ if (!read_len) {
+ warn_after_fread_failure(in_file, in_filename);
+ return false;
+ }
+ in_pos += read_len;
+
+ /* Write to pipe */
+ if (!write_all(out_pipe, buf, read_len)) {
+ warn("pipe write");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool handle_uncompressed(FILE *in_file, const char *in_filename,
+ int out_pipe)
+{
+ struct cpio_handle *cpio;
+ struct cpio_entry entry;
+ uint32_t pad;
+ int ret;
+
+ cpio = cpio_open(in_file, in_filename);
+ if (!cpio)
+ return false;
+
+ while ((ret = cpio_get_next(cpio, &entry)) > 0) {
+ if (!copy_to_pipe(in_file, in_filename, entry.start, entry.end, + out_pipe)) {
+ ret = -1;
+ break;
+ }
+ }
+
+ cpio_close(cpio);
+
+ if (ret < 0)
+ return false;
+
+ /* Skip trailer and any zero padidng */
+ fseek(in_file, entry.end, SEEK_SET);
+ while (fread(&pad, sizeof(pad), 1, in_file)) {
+ if (pad != 0) {
+ fseek(in_file, -sizeof(pad), SEEK_CUR);
+ break;
+ }
+ }
+
+ return true;
+}
+
+static bool handle_compressed(FILE *in_file, enum format format, int out_pipe) +{
+ const char *const *argv = decomp_table[format];
+ int in_fd = fileno(in_file);
+ off_t in_pos = ftell(in_file);
+ int pid, wstatus;
+
+ pid = fork();
+ if (pid < 0)
+ return false;
+
+ /* Child */
+ if (pid == 0) {
+ /*
+ * Make in_file stdin. Reset the position of the file
+ * descriptor because stdio will have read-ahead from
+ * the position it reported.
+ */
+ dup2(in_fd, 0);
+ close(in_fd);
+ lseek(0, in_pos, SEEK_SET);
+
+ /* Make out_pipe stdout */
+ dup2(out_pipe, 1);
+ close(out_pipe);
+
+ execlp(argv[0], argv[0], argv[1], NULL);
+ _exit(127);
+ }
+
+ /* Parent: wait for child */
+ if (waitpid(pid, &wstatus, 0) != pid ||
+ !WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
+ warnx("%s failed", argv[0]);
+ return false;
+ }
+ return true;
+}
+
+static bool write_trailer(int out_pipe)
+{
+ struct {
+ struct cpio_new header;
+ char name[sizeof(CPIO_NAME_TRAILER)];
+ char pad[-(sizeof(struct cpio_new) + sizeof(CPIO_NAME_TRAILER)) + & 3];
+ } __attribute__((packed)) trailer;
+ char name_size[8 + 1];
+
+ static_assert((sizeof(trailer) & 3) == 0, "pad miscalculated");
+
+ memset(&trailer.header, '0', sizeof(trailer.header));
+ memcpy(trailer.header.c_magic, CPIO_NEW_MAGIC, CPIO_MAGIC_LEN);
+ sprintf(name_size, "%08zX", sizeof(CPIO_NAME_TRAILER));
+ memcpy(trailer.header.c_namesize, name_size,
+ sizeof(trailer.header.c_namesize));
+
+ strcpy(trailer.name, CPIO_NAME_TRAILER);
+
+ memset(&trailer.pad, 0, sizeof(trailer.pad));
+
+ if (!write_all(out_pipe, &trailer, sizeof(trailer))) {
+ warn("pipe write");
+ return false;
+ }
+
+ return true;
+}
+
+static bool spawn_cpio(int optc, const char **optv, struct cpio_proc *proc)
+{
+ const char *argv[10];
+ int pipe_fds[2], pid;
+ size_t argc;
+
+ /* Combine base cpio command with extra options */
+ argc = 0;
+ argv[argc++] = "cpio";
+ argv[argc++] = "-i";
+ argv[argc++] = "--preserve-modification-time";
+ argv[argc++] = "--no-absolute-filenames";
+ argv[argc++] = "--quiet";
+ assert(argc + optc < sizeof(argv) / sizeof(argv[0]));
+ while (optc--)
+ argv[argc++] = *optv++;
[continued in next message]
--- SoupGate-Win32 v1.05
* Origin: you cannot sedate... all the things you hate (1:229/2)