You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Readarr/src/NzbDrone.Common/Disk/FileSystemLookupService.cs

226 lines
8.2 KiB

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Common.Disk
{
public interface IFileSystemLookupService
{
FileSystemResult LookupContents(string query, bool includeFiles, bool allowFoldersWithoutTrailingSlashes);
}
public class FileSystemLookupService : IFileSystemLookupService
{
private readonly IDiskProvider _diskProvider;
private readonly IRuntimeInfo _runtimeInfo;
private readonly HashSet<string> _setToRemove = new HashSet<string>
{
// Windows
"boot",
"bootmgr",
"cache",
"msocache",
"recovery",
"$recycle.bin",
"recycler",
"system volume information",
"temporary internet files",
"windows",
// OS X
".fseventd",
".spotlight",
".trashes",
".vol",
"cachedmessages",
"caches",
"trash",
// QNAP
".@__thumb",
// Synology
"@eadir"
};
public FileSystemLookupService(IDiskProvider diskProvider, IRuntimeInfo runtimeInfo)
{
_diskProvider = diskProvider;
_runtimeInfo = runtimeInfo;
}
public FileSystemResult LookupContents(string query, bool includeFiles, bool allowFoldersWithoutTrailingSlashes)
{
if (query.IsNullOrWhiteSpace())
{
if (OsInfo.IsWindows)
{
var result = new FileSystemResult();
result.Directories = GetDrives();
return result;
}
query = "/";
}
if (
allowFoldersWithoutTrailingSlashes &&
query.IsPathValid() &&
_diskProvider.FolderExists(query))
{
return GetResult(query, includeFiles);
}
var lastSeparatorIndex = query.LastIndexOf(Path.DirectorySeparatorChar);
var path = query.Substring(0, lastSeparatorIndex + 1);
if (lastSeparatorIndex != -1)
{
return GetResult(path, includeFiles);
}
return new FileSystemResult();
}
private List<FileSystemModel> GetDrives()
{
return _diskProvider.GetMounts()
.Where(d =>
{
// Fow Windows Services, exclude mapped network drives.
if (_runtimeInfo.IsWindowsService)
{
return d.DriveType != DriveType.Network;
}
return true;
})
.Select(d => new FileSystemModel
{
Type = FileSystemEntityType.Drive,
Name = d.VolumeName,
Path = d.RootDirectory,
LastModified = null
})
.ToList();
}
private FileSystemResult GetResult(string path, bool includeFiles)
{
var result = new FileSystemResult();
try
{
result.Parent = GetParent(path);
result.Directories = GetDirectories(path);
if (includeFiles)
{
result.Files = GetFiles(path);
}
}
catch (DirectoryNotFoundException)
{
return new FileSystemResult { Parent = GetParent(path) };
}
catch (ArgumentException)
{
return new FileSystemResult();
}
catch (IOException)
{
return new FileSystemResult { Parent = GetParent(path) };
}
catch (UnauthorizedAccessException)
{
return new FileSystemResult { Parent = GetParent(path) };
}
return result;
}
private List<FileSystemModel> GetDirectories(string path)
{
var directories = _diskProvider.GetDirectoryInfos(path)
.OrderBy(d => d.Name)
.Select(d => new FileSystemModel
{
Name = d.Name,
Path = GetDirectoryPath(d.FullName.GetActualCasing()),
LastModified = d.LastWriteTimeUtc,
Type = FileSystemEntityType.Folder
})
.ToList();
directories.RemoveAll(d => _setToRemove.Contains(d.Name.ToLowerInvariant()));
return directories;
}
private List<FileSystemModel> GetFiles(string path)
{
return _diskProvider.GetFileInfos(path)
.OrderBy(d => d.Name)
.Select(d => new FileSystemModel
{
Name = d.Name,
Path = d.FullName.GetActualCasing(),
LastModified = d.LastWriteTimeUtc,
Extension = d.Extension,
Size = d.Length,
Type = FileSystemEntityType.File
})
.ToList();
}
private static string GetVolumeName(IMount mountInfo)
{
if (mountInfo.VolumeLabel.IsNullOrWhiteSpace())
{
return mountInfo.Name;
}
return $"{mountInfo.Name} ({mountInfo.VolumeLabel})";
}
private string GetDirectoryPath(string path)
{
if (path.Last() != Path.DirectorySeparatorChar)
{
path += Path.DirectorySeparatorChar;
}
return path;
}
private static string GetParent(string path)
{
var di = new DirectoryInfo(path);
if (di.Parent != null)
{
var parent = di.Parent.FullName;
if (parent.Last() != Path.DirectorySeparatorChar)
{
parent += Path.DirectorySeparatorChar;
}
return parent;
}
if (!path.Equals("/"))
{
return string.Empty;
}
return null;
}
}
}