X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fcross_windows.cc;h=d732e9fe5e71c426c255429c6ce6a90ad16874c3;hb=7552a04c443c9c641ac580585f6d88900bf84d04;hp=169435a510f0ee52ea906f777b311c6c6c7dad55;hpb=a1f7bf2d9e5610075fbd898cdf52f4f8373741f2;p=dcpomatic.git diff --git a/src/lib/cross_windows.cc b/src/lib/cross_windows.cc index 169435a51..d732e9fe5 100644 --- a/src/lib/cross_windows.cc +++ b/src/lib/cross_windows.cc @@ -38,11 +38,13 @@ extern "C" { #include #include #include +#include #undef DATADIR #include #include #include #include +#include #include "i18n.h" @@ -56,9 +58,12 @@ using std::vector; using std::cerr; using std::cout; using std::runtime_error; +using std::map; using boost::shared_ptr; using boost::optional; +static std::vector > locked_volumes; + /** @param s Number of seconds to sleep for */ void dcpomatic_sleep_seconds (int s) @@ -122,8 +127,7 @@ run_ffprobe (boost::filesystem::path content, boost::filesystem::path out) } wchar_t dir[512]; - GetModuleFileName (GetModuleHandle (0), dir, sizeof (dir)); - PathRemoveFileSpec (dir); + MultiByteToWideChar (CP_UTF8, 0, directory_containing_executable().string().c_str(), -1, dir, sizeof(dir)); SetCurrentDirectory (dir); STARTUPINFO startup_info; @@ -180,29 +184,36 @@ mount_info () return m; } -static boost::filesystem::path -executable_path () + +boost::filesystem::path +directory_containing_executable () { return boost::dll::program_location().parent_path(); } + boost::filesystem::path shared_path () { - return executable_path().parent_path(); + return directory_containing_executable().parent_path(); } + boost::filesystem::path openssl_path () { - return executable_path() / "openssl.exe"; + return directory_containing_executable() / "openssl.exe"; } + +#ifdef DCPOMATIC_DISK boost::filesystem::path disk_writer_path () { - return executable_path() / "dcpomatic2_disk_writer.exe"; + return directory_containing_executable() / "dcpomatic2_disk_writer.exe"; } +#endif + /* Apparently there is no way to create an ofstream using a UTF-8 filename under Windows. We are hence reduced to using fopen @@ -239,10 +250,11 @@ Waker::~Waker () } + void -start_tool (boost::filesystem::path dcpomatic, string executable, string) +start_tool (string executable) { - boost::filesystem::path batch = dcpomatic.parent_path() / executable; + boost::filesystem::path batch = directory_containing_executable() / executable; STARTUPINFO startup_info; ZeroMemory (&startup_info, sizeof (startup_info)); @@ -256,18 +268,21 @@ start_tool (boost::filesystem::path dcpomatic, string executable, string) CreateProcess (0, cmd, 0, 0, FALSE, 0, 0, 0, &startup_info, &process_info); } + void -start_batch_converter (boost::filesystem::path dcpomatic) +start_batch_converter () { - start_tool (dcpomatic, "dcpomatic2_batch", "DCP-o-matic\\ 2\\ Batch\\ Converter.app"); + start_tool ("dcpomatic2_batch"); } + void -start_player (boost::filesystem::path dcpomatic) +start_player () { - start_tool (dcpomatic, "dcpomatic2_player", "DCP-o-matic\\ 2\\ Player.app"); + start_tool ("dcpomatic2_player"); } + uint64_t thread_id () { @@ -415,12 +430,28 @@ get_device_number (HDEVINFO device_info, SP_DEVINFO_DATA* device_info_data) return device_number.DeviceNumber; } +typedef map > MountPoints; + /** Take a volume path (with a trailing \) and add any disk numbers related to that volume * to @ref disks. */ static void -add_volume_disk_number (wchar_t* volume, vector& disks) +add_volume_mount_points (wchar_t* volume, MountPoints& mount_points) { + LOG_DISK("Looking at %1", wchar_to_utf8(volume)); + + wchar_t volume_path_names[512]; + vector mp; + DWORD returned; + if (GetVolumePathNamesForVolumeNameW(volume, volume_path_names, sizeof(volume_path_names) / sizeof(wchar_t), &returned)) { + wchar_t* p = volume_path_names; + while (*p != L'\0') { + mp.push_back (wchar_to_utf8(p)); + LOG_DISK ("Found mount point %1", wchar_to_utf8(p)); + p += wcslen(p) + 1; + } + } + /* Strip trailing \ */ size_t const len = wcslen (volume); DCPOMATIC_ASSERT (len > 0); @@ -442,41 +473,39 @@ add_volume_disk_number (wchar_t* volume, vector& disks) return; } DCPOMATIC_ASSERT (extents.NumberOfDiskExtents == 1); - return disks.push_back (extents.Extents[0].DiskNumber); + + mount_points[extents.Extents[0].DiskNumber] = mp; } -/* Return a list of disk numbers that contain volumes; i.e. a list of disk numbers that should - * not be offered as targets to write to as they are "mounted" (whatever that means on Windows). - */ -vector -disk_numbers_with_volumes () +MountPoints +find_mount_points () { - vector disks; + MountPoints mount_points; wchar_t volume_name[512]; HANDLE volume = FindFirstVolumeW (volume_name, sizeof(volume_name) / sizeof(wchar_t)); if (volume == INVALID_HANDLE_VALUE) { - return disks; + return MountPoints(); } - add_volume_disk_number (volume_name, disks); + add_volume_mount_points (volume_name, mount_points); while (true) { if (!FindNextVolumeW(volume, volume_name, sizeof(volume_name) / sizeof(wchar_t))) { break; } - add_volume_disk_number (volume_name, disks); + add_volume_mount_points (volume_name, mount_points); } FindVolumeClose (volume); - return disks; + return mount_points; } vector -get_drives () +Drive::get () { vector drives; - vector disks_to_ignore = disk_numbers_with_volumes (); + MountPoints mount_points = find_mount_points (); /* Get a `device information set' containing information about all disks */ HDEVINFO device_info = SetupDiGetClassDevsA (&GUID_DEVICE_INTERFACE_DISK, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); @@ -525,9 +554,18 @@ get_drives () &geom, sizeof(geom), &returned, 0 ); - if (r && find(disks_to_ignore.begin(), disks_to_ignore.end(), *device_number) == disks_to_ignore.end()) { + LOG_DISK("Having a looky through %1 locked volumes", locked_volumes.size()); + bool locked = false; + for (vector >::const_iterator i = locked_volumes.begin(); i != locked_volumes.end(); ++i) { + if (i->second == physical_drive) { + locked = true; + } + } + + if (r) { uint64_t const disk_size = geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector; - drives.push_back (Drive(physical_drive, disk_size, false, friendly_name, optional())); + drives.push_back (Drive(physical_drive, locked ? vector() : mount_points[*device_number], disk_size, friendly_name, optional())); + LOG_DISK("Added drive %1%2", drives.back().log_summary(), locked ? "(locked by us)" : ""); } CloseHandle (device); @@ -536,28 +574,36 @@ get_drives () return drives; } -string -Drive::description () const -{ - char gb[64]; - snprintf(gb, 64, "%.1f", _size / 1000000000.0); - string name; - if (_vendor) { - name += *_vendor; - } - if (_model) { - if (name.size() > 0) { - name += " " + *_model; - } +bool +Drive::unmount () +{ + LOG_DISK("Unmounting %1 with %2 mount points XXX! MMMYEAH!", _device, _mount_points.size()); + DCPOMATIC_ASSERT (_mount_points.size() == 1); + string const device_name = String::compose ("\\\\.\\%1", _mount_points.front()); + string const truncated = device_name.substr (0, device_name.length() - 1); + //LOG_DISK("Actually opening %1", _device); + //HANDLE device = CreateFileA (_device.c_str(), (GENERIC_READ | GENERIC_WRITE), FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); + LOG_DISK("Actually opening %1", truncated); + HANDLE device = CreateFileA (truncated.c_str(), (GENERIC_READ | GENERIC_WRITE), FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); + if (device == INVALID_HANDLE_VALUE) { + LOG_DISK("Could not open %1 for unmount (%2)", truncated, GetLastError()); + return false; } - if (name.size() == 0) { - name = _("Unknown"); + DWORD returned; + BOOL r = DeviceIoControl (device, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, &returned, 0); + if (!r) { + LOG_DISK("Unmount of %1 failed (%2)", truncated, GetLastError()); + return false; } - return String::compose("%1 (%2 GB) [%3]", name, gb, _internal_name); + LOG_DISK("Unmount of %1 succeeded", _device); + locked_volumes.push_back (make_pair(device, _device)); + + return true; } + boost::filesystem::path config_path () { @@ -566,3 +612,13 @@ config_path () p /= "dcpomatic2"; return p; } + +void +disk_write_finished () +{ + for (vector >::const_iterator i = locked_volumes.begin(); i != locked_volumes.end(); ++i) { + CloseHandle (i->first); + } +} + +