using System; using System.Collections.Generic; using System.Net; using System.IO; using com.clusterrr.clovershell; using System.Globalization; namespace mooftpserv { public class NesMiniFileSystemHandler : IFileSystemHandler { // list of supported operating systems private enum OS { WinNT, WinCE, Unix }; // currently used operating system private OS os; // current path as TVFS or unix-like private string currentPath; // clovershell private ClovershellConnection clovershell; public NesMiniFileSystemHandler(ClovershellConnection clovershell, string startPath) { os = OS.Unix; this.currentPath = startPath; this.clovershell = clovershell; } public NesMiniFileSystemHandler(ClovershellConnection clovershell) : this(clovershell, "/") { } private NesMiniFileSystemHandler(string path, OS os, ClovershellConnection clovershell) { this.currentPath = path; this.os = os; this.clovershell = clovershell; } public IFileSystemHandler Clone(IPEndPoint peer) { return new NesMiniFileSystemHandler(currentPath, os, clovershell); } public ResultOrError GetCurrentDirectory() { return MakeResult(currentPath); } public ResultOrError ChangeDirectory(string path) { string newPath = ResolvePath(path); try { clovershell.ExecuteSimple("cd \""+newPath+"\"", 1000 ,true); currentPath = newPath; } catch (Exception ex) { return MakeError(ex.Message); } return MakeResult(newPath); } public ResultOrError ChangeToParentDirectory() { return ChangeDirectory(".."); } public ResultOrError CreateDirectory(string path) { string newPath = ResolvePath(path); try { foreach (var c in newPath) if ((int)c > 255) throw new Exception("Invalid characters in directory name"); var newpath = DecodePath(newPath); clovershell.ExecuteSimple("mkdir \"" + newpath + "\""); } catch (Exception ex) { return MakeError(ex.Message); } return MakeResult(newPath); } public ResultOrError RemoveDirectory(string path) { string newPath = ResolvePath(path); try { var rpath = DecodePath(newPath); clovershell.ExecuteSimple("rm -rf \"" + rpath + "\""); } catch (Exception ex) { return MakeError(ex.Message); } return MakeResult(true); } public ResultOrError ReadFile(string path) { string newPath = ResolvePath(path); try { var data = new MemoryStream(); clovershell.Execute("cat \"" + newPath + "\"", null, data, null, 1000, true); data.Seek(0, SeekOrigin.Begin); return MakeResult(data); } catch (Exception ex) { return MakeError(ex.Message); } } public ResultOrError WriteFile(string path) { string newPath = ResolvePath(path); try { foreach (var c in newPath) if ((int)c > 255) throw new Exception("Invalid characters in directory name"); return MakeResult(new MemoryStream()); } catch (Exception ex) { return MakeError(ex.Message); } } public ResultOrError WriteFileFinalize(string path, Stream str) { string newPath = ResolvePath(path); try { str.Seek(0, SeekOrigin.Begin); string directory = "/"; int p = newPath.LastIndexOf("/"); if (p > 0) directory = newPath.Substring(0, p); clovershell.Execute("mkdir -p \"" + directory + "\" && cat > \"" + newPath + "\"", str, null, null, 1000, true); str.Dispose(); return MakeResult(true); } catch (Exception ex) { return MakeError(ex.Message); } } public ResultOrError RemoveFile(string path) { string newPath = ResolvePath(path); try { clovershell.ExecuteSimple("rm -rf \"" + newPath + "\"", 1000, true); } catch (Exception ex) { return MakeError(ex.Message); } return MakeResult(true); } public ResultOrError RenameFile(string fromPath, string toPath) { fromPath = ResolvePath(fromPath); toPath = ResolvePath(toPath); try { clovershell.ExecuteSimple("mv \"" + fromPath + "\" \"" + toPath + "\"", 1000, true); } catch (Exception ex) { return MakeError(ex.Message); } return MakeResult(true); } public ResultOrError ListEntries(string path) { string newPath = ResolvePath(path); List result = new List(); try { var lines = clovershell.ExecuteSimple("ls -lAp \"" + newPath + "\"", 1000, true) .Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { if (line.StartsWith("total")) continue; FileSystemEntry entry = new FileSystemEntry(); entry.Mode = line.Substring(0, 13).Trim(); entry.Name = line.Substring(57).Trim(); entry.IsDirectory = entry.Name.EndsWith("/"); if (entry.IsDirectory) entry.Name = entry.Name.Substring(0, entry.Name.Length - 1); entry.Size = long.Parse(line.Substring(34, 9).Trim()); var dt = line.Substring(44, 12).Trim(); try { entry.LastModifiedTimeUtc = DateTime.ParseExact(dt, "MMM d HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.AllowInnerWhite); } catch (FormatException) { entry.LastModifiedTimeUtc = DateTime.ParseExact(dt, "MMM d yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AllowInnerWhite); } result.Add(entry); } } catch (Exception ex) { return MakeError(ex.Message); } return MakeResult(result.ToArray()); } public ResultOrError ListEntriesRaw(string path) { if (path == null) path = "/"; if (path.StartsWith("-")) path = ". " + path; string newPath = ResolvePath(path); List result = new List(); try { var lines = clovershell.ExecuteSimple("ls " + newPath, 1000, true); return MakeResult(lines); } catch (Exception ex) { return MakeError(ex.Message); } } public ResultOrError GetFileSize(string path) { string newPath = ResolvePath(path); try { var size = clovershell.ExecuteSimple("stat -c%s \"" + newPath + "\"", 1000, true); return MakeResult(long.Parse(size)); } catch (Exception ex) { return MakeError(ex.Message); } } public ResultOrError GetLastModifiedTimeUtc(string path) { string newPath = ResolvePath(path); try { var time = clovershell.ExecuteSimple("stat -c%Z \"" + newPath + "\"", 1000, true); return MakeResult(DateTime.FromFileTime(long.Parse(time))); } catch (Exception ex) { return MakeError(ex.Message); } } private string ResolvePath(string path) { if (path == null) return currentPath; if (path.Contains(" -> ")) path = path.Substring(path.IndexOf(" -> ") + 4); return FileSystemHelper.ResolvePath(currentPath, path); } private string EncodePath(string path) { if (os == OS.WinNT) return "/" + path[0] + (path.Length > 2 ? path.Substring(2).Replace(@"\", "/") : ""); else if (os == OS.WinCE) return path.Replace(@"\", "/"); else return path; } private string DecodePath(string path) { if (path == null || path == "" || path[0] != '/') return null; if (os == OS.WinNT) { // some error checking for the drive layer if (path == "/") return null; // should have been caught elsewhere if (path.Length > 1 && path[1] == '/') return null; if (path.Length > 2 && path[2] != '/') return null; if (path.Length < 4) // e.g. "/C/" return path[1] + @":\"; else return path[1] + @":\" + path.Substring(3).Replace("/", @"\"); } else if (os == OS.WinCE) { return path.Replace("/", @"\"); } else { return path; } } /// /// Shortcut for ResultOrError.MakeResult() /// private ResultOrError MakeResult(T result) { return ResultOrError.MakeResult(result); } /// /// Shortcut for ResultOrError.MakeError() /// private ResultOrError MakeError(string error) { return ResultOrError.MakeError(error); } public ResultOrError ChmodFile(string mode, string path) { string newPath = ResolvePath(path); try { clovershell.ExecuteSimple(string.Format("chmod {0} {1}", mode, newPath), 1000, true); return ResultOrError.MakeResult(true); } catch (Exception ex) { return MakeError(ex.Message); } } public ResultOrError SetLastModifiedTimeUtc(string path, DateTime time) { string newPath = ResolvePath(path); try { clovershell.ExecuteSimple(string.Format("touch -ct {0:yyyyMMddHHmm.ss} \"{1}\"", time, newPath), 1000, true); return ResultOrError.MakeResult(true); } catch (Exception ex) { return MakeError(ex.Message); } } } }