+/*
+ * Reads the header from a WIM file.
+ *
+ * @filename
+ * Name of the WIM file (for error/debug messages only), or NULL if reading
+ * directly from file descriptor.
+ * @in_fd
+ * File descriptor, positioned at offset 0, to read the header from.
+ * @hdr
+ * Structure to read the header into.
+ *
+ * Return values:
+ * WIMLIB_ERR_SUCCESS (0)
+ * WIMLIB_ERR_IMAGE_COUNT
+ * WIMLIB_ERR_INVALID_CHUNK_SIZE
+ * WIMLIB_ERR_INVALID_PART_NUMBER
+ * WIMLIB_ERR_NOT_A_WIM_FILE
+ * WIMLIB_ERR_READ
+ * WIMLIB_ERR_UNEXPECTED_END_OF_FILE
+ * WIMLIB_ERR_UNKNOWN_VERSION
+ */
+int
+read_wim_header(const tchar *filename, struct filedes *in_fd,
+ struct wim_header *hdr)
+{
+ struct wim_header_disk disk_hdr _aligned_attribute(8);
+ int ret;
+ tchar *pipe_str;
+
+ wimlib_assert(in_fd->offset == 0);
+
+ if (!filename) {
+ pipe_str = alloca(40);
+ tsprintf(pipe_str, T("[fd %d]"), in_fd->fd);
+ filename = pipe_str;
+ }
+
+ BUILD_BUG_ON(sizeof(struct wim_header_disk) != WIM_HEADER_DISK_SIZE);
+
+ DEBUG("Reading WIM header from \"%"TS"\"", filename);
+
+ ret = full_read(in_fd, &disk_hdr, sizeof(disk_hdr));
+ if (ret)
+ goto read_error;
+
+ if (disk_hdr.magic != WIM_MAGIC) {
+ if (disk_hdr.magic == PWM_MAGIC) {
+ /* Pipable WIM: Use header at end instead, unless
+ * actually reading from a pipe. */
+ if (!in_fd->is_pipe) {
+ lseek(in_fd->fd, -WIM_HEADER_DISK_SIZE, SEEK_END);
+ ret = full_read(in_fd, &disk_hdr, sizeof(disk_hdr));
+ if (ret)
+ goto read_error;
+ }
+ } else {
+ ERROR("\"%"TS"\": Invalid magic characters in header", filename);
+ return WIMLIB_ERR_NOT_A_WIM_FILE;
+ }
+ }
+ hdr->magic = disk_hdr.magic;