Mount .iso file with python

71 Views Asked by At

I am trying to mount iso file with python on Windows 10. Here is the code:

import ctypes
from ctypes import wintypes

ByteArray8 = wintypes.BYTE * 8

src = r'F:\Backup\ubuntu.iso'


class GUID(ctypes.Structure):
    _fields_ = [
        ("Data1", ctypes.c_long),
        ("Data2", ctypes.c_short),
        ("Data3", ctypes.c_short),
        ("Data4", ByteArray8)
    ]


guid = GUID(0xec984aec, 0xa0f9, 0x47e9, ByteArray8(0x90, 0x1f, 0x71, 0x41, 0x5a, 0x66, 0x34, 0x5b))


class VIRTUAL_STORAGE_TYPE(ctypes.Structure):
    _fields_ = [
        ('DeviceId', ctypes.c_ulong),
        ('VendorId', GUID)
    ]


virtual_storage_type = VIRTUAL_STORAGE_TYPE(1, guid)
handle = wintypes.HANDLE()

Path = ctypes.c_wchar_p(src)

print(
    ctypes.windll.virtdisk.OpenVirtualDisk(
            ctypes.byref(virtual_storage_type),
            Path,
            0x000d0000,
            0x00000000,
            None,
            ctypes.byref(handle)
        )
)

print(
    ctypes.windll.virtdisk.AttachVirtualDisk(
        handle,
        None,
        0x00000001,
        0,
        None,
        None
    )
)

It shows two 0 after run, which means the open and attach operation succeed. But no new driver shown in explorer.

I want to know the reason and how to mount .iso file correctly. Here is reference: https://learn.microsoft.com/en-us/windows/win32/api/virtdisk/nf-virtdisk-openvirtualdisk https://learn.microsoft.com/en-us/windows/win32/api/virtdisk/nf-virtdisk-attachvirtualdisk

2

There are 2 best solutions below

0
CristiFati On BEST ANSWER

2 problems with the code:

  1. Functional. By default, disk is closed when its corresponding handle is (which happens automatically when the program ends). So, the disk was opened (and shown in Explorer), but only for a very short period of time (after the AttachVirtualDisk call till program end), so you were not able to see it. To be able to use the disk, either:

    • Don't stop the program until you're done using the disk (add an input statement at the very end)

    • Detach the disk lifetime from its handle's one (use ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME flag from [MS.Learn]: ATTACH_VIRTUAL_DISK_FLAG enumeration (virtdisk.h)).
      Needless to say that now, you'll have to detach the disk yourself, by either:

      • Eject it from Explorer

      • Enhancing code to call DetachVirtualDisk

      Also, not sure what are the implications of repeatedly attaching the disk (without detaching it)

  2. Coding - Undefined Behavior generator. Check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) for a common pitfall when working with CTypes (calling functions)

code00.py:

#!/usr/bin/env python

import ctypes as cts
import sys
from ctypes import wintypes as wts


class GUID(cts.Structure):
    _fields_ = (
        ("Data1", cts.c_ulong),
        ("Data2", cts.c_ushort),
        ("Data3", cts.c_ushort),
        ("Data4", cts.c_ubyte * 8),
    )


class VIRTUAL_STORAGE_TYPE(cts.Structure):
    _fields_ = (
        ("DeviceId", wts.ULONG),
        ("VendorId", GUID),
    )


ERROR_SUCCESS = 0
VIRTUAL_STORAGE_TYPE_DEVICE_ISO = 1
VIRTUAL_DISK_ACCESS_READ = 0x000D0000
OPEN_VIRTUAL_DISK_FLAG_NONE = 0x00000000
ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY = 0x00000001
ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME = 0x00000004
VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = GUID(0xEC984AEC, 0xA0F9, 0x47E9, (0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B))


def main(*argv):
    path = r"l:\Kit\Linux\Ubuntu\pc064\20\ubuntu-20.04.1-desktop-amd64.iso"

    virtdisk = cts.WinDLL("VirtDisk")
    OpenVirtualDisk = virtdisk.OpenVirtualDisk
    OpenVirtualDisk.argtypes = (cts.POINTER(VIRTUAL_STORAGE_TYPE), cts.c_wchar_p, cts.c_int, cts.c_int, cts.c_void_p, wts.HANDLE)
    OpenVirtualDisk.restype = wts.DWORD
    AttachVirtualDisk = virtdisk.AttachVirtualDisk
    AttachVirtualDisk.argtypes = (wts.HANDLE, cts.c_void_p, cts.c_int, wts.ULONG, cts.c_void_p, cts.c_void_p)
    AttachVirtualDisk.restype = wts.DWORD
    kernel32 = cts.WinDLL("Kernel32.dll")
    GetLastError = kernel32.GetLastError
    GetLastError.argtypes = ()
    GetLastError.restype = wts.DWORD
    CloseHandle = kernel32.CloseHandle
    CloseHandle.argtypes = (wts.HANDLE,)
    CloseHandle.restype = wts.BOOL

    vts = VIRTUAL_STORAGE_TYPE(VIRTUAL_STORAGE_TYPE_DEVICE_ISO, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT)
    handle = wts.HANDLE()

    res = OpenVirtualDisk(cts.byref(vts), path, VIRTUAL_DISK_ACCESS_READ, OPEN_VIRTUAL_DISK_FLAG_NONE, None, cts.byref(handle))
    if res != ERROR_SUCCESS:
        print(f"OpenVirtualDisk error: {GetLastError()}")
        return -1

    attach_flags = ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY
    permanent = bool(argv)  # Any argument was passed
    if permanent:
        attach_flags |= ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME

    res = AttachVirtualDisk(handle, None, attach_flags, 0, None, None)
    if res != ERROR_SUCCESS:
        print(f"AttachVirtualDisk error: {GetLastError()}")
        CloseHandle(handle)
        return -2

    input(f"Press <Enter> to continue{'' if permanent else ' (this also closes the ISO drive)'} ...")
    CloseHandle(handle)  # Performed automatically


if __name__ == "__main__":
    print(
        "Python {:s} {:03d}bit on {:s}\n".format(
            " ".join(elem.strip() for elem in sys.version.split("\n")),
            64 if sys.maxsize > 0x100000000 else 32,
            sys.platform,
        )
    )
    rc = main(*sys.argv[1:])
    print("\nDone.\n")
    sys.exit(rc)

Output:

[cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q078246936]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###

[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" ./code00.py
Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] 064bit on win32

Press <Enter> to continue (this also closes the ISO drive) ...

Done.


[prompt]>
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.10_test0\Scripts\python.exe" ./code00.py perm
Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] 064bit on win32

Press <Enter> to continue ...

Done.

In each of the 2 runs above, the effect is visible in Explorer (according to explanations from the beginning):

Img00

4
Salman Khan On

Why don't you use the PowerShell?

Mount-DiskImage -ImagePath "PATH\TO\ISOFILE"

In python, you will do something like:

import os

ISO_PATH = 'path to iso file'

os.system("Mount-DiskImage -ImagePath %s" % ISO_PATH)