diff options
Diffstat (limited to 'src/DirAsTag.cs')
-rw-r--r-- | src/DirAsTag.cs | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/src/DirAsTag.cs b/src/DirAsTag.cs new file mode 100644 index 0000000..b6f5a06 --- /dev/null +++ b/src/DirAsTag.cs @@ -0,0 +1,452 @@ +/* + * FsGateway - navigate a database structure as directory tree + * Copyright (C) 2009-2010 Torello Querci <torello@torosoft.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +using System; +using Mono.Unix.Native; +using System.Collections.Generic; +using Mono.Fuse; +using System.Text.RegularExpressions; + +namespace FsGateway +{ + + + public class DirAsTag: IFsGateway + { + + private SortedList<string,SortedList<string,List<string>>> listTags=new SortedList<string,SortedList<string,List<string>>>(); + private string root=""; + + public DirAsTag() + { + root=null; + } + + public DirAsTag(string homeDir, string[] args) + { + root=homeDir; + ParseDir(root); + } + + public void Dispose() { + } + + public bool Connect() { + return false; + } + + public bool Connect(string parameter) { + + bool ret; + SortedList<string,SortedList<string,List<string>>> oldListTags=listTags; + string oldRoot=root; + + root=parameter; + ret=ParseDir(parameter); + if (ret) { + root=parameter; + } else { + listTags=oldListTags; + root=oldRoot; + } + return ret; + } + + public string connectionParameter { + get { + return root; + } + } + + public void Unconnect() { + root=null; + } + + public string Usage { + get { + return "You need to specify the directory entry point where this fs start to examine."; + } + } + + public string storageType { + get { + return "tagfs"; + } + } + + public bool isConnect { + get { + return true; + } + } + + private bool ParseDir(string dir) { + + string name=""; + + if (!dir.StartsWith(root)) { + System.Console.Out.WriteLine("Error: "+dir+" is not child of "+root); + return false; + } + + System.Console.Out.WriteLine("ROOT="+root+" len="+root.Length+" DIR="+dir+" len="+dir.Length); + + string suffix=null; + string[] keys=null; + if (dir.Length!=root.Length) { + + suffix=dir.Substring(root.Length); + if (suffix[0]=='/') { + suffix=suffix.Substring(1); + } + keys=suffix.Split('/'); + } + + System.IntPtr dirHandle=Syscall.opendir(dir); + if (dirHandle!=null) { + + Dirent dirent=null; + Stat buf=new Stat(); + while ((dirent=Syscall.readdir(dirHandle))!=null) { + if (!dirent.d_name.Equals(".") && !dirent.d_name.Equals("..")) { + + name=dir+"/"+dirent.d_name; + + System.Console.Out.WriteLine("Name: "+name); + Syscall.lstat(name,out buf); + if ((buf.st_mode & Mono.Unix.Native.FilePermissions.S_IFDIR)!=0) { + // This file is a directory + + // Check if the directory is in the list + if (!listTags.ContainsKey(dirent.d_name)) { + // Directory not present in the list + listTags.Add(dirent.d_name,new SortedList<string,List<string>>()); + System.Console.Out.WriteLine("Directory name "+dirent.d_name+" added"); + } + + // Analyze the files contained in the directory + ParseDir(name); + + } else { + + // Check if you are in the root directory, so jump all the files present in the root directory + if (keys!=null) { + + // Otherwise suppose to be a file + foreach (string key in keys) { + + SortedList<string,List<string>> element=listTags[key]; + string name_key=dirent.d_name; + if (!element.ContainsKey(name_key)) { + element[name_key]=new List<string>(); + } + + element[name_key].Add(name); + } + } + } +// System.Console.Out.WriteLine("\t"+NativeConvert.ToFilePermissions(buf.st_mode)); + System.Console.Out.WriteLine("\t"+buf.st_mode.ToString()); + } + } + Syscall.closedir(dirHandle); + } + return true; + } + + public Errno OnReadHandle (string file + ,OpenedPathInfo info + ,byte[] buf + ,long offset + ,out int bytesWritten) { + bytesWritten=0; + return Errno.ENODATA; + } + + public Errno OnReadDirectory (string directory, OpenedPathInfo info, + out IEnumerable<DirectoryEntry> names) + { + names=null; + + // Check for root directory + if (directory.Equals("/")) { + + // Read all directory tag + IEnumerator<string> en=listTags.Keys.GetEnumerator(); + names=ListNames(en); + + } else { + // Expand path as list of tags + string[] tags=directory.Substring(1).Split('/'); + SortedList<string,List<string>> contents=null; + SortedList<string,List<string>> contentsPurged=null; + IEnumerator<string> en; + List<string> tagsList=new List<string>(); + string key=""; + foreach (string tag in tags) { + + // Check if is the first look + if (contents==null) { + contents=new SortedList<string,List<string>>(); + en=listTags[tag].Keys.GetEnumerator(); + while (en.MoveNext()) { + contents.Add(en.Current,listTags[tag][en.Current]); + } + } else { + en=contents.Keys.GetEnumerator(); + contentsPurged=new SortedList<string,List<string>>(); + while (en.MoveNext()) { + key=en.Current; + if (listTags[tag].ContainsKey(key)) { + contentsPurged.Add(key,contents[key]); + } + } + + contents=contentsPurged; + + if (contents.Count<1) { + break; + } + } + tagsList.Add(tag); + } + + // Add other tags + if (contents==null) { + contents=new SortedList<string,List<string>>(); + + } + + if (contents.Count>0) { + en=listTags.Keys.GetEnumerator(); + // Loop for all tags + while (en.MoveNext()) { + + // Check in this tags is already in the tag list + if (!tagsList.Contains(en.Current)) { + + // Check if this tag is already specify in the contents (file list) + // We need modify this behaviour later + if (!contents.ContainsKey(en.Current)) { + + // Check if this tag have some files with actual path + bool checkDir=false; + foreach (string filename in contents.Keys) { + if (listTags[en.Current].ContainsKey(filename)) { + checkDir=true; + break; + } + } + if (checkDir) { + contents.Add(en.Current,null); + } + } + } + } + } + + en=contents.Keys.GetEnumerator(); + List<string> simbolicName=new List<string>(); + IEnumerator<string> en_link=null; + while (en.MoveNext()) { + int count=1; + if (contents[en.Current]!=null) { + en_link=contents[en.Current].GetEnumerator(); + while (en_link.MoveNext()) { + while (simbolicName.Contains(en.Current + (count>1 ? " ("+count+")" : ""))) { + ++count; + } + simbolicName.Add(en.Current + (count>1 ? " ("+count+")" : "")); + + } + } else { + // Suppose to be a directory (TAG) + simbolicName.Add(en.Current + (count>1 ? " ("+count+")" : "")); + } + + } + en_link=simbolicName.GetEnumerator(); + names=ListNames(en_link); + } + return 0; + } + + public Errno OnGetPathStatus (string path, out Stat stbuf) + { +// System.Console.Out.Write("DEBUG: OnGetPathStatus for "+path+" UID="+Mono.Unix.Native.Syscall.getuid()+" GID="+Mono.Unix.Native.Syscall.getgid()); + + stbuf = new Stat (); + + stbuf.st_uid = Mono.Unix.Native.Syscall.getuid(); + stbuf.st_gid = Mono.Unix.Native.Syscall.getgid(); + + Mono.Unix.Native.Timeval timeval; + Mono.Unix.Native.Syscall.gettimeofday(out timeval); + stbuf.st_mtime = timeval.tv_sec; + + if (path == "/") { +// System.Console.Out.WriteLine("path=/"); + stbuf.st_mode = NativeConvert.FromUnixPermissionString ("dr-xr-xr-x"); + stbuf.st_nlink = 1; + return 0; + } + if (path.IndexOf('/',1)<=0) { +// System.Console.Out.WriteLine("path="+path); + if (!this.listTags.ContainsKey(path.Substring(1))) { + return Errno.ENOENT; + } + +// System.Console.Out.WriteLine("\t okPath"); + stbuf.st_mode = NativeConvert.FromUnixPermissionString ("dr-xr-xr-x"); + stbuf.st_nlink = 1; + return 0; + } else { +// System.Console.Out.WriteLine("other path="+path); + + // Path split to identify if the path is a directory of it is a file + string[] tags=path.Substring(1).Split('/'); + bool isDirectory=true; + foreach (string tag in tags) { + if (!listTags.ContainsKey(tag)) { + isDirectory=false; + break; + } + } + + if (isDirectory) { + stbuf.st_mode = NativeConvert.FromUnixPermissionString ("dr-xr-xr-x"); + stbuf.st_nlink = 1; + } else { + stbuf.st_mode = NativeConvert.FromUnixPermissionString ("lrwxrwxrwx"); + } + } + return 0; + } + + private IEnumerable<DirectoryEntry> ListNames (IEnumerator<string> directories) + { + while (directories.MoveNext()) { + yield return new DirectoryEntry (directories.Current); + } + } + + public Errno OnReadSymbolicLink (string link, out string target) { + System.Console.Out.WriteLine("DEBUG: OnReadSymbolicLynk for path="+link); + + Regex fileMultipleRegex = null; + + try { + fileMultipleRegex = new Regex(@"(?<filename>.+)(\((?<number>[0-9]+)\)$)", RegexOptions.Compiled | RegexOptions.IgnoreCase); +// fileMultipleRegex = new Regex(@"(?<filename>.*)(\((?<number>[0-9]+)\)$)", RegexOptions.Compiled | RegexOptions.IgnoreCase); + } catch (Exception ex) { + System.Console.WriteLine("Exception during the Regex creation: "+ex.Message); + } + + // Expand path as list of tags + string[] srcTags=link.Substring(1).Split('/'); + string[] tags=new string[srcTags.Length-1]; + Array.Copy(srcTags,tags,tags.Length); + + string file=srcTags[srcTags.Length-1]; + + // Check for namefile with number + int index=0; + if (fileMultipleRegex!=null) { + + Match match=null; + try { + match = fileMultipleRegex.Match(file); + } catch (Exception ex) { + System.Console.WriteLine("Exception during match routine. Message: "+ex.Message); + } + + try { + if (match != null && match.Success) { + index=System.Int32.Parse(match.Groups["number"].Value)-1; + file=match.Groups["filename"].Value; + file=file.Substring(0,file.Length-1); + } + } catch (Exception ex) { + System.Console.WriteLine("Exception generic: "+ex.Message); + } + + } + + List<string> contents=null; + List<string> contentsMerged=null; + IEnumerator<string> en; + + foreach (string tag in tags) { + + // Check if is the first look + if (contents==null) { + contents=new List<string>(); + en=listTags[tag][file].GetEnumerator(); + while (en.MoveNext()) { + contents.Add(en.Current); + } + } else if (!tag.Equals(file)) { + contentsMerged=new List<string>(); + + en=listTags[tag][file].GetEnumerator(); + while (en.MoveNext()) { + string key=en.Current; + if (contents.Contains(key)) { + contentsMerged.Add(key); + } + } + contents=contentsMerged; + } + } + + if (contents.Count>0) { + target=contents[index]; + } else { + target=""; + return Errno.ENOENT; + } + return 0; + } + + + private void dumpStructure() { + IEnumerator<string> en=listTags.Keys.GetEnumerator(); + + while (en.MoveNext()) { + System.Console.Out.WriteLine("TAG: "+en.Current); + SortedList<string,List<string>> element=listTags[en.Current]; + IEnumerator<string> en_link=element.Keys.GetEnumerator(); + while (en_link.MoveNext()) { + System.Console.Out.WriteLine("\t"+en_link.Current+" => "); + foreach (string destination_file in element[en_link.Current]) { + System.Console.Out.WriteLine("\t\t"+destination_file); + } + } + } + } + + + public static void Main(string[] args) { + + DirAsTag dirAsTag=new DirAsTag("/home/torello/mono_project",args); + dirAsTag.dumpStructure(); + + } + } +} |