Date: Wed, 25 Jan 2012 13:40:10 GMT From: Alex Samorukov <samm@os2.kiev.ua> To: freebsd-ports-bugs@FreeBSD.org Subject: Re: ports/164473: [NEW PORT] sysutils/fusefs-exfat: A full-featured exFAT FS implementation as a FUSE module Message-ID: <201201251340.q0PDeA50095012@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR ports/164473; it has been noted by GNATS. From: Alex Samorukov <samm@os2.kiev.ua> To: bug-followup@FreeBSD.org, samm@os2.kiev.ua Cc: Subject: Re: ports/164473: [NEW PORT] sysutils/fusefs-exfat: A full-featured exFAT FS implementation as a FUSE module Date: Wed, 25 Jan 2012 14:33:30 +0100 This is a multi-part message in MIME format. --------------020003060204000800060308 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit I forgotten patch to the io functions in original submit. Please, take it from this attach. --------------020003060204000800060308 Content-Type: text/x-csrc; name="patch-io.c" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="patch-io.c" --- libexfat/io.c 2012-01-25 13:07:21.467957180 +0000 +++ libexfat/io.c 2012-01-25 13:26:10.599952890 +0000 @@ -23,6 +23,7 @@ #include <sys/types.h> #include <sys/uio.h> #include <sys/stat.h> +#include <string.h> #include <fcntl.h> #define __USE_UNIX98 /* for pread() in Linux */ #include <unistd.h> @@ -49,26 +50,177 @@ exfat_error("failed to fstat `%s'", spec); return -1; } - if (!S_ISBLK(stbuf.st_mode) && !S_ISREG(stbuf.st_mode)) + if (!S_ISCHR(stbuf.st_mode) && !S_ISREG(stbuf.st_mode) && !S_ISBLK(stbuf.st_mode)) { close(fd); - exfat_error("`%s' is neither a block device, nor a regular file", + exfat_error("`%s' is neither a special device, nor a regular file", spec); return -1; } return fd; } +#define RAW_IO_MAX_SIZE (128 * 1024 * 1024) +#define DEVBSIZE 512 // better get from the device, but 512 should work as well +#define RAW_IO_ALIGNED(offset, count) \ + (DEVBSIZE == 0 || \ + ((offset) % DEVBSIZE == 0 && \ + (count) % DEVBSIZE == 0)) +#define RAW_IO_ALIGN(offset) \ + ((offset) / DEVBSIZE * DEVBSIZE) +#define RAW_IO_MAX_SIZE (128 * 1024 * 1024) + + +static int64_t aligned_pread(int fd, void *buf, int64_t count, int64_t offset) +{ + int64_t start, start_aligned; + int64_t end, end_aligned; + size_t count_aligned; + char *buf_aligned; + ssize_t nr; + + /* short-circuit for regular files */ + start = offset; + if (count > RAW_IO_MAX_SIZE) + count = RAW_IO_MAX_SIZE; + if (RAW_IO_ALIGNED(start, count)) + return pread(fd, buf, count, start); + + /* + * +- start_aligned +- end_aligned + * | | + * | +- start +- end | + * v v v v + * |----------|----------|----------| + * ^ ^ + * +----- count ------+ + * ^ ^ + * +-------- count_aligned ---------+ + */ + start_aligned = RAW_IO_ALIGN(start); + end = start + count; + end_aligned = RAW_IO_ALIGN(end) + + (RAW_IO_ALIGNED(end, 0) ? 0 : DEVBSIZE); + count_aligned = end_aligned - start_aligned; +/* exfat_debug( + "%s: count = 0x%llx/0x%x, start = 0x%llx/0x%llx, end = 0x%llx/0x%llx\n", + dev->d_name, count, count_aligned, + start, start_aligned, end, end_aligned); +*/ + /* allocate buffer */ + buf_aligned = malloc(count_aligned); + if (buf_aligned == NULL) { + exfat_debug("malloc(%zu) failed\n", count_aligned); + return -1; + } + + /* read aligned data */ + nr = pread(fd, buf_aligned, count_aligned, start_aligned); + if (nr == 0) + return 0; + if (nr < 0 || nr < start - start_aligned) { + free(buf_aligned); + return -1; + } + + /* copy out */ + memcpy(buf, buf_aligned + (start - start_aligned), count); + free(buf_aligned); + + nr -= start - start_aligned; + if (nr > count) + nr = count; + return nr; +} + +/** + * aligned_pwrite - Perform an aligned positioned write from the device + */ +static int64_t aligned_pwrite(int fd, void const *buf, size_t count, off_t offset) +{ + int64_t start, start_aligned; + int64_t end, end_aligned; + size_t count_aligned; + char *buf_aligned; + ssize_t nw; + + /* short-circuit for regular files */ + start = offset; + if (count > RAW_IO_MAX_SIZE) + count = RAW_IO_MAX_SIZE; + if (RAW_IO_ALIGNED(start, count)) + return pwrite(fd, buf, count, start); + + /* + * +- start_aligned +- end_aligned + * | | + * | +- start +- end | + * v v v v + * |----------|----------|----------| + * ^ ^ + * +----- count ------+ + * ^ ^ + * +-------- count_aligned ---------+ + */ + start_aligned = RAW_IO_ALIGN(start); + end = start + count; + end_aligned = RAW_IO_ALIGN(end) + + (RAW_IO_ALIGNED(end, 0) ? 0 : DEVBSIZE); + count_aligned = end_aligned - start_aligned; + exfat_debug( + "device:%d: count = 0x%llx/0x%x, start = 0x%llx/0x%llx, end = 0x%llx/0x%llx\n", + fd, count, count_aligned, + start, start_aligned, end, end_aligned); + + /* allocate buffer */ + buf_aligned = malloc(count_aligned); + if (buf_aligned == NULL) { + exfat_error("malloc(%d) failed\n", count_aligned); + return -1; + } + + /* read aligned lead-in */ + if (pread(fd, buf_aligned, DEVBSIZE, start_aligned) != DEVBSIZE) { + exfat_debug("read lead-in failed\n"); + free(buf_aligned); + return -1; + } + + /* read aligned lead-out */ + if (end != end_aligned && count_aligned > DEVBSIZE) { + if (pread(fd, buf_aligned + count_aligned - DEVBSIZE, DEVBSIZE, end_aligned - DEVBSIZE) != DEVBSIZE) { + exfat_error("read lead-out failed\n"); + free(buf_aligned); + return -1; + } + } + + /* copy data to write */ + memcpy(buf_aligned + (start - start_aligned), buf, count); + + /* write aligned data */ + nw = pwrite(fd, buf_aligned, count_aligned, start_aligned); + free(buf_aligned); + if (nw < 0 || nw < start - start_aligned) + return -1; + + nw -= start - start_aligned; + if (nw > count) + nw = count; + return nw; +} + + void exfat_read_raw(void* buffer, size_t size, off_t offset, int fd) { - if (pread(fd, buffer, size, offset) != size) + if (aligned_pread(fd, buffer, size, offset) != size) exfat_bug("failed to read %zu bytes from file at %"PRIu64, size, (uint64_t) offset); } void exfat_write_raw(const void* buffer, size_t size, off_t offset, int fd) { - if (pwrite(fd, buffer, size, offset) != size) + if (aligned_pwrite(fd, buffer, size, offset) != size) exfat_bug("failed to write %zu bytes to file at %"PRIu64, size, (uint64_t) offset); } --------------020003060204000800060308--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201201251340.q0PDeA50095012>