Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 05 Feb 2012 12:11:18 +0100
From:      Alex Samorukov <samm@os2.kiev.ua>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   ports/164790: [MAINTAINER] sysutils/fusefs-exfat: fix time/date handling, improve speed
Message-ID:  <E1Ru006-000HJR-1W@os2.ru>
Resent-Message-ID: <201202051120.q15BKAtg097885@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         164790
>Category:       ports
>Synopsis:       [MAINTAINER] sysutils/fusefs-exfat: fix time/date handling, improve speed
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          maintainer-update
>Submitter-Id:   current-users
>Arrival-Date:   Sun Feb 05 11:20:09 UTC 2012
>Closed-Date:
>Last-Modified:
>Originator:     Alex Samorukov
>Release:        FreeBSD 8.2-RELEASE i386
>Organization:
NetArt s.r.o.
>Environment:
System: FreeBSD bsd 8.2-RELEASE FreeBSD 8.2-RELEASE #0: Fri Feb 18 02:24:46 UTC 2011
>Description:
* Fixed time/date handling, fix taken from upstream
* Device block size is now requested from the device
* Added optional ublio support, enabled by default

Added file(s):
- files/patch-timefuncs

Generated with FreeBSD Port Tools 0.99
>How-To-Repeat:
>Fix:

--- fusefs-exfat-0.9.6_1.patch begins here ---
diff -ruN --exclude=CVS /usr/ports/sysutils/fusefs-exfat/Makefile /root/tmp/fusefs-exfat/Makefile
--- /usr/ports/sysutils/fusefs-exfat/Makefile	2012-01-31 06:42:27.000000000 +0100
+++ /root/tmp/fusefs-exfat/Makefile	2012-02-05 11:53:00.000000000 +0100
@@ -7,6 +7,7 @@
 
 PORTNAME=	exfat
 PORTVERSION=	0.9.6
+PORTREVISION=	1
 CATEGORIES=	sysutils
 MASTER_SITES=	GOOGLE_CODE
 PKGNAMEPREFIX=	fusefs-
@@ -23,16 +24,31 @@
 USE_ICONV=	yes
 USE_SCONS=	yes
 SCONS_ENV+=	LIBPATH=${PREFIX}/lib
-SCONS_BUILDENV=	${SCONS_ENV} CXXFLAGS=" -I${LOCALBASE}/include " \
-		LDFLAGS=" -L${LOCALBASE}/lib "
+SCONS_BUILDENV=	${SCONS_ENV} CXXFLAGS=" -I${LOCALBASE}/include ${CCFLAGS}" \
+		LDFLAGS=" -L${LOCALBASE}/lib ${LIBS}"
 SCONS_ARGS+=	prefix=${PREFIX} use_env=1
 
+OPTIONS=	UBLIO "Enable user space cache for improved speed" on
+
 MAN8=		mount.exfat-fuse.8
 PLIST_FILES=	bin/mount.exfat-fuse bin/mount.exfat
 
+.include <bsd.port.pre.mk>
+
+.if defined(WITH_UBLIO)
+LIB_DEPENDS+=	ublio.1:${PORTSDIR}/devel/libublio
+CCFLAGS=	-DUSE_UBLIO
+LIBS+=		-lublio
+.else
+pre-everything::
+	@${ECHO_MSG}
+	@${ECHO_MSG} "WARNING: FreeBSD does not have cache support for block devices. This will considerably reduce the performance of this application, please consider enabling the UBLIO option and following the indications in the post-installation message." | ${FMT}
+	@${ECHO_MSG}
+.endif
+
 do-install:
 	${INSTALL_PROGRAM} ${WRKSRC}/fuse/mount.exfat-fuse ${PREFIX}/bin
 	${LN} -s ${PREFIX}/bin/mount.exfat-fuse ${PREFIX}/bin/mount.exfat
 	${INSTALL_MAN} ${WRKSRC}/fuse/${MAN8} ${MAN8PREFIX}/man/man8
 
