summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--uniso.c108
1 files changed, 57 insertions, 51 deletions
diff --git a/uniso.c b/uniso.c
index bb3b27a..7e1adb6 100644
--- a/uniso.c
+++ b/uniso.c
@@ -217,117 +217,114 @@ struct uniso_context {
static int do_splice(struct uniso_context *ctx, int to_fd, int bytes)
{
- int r;
+ int r, left;
- do {
- r = splice(ctx->stream_fd, NULL, to_fd, NULL, bytes,
+ for (left = bytes; left; ) {
+ r = splice(ctx->stream_fd, NULL, to_fd, NULL, left,
SPLICE_F_MOVE);
- if (r < 0)
- return -errno;
-
- bytes -= r;
+ if (r < 0) return -errno;
+ if (r == 0) return bytes - left;
+ left -= r;
ctx->pos += r;
- } while (bytes != 0);
+ }
- return 0;
+ return bytes;
}
static int do_read(struct uniso_context *ctx, unsigned char *buf, int bytes)
{
- int r;
+ int r, left;
- do {
- r = read(ctx->stream_fd, buf, bytes);
+ for (left = bytes; left; ) {
+ r = read(ctx->stream_fd, buf, left);
if (r < 0) {
perror("read");
return -errno;
}
- bytes -= r;
+ if (r == 0) return bytes - left;
+ left -= r;
buf += r;
ctx->pos += r;
- } while (bytes != 0);
+ }
- return 0;
+ return bytes;
}
static int do_write(int tofd, const unsigned char *buf, int bytes)
{
- int r;
+ int r, left;
- do {
- r = write(tofd, buf, bytes);
+ for (left = bytes; left; ) {
+ r = write(tofd, buf, left);
if (r < 0) {
perror("write");
return -errno;
}
- bytes -= r;
+ left -= r;
buf += r;
- } while (bytes != 0);
+ }
- return 0;
+ return bytes;
}
static int do_skip(struct uniso_context *ctx, unsigned int bytes)
{
- int r, now;
+ int r, left, now;
switch (ctx->skip_method) {
case 0:
if (lseek(ctx->stream_fd, bytes, SEEK_CUR) != (off_t) -1) {
ctx->pos += bytes;
- break;
+ return bytes;
}
ctx->skip_method = 1;
case 1:
- if (do_splice(ctx, ctx->null_fd, bytes) == 0)
- break;
+ r = do_splice(ctx, ctx->null_fd, bytes);
+ if (r >= 0) return r;
ctx->skip_method = 2;
case 2:
- while (bytes) {
- now = bytes;
+ for (left = bytes; left; ) {
+ now = left;
if (now > ISOFS_TMPBUF_SIZE)
now = ISOFS_TMPBUF_SIZE;
-
r = do_read(ctx, ctx->tmpbuf, now);
- if (r < 0)
- return r;
-
- bytes -= now;
+ if (r < 0) return r;
+ if (r == 0) return bytes - left;
+ left -= now;
}
- break;
+ return bytes;
}
return 0;
}
-static int do_copy(struct uniso_context *ctx, int tofd, unsigned int bytes)
+static int do_copy(struct uniso_context *ctx, int tofd, int bytes)
{
- int r, now;
+ int r, now, left;
switch (ctx->copy_method) {
case 0:
- if (do_splice(ctx, tofd, bytes) == 0)
- break;
+ r = do_splice(ctx, tofd, bytes);
+ if (r >= 0) return r;
ctx->skip_method = 1;
case 1:
/* FIXME: Use mmaped IO */
ctx->skip_method = 2;
case 2:
- while (bytes) {
- now = bytes;
+ for (left = bytes; left; ) {
+ now = left;
if (now > ISOFS_TMPBUF_SIZE)
now = ISOFS_TMPBUF_SIZE;
r = do_read(ctx, ctx->tmpbuf, now);
- if (r < 0)
- return r;
+ if (r <= 0) return r < 0 ? r : -EIO;
+ now = r;
r = do_write(tofd, ctx->tmpbuf, now);
- if (r < 0)
- return r;
+ if (r != now) return r < 0 ? r : -EIO;
- bytes -= now;
+ left -= now;
}
- break;
+ return bytes;
}
return 0;
}
@@ -392,12 +389,10 @@ static int link_or_clone(const char *src, const char *dst, size_t bytes)
if (now > sizeof(buf))
now = sizeof(buf);
r = read(src_fd, buf, now);
- if (r < 0)
- return r;
+ if (r < 0) return r;
r = write(dst_fd, buf, now);
- if (r < 0)
- return r;
+ if (r < 0) return r;
bytes -= now;
}
close(dst_fd);
@@ -441,7 +436,9 @@ static int uniso_read_file(struct uniso_context *ctx,
rc = do_copy(ctx, fd, dir->size);
close(fd);
- return rc;
+ if (rc < 0) return rc;
+ if (rc != dir->size) return -EIO;
+ return 0;
}
static int uniso_read_directory(struct uniso_context *ctx,
@@ -581,7 +578,7 @@ int uniso(int fd)
{
struct uniso_context context, *ctx = &context;
struct uniso_reader *rd;
- int r;
+ int r, skipped;
memset(ctx, 0, sizeof(*ctx));
list_init(&ctx->parser_head);
@@ -608,6 +605,15 @@ int uniso(int fd)
return r;
}
+ if (ctx->skip_method) {
+ skipped = 0;
+ do {
+ r = do_skip(ctx, ISOFS_TMPBUF_SIZE);
+ if (r > 0) skipped += r;
+ } while (r == ISOFS_TMPBUF_SIZE);
+ if (ctx->loglevel > 1) fprintf(stderr, "Skipped %d bytes at the end\n", skipped);
+ }
+
free(ctx->tmpbuf);
close(ctx->null_fd);
}