archive: use reference counting for archive+input

Make the input_stream implementation hold a reference on the
archive_file object.  Allow the caller to "close" the archive_file
object immediately, no matter if the open_stream() method has
succeeded or not.
This commit is contained in:
Max Kellermann 2009-12-31 10:02:55 +01:00
parent 032c5376ad
commit aad05fd138
5 changed files with 32 additions and 8 deletions

View File

@ -25,6 +25,7 @@
#include "archive/bz2_archive_plugin.h" #include "archive/bz2_archive_plugin.h"
#include "archive_api.h" #include "archive_api.h"
#include "input_plugin.h" #include "input_plugin.h"
#include "refcount.h"
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
@ -40,6 +41,8 @@
struct bz2_archive_file { struct bz2_archive_file {
struct archive_file base; struct archive_file base;
struct refcount ref;
char *name; char *name;
bool reset; bool reset;
struct input_stream istream; struct input_stream istream;
@ -105,6 +108,7 @@ bz2_open(const char *pathname, GError **error_r)
context = g_malloc(sizeof(*context)); context = g_malloc(sizeof(*context));
archive_file_init(&context->base, &bz2_archive_plugin); archive_file_init(&context->base, &bz2_archive_plugin);
refcount_init(&context->ref);
//open archive //open archive
if (!input_stream_open(&context->istream, pathname, error_r)) { if (!input_stream_open(&context->istream, pathname, error_r)) {
@ -149,6 +153,9 @@ bz2_close(struct archive_file *file)
{ {
struct bz2_archive_file *context = (struct bz2_archive_file *) file; struct bz2_archive_file *context = (struct bz2_archive_file *) file;
if (!refcount_dec(&context->ref))
return;
g_free(context->name); g_free(context->name);
input_stream_close(&context->istream); input_stream_close(&context->istream);
@ -180,6 +187,8 @@ bz2_open_stream(struct archive_file *file, struct input_stream *is,
bis->eof = false; bis->eof = false;
refcount_inc(&context->ref);
return true; return true;
} }

View File

@ -25,6 +25,7 @@
#include "archive/iso9660_archive_plugin.h" #include "archive/iso9660_archive_plugin.h"
#include "archive_api.h" #include "archive_api.h"
#include "input_plugin.h" #include "input_plugin.h"
#include "refcount.h"
#include <cdio/cdio.h> #include <cdio/cdio.h>
#include <cdio/iso9660.h> #include <cdio/iso9660.h>
@ -37,6 +38,8 @@
struct iso9660_archive_file { struct iso9660_archive_file {
struct archive_file base; struct archive_file base;
struct refcount ref;
iso9660_t *iso; iso9660_t *iso;
GSList *list; GSList *list;
GSList *iter; GSList *iter;
@ -93,6 +96,7 @@ iso9660_archive_open(const char *pathname, GError **error_r)
g_new(struct iso9660_archive_file, 1); g_new(struct iso9660_archive_file, 1);
archive_file_init(&context->base, &iso9660_archive_plugin); archive_file_init(&context->base, &iso9660_archive_plugin);
refcount_init(&context->ref);
context->list = NULL; context->list = NULL;
@ -139,8 +143,11 @@ iso9660_archive_close(struct archive_file *file)
{ {
struct iso9660_archive_file *context = struct iso9660_archive_file *context =
(struct iso9660_archive_file *)file; (struct iso9660_archive_file *)file;
GSList *tmp; GSList *tmp;
if (!refcount_dec(&context->ref))
return;
if (context->list) { if (context->list) {
//free list //free list
for (tmp = context->list; tmp != NULL; tmp = g_slist_next(tmp)) for (tmp = context->list; tmp != NULL; tmp = g_slist_next(tmp))
@ -192,6 +199,9 @@ iso9660_archive_open_stream(struct archive_file *file, struct input_stream *is,
is->size = iis->statbuf->size; is->size = iis->statbuf->size;
iis->max_blocks = CEILING(iis->statbuf->size, ISO_BLOCKSIZE); iis->max_blocks = CEILING(iis->statbuf->size, ISO_BLOCKSIZE);
refcount_inc(&context->ref);
return true; return true;
} }

View File

@ -26,6 +26,7 @@
#include "archive_api.h" #include "archive_api.h"
#include "archive_api.h" #include "archive_api.h"
#include "input_plugin.h" #include "input_plugin.h"
#include "refcount.h"
#include <zzip/zzip.h> #include <zzip/zzip.h>
#include <glib.h> #include <glib.h>
@ -34,6 +35,8 @@
struct zzip_archive { struct zzip_archive {
struct archive_file base; struct archive_file base;
struct refcount ref;
ZZIP_DIR *dir; ZZIP_DIR *dir;
GSList *list; GSList *list;
GSList *iter; GSList *iter;
@ -56,6 +59,7 @@ zzip_archive_open(const char *pathname, GError **error_r)
ZZIP_DIRENT dirent; ZZIP_DIRENT dirent;
archive_file_init(&context->base, &zzip_archive_plugin); archive_file_init(&context->base, &zzip_archive_plugin);
refcount_init(&context->ref);
// open archive // open archive
context->list = NULL; context->list = NULL;
@ -102,6 +106,10 @@ static void
zzip_archive_close(struct archive_file *file) zzip_archive_close(struct archive_file *file)
{ {
struct zzip_archive *context = (struct zzip_archive *) file; struct zzip_archive *context = (struct zzip_archive *) file;
if (!refcount_dec(&context->ref))
return;
if (context->list) { if (context->list) {
//free list //free list
for (GSList *tmp = context->list; tmp != NULL; tmp = g_slist_next(tmp)) for (GSList *tmp = context->list; tmp != NULL; tmp = g_slist_next(tmp))
@ -151,6 +159,9 @@ zzip_archive_open_stream(struct archive_file *file, struct input_stream *is,
zzip_file_stat(zis->file, &z_stat); zzip_file_stat(zis->file, &z_stat);
is->size = z_stat.st_size; is->size = z_stat.st_size;
refcount_inc(&context->ref);
return true; return true;
} }

View File

@ -67,9 +67,6 @@ struct archive_plugin {
/** /**
* Opens an input_stream of a file within the archive. * Opens an input_stream of a file within the archive.
* *
* If this function succeeds, then the #input_stream "owns"
* the archive file and will automatically close it.
*
* @param path the path within the archive * @param path the path within the archive
* @param error_r location to store the error occuring, or * @param error_r location to store the error occuring, or
* NULL to ignore errors * NULL to ignore errors

View File

@ -67,11 +67,8 @@ input_archive_open(struct input_stream *is, const char *pathname,
//setup fileops //setup fileops
opened = archive_file_open_stream(file, is, filename, error_r); opened = archive_file_open_stream(file, is, filename, error_r);
g_free(pname);
if (!opened) {
archive_file_close(file); archive_file_close(file);
} g_free(pname);
return opened; return opened;
} }