1 Index: gvfs-svn/daemon/Makefile.am
2 ===================================================================
3 --- gvfs-svn/daemon/Makefile.am (revision 2345)
4 +++ gvfs-svn/daemon/Makefile.am (working copy)
6 libexec_PROGRAMS += gvfsd-smb-browse gvfsd-smb
9 +mount_in_files += rar.mount.in
10 +mount_DATA += rar.mount
11 +libexec_PROGRAMS += gvfsd-rar
13 mount_in_files += cdda.mount.in
15 mount_DATA += cdda.mount
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 \
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)
42 +/* -*- Mode: C; tab-width: 4 -*- */
43 +/* GIO - GLib Input, Output and Streaming Library
45 + * Copyright (C) 2006-2007 Red Hat, Inc.
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.
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.
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.
62 + * Author: Valmantas Palikša <walmis@balticum-tv.lt>
67 +#include <sys/types.h>
68 +#include <sys/stat.h>
75 +#include <glib/gstdio.h>
76 +#include <glib/gi18n.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;
97 +G_DEFINE_TYPE (GVfsBackendRar, g_vfs_backend_rar, G_VFS_TYPE_BACKEND)
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);
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);
113 +get_file_info(GVfsBackendRar *backend, RarFile* file, GVfsJob* job)
115 + GFileInfo* info = g_hash_table_lookup(backend->info_cache, file);
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);
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);
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,
150 + g_file_info_set_attribute_uint32 (info,
151 + G_FILE_ATTRIBUTE_TIME_ACCESS_USEC,
154 + g_file_info_set_attribute_uint64 (info,
155 + G_FILE_ATTRIBUTE_TIME_MODIFIED,
157 + g_file_info_set_attribute_uint32 (info,
158 + G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
161 + g_file_info_set_attribute_uint64 (info,
162 + G_FILE_ATTRIBUTE_TIME_CREATED,
164 + g_file_info_set_attribute_uint32 (info,
165 + G_FILE_ATTRIBUTE_TIME_CREATED_USEC,
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);
183 +do_mount (GVfsBackend *backend,
185 + GMountSpec *mount_spec,
186 + GMountSource *mount_source,
187 + gboolean is_automount)
189 + GVfsBackendRar *rar_backend = G_VFS_BACKEND_RAR (backend);
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"));
207 + filename = g_uri_unescape_string (host, NULL);
209 + filename = g_strdup(file);
212 + rar_backend->archive = rar_archive_new(filename, &gerr);
215 + g_warning("%s", gerr->message);
217 + g_vfs_job_failed_from_error(G_VFS_JOB (job), gerr);
219 + g_error_free(gerr);
223 + /* in case no gerror is returned */
224 + if(!rar_backend->archive) {
225 + g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
227 + _("Unknown error"));
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");
239 + filename = g_uri_escape_string(filename, NULL, FALSE);
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);
248 + if(rar_backend->archive->has_encrypted) {
250 + gchar* passw = NULL;
251 + g_mount_source_ask_password(mount_source,
252 + _("This archive contains encrypted files, please enter the password."),
255 + G_ASK_PASSWORD_NEED_PASSWORD,
263 + rar_archive_set_password(rar_backend->archive, passw);
270 + g_vfs_job_succeeded (G_VFS_JOB (job));
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);
287 + GError* gerr = NULL;
289 + file = rar_file_find(rar_backend->archive, filename);
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"));
308 + handle = rar_handle_open(file, &gerr);
311 + g_vfs_job_failed_from_error(G_VFS_JOB (job), gerr);
312 + g_error_free(gerr);
315 + g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
317 + _("Unknown read error"));
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));
330 +do_read (GVfsBackend *backend,
332 + GVfsBackendHandle handle,
334 + gsize bytes_requested)
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);
346 + g_vfs_job_failed_from_error(G_VFS_JOB (job), gerr);
347 + g_warning("%s", gerr->message);
348 + g_error_free(gerr);
353 + g_vfs_job_read_set_size (job, res);
354 + g_vfs_job_succeeded (G_VFS_JOB (job));
360 +try_seek_on_read (GVfsBackend *backend,
361 + GVfsJobSeekRead *job,
362 + GVfsBackendHandle handle,
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"));
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,
386 + g_vfs_job_seek_read_set_offset (job, final_offset);
387 + g_vfs_job_succeeded (G_VFS_JOB (job));
394 +do_query_info (GVfsBackend *backend,
395 + GVfsJobQueryInfo *job,
396 + const char *filename,
397 + GFileQueryInfoFlags flags,
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);
406 + gchar* display_name;
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);
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);
427 + file = rar_file_find(rar_backend->archive, filename);
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);
435 + g_vfs_job_failed (G_VFS_JOB (job),
436 + G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
437 + _("File not found"));
444 + g_vfs_job_succeeded (G_VFS_JOB (job));
449 +do_enumerate (GVfsBackend *backend,
450 + GVfsJobEnumerate *job,
451 + const char *filename,
452 + GFileAttributeMatcher *matcher,
453 + GFileQueryInfoFlags flags)
457 + GVfsBackendRar *rar_backend = G_VFS_BACKEND_RAR (backend);
459 + RarDirectory* dir = rar_directory_find(rar_backend->archive, filename);
461 + RarDirectory* tmp = NULL;
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);
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);
506 + g_vfs_job_enumerate_done (job);
509 + g_vfs_job_failed (G_VFS_JOB (job),
510 + G_IO_ERROR,G_IO_ERROR_NOT_FOUND,
511 + _("Path not found"));
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));
530 +try_query_fs_info (GVfsBackend *backend,
531 + GVfsJobQueryFsInfo *job,
532 + const char *filename,
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));
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));
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)
579 +/* GIO - GLib Input, Output and Streaming Library
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>
601 +#ifndef __G_VFS_BACKEND_RAR_H__
602 +#define __G_VFS_BACKEND_RAR_H__
604 +#include <gvfsbackend.h>
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);
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)
635 +/* -*- Mode: C; tab-width: 4 -*- */
636 +/***************************************************************************
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.
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.
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
661 +#include "rararchive.h"
663 +#include <gio/gunixinputstream.h>
665 +#include <glib/gprintf.h>
666 +#include <glib/gi18n.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,
730 +static guint32 crc32(guint32 crc, guchar *buf, gsize len)
735 + for (end = buf + len; buf < end; ++buf)
736 + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
740 +static time_t dos2unixtime(guint32 dostime)
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);
759 + if (!ar->new_name_style) {
760 + gchar letter = 'r';
761 + letter += volid / 100;
764 + volid = volid % 100;
765 + return g_strdup_printf("%s.%c%02d", ar->basename, letter, volid);
767 + return g_strdup_printf("%s.part%0*d.rar", ar->basename, ar->padding, volid + 2);
773 +static RarVolume *rar_archive_load_volume(RarArchive *ar, gint volid, GError **gerr)
775 + gchar *name = get_vol_name(ar, volid);
777 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_TOO_MANY, _("Too many volumes"));
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))
788 + vol->file = g_file_read(f, NULL, gerr);
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);
798 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_MISSING_VOLUME, _("Volume %s is missing"), name);
807 +static void rar_directory_destroy_fn(RarDirectory *dir)
809 + g_return_if_fail(dir != NULL);
811 + g_hash_table_destroy(dir->dirs);
813 + g_slist_free(dir->files);
815 + g_slist_free(dir->dirs_l);
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);
829 + g_free(ar->password);
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);
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);
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;
869 + re1 = g_regex_new("\\.part([0-9]*)\\.rar$", G_REGEX_OPTIMIZE, 0, NULL);
871 + re2 = g_regex_new("\\.[r-z][0-9]*$", G_REGEX_OPTIMIZE, 0, NULL);
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)) {
885 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_MISSING_ARCHIVE, _("Archive %s not found"), filepath);
891 + ar->filepath = g_strdup(filepath);
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);
897 + ar->padding = strlen(match);
903 + g_match_info_free(minfo);
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);
910 + tmp = ar->basename;
911 + ar->basename = g_regex_replace_literal(re3, ar->basename, -1, 0, "", 0, NULL);
914 + if (!rar_archive_load(ar, gerr)) {
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);
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, "/"))
937 + if (strcmp(path, "") == 0) {
940 + gchar** path_segments = g_strsplit(path, "/", 0);
941 + gint num_segments = g_strv_length(path_segments);
942 + RarDirectory* pos = ar->root;
944 + for (i = 0; i < num_segments; i++) {
945 + pos = g_hash_table_lookup(pos->dirs, path_segments[i]);
947 + g_strfreev(path_segments);
952 + g_strfreev(path_segments);
957 +/* adds a file to an internal file tree */
958 +static void rar_archive_register_file(RarArchive* ar, RarFile* file)
962 + gchar** path_segments = g_strsplit(file->path, "/", 0);
963 + gint num_segments = g_strv_length(path_segments);
965 + RarDirectory* pos = ar->root;
968 + gchar** tmp_pathv = g_malloc0(sizeof(gchar* )* (num_segments + 1));
969 + gchar* tmp_path = NULL;
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) {
979 + tmp = g_hash_table_lookup(pos->dirs, path_segments[i]);
981 + tmp = rar_directory_alloc(path_segments[i]);
983 + g_hash_table_insert(pos->dirs, g_strdup(path_segments[i]), tmp);
984 + pos->dirs_l = g_slist_append(pos->dirs_l, tmp);
987 + pos->files = g_slist_append(pos->files, file);
988 + g_printf("Adding File %s to RarDirectory %s\n", path_segments[i], pos->name);
991 + tmp = g_hash_table_lookup(pos->dirs, path_segments[i]);
993 + tmp = rar_directory_alloc(path_segments[i]);
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);
1005 + g_free(tmp_pathv);
1006 + g_strfreev(path_segments);
1010 +RarFile* rar_file_find(RarArchive* ar, const gchar* path)
1012 + g_return_val_if_fail(path != NULL && ar != NULL, NULL);
1014 + if (g_str_has_prefix(path, "/"))
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);
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;
1056 + re1 = g_regex_new("^Encrypted file:[ ]*CRC failed in.*\\(password incorrect \\?\\)$",
1057 + G_REGEX_OPTIMIZE, 0, NULL);
1059 + gchar* line = NULL;
1061 + switch (condition) {
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);
1070 + if (status != G_IO_STATUS_NORMAL) {
1071 + g_mutex_unlock(handle->mutex);
1072 + rar_unref(handle);
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);
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);
1099 + g_mutex_unlock(handle->mutex);
1100 + rar_unref(handle);
1103 + g_mutex_unlock(handle->mutex);
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"));
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);
1118 + h->mutex = g_mutex_new();
1119 + g_mutex_lock(h->mutex);
1121 + if (file->compressed || file->encrypted) {
1122 + gint stdin, stdout, stderr;
1124 + if (file->parent_archive->password) {
1125 + pw = g_strdup_printf("-p%s", file->parent_archive->password);
1129 + args[i++] = "unrar";
1131 + args[i++] = "-ierr";
1132 + args[i++] = "-idp";
1136 + args[i++] = "-pnull";
1137 + args[i++] = file->parent_archive->filepath;
1138 + args[i++] = file->path;
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,
1148 + g_warning("Unrar spawn failed!");
1149 + g_mutex_unlock(h->mutex);
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 */
1167 + g_mutex_unlock(h->mutex);
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))
1193 + rar_ref(handle->file->parent_archive);
1199 + if (pos >= handle->file->size || pos < 0)
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);
1209 + if ((handle->offset + pos) >= handle->file->size || (handle->offset + pos) < 0)
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;
1219 + if ((handle->file->size + pos) >= handle->file->size || (handle->file->size + pos) < 0)
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;
1229 + rar_unref(handle->file->parent_archive);
1230 + rar_unref(handle);
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);
1240 + g_mutex_lock(handle->mutex);
1242 + if (handle->file->parent_archive->wrong_password) {
1243 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_WRONG_PASSWORD, _("Wrong decryption password"));
1247 + if (handle->error_condition > 0) {
1248 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_UNKNOWN, _("Unknown error"));
1253 + res = g_input_stream_read(handle->pipe, buffer, len, cancellable, gerr);
1255 + g_mutex_unlock(handle->mutex);
1256 + rar_unref(handle);
1257 + rar_unref(handle->file->parent_archive);
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);
1268 + g_mutex_lock(handle->mutex);
1270 + goffset rel_offset = 0;
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)
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;
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)) {
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);
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);
1309 + handle->offset += len;
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);
1320 +static gboolean rar_archive_load(RarArchive* ar, GError** gerr)
1324 + BlockHeader header;
1325 + goffset data_size;
1327 + gchar* full_header;
1331 + gboolean next_volume;
1337 + next_volume = FALSE;
1338 + RarVolume* vol = rar_archive_load_volume(ar, n++, gerr);
1344 + if (g_input_stream_read(G_INPUT_STREAM(vol->file), mark, 7, NULL, gerr) == -1) {
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"));
1357 + if(!g_input_stream_read_all(G_INPUT_STREAM(vol->file), &header, sizeof(BlockHeader), &read, NULL, gerr)) {
1361 + /* some archives dont have ENDARC_HEAD headers */
1362 + if(read == 0 && next_volume) {
1363 + /* let's move on to the next volume */
1366 + if(read == 0 && !next_volume){
1367 + /* looks like we're finished */
1373 + g_printf("Header type: 0x%x\n", header.HeadType);
1375 + if (header.HeadType == ENDARC_HEAD) {
1376 + if ((header.Flags & 0x0001) == 0 && !next_volume) { /*no next volume */
1383 + full_header = g_malloc(header.HeadSize);
1384 + if (!full_header) {
1385 + g_set_error(gerr, RAR_ERROR, RAR_ERROR_INVALID_HEADER, _("Invalid header"));
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);
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);
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"),
1411 + g_free(full_header);
1415 + data_size = header.DataSize;
1416 + switch (header.HeadType) {
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"));
1429 +/* case NEWSUB_HEAD:
1430 + g_set_error(gerr, RAR_ERROR,
1431 + RAR_ERROR_UNSUPPORTED_HEADER,
1432 + _("Subheaders are not supported"));
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);
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);
1463 + for (i = 0;; i++) {
1464 + if (filename[i] == 0)
1466 + if (filename[i] == '\\')
1467 + filename[i] = '/';
1470 + if ((file_entry->Flags & 0xE0) == 0xE0)
1475 + f = rar_file_find(ar, filename);
1477 + f = g_new0(RarFile, 1);
1479 + f->path = g_strdup(filename);
1480 + f->name = g_path_get_basename(filename);
1482 + f->parent_archive = ar;
1484 + f->size = int32to64(unp_high, file_entry->UnpSize);
1485 + ar->total_size += f->size;
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;
1503 + MemoryMap* map = g_new0(MemoryMap, 1);
1505 + map->start = g_seekable_tell(G_SEEKABLE(vol->file));
1507 + map->end = map->start + data_size;
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;
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;
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);
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);
1556 + g_printf("Unknown block 0x%x\n", header.HeadType);
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)) {
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)
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.
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.
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
1608 +#define _FILE_OFFSET_BITS 64
1611 +#include <gio/gio.h>
1613 +#include <sys/types.h>
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))
1639 + PROTECT_HEAD=0x78,
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
1660 +#pragma pack(push) /* push current alignment to stack */
1661 +#pragma pack(1) /* set alignment to 1 byte boundary */
1670 + guint32 Reserved1;
1671 +} MainArchiveHeader;
1699 +#pragma pack(pop) /* restore original alignment from stack */
1701 +typedef struct _RarArchive RarArchive;
1704 + GFileInputStream* file;
1707 + MainArchiveHeader* main_header;
1708 + RarArchive* parent_archive;
1709 + GMutex* mutex; /* for io synchronization */
1713 + goffset off_start;
1720 +/* all items (files and directories) are stored in RarFile,
1721 +for file tree traversal RarDirectories are used */
1723 + //BlockFileHeader* file_header;
1724 + RarArchive* parent_archive;
1726 + goffset p_size; /* packed size */
1727 + goffset size; /* unpacked size */
1731 + guint8 dir : 1; /* a directory? */
1732 + guint8 compressed : 1;
1733 + guint8 encrypted : 1;
1737 + GPtrArray* memory_maps; /* MemoryMap* */
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;
1755 +typedef struct _RarDirectory {
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;
1763 +struct _RarArchive{
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;
1793 +void __rar_ref(RarRefCountable* obj);
1794 +void __rar_unref(RarRefCountable* obj);
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,
1815 + GCancellable* cancellable,
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)
1824 +Exec=@libexecdir@/gvfsd-rar