summaryrefslogtreecommitdiff
path: root/uniso.c
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2011-03-10 15:07:02 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2011-03-10 15:07:02 +0000
commitad87bc74d6ced0fae179847f19aa20f2d698264f (patch)
tree802503e90d0ee5bad45707e1022c14cba52922c5 /uniso.c
parentc39a30b6351f739644e92fcfbeea1dff7adede99 (diff)
downloadalpine-conf-ad87bc74d6ced0fae179847f19aa20f2d698264f.zip
uniso: try handle shared extents
We check if its shared with previous file. If it is, we try create a hardlink or we clone it. This should work in most cases.
Diffstat (limited to 'uniso.c')
-rw-r--r--uniso.c49
1 files changed, 48 insertions, 1 deletions
diff --git a/uniso.c b/uniso.c
index 2087c79..7606b0c 100644
--- a/uniso.c
+++ b/uniso.c
@@ -367,22 +367,69 @@ static int queue_reader(
static int queue_dirent(struct uniso_context *ctx, void *isode, const char *name);
+static int link_or_clone(const char *src, const char *dst, size_t bytes)
+{
+ int src_fd, dst_fd;
+ int r;
+ static char buf[ISOFS_TMPBUF_SIZE];
+
+ if (link(src, dst) == 0)
+ return 0;
+
+ src_fd = open(src, O_RDONLY);
+ if (src_fd < 0)
+ return src_fd;
+
+ dst_fd = open(dst, O_WRONLY | O_TRUNC | O_CREAT, 0777);
+ if (dst_fd < 0) {
+ close(src_fd);
+ return dst_fd;
+ }
+
+ while (bytes) {
+ size_t now = bytes;
+ if (now > sizeof(buf))
+ now = sizeof(buf);
+ r = read(src_fd, buf, now);
+ if (r < 0)
+ return r;
+
+ r = write(dst_fd, buf, now);
+ if (r < 0)
+ return r;
+ bytes -= now;
+ }
+ close(dst_fd);
+ close(src_fd);
+ return 0;
+}
+
static int uniso_read_file(struct uniso_context *ctx,
struct uniso_reader *rd)
{
struct uniso_dirent *dir = container_of(rd, struct uniso_dirent, reader);
int fd, rc;
+ static size_t prev_offset = 0;
+ static char prev_name[512];
+ static size_t prev_size = 0;
// FIXME: seems that hardlinked files get the same file extent
// shared. need to fix extraction of such files.
if (ctx->pos > rd->offset) {
- if (ctx->loglevel > 0)
+ rc = 1;
+ if (rd->offset == prev_offset)
+ rc = link_or_clone(prev_name, dir->name, prev_size);
+ if (ctx->loglevel > 0 && rc != 0)
fprintf(stderr, "WARNING: Not extracting '%s' as "
"it's sharing file-extents with "
"another file\n", dir->name);
return 0;
}
+ prev_offset = rd->offset;
+ strncpy(prev_name, dir->name, sizeof(prev_name));
+ prev_size = dir->size;
+
fd = open(dir->name, O_WRONLY | O_TRUNC | O_CREAT, 0777);
if (fd < 0)
return -errno;