Change the GC.GetTotalMemory() threshold to 10%; otherwise there are just too many...
[beagle.git] / Filters / FilterArchive.cs
blobd8faf59a4c8366282d55087b1f580110ae6c447e
1 //
2 // FilterArchive.cs
3 //
4 // Copyright (C) 2004-2006 Novell, Inc.
5 //
6 //
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
27 using System;
28 using System.Collections;
29 using System.IO;
31 using ICSharpCode.SharpZipLib;
32 using ICSharpCode.SharpZipLib.Zip;
33 using ICSharpCode.SharpZipLib.GZip;
34 using ICSharpCode.SharpZipLib.BZip2;
35 using ICSharpCode.SharpZipLib.Tar;
37 using Beagle;
38 using Beagle.Daemon;
39 using Beagle.Util;
41 namespace Beagle.Filters {
43 public class FilterArchive : Beagle.Daemon.Filter {
45 internal delegate ArchiveEntry GetNextEntry ();
47 private FileInfo file_info;
48 private Stream archive_stream;
49 private GetNextEntry get_next_entry;
51 // Fairly arbitrary number of files to limit
52 private const int MAX_CHILDREN = 30;
54 public FilterArchive ()
56 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/zip"));
57 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-bzip-compressed-tar"));
58 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-compressed-tar"));
59 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-tar"));
60 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-tgz"));
61 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-gzip"));
62 AddSupportedFlavor (FilterFlavor.NewFromMimeType ("application/x-bzip"));
65 protected override void DoOpen (FileInfo file_info)
67 this.file_info = file_info;
69 switch (MimeType) {
70 case "application/zip":
71 archive_stream = new ZipInputStream (Stream);
72 get_next_entry = GetNextEntryZip;
73 break;
75 case "application/x-bzip-compressed-tar":
76 archive_stream = new TarInputStream (new BZip2InputStream (Stream));
77 get_next_entry = GetNextEntryTar;
78 break;
80 case "application/x-compressed-tar":
81 case "application/x-tgz":
82 archive_stream = new TarInputStream (new GZipInputStream (Stream));
83 get_next_entry = GetNextEntryTar;
84 break;
86 case "application/x-tar":
87 archive_stream = new TarInputStream (Stream);
88 get_next_entry = GetNextEntryTar;
89 break;
91 case "application/x-gzip":
92 archive_stream = new GZipInputStream (Stream);
93 get_next_entry = GetNextEntrySingle;
94 break;
96 case "application/x-bzip":
97 archive_stream = new BZip2InputStream (Stream);
98 get_next_entry = GetNextEntrySingle;
99 break;
101 default:
102 throw new ArgumentException ("Invalid or unsupported mime type.");
107 protected override void DoPullProperties ()
109 // FIXME: Fetch the archive properties.
112 protected override void DoPullSetup ()
114 ArchiveEntry a_entry;
115 int count = 0;
117 while ((a_entry = this.get_next_entry ()) != null && count < MAX_CHILDREN) {
118 // FIXME: For nested archives, create uid:foo#bar
119 // instead of uid:foo#xxx#bar (avoid duplicates ?)
120 Indexable child = new Indexable (new Uri (Uri.ToString () + "#" + a_entry.Name, true));
122 child.CacheContent = false;
123 child.MimeType = a_entry.MimeType;
125 child.DisplayUri = new Uri (DisplayUri.ToString () + "#" + a_entry.Name, true);
126 child.ContentUri = UriFu.PathToFileUri (a_entry.TempFile);
127 child.DeleteContent = true;
129 child.AddProperty (Property.NewBool ("fixme:inside_archive", true));
131 child.AddProperty (Property.NewKeyword ("fixme:relativeuri", a_entry.Name));
133 if (a_entry.Comment != null)
134 child.AddProperty (Property.New ("fixme:comment", a_entry.Comment));
136 foreach (Property prop in Property.StandardFileProperties (Path.GetFileName (a_entry.Name), false))
137 child.AddProperty (prop);
139 AddChildIndexable (child);
141 ++count;
145 internal class ArchiveEntry {
146 public string Name;
147 public string MimeType;
148 public DateTime Modified;
149 public string Comment;
151 public string TempFile;
154 private static string StoreStreamInTempFile (Stream stream, DateTime mtime)
156 if (stream == null)
157 return null;
159 string filename = Path.GetTempFileName ();
160 FileStream file_stream = File.OpenWrite (filename);
162 Mono.Unix.Native.Syscall.chmod (filename, (Mono.Unix.Native.FilePermissions) 384); // 384 is 0600
164 BufferedStream buffered_stream = new BufferedStream (file_stream);
166 byte [] buffer = new byte [8192];
167 int read;
169 do {
170 read = stream.Read (buffer, 0, buffer.Length);
171 if (read > 0)
172 buffered_stream.Write (buffer, 0, read);
173 } while (read > 0);
175 buffered_stream.Close ();
177 File.SetLastWriteTimeUtc (filename, mtime);
179 Mono.Unix.Native.Syscall.chmod (filename, (Mono.Unix.Native.FilePermissions) 256); // 256 is 0400
181 return filename;
184 private ArchiveEntry GetNextEntryZip ()
186 ZipInputStream zip_stream = (ZipInputStream) archive_stream;
187 ZipEntry zip_entry;
189 do {
190 zip_entry = zip_stream.GetNextEntry ();
191 } while (zip_entry != null && zip_entry.IsDirectory);
193 // End of the entries.
194 if (zip_entry == null)
195 return null;
197 ArchiveEntry entry = new ArchiveEntry ();
198 entry.Name = zip_entry.Name;
199 entry.Modified = zip_entry.DateTime; // FIXME: Not sure zip_entry.DateTime is UTC.
200 entry.Comment = zip_entry.Comment;
202 entry.TempFile = StoreStreamInTempFile (archive_stream, entry.Modified);
203 entry.MimeType = XdgMime.GetMimeType (entry.TempFile);
205 return entry;
208 private ArchiveEntry GetNextEntryTar ()
210 TarInputStream tar_stream = (TarInputStream) archive_stream;
211 TarEntry tar_entry;
213 do {
214 tar_entry = tar_stream.GetNextEntry ();
215 } while (tar_entry != null && tar_entry.IsDirectory);
217 // End of the entries;
218 if (tar_entry == null)
219 return null;
221 ArchiveEntry entry = new ArchiveEntry ();
222 entry.Name = tar_entry.Name;
223 entry.Modified = tar_entry.ModTime;
225 entry.TempFile = StoreStreamInTempFile (archive_stream, entry.Modified);
226 entry.MimeType = XdgMime.GetMimeType (entry.TempFile);
228 return entry;
231 private bool handled_single = false;
233 private ArchiveEntry GetNextEntrySingle ()
235 if (handled_single)
236 return null;
238 ArchiveEntry entry = new ArchiveEntry ();
239 entry.Name = Path.GetFileNameWithoutExtension (this.file_info.Name);
240 entry.Modified = this.file_info.LastWriteTimeUtc;
242 entry.TempFile = StoreStreamInTempFile (archive_stream, entry.Modified);
243 entry.MimeType = XdgMime.GetMimeType (entry.TempFile);
245 handled_single = true;
247 return entry;