diff options
Diffstat (limited to 'exfat/libexfat/io.c')
-rw-r--r-- | exfat/libexfat/io.c | 114 |
1 files changed, 79 insertions, 35 deletions
diff --git a/exfat/libexfat/io.c b/exfat/libexfat/io.c index 306c5dd06..3d7aaad2e 100644 --- a/exfat/libexfat/io.c +++ b/exfat/libexfat/io.c @@ -3,7 +3,7 @@ exFAT file system implementation library. Free exFAT implementation. - Copyright (C) 2010-2013 Andrew Nayenko + Copyright (C) 2010-2015 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 @@ -24,13 +24,19 @@ #include <inttypes.h> #include <sys/types.h> #include <sys/stat.h> -#include <sys/mount.h> #include <fcntl.h> #include <unistd.h> #include <string.h> -#ifdef __APPLE__ +#include <errno.h> +#if defined(__APPLE__) #include <sys/disk.h> +#elif defined(__OpenBSD__) +#include <sys/param.h> +#include <sys/disklabel.h> +#include <sys/dkio.h> +#include <sys/ioctl.h> #endif +#include <sys/mount.h> #ifdef USE_UBLIO #include <sys/uio.h> #include <ublio.h> @@ -40,9 +46,9 @@ struct exfat_dev { int fd; enum exfat_mode mode; - off64_t size; /* in bytes */ + off_t size; /* in bytes */ #ifdef USE_UBLIO - off64_t pos; + off_t pos; ublio_filehandle_t ufh; #endif }; @@ -65,6 +71,7 @@ static int open_rw(const char* spec) if (fd != -1 && ioctl(fd, BLKROGET, &ro) == 0 && ro) { close(fd); + errno = EROFS; return -1; } #endif @@ -93,7 +100,8 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) if (dev->fd == -1) { free(dev); - exfat_error("failed to open `%s' in read-only mode", spec); + exfat_error("failed to open '%s' in read-only mode: %s", spec, + strerror(errno)); return NULL; } dev->mode = EXFAT_MODE_RO; @@ -103,7 +111,8 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) if (dev->fd == -1) { free(dev); - exfat_error("failed to open `%s' in read-write mode", spec); + exfat_error("failed to open '%s' in read-write mode: %s", spec, + strerror(errno)); return NULL; } dev->mode = EXFAT_MODE_RW; @@ -119,11 +128,11 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) if (dev->fd != -1) { dev->mode = EXFAT_MODE_RO; - exfat_warn("`%s' is write-protected, mounting read-only", spec); + exfat_warn("'%s' is write-protected, mounting read-only", spec); break; } free(dev); - exfat_error("failed to open `%s'", spec); + exfat_error("failed to open '%s': %s", spec, strerror(errno)); return NULL; } @@ -131,7 +140,7 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) { close(dev->fd); free(dev); - exfat_error("failed to fstat `%s'", spec); + exfat_error("failed to fstat '%s'", spec); return NULL; } if (!S_ISBLK(stbuf.st_mode) && @@ -140,11 +149,11 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) { close(dev->fd); free(dev); - exfat_error("`%s' is neither a device, nor a regular file", spec); + exfat_error("'%s' is neither a device, nor a regular file", spec); return NULL; } -#ifdef __APPLE__ +#if defined(__APPLE__) if (!S_ISREG(stbuf.st_mode)) { uint32_t block_size = 0; @@ -167,6 +176,32 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) dev->size = blocks * block_size; } else +#elif defined(__OpenBSD__) + if (!S_ISREG(stbuf.st_mode)) + { + struct disklabel lab; + struct partition* pp; + char* partition; + + if (ioctl(dev->fd, DIOCGDINFO, &lab) == -1) + { + close(dev->fd); + free(dev); + exfat_error("failed to get disklabel"); + return NULL; + } + + /* Don't need to check that partition letter is valid as we won't get + this far otherwise. */ + partition = strchr(spec, '\0') - 1; + pp = &(lab.d_partitions[*partition - 'a']); + dev->size = DL_GETPSIZE(pp) * lab.d_secsize; + + if (pp->p_fstype != FS_NTFS) + exfat_warn("partition type is not 0x07 (NTFS/exFAT); " + "you can fix this with fdisk(8)"); + } + else #endif { /* works for Linux, FreeBSD, Solaris */ @@ -175,14 +210,14 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) { close(dev->fd); free(dev); - exfat_error("failed to get size of `%s'", spec); + exfat_error("failed to get size of '%s'", spec); return NULL; } if (exfat_seek(dev, 0, SEEK_SET) == -1) { close(dev->fd); free(dev); - exfat_error("failed to seek to the beginning of `%s'", spec); + exfat_error("failed to seek to the beginning of '%s'", spec); return NULL; } } @@ -210,32 +245,41 @@ struct exfat_dev* exfat_open(const char* spec, enum exfat_mode mode) 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) { - free(dev); - exfat_error("failed to close device"); - return 1; + exfat_error("failed to close device: %s", strerror(errno)); + rc = -EIO; } free(dev); - return 0; + return rc; } int exfat_fsync(struct exfat_dev* dev) { + int rc = 0; + #ifdef USE_UBLIO if (ublio_fsync(dev->ufh) != 0) -#else - if (fsync(dev->fd) != 0) + { + exfat_error("ublio fsync failed"); + rc = -EIO; + } #endif + if (fsync(dev->fd) != 0) { - exfat_error("fsync failed"); - return 1; + exfat_error("fsync failed: %s", strerror(errno)); + rc = -EIO; } - return 0; + return rc; } enum exfat_mode exfat_get_mode(const struct exfat_dev* dev) @@ -243,18 +287,18 @@ enum exfat_mode exfat_get_mode(const struct exfat_dev* dev) return dev->mode; } -off64_t exfat_get_size(const struct exfat_dev* dev) +off_t exfat_get_size(const struct exfat_dev* dev) { return dev->size; } -off64_t exfat_seek(struct exfat_dev* dev, off64_t offset, int whence) +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 = lseek64(dev->fd, offset, whence); + return dev->pos = lseek(dev->fd, offset, whence); #else - return lseek64(dev->fd, offset, whence); + return lseek(dev->fd, offset, whence); #endif } @@ -283,31 +327,31 @@ ssize_t exfat_write(struct exfat_dev* dev, const void* buffer, size_t size) } ssize_t exfat_pread(struct exfat_dev* dev, void* buffer, size_t size, - off64_t offset) + off_t offset) { #ifdef USE_UBLIO return ublio_pread(dev->ufh, buffer, size, offset); #else - return pread64(dev->fd, buffer, size, offset); + return pread(dev->fd, buffer, size, offset); #endif } ssize_t exfat_pwrite(struct exfat_dev* dev, const void* buffer, size_t size, - off64_t offset) + off_t offset) { #ifdef USE_UBLIO return ublio_pwrite(dev->ufh, buffer, size, offset); #else - return pwrite64(dev->fd, buffer, size, offset); + return pwrite(dev->fd, buffer, size, offset); #endif } ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node, - void* buffer, size_t size, off64_t offset) + void* buffer, size_t size, off_t offset) { cluster_t cluster; char* bufp = buffer; - off64_t lsize, loffset, remainder; + off_t lsize, loffset, remainder; if (offset >= node->size) return 0; @@ -348,11 +392,11 @@ ssize_t exfat_generic_pread(const struct exfat* ef, struct exfat_node* node, } ssize_t exfat_generic_pwrite(struct exfat* ef, struct exfat_node* node, - const void* buffer, size_t size, off64_t offset) + const void* buffer, size_t size, off_t offset) { cluster_t cluster; const char* bufp = buffer; - off64_t lsize, loffset, remainder; + off_t lsize, loffset, remainder; if (offset > node->size) if (exfat_truncate(ef, node, offset, true) != 0) |