-.include <bsd.port.mk>
+.include <bsd.port.post.mk>
diff -ruN --exclude=CVS /usr/ports/sysutils/fusefs-exfat/files/patch-libexfat_io.c /root/tmp/fusefs-exfat/files/patch-libexfat_io.c
--- /usr/ports/sysutils/fusefs-exfat/files/patch-libexfat_io.c	2012-01-31 06:42:27.000000000 +0100
+++ /root/tmp/fusefs-exfat/files/patch-libexfat_io.c	2012-02-05 11:44:00.000000000 +0100
@@ -1,6 +1,6 @@
---- 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 @@
+--- libexfat/io.c.orig	2012-01-14 10:24:11.000000000 +0100
++++ libexfat/io.c	2012-02-05 11:37:13.872786157 +0100
+@@ -23,9 +23,29 @@
  #include <sys/types.h>
  #include <sys/uio.h>
  #include <sys/stat.h>
@@ -8,7 +8,29 @@
  #include <fcntl.h>
  #define __USE_UNIX98 /* for pread() in Linux */
  #include <unistd.h>
-@@ -49,26 +50,177 @@
++#ifdef __FreeBSD__
++#ifdef USE_UBLIO
++#include <sys/uio.h>
++#include "ublio.h"
++#define UBLIO_DEFAULT_BLOCKSIZE	262144
++#define UBLIO_DEFAULT_ITEMS	64
++#define UBLIO_DEFAULT_GRACE	32
++#define UBLIO_DEFAULT_SYNC_IO	0
++#define UBLIO_USE_API		1;
++struct unix_filehandle {
++	int fd;
++	ublio_filehandle_t ublio_fh;
++};
++
++struct unix_filehandle *ufh;
++#endif
++#include <sys/disk.h>
++static long devbsize; // block size for the gived device
++#endif
+ 
+ #if _FILE_OFFSET_BITS != 64
+ 	#error You should define _FILE_OFFSET_BITS=64
+@@ -49,26 +69,219 @@
  		exfat_error("failed to fstat `%s'", spec);
  		return -1;
  	}
@@ -21,20 +43,54 @@
  				spec);
  		return -1;
  	}
++#ifdef __FreeBSD__
++	devbsize = 512;
++	if (S_ISCHR(stbuf.st_mode) && ioctl(fd, DIOCGSECTORSIZE, &devbsize) < 0) {
++		exfat_error("Failed to ioctl(DIOCGSECTORSIZE) '%s'", spec);
++		return -1;
++	}
++#if USE_UBLIO
++	ufh = malloc(sizeof(*ufh));
++	if (!ufh)
++		return -1;
++
++	struct ublio_param up;
++	ufh->ublio_fh = NULL;
++	ufh->fd = fd;
++
++	up.up_blocksize = UBLIO_DEFAULT_BLOCKSIZE;
++	up.up_items = UBLIO_DEFAULT_ITEMS;
++	up.up_grace = UBLIO_DEFAULT_GRACE;
++	up.up_sync_io = UBLIO_DEFAULT_SYNC_IO;
++	up.up_priv	= &ufh->fd;
++	up.up_pread	= NULL;
++	up.up_preadv	= NULL;
++	up.up_pwrite	= NULL;
++	up.up_pwritev	= NULL; 
++	ufh->ublio_fh = ublio_open(&up);
++	if (!ufh->ublio_fh) {
++		close(fd);
++		exfat_error("ublio_open failed for %s", spec);
++		return -1;
++	}
++#endif
++
++#endif
  	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 DEVBSIZE 4096 // 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))
++	(devbsize == 0 ||			\
++	 ((offset) % devbsize == 0 &&	\
++	  (count) % devbsize == 0))
 +#define RAW_IO_ALIGN(offset)				\
-+	((offset) / DEVBSIZE * DEVBSIZE)
++	((offset) / devbsize * devbsize)
 +#define RAW_IO_MAX_SIZE (128 * 1024 * 1024)
 +
