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 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
;
70 case "application/zip":
71 archive_stream
= new ZipInputStream (Stream
);
72 get_next_entry
= GetNextEntryZip
;
75 case "application/x-bzip-compressed-tar":
76 archive_stream
= new TarInputStream (new BZip2InputStream (Stream
));
77 get_next_entry
= GetNextEntryTar
;
80 case "application/x-compressed-tar":
81 case "application/x-tgz":
82 archive_stream
= new TarInputStream (new GZipInputStream (Stream
));
83 get_next_entry
= GetNextEntryTar
;
86 case "application/x-tar":
87 archive_stream
= new TarInputStream (Stream
);
88 get_next_entry
= GetNextEntryTar
;
91 case "application/x-gzip":
92 archive_stream
= new GZipInputStream (Stream
);
93 get_next_entry
= GetNextEntrySingle
;
96 case "application/x-bzip":
97 archive_stream
= new BZip2InputStream (Stream
);
98 get_next_entry
= GetNextEntrySingle
;
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
;
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
);
145 internal class ArchiveEntry
{
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
)
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];
170 read
= stream
.Read (buffer
, 0, buffer
.Length
);
172 buffered_stream
.Write (buffer
, 0, read
);
175 buffered_stream
.Close ();
177 File
.SetLastWriteTimeUtc (filename
, mtime
);
179 Mono
.Unix
.Native
.Syscall
.chmod (filename
, (Mono
.Unix
.Native
.FilePermissions
) 256); // 256 is 0400
184 private ArchiveEntry
GetNextEntryZip ()
186 ZipInputStream zip_stream
= (ZipInputStream
) archive_stream
;
190 zip_entry
= zip_stream
.GetNextEntry ();
191 } while (zip_entry
!= null && zip_entry
.IsDirectory
);
193 // End of the entries.
194 if (zip_entry
== 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
);
208 private ArchiveEntry
GetNextEntryTar ()
210 TarInputStream tar_stream
= (TarInputStream
) archive_stream
;
214 tar_entry
= tar_stream
.GetNextEntry ();
215 } while (tar_entry
!= null && tar_entry
.IsDirectory
);
217 // End of the entries;
218 if (tar_entry
== 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
);
231 private bool handled_single
= false;
233 private ArchiveEntry
GetNextEntrySingle ()
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;