4 // Copyright (C) 2004-2006 Novell, Inc.
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.
28 using System
.Collections
;
31 using ICSharpCode
.SharpZipLib
;
32 using ICSharpCode
.SharpZipLib
.Zip
;
33 using ICSharpCode
.SharpZipLib
.GZip
;
34 using ICSharpCode
.SharpZipLib
.BZip2
;
35 using ICSharpCode
.SharpZipLib
.Tar
;
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 // 1: Store entry names as text content
59 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/zip"));
60 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-bzip-compressed-tar"));
61 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-compressed-tar"));
62 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-tar"));
63 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-tgz"));
64 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-gzip"));
65 AddSupportedFlavor (FilterFlavor
.NewFromMimeType ("application/x-bzip"));
68 protected override void DoOpen (FileInfo file_info
)
70 this.file_info
= file_info
;
73 case "application/zip":
74 archive_stream
= new ZipInputStream (Stream
);
75 get_next_entry
= GetNextEntryZip
;
78 case "application/x-bzip-compressed-tar":
79 archive_stream
= new TarInputStream (new BZip2InputStream (Stream
));
80 get_next_entry
= GetNextEntryTar
;
83 case "application/x-compressed-tar":
84 case "application/x-tgz":
85 archive_stream
= new TarInputStream (new GZipInputStream (Stream
));
86 get_next_entry
= GetNextEntryTar
;
89 case "application/x-tar":
90 archive_stream
= new TarInputStream (Stream
);
91 get_next_entry
= GetNextEntryTar
;
94 case "application/x-gzip":
95 archive_stream
= new GZipInputStream (Stream
);
96 get_next_entry
= GetNextEntrySingle
;
99 case "application/x-bzip":
100 archive_stream
= new BZip2InputStream (Stream
);
101 get_next_entry
= GetNextEntrySingle
;
105 throw new ArgumentException ("Invalid or unsupported mime type.");
110 protected override void DoPullProperties ()
112 // FIXME: Fetch the archive properties.
115 protected override void DoPullSetup ()
117 ArchiveEntry a_entry
;
120 while ((a_entry
= this.get_next_entry ()) != null && count
< MAX_CHILDREN
) {
121 // FIXME: For nested archives, create uid:foo#bar
122 // instead of uid:foo#xxx#bar (avoid duplicates ?)
123 Indexable child
= new Indexable (new Uri (Uri
.ToString () + "#" + a_entry
.Name
, true));
125 child
.CacheContent
= true;
126 child
.MimeType
= a_entry
.MimeType
;
128 child
.DisplayUri
= new Uri (DisplayUri
.ToString () + "#" + a_entry
.Name
, true);
129 child
.ContentUri
= UriFu
.PathToFileUri (a_entry
.TempFile
);
130 child
.DeleteContent
= true;
132 child
.AddProperty (Property
.NewBool ("fixme:inside_archive", true));
134 child
.AddProperty (Property
.NewKeyword ("fixme:relativeuri", a_entry
.Name
));
135 child
.AddProperty (Property
.New ("fixme:comment", a_entry
.Comment
));
137 foreach (Property prop
in Property
.StandardFileProperties (Path
.GetFileName (a_entry
.Name
), false))
138 child
.AddProperty (prop
);
140 AddChildIndexable (child
);
142 // Store file names in the archive
143 AppendText (Path
.GetFileName (a_entry
.Name
));
150 internal class ArchiveEntry
{
152 public string MimeType
;
153 public DateTime Modified
;
154 public string Comment
;
156 public string TempFile
;
159 private static string StoreStreamInTempFile (Stream stream
, DateTime mtime
)
164 string filename
= Path
.GetTempFileName ();
165 FileStream file_stream
= File
.OpenWrite (filename
);
167 Mono
.Unix
.Native
.Syscall
.chmod (filename
, (Mono
.Unix
.Native
.FilePermissions
) 384); // 384 is 0600
169 BufferedStream buffered_stream
= new BufferedStream (file_stream
);
171 byte [] buffer
= new byte [8192];
175 read
= stream
.Read (buffer
, 0, buffer
.Length
);
177 buffered_stream
.Write (buffer
, 0, read
);
180 buffered_stream
.Close ();
182 File
.SetLastWriteTimeUtc (filename
, mtime
);
184 Mono
.Unix
.Native
.Syscall
.chmod (filename
, (Mono
.Unix
.Native
.FilePermissions
) 256); // 256 is 0400
189 private ArchiveEntry
GetNextEntryZip ()
191 ZipInputStream zip_stream
= (ZipInputStream
) archive_stream
;
195 zip_entry
= zip_stream
.GetNextEntry ();
196 } while (zip_entry
!= null && zip_entry
.IsDirectory
);
198 // End of the entries.
199 if (zip_entry
== null)
202 ArchiveEntry entry
= new ArchiveEntry ();
203 entry
.Name
= zip_entry
.Name
;
204 entry
.Modified
= zip_entry
.DateTime
; // FIXME: Not sure zip_entry.DateTime is UTC.
205 entry
.Comment
= zip_entry
.Comment
;
207 entry
.TempFile
= StoreStreamInTempFile (archive_stream
, entry
.Modified
);
208 entry
.MimeType
= XdgMime
.GetMimeType (entry
.TempFile
);
213 private ArchiveEntry
GetNextEntryTar ()
215 TarInputStream tar_stream
= (TarInputStream
) archive_stream
;
219 tar_entry
= tar_stream
.GetNextEntry ();
220 } while (tar_entry
!= null && tar_entry
.IsDirectory
);
222 // End of the entries;
223 if (tar_entry
== null)
226 ArchiveEntry entry
= new ArchiveEntry ();
227 entry
.Name
= tar_entry
.Name
;
228 entry
.Modified
= tar_entry
.ModTime
;
230 entry
.TempFile
= StoreStreamInTempFile (archive_stream
, entry
.Modified
);
231 entry
.MimeType
= XdgMime
.GetMimeType (entry
.TempFile
);
236 private bool handled_single
= false;
238 private ArchiveEntry
GetNextEntrySingle ()
243 ArchiveEntry entry
= new ArchiveEntry ();
244 entry
.Name
= Path
.GetFileNameWithoutExtension (this.file_info
.Name
);
245 entry
.Modified
= this.file_info
.LastWriteTimeUtc
;
247 entry
.TempFile
= StoreStreamInTempFile (archive_stream
, entry
.Modified
);
248 entry
.MimeType
= XdgMime
.GetMimeType (entry
.TempFile
);
250 handled_single
= true;