-+
++#ifndef USE_UBLIO
 +static int64_t aligned_pread(int fd, void *buf, int64_t count, int64_t offset)
 +{
 +	int64_t start, start_aligned;
@@ -64,7 +120,7 @@
 +	start_aligned = RAW_IO_ALIGN(start);
 +	end = start + count;
 +	end_aligned = RAW_IO_ALIGN(end) +
-+	    (RAW_IO_ALIGNED(end, 0) ? 0 : DEVBSIZE);
++	    (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",
@@ -129,12 +185,12 @@
 +	start_aligned = RAW_IO_ALIGN(start);
 +	end = start + count;
 +	end_aligned = RAW_IO_ALIGN(end) +
-+	    (RAW_IO_ALIGNED(end, 0) ? 0 : DEVBSIZE);
++	    (RAW_IO_ALIGNED(end, 0) ? 0 : devbsize);
 +	count_aligned = end_aligned - start_aligned;
-+	exfat_debug(
++	/* 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);
++	    start, start_aligned, end, end_aligned); */
 +
 +	/* allocate buffer */
 +	buf_aligned = malloc(count_aligned);
@@ -144,15 +200,15 @@
 +	}
 +
 +	/* read aligned lead-in */
-+	if (pread(fd, buf_aligned, DEVBSIZE, start_aligned) != DEVBSIZE) {
++	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) {
++	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;
@@ -173,12 +229,16 @@
 +		nw = count;
 +	return nw;
 +}
-+
++#endif
 +
  void exfat_read_raw(void* buffer, size_t size, off_t offset, int fd)
  {
 -	if (pread(fd, buffer, size, offset) != size)
++#ifdef USE_UBLIO
++	if (ublio_pread(ufh->ublio_fh, buffer, size, offset) != size)
++#else
 +	if (aligned_pread(fd, buffer, size, offset) != size)
++#endif
  		exfat_bug("failed to read %zu bytes from file at %"PRIu64, size,
  				(uint64_t) offset);
  }
@@ -186,7 +246,26 @@
  void exfat_write_raw(const void* buffer, size_t size, off_t offset, int fd)
  {
 -	if (pwrite(fd, buffer, size, offset) != size)
++#ifdef USE_UBLIO
++	if (ublio_pwrite(ufh->ublio_fh, buffer, size, offset) != size)
++#else
 +	if (aligned_pwrite(fd, buffer, size, offset) != size)
++#endif
  		exfat_bug("failed to write %zu bytes to file at %"PRIu64, size,
  				(uint64_t) offset);
  }
+@@ -155,3 +368,14 @@
+ 	exfat_update_mtime(node);
+ 	return size - remainder;
+ }
++
++int exfat_close(int fd) {
++#ifdef USE_UBLIO
++	ublio_fsync(ufh->ublio_fh);
++	ublio_close(ufh->ublio_fh);
++	
++#endif
++	if (close(fd) < 0)	/* close descriptor immediately after fsync */
++		return -1;
++	return 0;
++}
diff -ruN --exclude=CVS /usr/ports/sysutils/fusefs-exfat/files/patch-timefuncs /root/tmp/fusefs-exfat/files/patch-timefuncs
--- /usr/ports/sysutils/fusefs-exfat/files/patch-timefuncs	1970-01-01 01:00:00.000000000 +0100
+++ /root/tmp/fusefs-exfat/files/patch-timefuncs	2012-02-05 11:43:00.000000000 +0100
@@ -0,0 +1,384 @@
+Index: libexfat/time.c
+===================================================================
+--- libexfat/time.c	(revision 0)
++++ libexfat/time.c	(revision 255)
+@@ -0,0 +1,156 @@
++/*
++	time.c (03.02.12)
++	exFAT file system implementation library.
++
++	Copyright (C) 2009, 2010  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
++	the Free Software Foundation, either version 3 of the License, or
++	(at your option) any later version.
++
++	This program is distributed in the hope that it will be useful,
++	but WITHOUT ANY WARRANTY; without even the implied warranty of
++	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++	GNU General Public License for more details.
++
++	You should have received a copy of the GNU General Public License
++	along with this program.  If not, see <http://www.gnu.org/licenses/>.
++*/
++
++#include "exfat.h"
++
++/* timezone offset from UTC in seconds; positive for western timezones,
++   negative for eastern ones */
++static long exfat_timezone;
++
++#define SEC_IN_MIN 60ll
++#define SEC_IN_HOUR (60 * SEC_IN_MIN)
++#define SEC_IN_DAY (24 * SEC_IN_HOUR)
++#define SEC_IN_YEAR (365 * SEC_IN_DAY) /* not leap year */
++/* Unix epoch started at 0:00:00 UTC 1 January 1970 */
++#define UNIX_EPOCH_YEAR 1970
++/* exFAT epoch started at 0:00:00 UTC 1 January 1980 */
++#define EXFAT_EPOCH_YEAR 1980
++/* number of years from Unix epoch to exFAT epoch */
++#define EPOCH_DIFF_YEAR (EXFAT_EPOCH_YEAR - UNIX_EPOCH_YEAR)
++/* number of days from Unix epoch to exFAT epoch (considering leap days) */
++#define EPOCH_DIFF_DAYS (EPOCH_DIFF_YEAR * 365 + EPOCH_DIFF_YEAR / 4)
++/* number of seconds from Unix epoch to exFAT epoch (considering leap days) */
++#define EPOCH_DIFF_SEC (EPOCH_DIFF_DAYS * SEC_IN_DAY)
++/* number of leap years passed from exFAT epoch to the specified year
++   (excluding the specified year itself) */
++#define LEAP_YEARS(year) ((EXFAT_EPOCH_YEAR + (year) - 1) / 4 \
++		- (EXFAT_EPOCH_YEAR - 1) / 4)
++/* checks whether the specified year is leap */
++#define IS_LEAP_YEAR(year) ((EXFAT_EPOCH_YEAR + (year)) % 4 == 0)
++
++static const time_t days_in_year[] =
++{
++	/* Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec */
++	0,   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334
++};
++
++time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec)
++{
++	time_t unix_time = EPOCH_DIFF_SEC;
++	uint16_t ndate = le16_to_cpu(date);
++	uint16_t ntime = le16_to_cpu(time);
++
++	uint16_t day    = ndate & 0x1f;      /* 5 bits, 1-31 */
++	uint16_t month  = ndate >> 5 & 0xf;  /* 4 bits, 1-12 */
++	uint16_t year   = ndate >> 9;        /* 7 bits, 1-127 (+1980) */
++
++	uint16_t twosec = ntime & 0x1f;      /* 5 bits, 0-29 (2 sec granularity) */
++	uint16_t min    = ntime >> 5 & 0x3f; /* 6 bits, 0-59 */
++	uint16_t hour   = ntime >> 11;       /* 5 bits, 0-23 */
++
++	if (day == 0 || month == 0 || month > 12)
++	{
++		exfat_error("bad date %hu-%02hu-%02hu",
++				year + EXFAT_EPOCH_YEAR, month, day);
++		return 0;
++	}
++	if (hour > 23 || min > 59 || twosec > 29)
++	{
++		exfat_error("bad time %hu:%02hu:%02hu",
++				hour, min, twosec * 2);
++		return 0;
++	}
++	if (centisec > 199)
++	{
++		exfat_error("bad centiseconds count %hhu", centisec);
++		return 0;
++	}
++
++	/* every 4th year between 1904 and 2096 is leap */
++	unix_time += year * SEC_IN_YEAR + LEAP_YEARS(year) * SEC_IN_DAY;
++	unix_time += days_in_year[month] * SEC_IN_DAY;
++	/* if it's leap year and February has passed we should add 1 day */
++	if ((EXFAT_EPOCH_YEAR + year) % 4 == 0 && month > 2)
++		unix_time += SEC_IN_DAY;
++	unix_time += (day - 1) * SEC_IN_DAY;
++
++	unix_time += hour * SEC_IN_HOUR;
++	unix_time += min * SEC_IN_MIN;
++	/* exFAT represents time with 2 sec granularity */
++	unix_time += twosec * 2;
++	unix_time += centisec / 100;
++
++	/* exFAT stores timestamps in local time, so we correct it to UTC */
++	unix_time += exfat_timezone;
++
++	return unix_time;
++}
++
++void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
++		uint8_t* centisec)
++{
++	time_t shift = EPOCH_DIFF_SEC + exfat_timezone;
++	uint16_t day, month, year;
++	uint16_t twosec, min, hour;
++	int days;
++	int i;
++
++	/* time before exFAT epoch cannot be represented */
++	if (unix_time < shift)
++		unix_time = shift;
++
++	unix_time -= shift;
++
++	days = unix_time / SEC_IN_DAY;
++	year = (4 * days) / (4 * 365 + 1);
++	days -= year * 365 + LEAP_YEARS(year);
++	month = 0;
++	for (i = 1; i <= 12; i++)
++	{
++		int leap_day = (IS_LEAP_YEAR(year) && i == 2);
++		int leap_sub = (IS_LEAP_YEAR(year) && i >= 3);
++
++		if (i == 12 || days - leap_sub < days_in_year[i + 1] + leap_day)
++		{
++			month = i;
++			days -= days_in_year[i] + leap_sub;
++			break;
++		}
++	}
++	day = days + 1;
++
++	hour = (unix_time % SEC_IN_DAY) / SEC_IN_HOUR;
++	min = (unix_time % SEC_IN_HOUR) / SEC_IN_MIN;
++	twosec = (unix_time % SEC_IN_MIN) / 2;
++
++	*date = cpu_to_le16(day | (month << 5) | (year << 9));
++	*time = cpu_to_le16(twosec | (min << 5) | (hour << 11));
++	if (centisec)
++		*centisec = (unix_time % 2) * 100;
++}
++
++void exfat_tzset(void)
++{
++	time_t now;
++
++	tzset();
++	now = time(NULL);
++	exfat_timezone = mktime(gmtime(&now)) - now;
++}
+7Index: libexfat/mount.c
+===================================================================
+Index: libexfat/node.c
+===================================================================
+--- libexfat/node.c	(revision 250)
++++ libexfat/node.c	(revision 255)
+@@ -735,8 +735,7 @@
+ 			&meta1.crtime_cs);
+ 	meta1.adate = meta1.mdate = meta1.crdate;
+ 	meta1.atime = meta1.mtime = meta1.crtime;
+-	/* crtime_cs and mtime_cs contain addition to the time in centiseconds;
+-	   just ignore those fields because we operate with 2 sec resolution */
++	meta1.mtime_cs = meta1.crtime_cs; /* there is no atime_cs */
+ 
+ 	memset(&meta2, 0, sizeof(meta2));
+ 	meta2.type = EXFAT_ENTRY_FILE_INFO;
+--- libexfat/utils.c	2012-01-14 10:24:11.000000000 +0100
++++ libexfat/utils.c	2012-02-05 09:53:10.704809558 +0100
+@@ -22,8 +22,6 @@
+ #include <string.h>
+ #include <stdio.h>
+ #include <inttypes.h>
+-#define _XOPEN_SOURCE /* for timezone in Linux */
+-#include <time.h>
+ 
+ void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
+ 		struct stat* stbuf)
+@@ -46,128 +44,6 @@
+ 	stbuf->st_ctime = node->mtime;
+ }
+ 
+-#define SEC_IN_MIN 60ll
+-#define SEC_IN_HOUR (60 * SEC_IN_MIN)
+-#define SEC_IN_DAY (24 * SEC_IN_HOUR)
+-#define SEC_IN_YEAR (365 * SEC_IN_DAY) /* not leap year */
+-/* Unix epoch started at 0:00:00 UTC 1 January 1970 */
+-#define UNIX_EPOCH_YEAR 1970
+-/* exFAT epoch started at 0:00:00 UTC 1 January 1980 */
+-#define EXFAT_EPOCH_YEAR 1980
+-/* number of years from Unix epoch to exFAT epoch */
+-#define EPOCH_DIFF_YEAR (EXFAT_EPOCH_YEAR - UNIX_EPOCH_YEAR)
+-/* number of days from Unix epoch to exFAT epoch (considering leap days) */
+-#define EPOCH_DIFF_DAYS (EPOCH_DIFF_YEAR * 365 + EPOCH_DIFF_YEAR / 4)
+-/* number of seconds from Unix epoch to exFAT epoch (considering leap days) */
+-#define EPOCH_DIFF_SEC (EPOCH_DIFF_DAYS * SEC_IN_DAY)
+-/* number of leap years passed from exFAT epoch to the specified year
+-   (excluding the specified year itself) */
+-#define LEAP_YEARS(year) ((EXFAT_EPOCH_YEAR + (year) - 1) / 4 \
+-		- (EXFAT_EPOCH_YEAR - 1) / 4)
+-/* checks whether the specified year is leap */
+-#define IS_LEAP_YEAR(year) ((EXFAT_EPOCH_YEAR + (year)) % 4 == 0)
+-
+-static const time_t days_in_year[] =
+-{
+-	/* Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec */
+-	0,   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334
+-};
+-
+-time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec)
+-{
+-	time_t unix_time = EPOCH_DIFF_SEC;
+-	uint16_t ndate = le16_to_cpu(date);
+-	uint16_t ntime = le16_to_cpu(time);
+-
+-	uint16_t day    = ndate & 0x1f;     /* 5 bits, 1-31 */
+-	uint16_t month  = ndate >> 5 & 0xf; /* 4 bits, 1-12 */
+-	uint16_t year   = ndate >> 9;       /* 7 bits, 1-127 (+1980) */
+-
+-	uint16_t twosec = ntime & 0x1f;     /* 5 bits, 0-29 (2 sec granularity) */
+-	uint16_t min    = ntime >> 5 & 0xf; /* 6 bits, 0-59 */
+-	uint16_t hour   = ntime >> 11;      /* 5 bits, 0-23 */
+-
+-	if (day == 0 || month == 0 || month > 12)
+-	{
+-		exfat_error("bad date %hu-%02hu-%02hu",
+-				year + EXFAT_EPOCH_YEAR, month, day);
+-		return 0;
+-	}
+-	if (hour > 23 || min > 59 || twosec > 29)
+-	{
+-		exfat_error("bad time %hu:%02hu:%02hu",
+-				hour, min, twosec * 2);
+-		return 0;
+-	}
+-	if (centisec > 199)
+-	{
+-		exfat_error("bad centiseconds count %hhu", centisec);
+-		return 0;
+-	}
+-
+-	/* every 4th year between 1904 and 2096 is leap */
+-	unix_time += year * SEC_IN_YEAR + LEAP_YEARS(year) * SEC_IN_DAY;
+-	unix_time += days_in_year[month] * SEC_IN_DAY;
+-	/* if it's leap year and February has passed we should add 1 day */
+-	if ((EXFAT_EPOCH_YEAR + year) % 4 == 0 && month > 2)
+-		unix_time += SEC_IN_DAY;
+-	unix_time += (day - 1) * SEC_IN_DAY;
+-
+-	unix_time += hour * SEC_IN_HOUR;
+-	unix_time += min * SEC_IN_MIN;
+-	/* exFAT represents time with 2 sec granularity */
+-	unix_time += twosec * 2;
+-	unix_time += centisec / 100;
+-
+-	/* exFAT stores timestamps in local time, so we correct it to UTC */
+-	unix_time += timezone;
+-
+-	return unix_time;
+-}
+-
+-void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
+-		uint8_t* centisec)
+-{
+-	time_t shift = EPOCH_DIFF_SEC + timezone;
+-	uint16_t day, month, year;
+-	uint16_t twosec, min, hour;
+-	int days;
+-	int i;
+-
+-	/* time before exFAT epoch cannot be represented */
+-	if (unix_time < shift)
+-		unix_time = shift;
+-
+-	unix_time -= shift;
+-
+-	days = unix_time / SEC_IN_DAY;
+-	year = (4 * days) / (4 * 365 + 1);
+-	days -= year * 365 + LEAP_YEARS(year);
+-	month = 0;
+-	for (i = 1; i <= 12; i++)
+-	{
+-		int leap_day = (IS_LEAP_YEAR(year) && i == 2);
+-		int leap_sub = (IS_LEAP_YEAR(year) && i >= 3);
+-
+-		if (i == 12 || days - leap_sub < days_in_year[i + 1] + leap_day)
+-		{
+-			month = i;
+-			days -= days_in_year[i] + leap_sub;
+-			break;
+-		}
+-	}
+-	day = days + 1;
+-
+-	hour = (unix_time % SEC_IN_DAY) / SEC_IN_HOUR;
+-	min = (unix_time % SEC_IN_HOUR) / SEC_IN_MIN;
+-	twosec = (unix_time % SEC_IN_MIN) / 2;
+-
+-	*date = cpu_to_le16(day | (month << 5) | (year << 9));
+-	*time = cpu_to_le16(twosec | (min << 5) | (hour << 11));
+-	if (centisec)
+-		*centisec = (unix_time % 2) * 100;
+-}
+-
+ void exfat_get_name(const struct exfat_node* node, char* buffer, size_t n)
+ {
+ 	if (utf16_to_utf8(buffer, node->name, n, EXFAT_NAME_MAX) != 0)
+@@ -234,7 +110,6 @@
+ 	return sum;
+ }
+ 
+-
+ le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name)
+ {
+ 	size_t i;
+--- libexfat/exfat.h.orig	2012-01-14 10:24:11.000000000 +0100
++++ libexfat/exfat.h	2012-02-05 10:51:10.721804789 +0100
+@@ -121,6 +121,7 @@
+ 	__attribute__((format(printf, 1, 2)));
+ 
+ int exfat_open(const char* spec, int ro);
++int exfat_close(int fd);
+ void exfat_read_raw(void* buffer, size_t size, off_t offset, int fd);
+ void exfat_write_raw(const void* buffer, size_t size, off_t offset, int fd);
+ ssize_t exfat_read(const struct exfat* ef, struct exfat_node* node,
+@@ -149,9 +150,6 @@
+ 
+ void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
+ 		struct stat* stbuf);
+-time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec);
+-void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
+-		uint8_t* centisec);
+ void exfat_get_name(const struct exfat_node* node, char* buffer, size_t n);
+ uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry);
+ uint16_t exfat_add_checksum(const void* entry, uint16_t sum);
+@@ -189,4 +187,9 @@
+ int exfat_mount(struct exfat* ef, const char* spec, const char* options);
+ void exfat_unmount(struct exfat* ef);
+ 
++time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec);
++void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
++		uint8_t* centisec);
++void exfat_tzset(void);
++
+ #endif /* ifndef EXFAT_H_INCLUDED */
+--- libexfat/mount.c	2012-01-14 10:24:11.000000000 +0100
++++ libexfat/mount.c	2012-02-05 10:52:28.913790209 +0100
+@@ -24,8 +24,6 @@
+ #include <errno.h>
+ #include <unistd.h>
+ #include <sys/types.h>
+-#define _XOPEN_SOURCE /* for tzset() in Linux */
+-#include <time.h>
+ 
+ static uint64_t rootdir_size(const struct exfat* ef)
+ {
+@@ -144,7 +142,7 @@
+ {
+ 	int rc;
+ 
+-	tzset();
++	exfat_tzset();
+ 	memset(ef, 0, sizeof(struct exfat));
+ 
+ 	parse_options(ef, options);
+@@ -301,7 +299,7 @@
+ 	free(ef->root);
+ 	ef->root = NULL;
+ 	finalize_super_block(ef);
+-	if (close(ef->fd) < 0)	/* close descriptor immediately after fsync */
++	if (exfat_close(ef->fd) < 0)	/* close descriptor immediately after fsync */
+ 		exfat_error("close failed");
+ 	ef->fd = 0;
+ 	free(ef->zero_cluster);
--- fusefs-exfat-0.9.6_1.patch ends here ---

>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E1Ru006-000HJR-1W>