]> wimlib.net Git - wimlib/blobdiff - src/wimboot.c
wimboot.c: Fix format string
[wimlib] / src / wimboot.c
index 35fe13a97e6fc12ff052b93d23fc4b73cb017659..6006bbe7f50c13b145dd732f5718ac2ad1c59593 100644 (file)
 /*
  * Copyright (C) 2014 Eric Biggers
  *
- * This file is part of wimlib, a library for working with WIM files.
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
  *
- * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  * details.
  *
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
  */
 
 #ifdef __WIN32__
@@ -77,19 +75,17 @@ query_device(HANDLE h, DWORD code, void *out, DWORD out_size)
  */
 static int
 query_partition_and_disk_info(const wchar_t *path,
-                             PARTITION_INFORMATION_EX *part_info_ret,
+                             PARTITION_INFORMATION_EX *part_info,
                              DRIVE_LAYOUT_INFORMATION_EX *drive_info_ret)
 {
-       HANDLE h;
        wchar_t vol_name[] = L"\\\\.\\X:";
        wchar_t disk_name[] = L"\\\\?\\PhysicalDriveXXXXXXXXXX";
-
-       PARTITION_INFORMATION_EX part_info;
-       size_t extents_size = sizeof(VOLUME_DISK_EXTENTS) + 4 * sizeof(DISK_EXTENT);
-       VOLUME_DISK_EXTENTS *extents = alloca(extents_size);
-       size_t drive_info_size = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
-                                       8 * sizeof(PARTITION_INFORMATION_EX);
-       DRIVE_LAYOUT_INFORMATION_EX *drive_info = alloca(drive_info_size);
+       HANDLE h = INVALID_HANDLE_VALUE;
+       VOLUME_DISK_EXTENTS *extents = NULL;
+       size_t extents_size;
+       DRIVE_LAYOUT_INFORMATION_EX *drive_info = NULL;
+       size_t drive_info_size;
+       int ret;
 
        wimlib_assert(path[0] != L'\0' && path[1] == L':');
 
@@ -97,36 +93,51 @@ query_partition_and_disk_info(const wchar_t *path,
 
        h = open_file(vol_name, GENERIC_READ);
        if (h == INVALID_HANDLE_VALUE) {
-               set_errno_from_GetLastError();
-               ERROR_WITH_ERRNO("\"%ls\": Can't open volume device", vol_name);
-               return WIMLIB_ERR_OPEN;
+               ERROR("\"%ls\": Can't open volume device (err=%"PRIu32")",
+                     vol_name, (u32)GetLastError());
+               ret = WIMLIB_ERR_OPEN;
+               goto out;
        }
 
        if (!query_device(h, IOCTL_DISK_GET_PARTITION_INFO_EX,
-                         &part_info, sizeof(part_info)))
+                         part_info, sizeof(PARTITION_INFORMATION_EX)))
        {
-               ERROR("\"%ls\": Can't get partition info (err=0x%08"PRIx32")",
+               ERROR("\"%ls\": Can't get partition info (err=%"PRIu32")",
                      vol_name, (u32)GetLastError());
-               CloseHandle(h);
-               return WIMLIB_ERR_READ;
+               ret = WIMLIB_ERR_READ;
+               goto out;
        }
 
-       if (!query_device(h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
-                         extents, extents_size))
-       {
-               ERROR("\"%ls\": Can't get volume extent info (err=0x%08"PRIx32")",
-                     vol_name, (u32)GetLastError());
-               CloseHandle(h);
-               return WIMLIB_ERR_READ;
+       extents_size = sizeof(VOLUME_DISK_EXTENTS);
+       for (;;) {
+               extents_size += 4 * sizeof(DISK_EXTENT);
+               extents = MALLOC(extents_size);
+               if (!extents) {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto out;
+               }
+
+               if (query_device(h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
+                                extents, extents_size))
+                       break;
+               if (GetLastError() != ERROR_MORE_DATA) {
+                       ERROR("\"%ls\": Can't get volume extent info (err=%"PRIu32")",
+                             vol_name, (u32)GetLastError());
+                       ret = WIMLIB_ERR_READ;
+                       goto out;
+               }
+               FREE(extents);
        }
 
        CloseHandle(h);
+       h = INVALID_HANDLE_VALUE;
 
        if (extents->NumberOfDiskExtents != 1) {
                ERROR("\"%ls\": This volume has %"PRIu32" disk extents, "
                      "but this code is untested for more than 1",
                      vol_name, (u32)extents->NumberOfDiskExtents);
-               return WIMLIB_ERR_UNSUPPORTED;
+               ret = WIMLIB_ERR_UNSUPPORTED;
+               goto out;
        }
 
        wsprintf(wcschr(disk_name, L'X'), L"%"PRIu32,
@@ -134,52 +145,74 @@ query_partition_and_disk_info(const wchar_t *path,
 
        h = open_file(disk_name, GENERIC_READ);
        if (h == INVALID_HANDLE_VALUE) {
-               set_errno_from_GetLastError();
-               ERROR_WITH_ERRNO("\"%ls\": Can't open disk device", disk_name);
-               return WIMLIB_ERR_OPEN;
+               ERROR("\"%ls\": Can't open disk device (err=%"PRIu32")",
+                     disk_name, (u32)GetLastError());
+               ret = WIMLIB_ERR_OPEN;
+               goto out;
        }
 
-       if (!query_device(h, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
-                         drive_info, drive_info_size))
-       {
-               ERROR("\"%ls\": Can't get disk info (err=0x%08"PRIx32")",
-                     disk_name, (u32)GetLastError());
-               CloseHandle(h);
-               return WIMLIB_ERR_READ;
+       drive_info_size = sizeof(DRIVE_LAYOUT_INFORMATION_EX);
+       for (;;) {
+               drive_info_size += 4 * sizeof(PARTITION_INFORMATION_EX);
+               drive_info = MALLOC(drive_info_size);
+               if (!drive_info) {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto out;
+               }
+
+               if (query_device(h, IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
+                                drive_info, drive_info_size))
+                       break;
+               if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+                       ERROR("\"%ls\": Can't get disk info (err=%"PRIu32")",
+                             disk_name, (u32)GetLastError());
+                       ret = WIMLIB_ERR_READ;
+                       goto out;
+               }
+               FREE(drive_info);
        }
 
+       *drive_info_ret = *drive_info;  /* doesn't include partitions */
        CloseHandle(h);
+       h = INVALID_HANDLE_VALUE;
 
-       if (drive_info->PartitionStyle != part_info.PartitionStyle) {
+       if (drive_info->PartitionStyle != part_info->PartitionStyle) {
                ERROR("\"%ls\", \"%ls\": Inconsistent partition table type!",
                      vol_name, disk_name);
-               return WIMLIB_ERR_UNSUPPORTED;
+               ret = WIMLIB_ERR_UNSUPPORTED;
+               goto out;
        }
 
-       if (part_info.PartitionStyle == PARTITION_STYLE_GPT) {
-               BUILD_BUG_ON(sizeof(part_info.Gpt.PartitionId) !=
+       if (part_info->PartitionStyle == PARTITION_STYLE_GPT) {
+               BUILD_BUG_ON(sizeof(part_info->Gpt.PartitionId) !=
                             sizeof(drive_info->Gpt.DiskId));
-               if (!memcmp(&part_info.Gpt.PartitionId,
+               if (!memcmp(&part_info->Gpt.PartitionId,
                            &drive_info->Gpt.DiskId,
                            sizeof(drive_info->Gpt.DiskId)))
                {
                        ERROR("\"%ls\", \"%ls\": Partition GUID is the "
                              "same as the disk GUID???", vol_name, disk_name);
-                       return WIMLIB_ERR_UNSUPPORTED;
+                       ret = WIMLIB_ERR_UNSUPPORTED;
+                       goto out;
                }
        }
 
-       if (part_info.PartitionStyle != PARTITION_STYLE_MBR &&
-           part_info.PartitionStyle != PARTITION_STYLE_GPT)
+       if (part_info->PartitionStyle != PARTITION_STYLE_MBR &&
+           part_info->PartitionStyle != PARTITION_STYLE_GPT)
        {
                ERROR("\"%ls\": Unknown partition style 0x%08"PRIx32,
-                     vol_name, (u32)part_info.PartitionStyle);
-               return WIMLIB_ERR_UNSUPPORTED;
+                     vol_name, (u32)part_info->PartitionStyle);
+               ret = WIMLIB_ERR_UNSUPPORTED;
+               goto out;
        }
 
-       *part_info_ret = part_info;
-       *drive_info_ret = *drive_info;
-       return 0;
+       ret = 0;
+out:
+       FREE(extents);
+       FREE(drive_info);
+       if (h != INVALID_HANDLE_VALUE)
+               CloseHandle(h);
+       return ret;
 }
 
 /*
@@ -831,26 +864,6 @@ out:
        return ret;
 }
 
-static int
-win32_get_drive_path(const wchar_t *file_path, wchar_t drive_path[7])
-{
-       tchar *file_abspath;
-
-       file_abspath = realpath(file_path, NULL);
-       if (!file_abspath)
-               return WIMLIB_ERR_NOMEM;
-
-       if (file_abspath[0] == L'\0' || file_abspath[1] != L':') {
-               ERROR("\"%ls\": Path format not recognized", file_abspath);
-               FREE(file_abspath);
-               return WIMLIB_ERR_UNSUPPORTED;
-       }
-
-       wsprintf(drive_path, L"\\\\.\\%lc:", file_abspath[0]);
-       FREE(file_abspath);
-       return 0;
-}
-
 /* Try to attach an instance of the Windows Overlay File System Filter Driver to
  * the specified drive (such as C:)  */
 static bool
@@ -1044,10 +1057,8 @@ out:
  * This turns it into a reparse point that redirects accesses to it, to the
  * corresponding resource in the WIM archive.
  *
- * @attr
- *     Object attributes that specify the path to the file.
- * @printable_name
- *     Printable representation of the path encoded in @attr.
+ * @h
+ *     Open handle to the file, with GENERIC_WRITE access.
  * @lte
  *     Unnamed data stream of the file.
  * @data_source_id
@@ -1058,33 +1069,18 @@ out:
  *     %true if the WOF driver appears to be available and working; %false if
  *     not.
  *
- * Returns 0 on success, or a positive error code on failure.
+ * Returns %true on success, or %false on failure with GetLastError() set.
  */
-int
-wimboot_set_pointer(OBJECT_ATTRIBUTES *attr,
-                   const wchar_t *printable_name,
+bool
+wimboot_set_pointer(HANDLE h,
                    const struct wim_lookup_table_entry *lte,
                    u64 data_source_id,
                    const u8 lookup_table_hash[SHA1_HASH_SIZE],
                    bool wof_running)
 {
-       int ret;
-       HANDLE h = NULL;
-       NTSTATUS status;
-       IO_STATUS_BLOCK iosb;
        DWORD bytes_returned;
        DWORD err;
 
-       status = (*func_NtOpenFile)(&h, GENERIC_WRITE | SYNCHRONIZE, attr,
-                                   &iosb, FILE_SHARE_VALID_FLAGS,
-                                   FILE_OPEN_FOR_BACKUP_INTENT |
-                                       FILE_OPEN_REPARSE_POINT |
-                                       FILE_SYNCHRONOUS_IO_NONALERT);
-       if (!NT_SUCCESS(status)) {
-               SetLastError((*func_RtlNtStatusToDosError)(status));
-               goto fail;
-       }
-
        if (wof_running) {
                /* The WOF driver is running.  We can create the reparse point
                 * using FSCTL_SET_EXTERNAL_BACKING.  */
@@ -1107,7 +1103,7 @@ wimboot_set_pointer(OBJECT_ATTRIBUTES *attr,
                if (!DeviceIoControl(h, FSCTL_SET_EXTERNAL_BACKING,
                                     &in, sizeof(in), NULL, 0,
                                     &bytes_returned, NULL))
-                       goto fail;
+                       return false;
        } else {
 
                /* The WOF driver is running.  We need to create the reparse
@@ -1145,7 +1141,7 @@ wimboot_set_pointer(OBJECT_ATTRIBUTES *attr,
 
                if (!DeviceIoControl(h, FSCTL_SET_REPARSE_POINT,
                                     &in, sizeof(in), NULL, 0, &bytes_returned, NULL))
-                       goto fail;
+                       return false;
 
                /* We also need to create an unnamed data stream of the correct
                 * size.  Otherwise the file shows up as zero length.  It can be
@@ -1153,31 +1149,18 @@ wimboot_set_pointer(OBJECT_ATTRIBUTES *attr,
                 * are unimportant.  */
                if (!DeviceIoControl(h, FSCTL_SET_SPARSE, NULL, 0, NULL, 0,
                                     &bytes_returned, NULL))
-                       goto fail;
+                       return false;
 
                if (!SetFilePointerEx(h,
                                      (LARGE_INTEGER){ .QuadPart = lte->size},
                                      NULL, FILE_BEGIN))
-                       goto fail;
+                       return false;
 
                if (!SetEndOfFile(h))
-                       goto fail;
+                       return false;
        }
 
-       ret = 0;
-       goto out;
-
-fail:
-       err = GetLastError();
-       set_errno_from_win32_error(err);
-       ERROR_WITH_ERRNO("\"%ls\": Couldn't set WIMBoot pointer data "
-                        "(err=%"PRIu32")", printable_name, (u32)err);
-       ret = WIMLIB_ERR_WIMBOOT;
-out:
-       if (h)
-               (*func_NtClose)(h);
-       return ret;
-
+       return true;
 }
 
 #endif /* __WIN32__ */