using MediaBrowser.Common.IO; using MediaBrowser.Model.Logging; using System; using System.IO; using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.IsoMounter { /// /// Class IsoManager /// public class PismoIsoManager : IIsoManager { /// /// The mount semaphore - limit to four at a time. /// private readonly SemaphoreSlim _mountSemaphore = new SemaphoreSlim(4,4); /// /// The PFM API /// private PfmApi _pfmApi; /// /// The _PFM API initialized /// private bool _pfmApiInitialized; /// /// The _PFM API sync lock /// private object _pfmApiSyncLock = new object(); /// /// Gets the display prefs. /// /// The display prefs. private PfmApi PfmApi { get { LazyInitializer.EnsureInitialized(ref _pfmApi, ref _pfmApiInitialized, ref _pfmApiSyncLock, () => { var err = PfmStatic.InstallCheck(); if (err != PfmInst.installed) { throw new Exception("Pismo File Mount Audit Package is not installed"); } PfmApi pfmApi; err = PfmStatic.ApiFactory(out pfmApi); if (err != 0) { throw new IOException("Unable to open PFM Api. Pismo File Mount Audit Package is probably not installed."); } return pfmApi; }); return _pfmApi; } } /// /// The _has initialized /// private bool _hasInitialized; /// /// Gets or sets the logger. /// /// The logger. private ILogger Logger { get; set; } public PismoIsoManager(ILogger logger) { Logger = logger; } /// /// The _my PFM file mount UI /// private readonly MyPfmFileMountUi _myPfmFileMountUi = new MyPfmFileMountUi(); /// /// Mounts the specified iso path. /// /// The iso path. /// The cancellation token. /// if set to true [visible to all processes]. /// IsoMount. /// isoPath /// Unable to create mount. public async Task Mount(string isoPath, CancellationToken cancellationToken, bool visibleToAllProcesses = true) { if (string.IsNullOrEmpty(isoPath)) { throw new ArgumentNullException("isoPath"); } PfmFileMount mount; var err = PfmApi.FileMountCreate(out mount); if (err != 0) { throw new IOException("Unable to create mount for " + isoPath); } _hasInitialized = true; var fmp = new PfmFileMountCreateParams { }; fmp.ui = _myPfmFileMountUi; fmp.fileMountFlags |= PfmFileMountFlag.inProcess; if (visibleToAllProcesses) { fmp.visibleProcessId = PfmVisibleProcessId.all; } fmp.mountFileName = isoPath; // unc only fmp.mountFlags |= PfmMountFlag.uncOnly; fmp.mountFlags |= PfmMountFlag.noShellNotify; fmp.mountFlags |= PfmMountFlag.readOnly; Logger.Info("Mounting {0}", isoPath); await _mountSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); err = mount.Start(fmp); if (err != 0) { _mountSemaphore.Release(); mount.Dispose(); throw new IOException("Unable to start mount for " + isoPath); } err = mount.WaitReady(); if (err != 0) { _mountSemaphore.Release(); mount.Dispose(); throw new IOException("Unable to start mount for " + isoPath); } return new PismoMount(mount, isoPath, this, Logger); } public void Dispose() { Dispose(true); } /// /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool dispose) { if (dispose) { if (_hasInitialized) { Logger.Info("Disposing PfmPapi"); _pfmApi.Dispose(); Logger.Info("PfmStatic.ApiUnload"); PfmStatic.ApiUnload(); } } } /// /// Gets a value indicating whether this instance can mount. /// /// The path. /// true if this instance can mount the specified path; otherwise, false. /// true if this instance can mount; otherwise, false. public bool CanMount(string path) { try { return string.Equals(Path.GetExtension(path), ".iso", StringComparison.OrdinalIgnoreCase) && PfmApi != null; } catch { return false; } } /// /// Called when [unmount]. /// /// The mount. internal void OnUnmount(PismoMount mount) { _mountSemaphore.Release(); } } }