alloc_sb.o \
alloc_stats.o \
alloc_tables.o \
+ atexit.o \
badblocks.o \
bb_inode.o \
bitmaps.o \
$(srcdir)/alloc_sb.c \
$(srcdir)/alloc_stats.c \
$(srcdir)/alloc_tables.c \
+ $(srcdir)/atexit.c \
$(srcdir)/badblocks.c \
$(srcdir)/bb_compat.c \
$(srcdir)/bb_inode.c \
$(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/ext2fsP.h
+atexit.o: $(srcdir)/atexit.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/ext2fsP.h
badblocks.o: $(srcdir)/badblocks.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
--- /dev/null
+/*
+ * atexit.c --- Clean things up when we exit normally.
+ *
+ * Copyright Oracle, 2014
+ * Author Darrick J. Wong <darrick.wong@oracle.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include "config.h"
+#include <stdlib.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "ext2fsP.h"
+
+struct exit_data {
+ ext2_exit_fn func;
+ void *data;
+};
+
+static struct exit_data *items;
+static size_t nr_items;
+
+static void handle_exit(void)
+{
+ struct exit_data *ed;
+
+ for (ed = items + nr_items - 1; ed >= items; ed--) {
+ if (ed->func == NULL)
+ continue;
+ ed->func(ed->data);
+ }
+
+ ext2fs_free_mem(&items);
+ nr_items = 0;
+}
+
+/*
+ * Schedule a function to be called at (normal) program termination.
+ * If you want this to be called during a signal exit, you must capture
+ * the signal and call exit() yourself!
+ */
+errcode_t ext2fs_add_exit_fn(ext2_exit_fn func, void *data)
+{
+ struct exit_data *ed, *free_ed = NULL;
+ size_t x;
+ errcode_t ret;
+
+ if (func == NULL)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ for (x = 0, ed = items; x < nr_items; x++, ed++) {
+ if (ed->func == func && ed->data == data)
+ return EXT2_ET_FILE_EXISTS;
+ if (ed->func == NULL)
+ free_ed = ed;
+ }
+
+ if (free_ed) {
+ free_ed->func = func;
+ free_ed->data = data;
+ return 0;
+ }
+
+ if (nr_items == 0) {
+ ret = atexit(handle_exit);
+ if (ret)
+ return ret;
+ }
+
+ ret = ext2fs_resize_mem(0, (nr_items + 1) * sizeof(struct exit_data),
+ &items);
+ if (ret)
+ return ret;
+
+ items[nr_items].func = func;
+ items[nr_items].data = data;
+ nr_items++;
+
+ return 0;
+}
+
+/* Remove a function from the exit cleanup list. */
+errcode_t ext2fs_remove_exit_fn(ext2_exit_fn func, void *data)
+{
+ struct exit_data *ed;
+ size_t x;
+
+ if (func == NULL)
+ return EXT2_ET_INVALID_ARGUMENT;
+
+ for (x = 0, ed = items; x < nr_items; x++, ed++) {
+ if (ed->func == NULL)
+ return 0;
+ if (ed->func == func && ed->data == data) {
+ size_t sz = (nr_items - (x + 1)) *
+ sizeof(struct exit_data);
+ memmove(ed, ed + 1, sz);
+ memset(items + nr_items - 1, 0,
+ sizeof(struct exit_data));
+ }
+ }
+
+ return 0;
+}
extern int ext2fs_file_block_offset_too_big(ext2_filsys fs,
struct ext2_inode *inode,
blk64_t offset);
+
+/* atexit support */
+typedef void (*ext2_exit_fn)(void *);
+errcode_t ext2fs_add_exit_fn(ext2_exit_fn fn, void *data);
+errcode_t ext2fs_remove_exit_fn(ext2_exit_fn fn, void *data);
#include "ext2_fs.h"
#include "ext2fs.h"
+#include "ext2fsP.h"
#ifdef __GNUC__
#define ATTR(x) __attribute__(x)
ext2fs_block_bitmap written_block_map;
struct struct_ext2_filsys fake_fs;
-
+ char *tdb_file;
struct undo_header hdr;
};
#define KEYS_PER_BLOCK(d) (((d)->tdb_data_size / sizeof(struct undo_key)) - 1)
return retval;
}
+static void undo_atexit(void *p)
+{
+ struct undo_private_data *data = p;
+ errcode_t err;
+
+ err = write_undo_indexes(data);
+ io_channel_close(data->undo_file);
+
+ com_err(data->tdb_file, err, "while force-closing undo file");
+}
+
static errcode_t undo_open(const char *name, int flags, io_channel *channel)
{
io_channel io = NULL;
if (retval)
goto cleanup;
- undo_fd = ext2fs_open_file(tdb_file, O_RDWR | O_CREAT, 0600);
+ data->tdb_file = strdup(tdb_file);
+ if (data->tdb_file == NULL)
+ goto cleanup;
+ undo_fd = ext2fs_open_file(data->tdb_file, O_RDWR | O_CREAT,
+ 0600);
if (undo_fd < 0)
goto cleanup;
- retval = undo_io_backing_manager->open(tdb_file, IO_FLAG_RW,
+ retval = undo_io_backing_manager->open(data->tdb_file,
+ IO_FLAG_RW,
&data->undo_file);
if (retval)
goto cleanup;
if (retval)
goto cleanup;
}
+ retval = ext2fs_add_exit_fn(undo_atexit, data);
+ if (retval)
+ goto cleanup;
*channel = io;
if (undo_fd >= 0)
return retval;
cleanup:
+ ext2fs_remove_exit_fn(undo_atexit, data);
if (undo_fd >= 0)
close(undo_fd);
if (data && data->undo_file)
io_channel_close(data->undo_file);
+ if (data && data->tdb_file)
+ free(data->tdb_file);
if (data && data->real)
io_channel_close(data->real);
if (data)
err = write_undo_indexes(data);
if (data->real)
retval = io_channel_close(data->real);
+ if (data->tdb_file)
+ free(data->tdb_file);
if (data->undo_file)
io_channel_close(data->undo_file);
ext2fs_free_mem(&data->keyb);
if (data->written_block_map)
ext2fs_free_generic_bitmap(data->written_block_map);
+ ext2fs_remove_exit_fn(undo_atexit, data);
ext2fs_free_mem(&channel->private_data);
if (channel->name)
ext2fs_free_mem(&channel->name);