diff --git a/MediaBrowser.Api/Library/LibraryHelpers.cs b/MediaBrowser.Api/Library/LibraryHelpers.cs index 4837c64d79..008cfb27f7 100644 --- a/MediaBrowser.Api/Library/LibraryHelpers.cs +++ b/MediaBrowser.Api/Library/LibraryHelpers.cs @@ -12,8 +12,8 @@ namespace MediaBrowser.Api.Library /// public static class LibraryHelpers { - private const string ShortcutFileExtension = ".lnk"; - private const string ShortcutFileSearch = "*.lnk"; + private const string ShortcutFileExtension = ".mblink"; + private const string ShortcutFileSearch = "*" + ShortcutFileExtension; /// /// Adds the virtual folder. diff --git a/MediaBrowser.Controller/IO/FileSystem.cs b/MediaBrowser.Controller/IO/FileSystem.cs index 56b1be6b59..1c49545be1 100644 --- a/MediaBrowser.Controller/IO/FileSystem.cs +++ b/MediaBrowser.Controller/IO/FileSystem.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Model.Logging; +using System.Collections.Generic; +using System.Linq; +using MediaBrowser.Model.Logging; using System; using System.Collections.Specialized; using System.IO; @@ -130,16 +132,21 @@ namespace MediaBrowser.Controller.IO throw new ArgumentNullException("filename"); } - return new WindowsShortcut(filename).ResolvedPath; + if (string.Equals(Path.GetExtension(filename), ".mblink", StringComparison.OrdinalIgnoreCase)) + { + return File.ReadAllText(filename); + } - //var link = new ShellLink(); - //((IPersistFile)link).Load(filename, NativeMethods.STGM_READ); - //// TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files. - //// ((IShellLinkW)link).Resolve(hwnd, 0) - //var sb = new StringBuilder(NativeMethods.MAX_PATH); - //WIN32_FIND_DATA data; - //((IShellLinkW)link).GetPath(sb, sb.Capacity, out data, 0); - //return sb.ToString(); + //return new WindowsShortcut(filename).ResolvedPath; + + var link = new ShellLink(); + ((IPersistFile)link).Load(filename, NativeMethods.STGM_READ); + // TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files. + // ((IShellLinkW)link).Resolve(hwnd, 0) + var sb = new StringBuilder(NativeMethods.MAX_PATH); + WIN32_FIND_DATA data; + ((IShellLinkW)link).GetPath(sb, sb.Capacity, out data, 0); + return sb.ToString(); } /// @@ -160,13 +167,18 @@ namespace MediaBrowser.Controller.IO throw new ArgumentNullException("target"); } - var link = new ShellLink(); + File.WriteAllText(shortcutPath, target); - ((IShellLinkW)link).SetPath(target); + //var link = new ShellLink(); - ((IPersistFile)link).Save(shortcutPath, true); + //((IShellLinkW)link).SetPath(target); + + //((IPersistFile)link).Save(shortcutPath, true); } + private static readonly Dictionary ShortcutExtensionsDictionary = new[] { ".mblink", ".lnk" } + .ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); + /// /// Determines whether the specified filename is shortcut. /// @@ -180,7 +192,9 @@ namespace MediaBrowser.Controller.IO throw new ArgumentNullException("filename"); } - return string.Equals(Path.GetExtension(filename), ".lnk", StringComparison.OrdinalIgnoreCase); + var extension = Path.GetExtension(filename); + + return !string.IsNullOrEmpty(extension) && ShortcutExtensionsDictionary.ContainsKey(extension); } /// @@ -258,7 +272,7 @@ namespace MediaBrowser.Controller.IO public WindowsShortcut(string file) { - ParseLink(File.ReadAllBytes(file)); + ParseLink(File.ReadAllBytes(file), Encoding.UTF8); } private static bool isMagicPresent(byte[] link) @@ -274,7 +288,7 @@ namespace MediaBrowser.Controller.IO * Gobbles up link data by parsing it and storing info in member fields * @param link all the bytes from the .lnk file */ - private void ParseLink(byte[] link) + private void ParseLink(byte[] link, Encoding encoding) { if (!isMagicPresent(link)) throw new IOException("Invalid shortcut; magic is missing", 0); @@ -317,11 +331,11 @@ namespace MediaBrowser.Controller.IO const int networkVolumeTable_offset_offset = 0x14; const int finalname_offset_offset = 0x18; int finalname_offset = link[file_start + finalname_offset_offset] + file_start; - String finalname = getNullDelimitedString(link, finalname_offset); + String finalname = getNullDelimitedString(link, finalname_offset, encoding); if (IsLocal) { int basename_offset = link[file_start + basename_offset_offset] + file_start; - String basename = getNullDelimitedString(link, basename_offset); + String basename = getNullDelimitedString(link, basename_offset, encoding); ResolvedPath = basename + finalname; } else @@ -330,12 +344,12 @@ namespace MediaBrowser.Controller.IO int shareName_offset_offset = 0x08; int shareName_offset = link[networkVolumeTable_offset + shareName_offset_offset] + networkVolumeTable_offset; - String shareName = getNullDelimitedString(link, shareName_offset); + String shareName = getNullDelimitedString(link, shareName_offset, encoding); ResolvedPath = shareName + "\\" + finalname; } } - private static string getNullDelimitedString(byte[] bytes, int off) + private static string getNullDelimitedString(byte[] bytes, int off, Encoding encoding) { int len = 0; @@ -349,7 +363,7 @@ namespace MediaBrowser.Controller.IO len++; } - return Encoding.UTF8.GetString(bytes, off, len); + return encoding.GetString(bytes, off, len); } /* diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 27b71cc8a6..de096e3b3b 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1084,7 +1084,7 @@ namespace MediaBrowser.Server.Implementations.Library { Name = Path.GetFileName(dir), - Locations = Directory.EnumerateFiles(dir, "*.lnk", SearchOption.TopDirectoryOnly) + Locations = Directory.EnumerateFiles(dir, "*.mblink", SearchOption.TopDirectoryOnly) .Select(FileSystem.ResolveShortcut) .OrderBy(i => i) .ToList(), diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs index 7780d47452..7e19e5f951 100644 --- a/MediaBrowser.ServerApplication/MainStartup.cs +++ b/MediaBrowser.ServerApplication/MainStartup.cs @@ -2,6 +2,7 @@ using MediaBrowser.Common.Constants; using MediaBrowser.Common.Implementations.Logging; using MediaBrowser.Common.Implementations.Updates; +using MediaBrowser.Controller.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Server.Implementations; using MediaBrowser.ServerApplication.Native; @@ -187,6 +188,8 @@ namespace MediaBrowser.ServerApplication SystemEvents.SessionEnding += SystemEvents_SessionEnding; SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; + MigrateShortcuts(appPaths.RootFolderPath); + _appHost = new ApplicationHost(appPaths, logManager); _app = new App(_appHost, _appHost.LogManager.GetLogger("App"), runService); @@ -523,5 +526,34 @@ namespace MediaBrowser.ServerApplication /// SEM_NOOPENFILEERRORBOX = 0x8000 } + + private static void MigrateShortcuts(string directory) + { + Directory.CreateDirectory(directory); + + foreach (var file in Directory.EnumerateFiles(directory, "*.lnk", SearchOption.AllDirectories).ToList()) + { + MigrateShortcut(file); + } + } + + private static void MigrateShortcut(string file) + { + var newFile = Path.ChangeExtension(file, ".mblink"); + + try + { + var resolvedPath = FileSystem.ResolveShortcut(file); + + if (!string.IsNullOrEmpty(resolvedPath)) + { + FileSystem.CreateShortcut(newFile, resolvedPath); + } + } + finally + { + File.Delete(file); + } + } } }