updated on Thu Jan 12 16:09:17 UTC 2012
[aur-mirror.git] / gvfs-rar / rarfs.patch
blob19b2f5ee73befa00c6e10d20e4af3c38c946185f
1 Index: gvfs-svn/daemon/Makefile.am
2 ===================================================================
3 --- gvfs-svn/daemon/Makefile.am (revision 2345)
4 +++ gvfs-svn/daemon/Makefile.am (working copy)
5 @@ -56,6 +56,10 @@
6 libexec_PROGRAMS += gvfsd-smb-browse gvfsd-smb
7 endif
9 +mount_in_files += rar.mount.in
10 +mount_DATA += rar.mount
11 +libexec_PROGRAMS += gvfsd-rar
13 mount_in_files += cdda.mount.in
14 if USE_CDDA
15 mount_DATA += cdda.mount
16 @@ -315,7 +319,20 @@
18 gvfsd_dnssd_LDADD = $(libraries) $(AVAHI_LIBS) $(top_builddir)/common/libgvfscommon-dnssd.la
20 +gvfsd_rar_SOURCES = \
21 + gvfsbackendrar.c gvfsbackendrar.h \
22 + daemon-main.c daemon-main.h \
23 + daemon-main-generic.c \
24 + rararchive.c \
25 + rararchive.h
27 +gvfsd_rar_CPPFLAGS = \
28 + -DBACKEND_HEADER=gvfsbackendrar.h -DDEFAULT_BACKEND_TYPE=rar \
29 + -DMAX_JOB_THREADS=1 -DBACKEND_TYPES='"rar", \
30 + G_VFS_TYPE_BACKEND_RAR,'
32 +gvfsd_rar_LDADD = $(libraries)
34 gvfsd_archive_SOURCES = \
35 gvfsbackendarchive.c gvfsbackendarchive.h \
36 daemon-main.c daemon-main.h \
37 Index: gvfs-svn/daemon/gvfsbackendrar.c
38 ===================================================================
39 --- gvfs-svn/daemon/gvfsbackendrar.c (revision 0)
40 +++ gvfs-svn/daemon/gvfsbackendrar.c (revision 0)
41 @@ -0,0 +1,532 @@
42 +/* -*- Mode: C; tab-width: 4 -*- */
43 +/* GIO - GLib Input, Output and Streaming Library
44 + *
45 + * Copyright (C) 2006-2007 Red Hat, Inc.
46 + *
47 + * This library is free software; you can redistribute it and/or
48 + * modify it under the terms of the GNU Lesser General Public
49 + * License as published by the Free Software Foundation; either
50 + * version 2 of the License, or (at your option) any later version.
51 + *
52 + * This library is distributed in the hope that it will be useful,
53 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
54 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
55 + * Lesser General Public License for more details.
56 + *
57 + * You should have received a copy of the GNU Lesser General
58 + * Public License along with this library; if not, write to the
59 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
60 + * Boston, MA 02111-1307, USA.
61 + *
62 + * Author: Valmantas Palikša <walmis@balticum-tv.lt>
63 + */
65 +#include <config.h>
67 +#include <sys/types.h>
68 +#include <sys/stat.h>
69 +#include <errno.h>
70 +#include <unistd.h>
71 +#include <fcntl.h>
72 +#include <string.h>
75 +#include <glib/gstdio.h>
76 +#include <glib/gi18n.h>
77 +#include <gio/gio.h>
79 +#include "gvfsbackendrar.h"
80 +#include "gvfsjobopenforread.h"
81 +#include "gvfsjobread.h"
82 +#include "gvfsjobseekread.h"
83 +#include "gvfsjobqueryinfo.h"
84 +#include "gvfsjobenumerate.h"
85 +#include "gvfsdaemonutils.h"
86 +#include "rararchive.h"
88 +struct _GVfsBackendRar
90 + GVfsBackend parent_instance;
92 + RarArchive* archive;
93 + GHashTable* info_cache;
95 +};
97 +G_DEFINE_TYPE (GVfsBackendRar, g_vfs_backend_rar, G_VFS_TYPE_BACKEND)
99 +static void
100 +g_vfs_backend_rar_finalize (GObject *object)
102 + if (G_OBJECT_CLASS (g_vfs_backend_rar_parent_class)->finalize)
103 + (*G_OBJECT_CLASS (g_vfs_backend_rar_parent_class)->finalize) (object);
106 +static void
107 +g_vfs_backend_rar_init (GVfsBackendRar *backend)
109 + backend->info_cache = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_object_unref);
112 +static GFileInfo*
113 +get_file_info(GVfsBackendRar *backend, RarFile* file, GVfsJob* job)
115 + GFileInfo* info = g_hash_table_lookup(backend->info_cache, file);
116 + if(!info) {
117 + gchar* disp_name;
118 + info = g_file_info_new ();
120 + gvfs_file_info_populate_default (info, file->name, (file->dir)?G_FILE_TYPE_DIRECTORY:G_FILE_TYPE_REGULAR);
122 + if((file->compressed || file->encrypted) && !file->dir) {
123 + if(!file->encrypted) {
124 + disp_name = g_strdup_printf(_("%s (compressed)"), file->name);
125 + } else {
126 + disp_name = g_strdup_printf(_("%s (encrypted)"), file->name);
128 + g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, disp_name);
129 + g_free(disp_name);
131 + /***** HACK ALERT! HACK ALERT! *****/
132 + if(file->compressed || file->encrypted) {
133 + /* prevent reading video files when properties are opened, when no seeking
134 + is available it takes a while */
135 + if(file->size > 200*1024*1024) {
136 + g_file_info_set_attribute_string(info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, "application/octet-stream");
137 + g_file_info_set_attribute_string(info, G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE, "application/octet-stream");
140 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE);
141 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
142 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
143 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, (file->dir)?TRUE:FALSE);
144 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
145 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, FALSE);
147 + g_file_info_set_attribute_uint64 (info,
148 + G_FILE_ATTRIBUTE_TIME_ACCESS,
149 + file->time);
150 + g_file_info_set_attribute_uint32 (info,
151 + G_FILE_ATTRIBUTE_TIME_ACCESS_USEC,
152 + 0);
154 + g_file_info_set_attribute_uint64 (info,
155 + G_FILE_ATTRIBUTE_TIME_MODIFIED,
156 + file->time);
157 + g_file_info_set_attribute_uint32 (info,
158 + G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
159 + 0);
161 + g_file_info_set_attribute_uint64 (info,
162 + G_FILE_ATTRIBUTE_TIME_CREATED,
163 + file->time);
164 + g_file_info_set_attribute_uint32 (info,
165 + G_FILE_ATTRIBUTE_TIME_CREATED_USEC,
166 + 0);
168 + if(g_str_has_prefix(file->name, "."))
169 + g_file_info_set_attribute_boolean(info, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN, TRUE);
171 + g_file_info_set_size (info, file->size);
173 + g_file_info_set_name(info, file->name);
175 + g_hash_table_insert(backend->info_cache, file, info);
177 + info = g_file_info_dup(info);
179 + return info;
182 +static void
183 +do_mount (GVfsBackend *backend,
184 + GVfsJobMount *job,
185 + GMountSpec *mount_spec,
186 + GMountSource *mount_source,
187 + gboolean is_automount)
189 + GVfsBackendRar *rar_backend = G_VFS_BACKEND_RAR (backend);
190 + gchar* filename;
191 + const char* host;
192 + const char* file;
194 + GError* gerr = NULL;
196 + host = g_mount_spec_get (mount_spec, "host");
197 + file = g_mount_spec_get (mount_spec, "file");
199 + if(!host && !file) {
200 + g_vfs_job_failed (G_VFS_JOB (job),
201 + G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
202 + _("Missing file path"));
203 + return;
205 + } else {
206 + if(host) {
207 + filename = g_uri_unescape_string (host, NULL);
208 + } else {
209 + filename = g_strdup(file);
212 + rar_backend->archive = rar_archive_new(filename, &gerr);
214 + if(gerr != NULL) {
215 + g_warning("%s", gerr->message);
217 + g_vfs_job_failed_from_error(G_VFS_JOB (job), gerr);
218 + g_free(filename);
219 + g_error_free(gerr);
220 + gerr = NULL;
221 + return;
223 + /* in case no gerror is returned */
224 + if(!rar_backend->archive) {
225 + g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
226 + G_IO_ERROR_FAILED,
227 + _("Unknown error"));
228 + return;
230 + gchar* basename = g_path_get_basename(rar_backend->archive->basename);
232 + g_vfs_backend_set_display_name (backend, basename);
233 + g_vfs_backend_set_icon_name (backend, "gnome-mime-application-x-rar");
235 + mount_spec = g_mount_spec_new ("rar");
237 + gchar* tmp;
238 + tmp = filename;
239 + filename = g_uri_escape_string(filename, NULL, FALSE);
240 + g_free(tmp);
242 + g_mount_spec_set(mount_spec, "host", filename);
243 + g_vfs_backend_set_mount_spec (backend, mount_spec);
244 + g_mount_spec_unref (mount_spec);
245 + g_free(basename);
246 + g_free(filename);
248 + if(rar_backend->archive->has_encrypted) {
249 + gboolean aborted;
250 + gchar* passw = NULL;
251 + g_mount_source_ask_password(mount_source,
252 + _("This archive contains encrypted files, please enter the password."),
253 + NULL,
254 + NULL,
255 + G_ASK_PASSWORD_NEED_PASSWORD,
256 + &aborted,
257 + &passw,
258 + NULL,
259 + NULL,
260 + NULL,
261 + NULL);
262 + if(passw) {
263 + rar_archive_set_password(rar_backend->archive, passw);
264 + g_free(passw);
270 + g_vfs_job_succeeded (G_VFS_JOB (job));
271 + return;
276 +static void
277 +do_open_for_read (GVfsBackend *backend,
278 + GVfsJobOpenForRead *job,
279 + const char *filename)
281 + g_print ("try_open_for_read (%s)\n", filename);
283 + GVfsBackendRar *rar_backend = G_VFS_BACKEND_RAR (backend);
285 + RarFile* file;
286 + RarHandle* handle;
287 + GError* gerr = NULL;
289 + file = rar_file_find(rar_backend->archive, filename);
292 + if (!file) {
293 + g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
294 + G_IO_ERROR_NOT_FOUND,
295 + _("File not found"));
296 + } else if(file->dir) {
297 + g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
298 + G_IO_ERROR_IS_DIRECTORY,
299 + _("Can't open directory"));
301 + } /*else if(file->encrypted) {
302 + g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
303 + G_IO_ERROR_NOT_SUPPORTED,
304 + _("Can't open encrypted files"));
306 + }*/ else {
308 + handle = rar_handle_open(file, &gerr);
309 + if(!handle) {
310 + if(gerr) {
311 + g_vfs_job_failed_from_error(G_VFS_JOB (job), gerr);
312 + g_error_free(gerr);
313 + gerr = NULL;
314 + } else {
315 + g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
316 + G_IO_ERROR_FAILED,
317 + _("Unknown read error"));
319 + } else {
320 + g_vfs_job_open_for_read_set_handle(job, handle);
321 + g_vfs_job_open_for_read_set_can_seek(job, rar_handle_can_seek(handle));
322 + g_vfs_job_succeeded (G_VFS_JOB (job));
329 +static void
330 +do_read (GVfsBackend *backend,
331 + GVfsJobRead *job,
332 + GVfsBackendHandle handle,
333 + char *buffer,
334 + gsize bytes_requested)
336 + goffset res;
337 + GError* gerr = NULL;
338 + RarHandle* f = (RarHandle*)handle;
339 + /* without this, under some circumstances this daemon deadlocks with large reads */
340 + if (bytes_requested > 65536)
341 + bytes_requested = 65536;
343 + res = rar_handle_read(f, bytes_requested, buffer, G_VFS_JOB(job)->cancellable, &gerr);
345 + if(gerr != NULL) {
346 + g_vfs_job_failed_from_error(G_VFS_JOB (job), gerr);
347 + g_warning("%s", gerr->message);
348 + g_error_free(gerr);
349 + gerr = NULL;
350 + return;
353 + g_vfs_job_read_set_size (job, res);
354 + g_vfs_job_succeeded (G_VFS_JOB (job));
359 +static gboolean
360 +try_seek_on_read (GVfsBackend *backend,
361 + GVfsJobSeekRead *job,
362 + GVfsBackendHandle handle,
363 + goffset offset,
364 + GSeekType type)
366 + goffset final_offset;
368 + RarHandle* f = (RarHandle*)handle;
369 + if(!rar_handle_can_seek(handle)) {
370 + g_vfs_job_failed (G_VFS_JOB (job),
371 + G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
372 + _("Seeking not supported"));
373 + return TRUE;
376 + final_offset = rar_handle_seek(f, offset, type);
378 + if (final_offset == -1)
380 + g_vfs_job_failed (G_VFS_JOB (job),
381 + G_IO_ERROR, G_IO_ERROR_FAILED,
382 + _("Seek failed"));
384 + else
386 + g_vfs_job_seek_read_set_offset (job, final_offset);
387 + g_vfs_job_succeeded (G_VFS_JOB (job));
390 + return TRUE;
393 +static void
394 +do_query_info (GVfsBackend *backend,
395 + GVfsJobQueryInfo *job,
396 + const char *filename,
397 + GFileQueryInfoFlags flags,
398 + GFileInfo *info,
399 + GFileAttributeMatcher *matcher)
402 + g_print ("do_get_file_info (%s)\n", filename);
403 + GFileInfo* info_src;
404 + GVfsBackendRar *rar_backend = G_VFS_BACKEND_RAR (backend);
405 + RarFile* file;
406 + gchar* display_name;
407 + gchar* basename;
409 + if(strcmp(filename, "/") == 0) {
410 + gvfs_file_info_populate_default (info, filename, G_FILE_TYPE_DIRECTORY);
412 + basename = g_path_get_basename(rar_backend->archive->basename);
413 + display_name = g_strdup_printf (_("%s in %s"), filename, basename);
414 + g_file_info_set_display_name (info, display_name);
415 + g_free(display_name);
416 + g_free(basename);
418 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE);
419 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
420 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
421 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, TRUE);
422 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
423 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, FALSE);
425 + } else {
427 + file = rar_file_find(rar_backend->archive, filename);
428 + if(file) {
430 + info_src = get_file_info(rar_backend, file, G_VFS_JOB(job));
431 + g_file_info_copy_into(info_src, info);
432 + g_object_unref(info_src);
434 + } else {
435 + g_vfs_job_failed (G_VFS_JOB (job),
436 + G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
437 + _("File not found"));
438 + return;
444 + g_vfs_job_succeeded (G_VFS_JOB (job));
448 +static void
449 +do_enumerate (GVfsBackend *backend,
450 + GVfsJobEnumerate *job,
451 + const char *filename,
452 + GFileAttributeMatcher *matcher,
453 + GFileQueryInfoFlags flags)
455 + GFileInfo *info;
457 + GVfsBackendRar *rar_backend = G_VFS_BACKEND_RAR (backend);
459 + RarDirectory* dir = rar_directory_find(rar_backend->archive, filename);
461 + RarDirectory* tmp = NULL;
462 + if(dir) {
463 + g_vfs_job_succeeded (G_VFS_JOB (job));
465 + GSList* node = dir->dirs_l;
467 + while(node != NULL) {
468 + tmp = (RarDirectory*)node->data;
469 + info = g_file_info_new ();
470 + gvfs_file_info_populate_default (info, tmp->name, G_FILE_TYPE_DIRECTORY);
472 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE);
473 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
474 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
475 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, TRUE);
476 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
477 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, FALSE);
479 + if(g_str_has_prefix(tmp->name, "."))
480 + g_file_info_set_attribute_boolean(info, G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN, TRUE);
482 + g_file_info_set_name(info, tmp->name);
484 + g_vfs_job_enumerate_add_info (job, info);
486 + g_object_unref(info);
489 + node = node->next;
491 + node = dir->files;
493 + RarFile* f;
494 + while(node != NULL) {
495 + f = (RarFile*)node->data;
498 + info = get_file_info(rar_backend, f, G_VFS_JOB(job));
500 + g_vfs_job_enumerate_add_info (job, info);
501 + g_object_unref(info);
503 + node = node->next;
504 + }
506 + g_vfs_job_enumerate_done (job);
508 + } else {
509 + g_vfs_job_failed (G_VFS_JOB (job),
510 + G_IO_ERROR,G_IO_ERROR_NOT_FOUND,
511 + _("Path not found"));
516 +static gboolean
517 +do_close_read (GVfsBackend *backend,
518 + GVfsJobCloseRead *job,
519 + GVfsBackendHandle handle)
522 + RarHandle* f = (RarHandle*)handle;
523 + rar_handle_close(f);
525 + g_vfs_job_succeeded (G_VFS_JOB (job));
526 + return TRUE;
529 +static gboolean
530 +try_query_fs_info (GVfsBackend *backend,
531 + GVfsJobQueryFsInfo *job,
532 + const char *filename,
533 + GFileInfo *info,
534 + GFileAttributeMatcher *attribute_matcher)
536 + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
537 + g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL);
538 + //g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW, G_FILESYSTEM_PREVIEW_TYPE_NEVER);
539 + g_file_info_set_attribute_uint64(info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, G_VFS_BACKEND_RAR(backend)->archive->total_size);
540 + g_file_info_set_attribute_uint64(info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, 0);
541 + g_file_info_set_attribute_string(info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, "rarfs");
543 + g_vfs_job_succeeded (G_VFS_JOB (job));
544 + return TRUE;
547 +static gboolean try_unmount(GVfsBackend* backend, GVfsJobUnmount* job) {
548 + g_return_val_if_fail(G_VFS_BACKEND_RAR(backend)->archive != NULL, TRUE);
550 + rar_unref(G_VFS_BACKEND_RAR(backend)->archive);
551 + g_vfs_job_succeeded(G_VFS_JOB(job));
552 + return TRUE;
556 +static void
557 +g_vfs_backend_rar_class_init (GVfsBackendRarClass *klass)
559 + GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
560 + GVfsBackendClass *backend_class = G_VFS_BACKEND_CLASS (klass);
562 + gobject_class->finalize = g_vfs_backend_rar_finalize;
564 + backend_class->mount = do_mount;
565 + backend_class->open_for_read = do_open_for_read;
566 + backend_class->read = do_read;
567 + backend_class->try_seek_on_read = try_seek_on_read;
568 + backend_class->query_info = do_query_info;
569 + backend_class->enumerate = do_enumerate;
570 + backend_class->try_close_read = do_close_read;
571 + backend_class->try_query_fs_info = try_query_fs_info;
572 + backend_class->try_unmount = try_unmount;
574 Index: gvfs-svn/daemon/gvfsbackendrar.h
575 ===================================================================
576 --- gvfs-svn/daemon/gvfsbackendrar.h (revision 0)
577 +++ gvfs-svn/daemon/gvfsbackendrar.h (revision 0)
578 @@ -0,0 +1,51 @@
579 +/* GIO - GLib Input, Output and Streaming Library
580 + *
581 + * Copyright (C) 2006-2007 Red Hat, Inc.
583 + * This library is free software; you can redistribute it and/or
584 + * modify it under the terms of the GNU Lesser General Public
585 + * License as published by the Free Software Foundation; either
586 + * version 2 of the License, or (at your option) any later version.
588 + * This library is distributed in the hope that it will be useful,
589 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
590 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
591 + * Lesser General Public License for more details.
593 + * You should have received a copy of the GNU Lesser General
594 + * Public License along with this library; if not, write to the
595 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
596 + * Boston, MA 02111-1307, USA.
598 + * Author: Valmantas Palikša <walmis@balticum-tv.lt>
599 + */
601 +#ifndef __G_VFS_BACKEND_RAR_H__
602 +#define __G_VFS_BACKEND_RAR_H__
604 +#include <gvfsbackend.h>
606 +G_BEGIN_DECLS
608 +#define G_VFS_TYPE_BACKEND_RAR (g_vfs_backend_rar_get_type ())
609 +#define G_VFS_BACKEND_RAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_BACKEND_RAR, GVfsBackendRar))
610 +#define G_VFS_BACKEND_RAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_BACKEND_RAR, GVfsBackendRarClass))
611 +#define G_VFS_IS_BACKEND_RAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_BACKEND_RAR))
612 +#define G_VFS_IS_BACKEND_RAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_BACKEND_RAR))
613 +#define G_VFS_BACKEND_RAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_BACKEND_RAR, GVfsBackendRarClass))
615 +typedef struct _GVfsBackendRar GVfsBackendRar;
616 +typedef struct _GVfsBackendRarClass GVfsBackendRarClass;
618 +struct _GVfsBackendRarClass
620 + GVfsBackendClass parent_class;
623 +GType g_vfs_backend_rar_get_type (void) G_GNUC_CONST;
625 +GVfsBackendRar *g_vfs_backend_rar_new (void);
627 +G_END_DECLS
629 +#endif /* __G_VFS_BACKEND_RAR_H__ */
630 Index: gvfs-svn/daemon/rararchive.c
631 ===================================================================
632 --- gvfs-svn/daemon/rararchive.c (revision 0)
633 +++ gvfs-svn/daemon/rararchive.c (revision 0)
634 @@ -0,0 +1,952 @@
635 +/* -*- Mode: C; tab-width: 4 -*- */
636 +/***************************************************************************
637 + * rararchive.c
639 + * A library for reading rar files
641 + * Sun Jan 11 18:27:04 2009
642 + * Copyright 2009 Valmantas Paliksa
643 + * <walmis@balticum-tv.lt>
644 + ****************************************************************************/
647 + * This program is free software; you can redistribute it and/or modify
648 + * it under the terms of the GNU General Public License as published by
649 + * the Free Software Foundation; either version 2 of the License, or
650 + * (at your option) any later version.
651 + *
652 + * This program is distributed in the hope that it will be useful,
653 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
654 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
655 + * GNU Library General Public License for more details.
656 + *
657 + * You should have received a copy of the GNU General Public License
658 + * along with this program; if not, write to the Free Software
659 + * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
660 + */
661 +#include "rararchive.h"
663 +#include <gio/gunixinputstream.h>
664 +#include <string.h>
665 +#include <glib/gprintf.h>
666 +#include <glib/gi18n.h>
667 +#include <errno.h>
668 +#include <stdio.h>
669 +#include <signal.h>
671 +static gboolean rar_archive_load(RarArchive *ar, GError **gerr);
672 +static RarDirectory *rar_directory_alloc(const gchar *filepath);
674 +/* Table computed with Mark Adler's makecrc.c utility. */
675 +static const guint32 crc32_table[256] = {
676 + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
677 + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
678 + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
679 + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
680 + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
681 + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
682 + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
683 + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
684 + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
685 + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
686 + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
687 + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
688 + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
689 + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
690 + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
691 + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
692 + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
693 + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
694 + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
695 + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
696 + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
697 + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
698 + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
699 + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
700 + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
701 + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
702 + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
703 + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
704 + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
705 + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
706 + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
707 + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
708 + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
709 + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
710 + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
711 + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
712 + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
713 + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
714 + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
715 + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
716 + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
717 + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
718 + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
719 + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
720 + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
721 + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
722 + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
723 + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
724 + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
725 + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
726 + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
727 + 0x2d02ef8d
730 +static guint32 crc32(guint32 crc, guchar *buf, gsize len)
732 + guchar *end;
734 + crc = ~crc;
735 + for (end = buf + len; buf < end; ++buf)
736 + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
737 + return ~crc;
740 +static time_t dos2unixtime(guint32 dostime)
742 + struct tm time;
743 + time.tm_sec = 2 * (dostime & 0x1f);
744 + time.tm_min = (dostime >> 5) & 0x3f;
745 + time.tm_hour = (dostime >> 11) & 0x1f;
746 + time.tm_mday = (dostime >> 16) & 0x1f;
747 + time.tm_mon = ((dostime >> 21) & 0x0f) - 1;
748 + time.tm_year = ((dostime >> 25) & 0x7f) + 80;
749 + time.tm_isdst = -1;
750 + return mktime(&time);
753 +static gchar *get_vol_name(RarArchive *ar, gint volid)
756 + if (volid == -1 && !ar->new_name_style)
757 + return g_strdup_printf("%s.rar", ar->basename);
758 + else {
759 + if (!ar->new_name_style) {
760 + gchar letter = 'r';
761 + letter += volid / 100;
762 + if (letter > 'z')
763 + return NULL;
764 + volid = volid % 100;
765 + return g_strdup_printf("%s.%c%02d", ar->basename, letter, volid);
766 + } else {
767 + return g_strdup_printf("%s.part%0*d.rar", ar->basename, ar->padding, volid + 2);
770 + return NULL;
773 +static RarVolume *rar_archive_load_volume(RarArchive *ar, gint volid, GError **gerr)
775 + gchar *name = get_vol_name(ar, volid);
776 + if (!name) {
777 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_TOO_MANY, _("Too many volumes"));
778 + return NULL;
780 + RarVolume *vol = g_new0(RarVolume, 1);
781 + g_print("Loading volume %d %s\n", volid + 1, name);
783 + GFile *f = g_file_new_for_commandline_arg(name);
785 + if (!g_file_query_exists(f, NULL))
786 + goto error;
788 + vol->file = g_file_read(f, NULL, gerr);
789 + g_object_unref(f);
791 + vol->mutex = g_mutex_new();
792 + vol->filepath = name;
793 + vol->parent_archive = ar;
794 + g_hash_table_insert(ar->volumes, GINT_TO_POINTER(volid), vol);
795 + return vol;
797 + error:
798 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_MISSING_VOLUME, _("Volume %s is missing"), name);
799 + g_object_unref(f);
801 + g_free(name);
802 + if (vol)
803 + g_free(vol);
804 + return NULL;
807 +static void rar_directory_destroy_fn(RarDirectory *dir)
809 + g_return_if_fail(dir != NULL);
810 + g_free(dir->name);
811 + g_hash_table_destroy(dir->dirs);
812 + if (dir->files)
813 + g_slist_free(dir->files);
814 + if (dir->dirs_l)
815 + g_slist_free(dir->dirs_l);
816 + g_free(dir);
819 +static void rar_archive_destroy_fn(RarArchive *ar)
821 + g_warning("RarArchive Destroy");
822 + g_return_if_fail(ar != NULL);
823 + g_free(ar->filepath);
824 + g_free(ar->basename);
825 + g_hash_table_destroy(ar->volumes);
826 + g_hash_table_destroy(ar->items);
827 + rar_directory_destroy_fn(ar->root);
828 + if (ar->password)
829 + g_free(ar->password);
830 + g_free(ar);
833 +static void rar_items_destroy_fn(RarFile* file)
835 + g_return_if_fail(file != NULL);
836 + //g_free(file->file_header);
837 + g_free(file->path);
838 + g_free(file->name);
839 + if (file->memory_maps) {
840 + g_ptr_array_foreach(file->memory_maps, (GFunc) g_free, NULL);
841 + g_ptr_array_free(file->memory_maps, TRUE);
843 + g_free(file);
846 +static void rar_volumes_destroy_fn(RarVolume* vol)
848 + g_return_if_fail(vol != NULL);
850 + g_input_stream_close(G_INPUT_STREAM(vol->file), NULL, NULL);
851 + g_object_unref(vol->file);
853 + g_free(vol->filepath);
854 + g_free(vol->main_header);
855 + g_mutex_free(vol->mutex);
856 + g_free(vol);
859 +RarArchive* rar_archive_new(const gchar* filepath, GError** gerr)
861 + if (!g_thread_supported())
862 + g_thread_init(NULL);
864 + //cache re`s so they can be reused
865 + static GRegex* re1 = NULL;
866 + static GRegex* re2 = NULL;
867 + static GRegex* re3 = NULL;
868 + if (!re1)
869 + re1 = g_regex_new("\\.part([0-9]*)\\.rar$", G_REGEX_OPTIMIZE, 0, NULL);
870 + if (!re2)
871 + re2 = g_regex_new("\\.[r-z][0-9]*$", G_REGEX_OPTIMIZE, 0, NULL);
872 + if (!re3)
873 + re3 = g_regex_new("\\.rar$", G_REGEX_OPTIMIZE, 0, NULL);
875 + RarArchive* ar = g_new0(RarArchive, 1);
876 + ar->volumes = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) rar_volumes_destroy_fn);
877 + ar->items = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) rar_items_destroy_fn);
878 + ar->root = rar_directory_alloc("/");
880 + REFCOUNT_INIT(ar, rar_archive_destroy_fn);
882 + GFile* f = g_file_new_for_commandline_arg(filepath);
883 + if (!g_file_query_exists(f, NULL)) {
884 + g_object_unref(f);
885 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_MISSING_ARCHIVE, _("Archive %s not found"), filepath);
886 + g_free(ar);
887 + return NULL;
889 + g_object_unref(f);
891 + ar->filepath = g_strdup(filepath);
892 + GMatchInfo* minfo;
893 + if (g_regex_match(re1, ar->filepath, 0, &minfo)) {
894 + ar->new_name_style = TRUE;
895 + gchar* match = g_match_info_fetch(minfo, 1);
896 + if (match) {
897 + ar->padding = strlen(match);
898 + g_free(match);
903 + g_match_info_free(minfo);
905 + gchar* tmp;
906 + ar->basename = g_regex_replace_literal(re1, ar->filepath, -1, 0, "", 0, NULL);
907 + tmp = ar->basename;
908 + ar->basename = g_regex_replace_literal(re2, ar->basename, -1, 0, "", 0, NULL);
909 + g_free(tmp);
910 + tmp = ar->basename;
911 + ar->basename = g_regex_replace_literal(re3, ar->basename, -1, 0, "", 0, NULL);
912 + g_free(tmp);
914 + if (!rar_archive_load(ar, gerr)) {
915 + rar_unref(ar);
916 + return NULL;
919 + return ar;
923 +static RarDirectory* rar_directory_alloc(const gchar* filepath)
925 + RarDirectory* dir = g_new0(RarDirectory, 1);
926 + dir->name = g_strdup(filepath);
927 + dir->dirs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) rar_directory_destroy_fn);
928 + return dir;
931 +RarDirectory* rar_directory_find(RarArchive* ar, const gchar* path)
933 + g_return_val_if_fail(path != NULL && ar != NULL, NULL);
934 + if (g_str_has_prefix(path, "/"))
935 + path = path + 1;
937 + if (strcmp(path, "") == 0) {
938 + return ar->root;
939 + } else {
940 + gchar** path_segments = g_strsplit(path, "/", 0);
941 + gint num_segments = g_strv_length(path_segments);
942 + RarDirectory* pos = ar->root;
943 + gint i;
944 + for (i = 0; i < num_segments; i++) {
945 + pos = g_hash_table_lookup(pos->dirs, path_segments[i]);
946 + if (!pos) {
947 + g_strfreev(path_segments);
948 + return NULL;
952 + g_strfreev(path_segments);
953 + return pos;
957 +/* adds a file to an internal file tree */
958 +static void rar_archive_register_file(RarArchive* ar, RarFile* file)
960 + rar_ref(ar);
962 + gchar** path_segments = g_strsplit(file->path, "/", 0);
963 + gint num_segments = g_strv_length(path_segments);
965 + RarDirectory* pos = ar->root;
966 + RarDirectory* tmp;
968 + gchar** tmp_pathv = g_malloc0(sizeof(gchar* )* (num_segments + 1));
969 + gchar* tmp_path = NULL;
970 + gint i;
972 + for (i = 0; i < num_segments; i++) {
973 + tmp_pathv[i] = path_segments[i];
975 + tmp_path = g_build_pathv("/", tmp_pathv);
977 + if (i == num_segments - 1) {
978 + if (file->dir) {
979 + tmp = g_hash_table_lookup(pos->dirs, path_segments[i]);
980 + if (!tmp) {
981 + tmp = rar_directory_alloc(path_segments[i]);
982 + tmp->parent = pos;
983 + g_hash_table_insert(pos->dirs, g_strdup(path_segments[i]), tmp);
984 + pos->dirs_l = g_slist_append(pos->dirs_l, tmp);
986 + } else {
987 + pos->files = g_slist_append(pos->files, file);
988 + g_printf("Adding File %s to RarDirectory %s\n", path_segments[i], pos->name);
990 + } else {
991 + tmp = g_hash_table_lookup(pos->dirs, path_segments[i]);
992 + if (!tmp) {
993 + tmp = rar_directory_alloc(path_segments[i]);
994 + tmp->parent = pos;
995 + g_hash_table_insert(pos->dirs, g_strdup(path_segments[i]), tmp);
996 + pos->dirs_l = g_slist_append(pos->dirs_l, tmp);
997 + g_printf("Adding %s to RarDirectory %s\n", path_segments[i], pos->name);
998 + pos = tmp;
1000 + pos = tmp;
1003 + g_free(tmp_path);
1005 + g_free(tmp_pathv);
1006 + g_strfreev(path_segments);
1007 + rar_unref(ar);
1010 +RarFile* rar_file_find(RarArchive* ar, const gchar* path)
1012 + g_return_val_if_fail(path != NULL && ar != NULL, NULL);
1013 + rar_ref(ar);
1014 + if (g_str_has_prefix(path, "/"))
1015 + path = path + 1;
1017 + rar_unref(ar);
1018 + return g_hash_table_lookup(ar->items, path);
1021 +static void rar_handle_destroy_fn(RarHandle* handle)
1023 + g_return_if_fail(handle != NULL);
1024 + rar_unref(handle->file->parent_archive);
1025 + g_mutex_free(handle->mutex);
1026 + if (handle->pipe) {
1027 + g_input_stream_close(handle->pipe, NULL, NULL);
1028 + g_object_unref(handle->pipe);
1030 + if (handle->stderr_pipe) {
1031 + g_io_channel_shutdown(handle->stderr_pipe, FALSE, NULL);
1032 + g_io_channel_unref(handle->stderr_pipe);
1033 + if(handle->unrar != 0)
1034 + g_spawn_close_pid(handle->unrar);
1036 + g_free(handle);
1039 +gboolean rar_archive_has_password(RarArchive* ar)
1041 + g_return_val_if_fail(ar != NULL, FALSE);
1042 + return (ar->password != NULL);
1045 +void rar_archive_set_password(RarArchive* ar, const gchar* password)
1047 + g_return_if_fail(ar != NULL && password != NULL);
1048 + ar->password = g_strdup(password);
1051 +static gboolean unrar_stderr_io(GIOChannel* source, GIOCondition condition, RarHandle* handle)
1053 + g_mutex_lock(handle->mutex);
1054 + static GRegex* re1 = NULL;
1055 + if (!re1)
1056 + re1 = g_regex_new("^Encrypted file:[ ]*CRC failed in.*\\(password incorrect \\?\\)$",
1057 + G_REGEX_OPTIMIZE, 0, NULL);
1059 + gchar* line = NULL;
1060 + GIOStatus status;
1061 + switch (condition) {
1062 + case G_IO_IN:
1063 + status = g_io_channel_read_line(source, &line, NULL, NULL, NULL);
1064 + if (status == G_IO_STATUS_AGAIN) {
1065 + g_mutex_unlock(handle->mutex);
1067 + g_free(line);
1068 + return TRUE;
1070 + if (status != G_IO_STATUS_NORMAL) {
1071 + g_mutex_unlock(handle->mutex);
1072 + rar_unref(handle);
1074 + g_free(line);
1075 + return FALSE;
1077 + g_printf("Unrar: %s", line);
1078 + if (g_str_has_prefix(line, "Total errors:")) {
1079 + g_warning("unknown error");
1080 + handle->error_condition = RAR_ERROR_UNKNOWN;
1081 + g_mutex_unlock(handle->mutex);
1082 + rar_unref(handle);
1084 + g_free(line);
1085 + return FALSE;
1086 + } else if (g_regex_match(re1, line, 0, NULL)) {
1087 + handle->file->parent_archive->wrong_password = TRUE;
1088 + g_mutex_unlock(handle->mutex);
1089 + rar_unref(handle);
1091 + g_free(line);
1092 + return FALSE;
1095 + g_free(line);
1096 + break;
1097 + case G_IO_HUP:
1098 + default:
1099 + g_mutex_unlock(handle->mutex);
1100 + rar_unref(handle);
1101 + return FALSE;
1103 + g_mutex_unlock(handle->mutex);
1104 + return TRUE;
1107 +RarHandle* rar_handle_open(RarFile* file, GError** gerr)
1109 + if (file->parent_archive->wrong_password) {
1110 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_WRONG_PASSWORD, _("Wrong decryption password"));
1111 + return NULL;
1113 + rar_ref(file->parent_archive); /*dont unref this now, unref will happen when handle is closed */
1114 + RarHandle* h = g_new0(RarHandle, 1);
1115 + REFCOUNT_INIT(h, rar_handle_destroy_fn);
1116 + h->file = file;
1117 + h->offset = 0;
1118 + h->mutex = g_mutex_new();
1119 + g_mutex_lock(h->mutex);
1121 + if (file->compressed || file->encrypted) {
1122 + gint stdin, stdout, stderr;
1123 + gchar* pw = NULL;
1124 + if (file->parent_archive->password) {
1125 + pw = g_strdup_printf("-p%s", file->parent_archive->password);
1127 + gchar* args[10];
1128 + gint i = 0;
1129 + args[i++] = "unrar";
1130 + args[i++] = "p";
1131 + args[i++] = "-ierr";
1132 + args[i++] = "-idp";
1133 + if (pw)
1134 + args[i++] = pw;
1135 + else
1136 + args[i++] = "-pnull";
1137 + args[i++] = file->parent_archive->filepath;
1138 + args[i++] = file->path;
1139 + args[i++] = NULL;
1141 + if (!g_spawn_async_with_pipes(NULL, args, NULL,
1142 + /*G_SPAWN_DO_NOT_REAP_CHILD | */
1143 + G_SPAWN_SEARCH_PATH, NULL, NULL, &h->unrar, &stdin, &stdout, &stderr,
1144 + gerr)) {
1145 + if (pw)
1146 + g_free(pw);
1148 + g_warning("Unrar spawn failed!");
1149 + g_mutex_unlock(h->mutex);
1150 + g_free(h);
1151 + return NULL;
1152 + } else {
1153 + g_message("Unrar spawned OK!");
1154 + h->pipe = g_unix_input_stream_new(stdout, TRUE);
1155 + h->stderr_pipe = g_io_channel_unix_new(stderr);
1156 + g_io_channel_set_close_on_unref(h->stderr_pipe, TRUE);
1157 + g_io_channel_set_flags(h->stderr_pipe, G_IO_FLAG_NONBLOCK, NULL);
1158 + g_io_add_watch(h->stderr_pipe, G_IO_IN | G_IO_HUP | G_IO_ERR, (GIOFunc) unrar_stderr_io, h);
1160 + rar_ref(h); /* unrefed when unrar is closed */
1163 + if (pw)
1164 + g_free(pw);
1167 + g_mutex_unlock(h->mutex);
1168 + return h;
1171 +gboolean rar_handle_can_seek(RarHandle* handle)
1173 + return (handle->pipe == NULL);
1176 +void rar_handle_close(RarHandle* handle)
1178 + g_mutex_lock(handle->mutex);
1179 + if (handle->unrar != 0) {
1180 + kill(handle->unrar, SIGHUP);
1181 + g_spawn_close_pid(handle->unrar);
1182 + handle->unrar = 0;
1184 + g_mutex_unlock(handle->mutex);
1185 + rar_unref(handle);
1188 +goffset rar_handle_seek(RarHandle* handle, goffset pos, GSeekType whence)
1190 + if (!rar_handle_can_seek(handle))
1191 + return -1;
1193 + rar_ref(handle->file->parent_archive);
1194 + rar_ref(handle);
1196 + switch (whence) {
1198 + case G_SEEK_SET:
1199 + if (pos >= handle->file->size || pos < 0)
1200 + goto error;
1201 + g_mutex_lock(handle->mutex);
1202 + handle->offset = pos;
1203 + g_mutex_unlock(handle->mutex);
1204 + rar_unref(handle);
1205 + rar_unref(handle->file->parent_archive);
1206 + return pos;
1208 + case G_SEEK_CUR:
1209 + if ((handle->offset + pos) >= handle->file->size || (handle->offset + pos) < 0)
1210 + goto error;
1211 + g_mutex_lock(handle->mutex);
1212 + handle->offset = handle->offset + pos;
1213 + g_mutex_unlock(handle->mutex);
1214 + rar_unref(handle);
1215 + rar_unref(handle->file->parent_archive);
1216 + return handle->offset;
1218 + case G_SEEK_END:
1219 + if ((handle->file->size + pos) >= handle->file->size || (handle->file->size + pos) < 0)
1220 + goto error;
1221 + g_mutex_lock(handle->mutex);
1222 + handle->offset = handle->file->size + pos;
1223 + g_mutex_unlock(handle->mutex);
1224 + rar_unref(handle);
1225 + rar_unref(handle->file->parent_archive);
1226 + return handle->offset;
1228 + error:
1229 + rar_unref(handle->file->parent_archive);
1230 + rar_unref(handle);
1231 + return -1;
1234 +static gssize rar_handle_read_pipe(RarHandle* handle, gsize len, gpointer buffer,
1235 + GCancellable* cancellable, GError** gerr)
1237 + g_return_val_if_fail(handle != NULL && handle->pipe != NULL, -1);
1238 + rar_ref(handle->file->parent_archive);
1239 + rar_ref(handle);
1240 + g_mutex_lock(handle->mutex);
1241 + gssize res;
1242 + if (handle->file->parent_archive->wrong_password) {
1243 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_WRONG_PASSWORD, _("Wrong decryption password"));
1244 + res = -1;
1245 + goto cleanup;
1247 + if (handle->error_condition > 0) {
1248 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_UNKNOWN, _("Unknown error"));
1249 + res = -1;
1250 + goto cleanup;
1253 + res = g_input_stream_read(handle->pipe, buffer, len, cancellable, gerr);
1254 + cleanup:
1255 + g_mutex_unlock(handle->mutex);
1256 + rar_unref(handle);
1257 + rar_unref(handle->file->parent_archive);
1258 + return res;
1261 +gssize rar_handle_read(RarHandle* handle, gsize len, gpointer buffer, GCancellable* cancellable, GError** gerr)
1263 + if (!rar_handle_can_seek(handle))
1264 + return rar_handle_read_pipe(handle, len, buffer, cancellable, gerr);
1266 + rar_ref(handle->file->parent_archive);
1267 + rar_ref(handle);
1268 + g_mutex_lock(handle->mutex);
1269 + gint i;
1270 + goffset rel_offset = 0;
1271 + goffset left;
1273 + if (!handle->map || !(handle->offset >= handle->map->off_start && handle->offset < handle->map->off_end)) {
1274 + for (i = 0; i < handle->file->memory_maps->len; i++) {
1275 + handle->map = g_ptr_array_index(handle->file->memory_maps, i);
1276 + if (handle->offset >= handle->map->off_start && handle->offset < handle->map->off_end)
1277 + break;
1280 + g_mutex_lock(handle->map->vol->mutex);
1281 + rel_offset = handle->offset - handle->map->off_start;
1282 + left = handle->map->off_end - handle->offset;
1284 + if (len > left)
1285 + len = left;
1287 + if (g_seekable_tell(G_SEEKABLE(handle->map->vol->file)) != (handle->map->start + rel_offset)) {
1288 + if (!g_seekable_seek
1289 + (G_SEEKABLE(handle->map->vol->file), (handle->map->start + rel_offset), G_SEEK_SET, NULL, gerr)) {
1290 + len = 0;
1291 + goto cleanup;
1295 + g_printf("read map: %p, off: %" G_GINT64_FORMAT " start: %"
1296 + G_GINT64_FORMAT ". end: %" G_GINT64_FORMAT "\n", handle->map,
1297 + handle->offset, (handle->map->start + rel_offset), (handle->map->start + rel_offset) + len);
1299 + if (left >= 0) {
1300 + len = g_input_stream_read(G_INPUT_STREAM(handle->map->vol->file), buffer, len, cancellable, gerr);
1302 + if(left-len > 0 && len == 0) {
1303 + gchar* name = g_path_get_basename(handle->map->vol->filepath);
1304 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_UNEXPECTED_EOF, "Unexpected end-of-file in: %s", name);
1305 + g_free(name);
1308 + if (len > 0)
1309 + handle->offset += len;
1311 + cleanup:
1312 + g_mutex_unlock(handle->map->vol->mutex);
1313 + g_mutex_unlock(handle->mutex);
1314 + rar_unref(handle);
1315 + rar_unref(handle->file->parent_archive);
1316 + return len;
1320 +static gboolean rar_archive_load(RarArchive* ar, GError** gerr)
1322 + rar_ref(ar);
1323 + int n = -1;
1324 + BlockHeader header;
1325 + goffset data_size;
1327 + gchar* full_header;
1329 + gchar* filename;
1330 + gboolean dir;
1331 + gboolean next_volume;
1332 + gsize read;
1334 + RarFile* f;
1336 + while (1) {
1337 + next_volume = FALSE;
1338 + RarVolume* vol = rar_archive_load_volume(ar, n++, gerr);
1339 + if (!vol) {
1340 + rar_unref(ar);
1341 + return FALSE;
1343 + gchar mark[7];
1344 + if (g_input_stream_read(G_INPUT_STREAM(vol->file), mark, 7, NULL, gerr) == -1) {
1345 + rar_unref(ar);
1346 + return FALSE;
1349 + if (!memcmp(&mark, "\x52\x61\x72\x21\x1a\x07\x00", 7) == 0) {
1350 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_INVALID_HEADER, _("Not a RAR file"));
1351 + rar_unref(ar);
1352 + return FALSE;
1355 + while (1) {
1357 + if(!g_input_stream_read_all(G_INPUT_STREAM(vol->file), &header, sizeof(BlockHeader), &read, NULL, gerr)) {
1358 + rar_unref(ar);
1359 + return FALSE;
1361 + /* some archives dont have ENDARC_HEAD headers */
1362 + if(read == 0 && next_volume) {
1363 + /* let's move on to the next volume */
1364 + break;
1365 + } else
1366 + if(read == 0 && !next_volume){
1367 + /* looks like we're finished */
1368 + rar_unref(ar);
1369 + return TRUE;
1372 +#ifdef DEBUG
1373 + g_printf("Header type: 0x%x\n", header.HeadType);
1374 +#endif
1375 + if (header.HeadType == ENDARC_HEAD) {
1376 + if ((header.Flags & 0x0001) == 0 && !next_volume) { /*no next volume */
1377 + rar_unref(ar);
1378 + return TRUE;
1380 + break;
1383 + full_header = g_malloc(header.HeadSize);
1384 + if (!full_header) {
1385 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_INVALID_HEADER, _("Invalid header"));
1386 + rar_unref(ar);
1387 + return FALSE;
1389 + memcpy(full_header, &header, sizeof(BlockHeader));
1391 + if(!g_input_stream_read_all(G_INPUT_STREAM(vol->file), full_header + sizeof(BlockHeader),
1392 + header.HeadSize - sizeof(BlockHeader), &read, NULL, gerr))
1394 + g_free(full_header);
1395 + rar_unref(ar);
1396 + return FALSE;
1397 + }
1399 + if (read < (header.HeadSize - sizeof(BlockHeader))) {
1400 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_UNEXPECTED_EOF, _("Unexpected end of file"));
1401 + g_free(full_header);
1402 + rar_unref(ar);
1403 + return FALSE;
1406 + if (!check_header_crc(header.HeadCRC, full_header, header.HeadSize)) {
1407 + gchar* name = g_path_get_basename(vol->filepath);
1408 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_CORRUPT_HEADER, _("Checksum mismatch in %s"),
1409 + name);
1410 + g_free(name);
1411 + g_free(full_header);
1412 + rar_unref(ar);
1413 + return FALSE;
1415 + data_size = header.DataSize;
1416 + switch (header.HeadType) {
1417 + case MAIN_HEAD:
1418 + vol->main_header = g_memdup(full_header, sizeof(MainArchiveHeader));
1420 + if ((header.Flags & 0x0080) == 0x0080) {
1421 + g_set_error(gerr, RAR_ERROR,
1422 + RAR_ERROR_ENCRYPTED_HEADERS,
1423 + _("Encrypted headers, cannot open archive"));
1424 + rar_unref(ar);
1425 + return FALSE;
1428 + break;
1429 +/* case NEWSUB_HEAD:
1430 + g_set_error(gerr, RAR_ERROR,
1431 + RAR_ERROR_UNSUPPORTED_HEADER,
1432 + _("Subheaders are not supported"));
1433 + rar_unref(ar);
1434 + return FALSE;
1435 +*/
1436 + case FILE_HEAD:
1438 + BlockFileHeader* file_entry;
1440 + guint32 pack_high = 0;
1441 + guint32 unp_high = 0;
1443 + file_entry = (BlockFileHeader* ) full_header;
1445 + gchar* pos = full_header + sizeof(BlockFileHeader);
1446 + if (file_entry->Flags & 0x0100) {
1447 + /*read the high bytes */
1448 + g_memmove(&pack_high, pos, sizeof(guint32));
1449 + pos += sizeof(guint32);
1450 + g_memmove(&unp_high, pos, sizeof(guint32));
1451 + pos += sizeof(guint32);
1452 + } else {
1453 + if (file_entry->UnpSize == 0xffffffff) {
1454 + file_entry->UnpSize = (gint32) (G_MAXINT64);
1455 + unp_high = (gint32) (G_MAXINT64 >> 32);
1459 + filename = g_malloc0(file_entry->NameSize + 1);
1460 + g_memmove(filename, pos, file_entry->NameSize);
1462 + gint i;
1463 + for (i = 0;; i++) {
1464 + if (filename[i] == 0)
1465 + break;
1466 + if (filename[i] == '\\')
1467 + filename[i] = '/';
1470 + if ((file_entry->Flags & 0xE0) == 0xE0)
1471 + dir = TRUE;
1472 + else
1473 + dir = FALSE;
1475 + f = rar_file_find(ar, filename);
1476 + if (!f) {
1477 + f = g_new0(RarFile, 1);
1479 + f->path = g_strdup(filename);
1480 + f->name = g_path_get_basename(filename);
1481 + f->dir = dir;
1482 + f->parent_archive = ar;
1484 + f->size = int32to64(unp_high, file_entry->UnpSize);
1485 + ar->total_size += f->size;
1487 + if (!dir) {
1488 + f->memory_maps = g_ptr_array_new();
1490 + g_hash_table_insert(ar->items, g_strdup(f->path), f);
1492 + f->compressed = file_entry->Method != 48;
1493 + ar->has_compressed |= f->compressed;
1494 + f->encrypted = (file_entry->Flags & 0x0004) == 0x0004;
1495 + ar->has_encrypted |= f->encrypted;
1496 + f->time = dos2unixtime(file_entry->FileTime);
1498 + rar_archive_register_file(ar, f);
1500 + data_size = int32to64(pack_high, file_entry->PackSize);
1501 + f->p_size += data_size;
1502 + if (!dir) {
1503 + MemoryMap* map = g_new0(MemoryMap, 1);
1505 + map->start = g_seekable_tell(G_SEEKABLE(vol->file));
1507 + map->end = map->start + data_size;
1508 + map->vol = vol;
1510 + if ((file_entry->Flags & 0x01) == 0x01) { /*there is data in the prev volume */
1511 + MemoryMap* prev = g_ptr_array_index(f->memory_maps,
1512 + f->memory_maps->len - 1);
1513 + map->off_start = prev->off_end;
1514 + map->off_end = map->off_start + data_size;
1515 + } else {
1516 + map->off_start = 0;
1517 + map->off_end = data_size;
1519 + g_ptr_array_add(f->memory_maps, map);
1521 + next_volume |= (file_entry->Flags & 0x02) == 0x02;
1523 +#ifdef DEBUG
1524 + g_print("Header CRC: 0x%01x\n", file_entry->HeadCRC);
1525 + g_print("Header Flags: 0x%01x\n", file_entry->Flags);
1526 + g_print("Header Size: %u\n", file_entry->HeadSize);
1527 + g_print("Packed size: %" G_GINT64_FORMAT "\n", data_size);
1528 + g_print("Unpacked size: %" G_GINT64_FORMAT "\n", f->size);
1529 + g_print("Host OS: 0x%01x\n", file_entry->HostOS);
1530 + g_print("File CRC32: 0x%01x\n", file_entry->FileCRC);
1531 + g_print("File Time: %u\n", file_entry->FileTime);
1532 + g_print("Name size: %u\n", file_entry->NameSize);
1533 + g_print("Filename: %s\n", filename);
1534 + g_print("Directory: %d\n", dir);
1535 + g_print("Data in prev file %d\n", (file_entry->Flags & 0x01));
1536 + g_print("Data in next file %d\n", (file_entry->Flags & 0x02));
1537 + g_print("Compressed %d\n", file_entry->Method != 48);
1538 + g_print("Encrypted %d\n\n", file_entry->Flags & 0x0004);
1539 +#endif
1540 + g_free(filename);
1542 + break;
1544 + case ENDARC_HEAD:
1545 + break;
1547 + /*case PROTECT_HEAD:
1548 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_UNSUPPORTED_HEADER,
1549 + _("Protected headers are not supported"));
1550 + g_free(full_header);
1551 + rar_unref(ar);
1552 + return FALSE;
1554 + break;*/
1555 + default:
1556 + g_printf("Unknown block 0x%x\n", header.HeadType);
1557 + break;
1559 + g_free(full_header);
1560 + memset(&header, 0, sizeof(BlockHeader));
1562 + /*move to the next header */
1563 + if (!g_seekable_seek(G_SEEKABLE(vol->file), data_size, G_SEEK_CUR, NULL, gerr)) {
1564 + rar_unref(ar);
1565 + return FALSE;
1571 +void __rar_ref(RarRefCountable* obj)
1573 + g_return_if_fail(obj != NULL);
1574 + g_atomic_int_inc(&obj->refcount);
1575 + /*g_print("ref++ %p, now %d\n", obj, obj->refcount); */
1578 +void __rar_unref(RarRefCountable* obj)
1580 + g_return_if_fail(obj != NULL);
1582 + if (g_atomic_int_dec_and_test(&obj->refcount)) {
1583 + g_print("ref-- %p, now %d\n", obj, obj->refcount);
1584 + obj->ref_destr_fn(obj);
1587 Index: gvfs-svn/daemon/rararchive.h
1588 ===================================================================
1589 --- gvfs-svn/daemon/rararchive.h (revision 0)
1590 +++ gvfs-svn/daemon/rararchive.h (revision 0)
1591 @@ -0,0 +1,225 @@
1592 +/* -*- Mode: C; tab-width: 4 -*- */
1594 + * This program is free software; you can redistribute it and/or modify
1595 + * it under the terms of the GNU General Public License as published by
1596 + * the Free Software Foundation; either version 2 of the License, or
1597 + * (at your option) any later version.
1598 + *
1599 + * This program is distributed in the hope that it will be useful,
1600 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1601 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1602 + * GNU Library General Public License for more details.
1603 + *
1604 + * You should have received a copy of the GNU General Public License
1605 + * along with this program; if not, write to the Free Software
1606 + * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
1607 + */
1608 +#define _FILE_OFFSET_BITS 64
1610 +#include <glib.h>
1611 +#include <gio/gio.h>
1612 +#include <stdio.h>
1613 +#include <sys/types.h>
1615 +#define DEBUG 1
1617 +#define rar_ref(x) __rar_ref((RarRefCountable*)x)
1618 +#define rar_unref(x) __rar_unref((RarRefCountable*)x)
1620 +#define RAR_ERROR g_quark_from_static_string ("rar-error-quark")
1622 +/* the first two bytes is the actual checksum */
1623 +#define check_header_crc(orig_crc, buffer, len) (orig_crc == (guint16)crc32(0, (guchar*)buffer+sizeof(guint16), len-sizeof(guint16)))
1625 +#define RAR_REFCOUNTABLE volatile gint refcount; \
1626 +GDestroyNotify ref_destr_fn; \
1628 +#define REFCOUNT_INIT(x, fn) x->refcount = 1; x->ref_destr_fn = (GDestroyNotify)fn;
1630 +#define int32to64(high,low) ((((gint64)(high))<<32)+(low))
1632 +typedef enum {
1633 + MARK_HEAD=0x72,
1634 + MAIN_HEAD=0x73,
1635 + FILE_HEAD=0x74,
1636 + COMM_HEAD=0x75,
1637 + AV_HEAD=0x76,
1638 + SUB_HEAD=0x77,
1639 + PROTECT_HEAD=0x78,
1640 + SIGN_HEAD=0x79,
1641 + NEWSUB_HEAD=0x7a,
1642 + ENDARC_HEAD=0x7b
1643 +} BlockType;
1645 +typedef enum {
1646 + RAR_ERROR_UNKNOWN = 1,
1647 + RAR_ERROR_CORRUPT_HEADER,
1648 + RAR_ERROR_INVALID_HEADER,
1649 + RAR_ERROR_UNSUPPORTED_HEADER,
1650 + RAR_ERROR_ENCRYPTED_HEADERS,
1651 + RAR_ERROR_MISSING_VOLUME,
1652 + RAR_ERROR_MISSING_ARCHIVE,
1653 + RAR_ERROR_UNEXPECTED_EOF,
1654 + RAR_ERROR_OPEN_FAILED,
1655 + RAR_ERROR_TOO_MANY,
1656 + RAR_ERROR_IO_ERROR,
1657 + RAR_ERROR_WRONG_PASSWORD
1658 +} RarError;
1660 +#pragma pack(push) /* push current alignment to stack */
1661 +#pragma pack(1) /* set alignment to 1 byte boundary */
1663 +typedef struct
1665 + guint16 HeadCRC;
1666 + guint8 HeadType;
1667 + guint16 Flags;
1668 + guint16 HeadSize;
1669 + guint16 Reserved;
1670 + guint32 Reserved1;
1671 +} MainArchiveHeader;
1673 +typedef struct
1675 + guint16 HeadCRC;
1676 + guint8 HeadType;
1677 + guint16 Flags;
1678 + guint16 HeadSize;
1679 + guint32 PackSize;
1680 + guint32 UnpSize;
1681 + guint8 HostOS;
1682 + guint32 FileCRC;
1683 + guint32 FileTime;
1684 + guint8 UnpVer;
1685 + guint8 Method;
1686 + guint16 NameSize;
1687 + guint32 FileAttr;
1688 +} BlockFileHeader;
1690 +typedef struct
1692 + guint16 HeadCRC;
1693 + guint8 HeadType;
1694 + guint16 Flags;
1695 + guint16 HeadSize;
1696 + guint32 DataSize;
1697 +} BlockHeader;
1699 +#pragma pack(pop) /* restore original alignment from stack */
1701 +typedef struct _RarArchive RarArchive;
1703 +typedef struct {
1704 + GFileInputStream* file;
1706 + gchar* filepath;
1707 + MainArchiveHeader* main_header;
1708 + RarArchive* parent_archive;
1709 + GMutex* mutex; /* for io synchronization */
1710 +} RarVolume;
1712 +typedef struct {
1713 + goffset off_start;
1714 + goffset off_end;
1715 + goffset start;
1716 + goffset end;
1717 + RarVolume* vol;
1718 +} MemoryMap;
1720 +/* all items (files and directories) are stored in RarFile,
1721 +for file tree traversal RarDirectories are used */
1722 +typedef struct {
1723 + //BlockFileHeader* file_header;
1724 + RarArchive* parent_archive;
1726 + goffset p_size; /* packed size */
1727 + goffset size; /* unpacked size */
1729 + gchar* path;
1730 + gchar* name;
1731 + guint8 dir : 1; /* a directory? */
1732 + guint8 compressed : 1;
1733 + guint8 encrypted : 1;
1735 + time_t time;
1737 + GPtrArray* memory_maps; /* MemoryMap* */
1738 +} RarFile;
1740 +typedef struct {
1741 + RAR_REFCOUNTABLE
1743 + GMutex* mutex;
1744 + goffset offset;
1745 + RarFile* file;
1746 + MemoryMap* map; /* the last used memory map */
1748 + /* following members are used when streaming from unrar */
1749 + GInputStream* pipe;
1750 + RarError error_condition;
1751 + GIOChannel* stderr_pipe;
1752 + GPid unrar;
1753 +} RarHandle;
1755 +typedef struct _RarDirectory {
1756 + gchar* name;
1757 + GSList* files;
1758 + GSList* dirs_l; /* linked list of RarDirectory for faster enumeration */
1759 + GHashTable* dirs; /* hash table of RarDirectory for faster lookup */
1760 + struct _RarDirectory* parent;
1761 +} RarDirectory;
1763 +struct _RarArchive{
1764 + RAR_REFCOUNTABLE
1766 + gchar* filepath;
1767 + gchar* basename; /* filepath without extension */
1769 + guint64 total_size; /* size of all files */
1771 + GHashTable* volumes; /* RarVolume */
1772 + GHashTable* items; /* key:path val:RarFile */
1774 + RarDirectory* root;
1776 + gchar* password; /* decryption password */
1778 + guint8 has_encrypted : 1; /* files */
1779 + guint8 has_compressed : 1; /* files */
1781 + guint8 new_name_style : 1;
1782 + /* set when it's known that the encryption
1783 + password is wrong */
1784 + guint8 wrong_password : 1;
1785 + guint8 padding : 4;
1789 +typedef struct {
1790 + RAR_REFCOUNTABLE
1791 +} RarRefCountable;
1793 +void __rar_ref(RarRefCountable* obj);
1794 +void __rar_unref(RarRefCountable* obj);
1796 +/* public api */
1798 +RarArchive* rar_archive_new(const gchar* filepath, GError** gerr);
1799 +/* set decryption password */
1800 +void rar_archive_set_password(RarArchive* ar, const gchar* password);
1801 +gboolean rar_archive_has_password(RarArchive* ar);
1803 +RarDirectory* rar_directory_find(RarArchive* ar, const gchar* path);
1805 +RarFile* rar_file_find(RarArchive* ar, const gchar* path);
1807 +RarHandle* rar_handle_open(RarFile* file, GError** gerr);
1808 +void rar_handle_close(RarHandle* handle);
1809 +goffset rar_handle_seek(RarHandle* handle, goffset pos, GSeekType whence);
1810 +gboolean rar_handle_can_seek(RarHandle* handle);
1812 +gssize rar_handle_read(RarHandle* handle,
1813 + gsize len,
1814 + gpointer buffer,
1815 + GCancellable* cancellable,
1816 + GError** gerr);
1817 Index: gvfs-svn/daemon/rar.mount.in
1818 ===================================================================
1819 --- gvfs-svn/daemon/rar.mount.in (revision 0)
1820 +++ gvfs-svn/daemon/rar.mount.in (revision 0)
1821 @@ -0,0 +1,4 @@
1822 +[Mount]
1823 +Type=rar
1824 +Exec=@libexecdir@/gvfsd-rar
1825 +AutoMount=false