From 747e81de1927c71b39dc916be05bb9296ca6b882 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 9 Apr 2020 20:53:22 +0200 Subject: [PATCH] Support unmounting on macOS and Windows. --- platform/osx/set_paths.sh | 8 +- platform/windows/build.sh | 6 ++ platform/windows/config.sh | 6 ++ src/lib/cross.h | 3 + src/lib/cross_linux.cc | 11 ++- src/lib/cross_osx.cc | 120 ++++++++++++++++++++++------- src/lib/cross_windows.cc | 100 ++++++++++++++++++++---- src/tools/dcpomatic_disk.cc | 44 ++++++++++- src/tools/dcpomatic_disk_writer.cc | 41 ++++++---- src/wx/try_unmount_dialog.cc | 2 +- 10 files changed, 273 insertions(+), 68 deletions(-) create mode 100644 platform/windows/build.sh create mode 100644 platform/windows/config.sh diff --git a/platform/osx/set_paths.sh b/platform/osx/set_paths.sh index f5e1bd80f..5a84a82d9 100644 --- a/platform/osx/set_paths.sh +++ b/platform/osx/set_paths.sh @@ -2,11 +2,11 @@ base=$HOME/dcpomatic env=$HOME/osx-environment sdk=$HOME/SDK -export CPPFLAGS= LDFLAGS="-L$base/lib -L$env/lib -isysroot $sdk/MacOSX10.9.sdk -arch x86_64" -export LINKFLAGS="-L$base/lib -L$env/lib -isysroot $sdk/MacOSX10.9.sdk -arch x86_64" +export CPPFLAGS= LDFLAGS="-L$base/lib -L$env/64/lib -isysroot $sdk/MacOSX10.9.sdk -arch x86_64" +export LINKFLAGS="-L$base/lib -L$env/64/lib -isysroot $sdk/MacOSX10.9.sdk -arch x86_64" export MACOSX_DEPLOYMENT_TARGET=10.9 -export CXXFLAGS="-I$base/include -I$env/include -isysroot $sdk/MacOSX10.9.sdk -arch x86_64" -export CFLAGS="-I$base/include -I$env/include -isysroot $sdk/MacOSX10.9.sdk -arch x86_64" +export CXXFLAGS="-I$base/include -I$env/64/include -isysroot $sdk/MacOSX10.9.sdk -arch x86_64" +export CFLAGS="-I$base/include -I$env/64/include -isysroot $sdk/MacOSX10.9.sdk -arch x86_64" export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$base/lib:$env/64/lib export PATH=$env/64/bin:$PATH export PKG_CONFIG_PATH=$env/64/lib/pkgconfig:$base/lib/pkgconfig diff --git a/platform/windows/build.sh b/platform/windows/build.sh new file mode 100644 index 000000000..dd10472e4 --- /dev/null +++ b/platform/windows/build.sh @@ -0,0 +1,6 @@ +user=cah +container=371eb645f2c3 +src=/home/cah/src/dcpomatic-windows + +docker exec -u $user -e src=$src -i -t $container /bin/bash -c 'export CPPFLAGS= LD=x86_64-w64-mingw32.shared-ld PKG_CONFIG_LIBDIR=/opt/mxe/usr/x86_64-w64-mingw32.shared/lib/pkgconfig CC=x86_64-w64-mingw32.shared-gcc WINRC=x86_64-w64-mingw32.shared-windres RANLIB=x86_64-w64-mingw32.shared-ranlib CXXFLAGS="-I/opt/mxe/usr/x86_64-w64-mingw32.shared/include -I$src/include" CXX=x86_64-w64-mingw32.shared-g++ LDFLAGS="-L/opt/mxe/usr/x86_64-w64-mingw32.shared/lib -L$src/lib" PKG_CONFIG_PATH=$src/lib/pkgconfig:$src/bin/pkgconfig PATH=/opt/mxe/usr/x86_64-w64-mingw32.shared/bin:/opt/mxe/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:$srcbin LINKFLAGS="-L/opt/mxe/usr/x86_64-w64-mingw32.shared/lib -L$src/lib" ; cd $src/src/dcpomatic; ./waf' + diff --git a/platform/windows/config.sh b/platform/windows/config.sh new file mode 100644 index 000000000..8445f5f65 --- /dev/null +++ b/platform/windows/config.sh @@ -0,0 +1,6 @@ +user=cah +container=371eb645f2c3 +src=/home/cah/src/dcpomatic-windows + +docker exec -u $user -e src=$src -i -t $container /bin/bash -c 'export CPPFLAGS= LD=x86_64-w64-mingw32.shared-ld PKG_CONFIG_LIBDIR=/opt/mxe/usr/x86_64-w64-mingw32.shared/lib/pkgconfig CC=x86_64-w64-mingw32.shared-gcc WINRC=x86_64-w64-mingw32.shared-windres RANLIB=x86_64-w64-mingw32.shared-ranlib CXXFLAGS="-I/opt/mxe/usr/x86_64-w64-mingw32.shared/include -I$src/include" CXX=x86_64-w64-mingw32.shared-g++ LDFLAGS="-L/opt/mxe/usr/x86_64-w64-mingw32.shared/lib -L$src/lib" PKG_CONFIG_PATH=$src/lib/pkgconfig:$src/bin/pkgconfig PATH=/opt/mxe/usr/x86_64-w64-mingw32.shared/bin:/opt/mxe/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:$srcbin LINKFLAGS="-L/opt/mxe/usr/x86_64-w64-mingw32.shared/lib -L$src/lib" ; cd $src/src/dcpomatic; ./waf configure --target-windows --disable-tests' + diff --git a/src/lib/cross.h b/src/lib/cross.h index ece36fe25..114581269 100644 --- a/src/lib/cross.h +++ b/src/lib/cross.h @@ -31,6 +31,7 @@ #include #include #include +#include #ifdef DCPOMATIC_WINDOWS #define WEXITSTATUS(w) (w) @@ -138,4 +139,6 @@ private: boost::optional _model; }; +void disk_write_finished (); + #endif diff --git a/src/lib/cross_linux.cc b/src/lib/cross_linux.cc index d8a33482f..36683a0cd 100644 --- a/src/lib/cross_linux.cc +++ b/src/lib/cross_linux.cc @@ -32,6 +32,7 @@ extern "C" { } #include #include +#include #ifdef DCPOMATIC_DISK #include #endif @@ -58,6 +59,7 @@ using std::cout; using std::runtime_error; using boost::shared_ptr; using boost::optional; +using boost::function; /** @param s Number of seconds to sleep for */ void @@ -329,7 +331,7 @@ Drive::get () bool -Drive::unmount () +Drive::unmount () { BOOST_FOREACH (boost::filesystem::path i, _mount_points) { int const r = umount(i.string().c_str()); @@ -372,3 +374,10 @@ config_path () return p; } + +void +disk_write_finished () +{ + +} + diff --git a/src/lib/cross_osx.cc b/src/lib/cross_osx.cc index a363f0570..6e8ef168c 100644 --- a/src/lib/cross_osx.cc +++ b/src/lib/cross_osx.cc @@ -58,8 +58,10 @@ using std::vector; using std::cerr; using std::cout; using std::runtime_error; +using std::map; using boost::shared_ptr; using boost::optional; +using boost::function; /** @param s Number of seconds to sleep for */ void @@ -145,6 +147,7 @@ openssl_path () } #ifdef DCPOMATIC_DISK +/* Note: this isn't actually used at the moment as the disk writer is started as a service */ boost::filesystem::path disk_writer_path () { @@ -333,25 +336,28 @@ is_whole_drive (DADiskRef& disk) return whole_media; } -static bool -is_mounted (CFDictionaryRef& description) +static optional +mount_point (CFDictionaryRef& description) { CFURLRef volume_path_key = (CFURLRef) CFDictionaryGetValue (description, kDADiskDescriptionVolumePathKey); char mount_path_buffer[1024]; - return CFURLGetFileSystemRepresentation(volume_path_key, false, (UInt8 *) mount_path_buffer, sizeof(mount_path_buffer)); + if (!CFURLGetFileSystemRepresentation(volume_path_key, false, (UInt8 *) mount_path_buffer, sizeof(mount_path_buffer))) { + return boost::optional(); + } + return boost::filesystem::path(mount_path_buffer); } /* Here follows some rather intricate and (probably) fragile code to find the list of available * "real" drives on macOS that we might want to write a DCP to. * - * We use the Disk Arbitration framework to give us a series of devices (/dev/disk0, /dev/disk1, - * /dev/disk1s1 and so on) and we use the API to gather useful information about these devices into + * We use the Disk Arbitration framework to give us a series of mount_points (/dev/disk0, /dev/disk1, + * /dev/disk1s1 and so on) and we use the API to gather useful information about these mount_points into * a vector of Disk structs. * * Then we read the Disks that we found and try to derive a list of drives that we should offer to the * user, with details of whether those drives are currently mounted or not. * - * At the basic level we find the "disk"-level devices, looking at whether any of their partitions are mounted. + * At the basic level we find the "disk"-level mount_points, looking at whether any of their partitions are mounted. * * This is complicated enormously by recent-ish macOS versions' habit of making `synthesized' volumes which * reflect data in `real' partitions. So, for example, we might have a real (physical) drive /dev/disk2 with @@ -367,13 +373,13 @@ is_mounted (CFDictionaryRef& description) struct Disk { - string device; + string mount_point; optional vendor; optional model; bool real; string prt; bool whole; - bool mounted; + vector mount_points; unsigned long size; }; @@ -388,7 +394,7 @@ disk_appeared (DADiskRef disk, void* context) Disk this_disk; - this_disk.device = string("/dev/") + bsd_name; + this_disk.mount_point = string("/dev/") + bsd_name; CFDictionaryRef description = DADiskCopyDescription (disk); @@ -405,8 +411,18 @@ disk_appeared (DADiskRef disk, void* context) this_disk.real = media_path->real; this_disk.prt = media_path->prt; this_disk.whole = is_whole_drive (disk); - this_disk.mounted = is_mounted (description); - LOG_DISK("%1 prt %2 whole %3 mounted %4", this_disk.real ? "Real" : "Synth", this_disk.prt, this_disk.whole ? "whole" : "part", this_disk.mounted ? "mounted" : "unmounted"); + optional mp = mount_point (description); + if (mp) { + this_disk.mount_points.push_back (*mp); + } + + LOG_DISK( + "%1 prt %2 whole %3 mounted %4", + this_disk.real ? "Real" : "Synth", + this_disk.prt, + this_disk.whole ? "whole" : "part", + mp ? ("mounted at " + mp->string()) : "unmounted" + ); CFNumberGetValue ((CFNumberRef) CFDictionaryGetValue (description, kDADiskDescriptionMediaSizeKey), kCFNumberLongType, &this_disk.size); CFRelease (description); @@ -415,7 +431,7 @@ disk_appeared (DADiskRef disk, void* context) } vector -get_drives () +Drive::get () { using namespace boost::algorithm; vector disks; @@ -439,27 +455,30 @@ get_drives () continue; } BOOST_FOREACH (Disk& j, disks) { - if (j.mounted && starts_with(j.device, i.device)) { - LOG_DISK("Marking %1 as mounted because %2 is", i.device, j.device); - i.mounted = true; + if (!j.mount_points.empty() && starts_with(j.mount_point, i.mount_point)) { + LOG_DISK("Marking %1 as mounted because %2 is", i.mount_point, j.mount_point); + std::copy(j.mount_points.begin(), j.mount_points.end(), back_inserter(i.mount_points)); } } } - /* Make a list of the PRT codes of mounted, synthesized disks */ - vector mounted_synths; + /* Make a map of the PRT codes and mount points of mounted, synthesized disks */ + map > mounted_synths; BOOST_FOREACH (Disk& i, disks) { - if (!i.real && i.mounted) { - LOG_DISK("Found a mounted synth %1 with %2", i.device, i.prt); - mounted_synths.push_back (i.prt); + if (!i.real && !i.mount_points.empty()) { + LOG_DISK("Found a mounted synth %1 with %2", i.mount_point, i.prt); + mounted_synths[i.prt] = i.mount_points; } } /* Mark containers of those mounted synths as themselves mounted */ BOOST_FOREACH (Disk& i, disks) { - if (i.real && find(mounted_synths.begin(), mounted_synths.end(), i.prt) != mounted_synths.end()) { - LOG_DISK("Marking %1 (%2) as mounted because it contains a mounted synth", i.device, i.prt); - i.mounted = true; + if (i.real) { + map >::const_iterator j = mounted_synths.find(i.prt); + if (j != mounted_synths.end()) { + LOG_DISK("Marking %1 (%2) as mounted because it contains a mounted synth", i.mount_point, i.prt); + std::copy(j->second.begin(), j->second.end(), back_inserter(i.mount_points)); + } } } @@ -467,8 +486,8 @@ get_drives () BOOST_FOREACH (Disk& i, disks) { if (i.whole) { /* A whole disk that is not a container for a mounted synth */ - LOG_DISK("Adding drive: %1 %2 %3 %4 %5", i.device, i.size, i.mounted ? "mounted" : "unmounted", i.vendor.get_value_or("[none]"), i.model.get_value_or("[none]")); - drives.push_back(Drive(i.device, i.size, i.mounted, i.vendor, i.model)); + drives.push_back(Drive(i.mount_point, i.mount_points, i.size, i.vendor, i.model)); + LOG_DISK_NC(drives.back().log_summary()); } } return drives; @@ -486,11 +505,54 @@ config_path () return p; } + +void done_callback(DADiskRef disk, DADissenterRef dissenter, void* context) +{ + LOG_DISK_NC("Unmount finished"); + bool* success = reinterpret_cast (context); + if (dissenter) { + LOG_DISK("Error: %1", DADissenterGetStatus(dissenter)); + *success = false; + } else { + LOG_DISK_NC("Successful"); + *success = true; + } +} + + bool -unmount_device (string device) +Drive::unmount () +{ + LOG_DISK_NC("Unmount operation started"); + + DASessionRef session = DASessionCreate(kCFAllocatorDefault); + if (!session) { + return false; + } + + DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, _device.c_str()); + if (!disk) { + return false; + } + LOG_DISK("Requesting unmount of %1 from %2", _device, thread_id()); + bool success = false; + DADiskUnmount(disk, kDADiskUnmountOptionWhole, &done_callback, &success); + CFRelease (disk); + + CFRunLoopRef run_loop = CFRunLoopGetCurrent (); + DASessionScheduleWithRunLoop (session, run_loop, kCFRunLoopDefaultMode); + CFRunLoopStop (run_loop); + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, 0); + CFRelease(session); + + LOG_DISK_NC("End of unmount"); + return success; +} + + +void +disk_write_finished () { - int const r = umount(device.c_str()); - LOG_DISK("Tried to unmount %1 and got %2 and %3", device, r, errno); - return r == 0; } + diff --git a/src/lib/cross_windows.cc b/src/lib/cross_windows.cc index f55e0a9c2..8ccc790d6 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) @@ -417,12 +422,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); @@ -444,41 +465,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); @@ -527,9 +546,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); @@ -538,6 +566,36 @@ get_drives () return drives; } + +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; + } + 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; + } + + LOG_DISK("Unmount of %1 succeeded", _device); + locked_volumes.push_back (make_pair(device, _device)); + + return true; +} + + boost::filesystem::path config_path () { @@ -546,3 +604,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); + } +} + + diff --git a/src/tools/dcpomatic_disk.cc b/src/tools/dcpomatic_disk.cc index 3ceead860..bf4d45e20 100644 --- a/src/tools/dcpomatic_disk.cc +++ b/src/tools/dcpomatic_disk.cc @@ -178,7 +178,7 @@ private: if (!_nanomsg.send(DISK_WRITER_UNMOUNT "\n", 2000)) { throw CommunicationFailedError (); } - if (!_nanomsg.send(drive.as_xml() + "\n", 2000)) { + if (!_nanomsg.send(drive.as_xml(), 2000)) { throw CommunicationFailedError (); } optional reply = _nanomsg.receive (2000); @@ -194,7 +194,7 @@ private: } } - + DriveWipeWarningDialog* d = new DriveWipeWarningDialog (this, _drive->GetString(_drive->GetSelection())); int const r = d->ShowModal (); bool ok = r == wxID_OK && d->confirmed(); @@ -244,7 +244,9 @@ private: JobManagerView* _jobs; boost::optional _dcp_path; std::vector _drives; +#ifndef DCPOMATIC_OSX boost::process::child* _writer; +#endif Nanomsg _nanomsg; wxSizer* _sizer; }; @@ -330,6 +332,44 @@ public: ev.Skip (); } + void report_exception () + { + try { + throw; + } catch (FileError& e) { + error_dialog ( + 0, + wxString::Format ( + _("An exception occurred: %s (%s)\n\n") + REPORT_PROBLEM, + std_to_wx (e.what()), + std_to_wx (e.file().string().c_str ()) + ) + ); + } catch (exception& e) { + error_dialog ( + 0, + wxString::Format ( + _("An exception occurred: %s.\n\n") + REPORT_PROBLEM, + std_to_wx (e.what ()) + ) + ); + } catch (...) { + error_dialog (0, _("An unknown exception occurred.") + " " + REPORT_PROBLEM); + } + } + + bool OnExceptionInMainLoop () + { + report_exception (); + /* This will terminate the program */ + return false; + } + + void OnUnhandledException () + { + report_exception (); + } + DOMFrame* _frame; }; diff --git a/src/tools/dcpomatic_disk_writer.cc b/src/tools/dcpomatic_disk_writer.cc index 4a93cba98..feee687f8 100644 --- a/src/tools/dcpomatic_disk_writer.cc +++ b/src/tools/dcpomatic_disk_writer.cc @@ -119,6 +119,8 @@ write (boost::filesystem::path from, boost::filesystem::path to, uint64_t& total uint8_t* buffer = new uint8_t[block_size]; Digester digester; + int progress_frequency = 5000; + int progress_count = 0; uint64_t remaining = file_size (from); while (remaining > 0) { uint64_t const this_time = min(remaining, block_size); @@ -148,7 +150,11 @@ write (boost::filesystem::path from, boost::filesystem::path to, uint64_t& total } remaining -= this_time; total_remaining -= this_time; - nanomsg->send(String::compose(DISK_WRITER_PROGRESS "\n%1\n", (1 - float(total_remaining) / total)), SHORT_TIMEOUT); + + ++progress_count; + if ((progress_count % progress_frequency) == 0) { + nanomsg->send(String::compose(DISK_WRITER_PROGRESS "\n%1\n", (1 - float(total_remaining) / total)), SHORT_TIMEOUT); + } } fclose (in); @@ -276,16 +282,18 @@ try } LOG_DISK_NC ("Wrote MBR"); -#ifdef DCPOMATIC_WINDOWS struct ext4_mbr_bdevs bdevs; r = ext4_mbr_scan (bd, &bdevs); if (r != EOK) { throw CopyError ("Failed to read MBR", r); } +#ifdef DCPOMATIC_WINDOWS file_windows_partition_set (bdevs.partitions[0].part_offset, bdevs.partitions[0].part_size); #endif + LOG_DISK ("Writing to partition at %1 size %2; bd part size is %3", bdevs.partitions[0].part_offset, bdevs.partitions[0].part_size, bd->part_size); + #ifdef DCPOMATIC_LINUX /* Re-read the partition table */ int fd = open(device.c_str(), O_RDONLY); @@ -354,6 +362,8 @@ try if (!nanomsg->send(DISK_WRITER_OK "\n", LONG_TIMEOUT)) { throw CommunicationFailedError (); } + + disk_write_finished (); } catch (CopyError& e) { LOG_DISK("CopyError (from write): %1 %2", e.message(), e.number().get_value_or(0)); nanomsg->send(String::compose(DISK_WRITER_ERROR "\n%1\n%2\n", e.message(), e.number().get_value_or(0)), LONG_TIMEOUT); @@ -388,6 +398,7 @@ polkit_callback (GObject *, GAsyncResult* res, gpointer data) } #endif + bool idle () try @@ -399,6 +410,8 @@ try return true; } + LOG_DISK("Writer receives command: %1", *s); + if (*s == DISK_WRITER_QUIT) { exit (EXIT_SUCCESS); } else if (*s == DISK_WRITER_UNMOUNT) { @@ -406,21 +419,19 @@ try optional xml_head = nanomsg->receive (LONG_TIMEOUT); optional xml_body = nanomsg->receive (LONG_TIMEOUT); if (!xml_head || !xml_body) { + LOG_DISK_NC("Failed to receive unmount request"); throw CommunicationFailedError (); } - if (Drive(*xml_head + *xml_body).unmount()) { - if (!nanomsg->send (DISK_WRITER_OK "\n", LONG_TIMEOUT)) { - throw CommunicationFailedError(); - } - } else { - if (!nanomsg->send (DISK_WRITER_ERROR "\n", LONG_TIMEOUT)) { - throw CommunicationFailedError(); - } + bool const success = Drive(*xml_head + *xml_body).unmount(); + if (!nanomsg->send (success ? (DISK_WRITER_OK "\n") : (DISK_WRITER_ERROR "\n"), LONG_TIMEOUT)) { + LOG_DISK_NC("CommunicationFailedError in unmount_finished"); + throw CommunicationFailedError (); } - } else { - optional dcp_path = nanomsg->receive(LONG_TIMEOUT); - optional device = nanomsg->receive(LONG_TIMEOUT); + } else if (*s == DISK_WRITER_WRITE) { + optional dcp_path = nanomsg->receive (LONG_TIMEOUT); + optional device = nanomsg->receive (LONG_TIMEOUT); if (!dcp_path || !device) { + LOG_DISK_NC("Failed to receive write request"); throw CommunicationFailedError(); } @@ -429,7 +440,7 @@ try #ifdef DCPOMATIC_OSX if (!starts_with(*device, "/dev/disk")) { LOG_DISK ("Will not write to %1", *device); - nanomsg->try_send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n", LONG_TIMEOUT); + nanomsg->send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n", LONG_TIMEOUT); return true; } #endif @@ -443,7 +454,7 @@ try #ifdef DCPOMATIC_WINDOWS if (!starts_with(*device, "\\\\.\\PHYSICALDRIVE")) { LOG_DISK ("Will not write to %1", *device); - nanomsg->try_send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n", LONG_TIMEOUT); + nanomsg->send(DISK_WRITER_ERROR "\nRefusing to write to this drive\n1\n", LONG_TIMEOUT); return true; } #endif diff --git a/src/wx/try_unmount_dialog.cc b/src/wx/try_unmount_dialog.cc index d25ae8c3e..2ca76527d 100644 --- a/src/wx/try_unmount_dialog.cc +++ b/src/wx/try_unmount_dialog.cc @@ -27,7 +27,7 @@ TryUnmountDialog::TryUnmountDialog (wxWindow* parent, wxString description) : wxDialog (parent, wxID_ANY, _("DCP-o-matic Disk Writer")) { wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); - wxStaticText* text = new StaticText (this, wxString::Format(_("The drive %s is mounted.\nIt must be unmounted before DCP-o-matic can write to it. Do you want to try to unmount it now?"), description)); + wxStaticText* text = new StaticText (this, wxString::Format(_("The drive %s is mounted.\nIt must be unmounted before DCP-o-matic can write to it. Should DCP-o-matic try to unmount it now?"), description)); sizer->Add (text, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER); wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); -- 2.30.2