X-Git-Url: https://git.sven.stormbind.net/?p=sven%2Fexfat-utils.git;a=blobdiff_plain;f=libexfat%2Fio.c;h=bc92c7cf9eab396eb465b93400cff7fc448a778b;hp=514383ca4bedb64bf12ed4a28c6e4bbf3c87d6f6;hb=276900f1c02916b78f58fa21b736aa80ffd04bf5;hpb=2fa6c5654e0a345af10df5227b77d9f468759f20 diff --git a/libexfat/io.c b/libexfat/io.c index 514383c..bc92c7c 100644 --- a/libexfat/io.c +++ b/libexfat/io.c @@ -3,7 +3,7 @@ exFAT file system implementation library. Free exFAT implementation. - Copyright (C) 2010-2017 Andrew Nayenko + Copyright (C) 2010-2018 Andrew Nayenko This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,16 +35,30 @@ #include #include #include -#endif +#elif __linux__ #include +#endif +#ifdef USE_UBLIO +#include +#include +#endif struct exfat_dev { int fd; enum exfat_mode mode; off_t size; /* in bytes */ +#ifdef USE_UBLIO + off_t pos; + ublio_filehandle_t ufh; +#endif }; +static bool is_open(int fd) +{ + return fcntl(fd, F_GETFD) != -1; +} + static int open_ro(const char* spec) { return open(spec, O_RDONLY); @@ -74,6 +88,27 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) { struct exfat_dev* dev; struct stat stbuf; +#ifdef USE_UBLIO + struct ublio_param up; +#endif + + /* The system allocates file descriptors sequentially. If we have been + started with stdin (0), stdout (1) or stderr (2) closed, the system + will give us descriptor 0, 1 or 2 later when we open block device, + FUSE communication pipe, etc. As a result, functions using stdin, + stdout or stderr will actually work with a different thing and can + corrupt it. Protect descriptors 0, 1 and 2 from such misuse. */ + while (!is_open(STDIN_FILENO) + || !is_open(STDOUT_FILENO) + || !is_open(STDERR_FILENO)) + { + /* we don't need those descriptors, let them leak */ + if (open("/dev/null", O_RDWR) == -1) + { + exfat_error("failed to open /dev/null"); + return NULL; + } + } dev = malloc(sizeof(struct exfat_dev)); if (dev == NULL) @@ -211,6 +246,24 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) } } +#ifdef USE_UBLIO + memset(&up, 0, sizeof(struct ublio_param)); + up.up_blocksize = 256 * 1024; + up.up_items = 64; + up.up_grace = 32; + up.up_priv = &dev->fd; + + dev->pos = 0; + dev->ufh = ublio_open(&up); + if (dev->ufh == NULL) + { + close(dev->fd); + free(dev); + exfat_error("failed to initialize ublio"); + return NULL; + } +#endif + return dev; } @@ -218,6 +271,13 @@ int exfat_close(struct exfat_dev* dev) { int rc = 0; +#ifdef USE_UBLIO + if (ublio_close(dev->ufh) != 0) + { + exfat_error("failed to close ublio"); + rc = -EIO; + } +#endif if (close(dev->fd) != 0) { exfat_error("failed to close device: %s", strerror(errno)); @@ -231,6 +291,13 @@ int exfat_fsync(struct exfat_dev* dev) { int rc = 0; +#ifdef USE_UBLIO + if (ublio_fsync(dev->ufh) != 0) + { + exfat_error("ublio fsync failed"); + rc = -EIO; + } +#endif if (fsync(dev->fd) != 0) { exfat_error("fsync failed: %s", strerror(errno)); @@ -251,29 +318,56 @@ off_t exfat_get_size(const struct exfat_dev* dev) off_t exfat_seek(struct exfat_dev* dev, off_t offset, int whence) { +#ifdef USE_UBLIO + /* XXX SEEK_CUR will be handled incorrectly */ + return dev->pos = lseek(dev->fd, offset, whence); +#else return lseek(dev->fd, offset, whence); +#endif } ssize_t exfat_read(struct exfat_dev* dev, void* buffer, size_t size) { +#ifdef USE_UBLIO + ssize_t result = ublio_pread(dev->ufh, buffer, size, dev->pos); + if (result >= 0) + dev->pos += size; + return result; +#else return read(dev->fd, buffer, size); +#endif } ssize_t exfat_write(struct exfat_dev* dev, const void* buffer, size_t size) { +#ifdef USE_UBLIO + ssize_t result = ublio_pwrite(dev->ufh, buffer, size, dev->pos); + if (result >= 0) + dev->pos += size; + return result; +#else return write(dev->fd, buffer, size); +#endif } ssize_t exfat_pread(struct exfat_dev* dev, void* buffer, size_t size, off_t offset) { +#ifdef USE_UBLIO + return ublio_pread(dev->ufh, buffer, size, offset); +#else return pread(dev->fd, buffer, size, offset); +#endif } ssize_t exfat_pwrite(struct exfat_dev* dev, const void* buffer, size_t size, off_t offset) { +#ifdef USE_UBLIO + return ublio_pwrite(dev->ufh, buffer, size, offset); +#else return pwrite(dev->fd, buffer, size, offset); +#endif } ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node, @@ -289,7 +383,7 @@ ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node, return 0; cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb)); - if (CLUSTER_INVALID(cluster)) + if (CLUSTER_INVALID(*ef->sb, cluster)) { exfat_error("invalid cluster 0x%x while reading", cluster); return -EIO; @@ -299,7 +393,7 @@ ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node, remainder = MIN(size, node->size - offset); while (remainder > 0) { - if (CLUSTER_INVALID(cluster)) + if (CLUSTER_INVALID(*ef->sb, cluster)) { exfat_error("invalid cluster 0x%x while reading", cluster); return -EIO; @@ -345,7 +439,7 @@ ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node, return 0; cluster = exfat_advance_cluster(ef, node, offset / CLUSTER_SIZE(*ef->sb)); - if (CLUSTER_INVALID(cluster)) + if (CLUSTER_INVALID(*ef->sb, cluster)) { exfat_error("invalid cluster 0x%x while writing", cluster); return -EIO; @@ -355,7 +449,7 @@ ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node, remainder = size; while (remainder > 0) { - if (CLUSTER_INVALID(cluster)) + if (CLUSTER_INVALID(*ef->sb, cluster)) { exfat_error("invalid cluster 0x%x while writing", cluster); return -EIO;