diff options
Diffstat (limited to 'Emby.Server.Implementations/IO/SharpCifsFileSystem.cs')
| -rw-r--r-- | Emby.Server.Implementations/IO/SharpCifsFileSystem.cs | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs b/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs new file mode 100644 index 000000000..1d21796b1 --- /dev/null +++ b/Emby.Server.Implementations/IO/SharpCifsFileSystem.cs @@ -0,0 +1,604 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using MediaBrowser.Model.IO; +using SharpCifs.Smb; + +namespace Emby.Server.Implementations.IO +{ + public class SharpCifsFileSystem + { + private readonly MediaBrowser.Model.System.OperatingSystem _operatingSystem; + + public SharpCifsFileSystem(MediaBrowser.Model.System.OperatingSystem operatingSystem) + { + _operatingSystem = operatingSystem; + } + + public bool IsEnabledForPath(string path) + { + if (_operatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows) + { + return false; + } + + return path.StartsWith("smb://", StringComparison.OrdinalIgnoreCase) || IsUncPath(path); + } + + public string NormalizePath(string path) + { + if (path.StartsWith("smb://", StringComparison.OrdinalIgnoreCase)) + { + return path; + } + + if (IsUncPath(path)) + { + return ConvertUncToSmb(path); + } + + return path; + } + + public string GetDirectoryName(string path) + { + var separator = GetDirectorySeparatorChar(path); + var result = Path.GetDirectoryName(path); + + if (separator == '/') + { + result = result.Replace('\\', '/'); + + if (result.StartsWith("smb:/", StringComparison.OrdinalIgnoreCase) && !result.StartsWith("smb://", StringComparison.OrdinalIgnoreCase)) + { + result = result.Replace("smb:/", "smb://"); + } + } + + return result; + } + + public char GetDirectorySeparatorChar(string path) + { + if (path.IndexOf('/') != -1) + { + return '/'; + } + + return '\\'; + } + + public FileSystemMetadata GetFileSystemInfo(string path) + { + var file = CreateSmbFile(path); + return ToMetadata(file); + } + + public FileSystemMetadata GetFileInfo(string path) + { + var file = CreateSmbFile(path); + return ToMetadata(file, false); + } + + public FileSystemMetadata GetDirectoryInfo(string path) + { + var file = CreateSmbFile(path); + return ToMetadata(file, true); + } + + private bool IsUncPath(string path) + { + return path.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase); + } + + private string GetReturnPath(SmbFile file) + { + return file.GetCanonicalPath().TrimEnd('/'); + //return file.GetPath(); + } + + private string ConvertUncToSmb(string path) + { + if (IsUncPath(path)) + { + path = path.Replace('\\', '/'); + path = "smb:" + path; + } + return path; + } + + private string AddAuthentication(string path) + { + return path; + } + + private SmbFile CreateSmbFile(string path) + { + path = ConvertUncToSmb(path); + path = AddAuthentication(path); + + return new SmbFile(path); + } + + DateTime baseDate = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + private FileSystemMetadata ToMetadata(SmbFile info, bool? isDirectory = null) + { + var result = new FileSystemMetadata(); + + result.Exists = info.Exists(); + result.FullName = GetReturnPath(info); + result.Extension = Path.GetExtension(result.FullName); + result.Name = info.GetName(); + + if (result.Exists) + { + result.IsDirectory = info.IsDirectory(); + result.IsHidden = info.IsHidden(); + + result.IsReadOnly = !info.CanWrite(); + + if (info.IsFile()) + { + result.Length = info.Length(); + result.DirectoryName = info.GetParent(); + } + + result.CreationTimeUtc = baseDate.AddMilliseconds(info.CreateTime()); + result.LastWriteTimeUtc = baseDate.AddMilliseconds(info.GetLastModified()); + } + else + { + if (isDirectory.HasValue) + { + result.IsDirectory = isDirectory.Value; + } + } + + return result; + } + + public void SetHidden(string path, bool isHidden) + { + var file = CreateSmbFile(path); + SetHidden(file, isHidden); + } + + public void SetReadOnly(string path, bool isReadOnly) + { + var file = CreateSmbFile(path); + SetReadOnly(file, isReadOnly); + } + + public void SetAttributes(string path, bool isHidden, bool isReadOnly) + { + var file = CreateSmbFile(path); + SetHidden(file, isHidden); + SetReadOnly(file, isReadOnly); + } + + private void SetHidden(SmbFile file, bool isHidden) + { + var isCurrentlyHidden = file.IsHidden(); + + if (isCurrentlyHidden && !isHidden) + { + file.SetAttributes(file.GetAttributes() & ~SmbFile.AttrHidden); + } + else if (!isCurrentlyHidden && isHidden) + { + file.SetAttributes(file.GetAttributes() | SmbFile.AttrHidden); + } + } + + private void SetReadOnly(SmbFile file, bool isReadOnly) + { + var isCurrentlyReadOnly = !file.CanWrite(); + + if (isCurrentlyReadOnly && !isReadOnly) + { + file.SetReadWrite(); + } + else if (!isCurrentlyReadOnly && isReadOnly) + { + file.SetReadOnly(); + } + } + + public void DeleteFile(string path) + { + var file = CreateSmbFile(path); + + AssertFileExists(file, path); + + file.Delete(); + } + + public void DeleteDirectory(string path, bool recursive) + { + var file = CreateSmbFile(path); + + AssertDirectoryExists(file, path); + + file.Delete(); + } + + public void CreateDirectory(string path) + { + } + + public string[] ReadAllLines(string path) + { + var lines = new List<string>(); + + using (var stream = OpenRead(path)) + { + using (var reader = new StreamReader(stream)) + { + while (!reader.EndOfStream) + { + lines.Add(reader.ReadLine()); + } + } + } + + return lines.ToArray(); + } + + public void WriteAllLines(string path, IEnumerable<string> lines) + { + using (var stream = GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None)) + { + using (var writer = new StreamWriter(stream)) + { + foreach (var line in lines) + { + writer.WriteLine(line); + } + } + } + } + + private void AssertFileExists(SmbFile file, string path) + { + if (!file.Exists()) + { + throw new FileNotFoundException("File not found.", path); + } + } + + private void AssertDirectoryExists(SmbFile file, string path) + { + if (!file.Exists()) + { + throw new FileNotFoundException("File not found.", path); + } + } + + public Stream OpenRead(string path) + { + var file = CreateSmbFile(path); + + AssertFileExists(file, path); + + return file.GetInputStream(); + } + + private Stream OpenWrite(string path) + { + var file = CreateSmbFile(path); + + AssertFileExists(file, path); + + return file.GetInputStream(); + } + + public void CopyFile(string source, string target, bool overwrite) + { + if (string.Equals(source, target, StringComparison.Ordinal)) + { + throw new ArgumentException("Cannot CopyFile when source and target are the same"); + } + + using (var input = OpenRead(source)) + { + using (var output = GetFileStream(target, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None)) + { + input.CopyTo(output); + } + } + } + + public void MoveFile(string source, string target) + { + if (string.Equals(source, target, StringComparison.Ordinal)) + { + throw new ArgumentException("Cannot MoveFile when source and target are the same"); + } + + using (var input = OpenRead(source)) + { + using (var output = GetFileStream(target, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None)) + { + input.CopyTo(output); + } + } + + DeleteFile(source); + } + + public void MoveDirectory(string source, string target) + { + throw new NotImplementedException(); + } + + public bool DirectoryExists(string path) + { + var dir = CreateSmbFile(path); + + return dir.Exists() && dir.IsDirectory(); + } + + public bool FileExists(string path) + { + var file = CreateSmbFile(path); + return file.Exists(); + } + + public string ReadAllText(string path, Encoding encoding) + { + using (var stream = OpenRead(path)) + { + using (var reader = new StreamReader(stream, encoding)) + { + return reader.ReadToEnd(); + } + } + } + + public Stream GetFileStream(string path, FileOpenMode mode, FileAccessMode access, FileShareMode share) + { + if (mode == FileOpenMode.OpenOrCreate) + { + var file = CreateSmbFile(path); + if (!file.Exists()) + { + file.CreateNewFile(); + } + + mode = FileOpenMode.Open; + } + + if (mode == FileOpenMode.CreateNew) + { + var file = CreateSmbFile(path); + if (file.Exists()) + { + throw new IOException("File already exists"); + } + + file.CreateNewFile(); + + mode = FileOpenMode.Open; + } + + if (mode == FileOpenMode.Create) + { + var file = CreateSmbFile(path); + if (file.Exists()) + { + if (file.IsHidden()) + { + throw new UnauthorizedAccessException(string.Format("File {0} already exists and is hidden", path)); + } + + file.Delete(); + file.CreateNewFile(); + } + else + { + file.CreateNewFile(); + } + + mode = FileOpenMode.Open; + } + + if (mode == FileOpenMode.Open) + { + if (access == FileAccessMode.Read) + { + return OpenRead(path); + } + if (access == FileAccessMode.Write) + { + return OpenWrite(path); + } + throw new NotImplementedException(); + } + throw new NotImplementedException(); + } + + public void WriteAllBytes(string path, byte[] bytes) + { + using (var stream = GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None)) + { + stream.Write(bytes, 0, bytes.Length); + } + } + + public void WriteAllText(string path, string text) + { + using (var stream = GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None)) + { + using (var writer = new StreamWriter(stream)) + { + writer.Write(text); + } + } + } + + public void WriteAllText(string path, string text, Encoding encoding) + { + using (var stream = GetFileStream(path, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None)) + { + using (var writer = new StreamWriter(stream, encoding)) + { + writer.Write(text); + } + } + } + + public string ReadAllText(string path) + { + using (var stream = OpenRead(path)) + { + using (var reader = new StreamReader(stream)) + { + return reader.ReadToEnd(); + } + } + } + + public byte[] ReadAllBytes(string path) + { + using (var stream = OpenRead(path)) + { + using (var ms = new MemoryStream()) + { + stream.CopyTo(ms); + ms.Position = 0; + return ms.ToArray(); + } + } + } + + private SmbFile CreateSmbDirectoryForListFiles(string path) + { + // In order to call ListFiles, it has to end with the separator + + return CreateSmbFile(path.TrimEnd('/') + '/'); + } + + public IEnumerable<FileSystemMetadata> GetDirectories(string path, bool recursive = false) + { + var dir = CreateSmbDirectoryForListFiles(path); + AssertDirectoryExists(dir, path); + + var list = ListFiles(dir, recursive); + + foreach (var file in list) + { + if (file.IsDirectory()) + { + yield return ToMetadata(file); + } + } + } + + public IEnumerable<FileSystemMetadata> GetFiles(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false) + { + var dir = CreateSmbDirectoryForListFiles(path); + AssertDirectoryExists(dir, path); + + var list = ListFiles(dir, recursive); + + foreach (var file in list) + { + if (file.IsFile()) + { + var filePath = GetReturnPath(file); + var extension = Path.GetExtension(filePath); + + if (extensions == null || extensions.Length == 0 || extensions.Contains(extension ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + { + yield return ToMetadata(file); + } + } + } + } + + public IEnumerable<FileSystemMetadata> GetFileSystemEntries(string path, bool recursive = false) + { + var dir = CreateSmbDirectoryForListFiles(path); + AssertDirectoryExists(dir, path); + + var list = ListFiles(dir, recursive); + + foreach (var file in list) + { + yield return ToMetadata(file); + } + } + + public IEnumerable<string> GetFileSystemEntryPaths(string path, bool recursive = false) + { + var dir = CreateSmbDirectoryForListFiles(path); + AssertDirectoryExists(dir, path); + + var list = ListFiles(dir, recursive); + + foreach (var file in list) + { + yield return GetReturnPath(file); + } + } + + public IEnumerable<string> GetFilePaths(string path, string[] extensions, bool enableCaseSensitiveExtensions, bool recursive = false) + { + var dir = CreateSmbDirectoryForListFiles(path); + AssertDirectoryExists(dir, path); + + var list = ListFiles(dir, recursive); + + foreach (var file in list) + { + if (file.IsFile()) + { + var filePath = GetReturnPath(file); + var extension = Path.GetExtension(filePath); + + if (extensions == null || extensions.Length == 0 || extensions.Contains(extension ?? string.Empty, StringComparer.OrdinalIgnoreCase)) + { + yield return filePath; + } + } + } + } + + public IEnumerable<string> GetDirectoryPaths(string path, bool recursive = false) + { + var dir = CreateSmbDirectoryForListFiles(path); + AssertDirectoryExists(dir, path); + + var list = ListFiles(dir, recursive); + + foreach (var file in list) + { + if (file.IsDirectory()) + { + yield return GetReturnPath(file); + } + } + } + + private IEnumerable<SmbFile> ListFiles(SmbFile dir, bool recursive) + { + var list = dir.ListFiles(); + + foreach (var file in list) + { + yield return file; + + if (recursive && file.IsDirectory()) + { + foreach (var subFile in ListFiles(file, recursive)) + { + yield return subFile; + } + } + } + } + } +} |
