bool "enable statistics for bigdata"
depends on SDFAT_FS
default y
+
+config SDFAT_UEVENT
+ bool "Enable uevent"
+ depends on SDFAT_FS
+ default y
/* Type Definitions */
/*----------------------------------------------------------------------*/
/* should be merged it to DATE_TIME_T */
+typedef union {
+ struct {
+ u8 off : 7;
+ u8 valid : 1;
+ };
+ u8 value;
+} TIMEZONE_T;
+
typedef struct {
u16 sec; /* 0 ~ 59 */
u16 min; /* 0 ~ 59 */
u16 day; /* 1 ~ 31 */
u16 mon; /* 1 ~ 12 */
u16 year; /* 0 ~ 127 (since 1980) */
+ TIMEZONE_T tz;
} TIMESTAMP_T;
-
typedef struct {
u16 Year;
u16 Month;
u16 Minute;
u16 Second;
u16 MilliSecond;
+ TIMEZONE_T Timezone;
} DATE_TIME_T;
typedef struct {
#include <linux/writeback.h>
#include <linux/kernel.h>
#include <linux/log2.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
+#include <linux/iversion.h>
+#endif
#include "sdfat.h"
#include "core.h"
#include <asm/byteorder.h>
#include <asm/unaligned.h>
+
+/*************************************************************************
+ * FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
+ *************************************************************************/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)
+static inline u64 inode_peek_iversion(struct inode *inode)
+{
+ return inode->i_version;
+}
+#endif
+
+
/*----------------------------------------------------------------------*/
/* Constant & Macro Definitions */
/*----------------------------------------------------------------------*/
return ret;
/* check the validation of hint_stat and initialize it if required */
- if (dir_fid->version != (u32)(inode->i_version & 0xffffffff)) {
+ if (dir_fid->version != (u32)inode_peek_iversion(inode)) {
dir_fid->hint_stat.clu = dir.dir;
dir_fid->hint_stat.eidx = 0;
- dir_fid->version = (u32)(inode->i_version & 0xffffffff);
+ dir_fid->version = (u32)inode_peek_iversion(inode);
dir_fid->hint_femp.eidx = -1;
}
info->CreateTimestamp.Minute = tm.min;
info->CreateTimestamp.Second = tm.sec;
info->CreateTimestamp.MilliSecond = 0;
+ info->CreateTimestamp.Timezone.value = tm.tz.value;
fsi->fs_func->get_entry_time(ep, &tm, TM_MODIFY);
info->ModifyTimestamp.Year = tm.year;
info->ModifyTimestamp.Minute = tm.min;
info->ModifyTimestamp.Second = tm.sec;
info->ModifyTimestamp.MilliSecond = 0;
+ info->ModifyTimestamp.Timezone.value = tm.tz.value;
memset((s8 *) &info->AccessTimestamp, 0, sizeof(DATE_TIME_T));
fsi->fs_func->set_entry_attr(ep, info->Attr);
/* set FILE_INFO structure using the acquired DENTRY_T */
+ tm.tz = info->CreateTimestamp.Timezone;
tm.sec = info->CreateTimestamp.Second;
tm.min = info->CreateTimestamp.Minute;
tm.hour = info->CreateTimestamp.Hour;
tm.year = info->CreateTimestamp.Year;
fsi->fs_func->set_entry_time(ep, &tm, TM_CREATE);
+ tm.tz = info->ModifyTimestamp.Timezone;
tm.sec = info->ModifyTimestamp.Second;
tm.min = info->ModifyTimestamp.Minute;
tm.hour = info->ModifyTimestamp.Hour;
static void exfat_get_entry_time(DENTRY_T *p_entry, TIMESTAMP_T *tp, u8 mode)
{
- u16 t = 0x00, d = 0x21;
+ u16 t = 0x00, d = 0x21, tz = 0x00;
FILE_DENTRY_T *ep = (FILE_DENTRY_T *)p_entry;
switch (mode) {
case TM_CREATE:
t = le16_to_cpu(ep->create_time);
d = le16_to_cpu(ep->create_date);
+ tz = ep->create_tz;
break;
case TM_MODIFY:
t = le16_to_cpu(ep->modify_time);
d = le16_to_cpu(ep->modify_date);
+ tz = ep->modify_tz;
break;
case TM_ACCESS:
t = le16_to_cpu(ep->access_time);
d = le16_to_cpu(ep->access_date);
+ tz = ep->access_tz;
break;
}
+ tp->tz.value = tz;
tp->sec = (t & 0x001F) << 1;
tp->min = (t >> 5) & 0x003F;
tp->hour = (t >> 11);
case TM_CREATE:
ep->create_time = cpu_to_le16(t);
ep->create_date = cpu_to_le16(d);
+ ep->create_tz = tp->tz.value;
break;
case TM_MODIFY:
ep->modify_time = cpu_to_le16(t);
ep->modify_date = cpu_to_le16(d);
+ ep->modify_tz = tp->tz.value;
break;
case TM_ACCESS:
ep->access_time = cpu_to_le16(t);
ep->access_date = cpu_to_le16(d);
+ ep->access_tz = tp->tz.value;
break;
}
} /* end of exfat_set_entry_time */
exfat_set_entry_time((DENTRY_T *) ep, tp, TM_ACCESS);
ep->create_time_ms = 0;
ep->modify_time_ms = 0;
- ep->access_time_ms = 0;
} /* end of __init_file_entry */
static void __init_strm_entry(STRM_DENTRY_T *ep, u8 flags, u32 start_clu, u64 size)
break;
}
+ tp->tz.value = 0x00;
tp->sec = (t & 0x001F) << 1;
tp->min = (t >> 5) & 0x003F;
tp->hour = (t >> 11);
/*************************************************************************
* FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
*************************************************************************/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
-#define CURRENT_TIME_SEC timespec_trunc(current_kernel_time(), NSEC_PER_SEC)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
+#define CURRENT_TIME_SEC timespec64_trunc(current_kernel_time64(), NSEC_PER_SEC)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+#define CURRENT_TIME_SEC timespec_trunc(current_kernel_time(), NSEC_PER_SEC)
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
+ /* EMPTY */
#endif
+#ifdef CONFIG_SDFAT_UEVENT
+static struct kobject sdfat_uevent_kobj;
+
+int sdfat_uevent_init(struct kset *sdfat_kset)
+{
+ int err;
+ struct kobj_type *ktype = get_ktype(&sdfat_kset->kobj);
+
+ sdfat_uevent_kobj.kset = sdfat_kset;
+ err = kobject_init_and_add(&sdfat_uevent_kobj, ktype, NULL, "uevent");
+ if (err)
+ pr_err("[SDFAT] Unable to create sdfat uevent kobj\n");
+
+ return err;
+}
+
+void sdfat_uevent_uninit(void)
+{
+ kobject_del(&sdfat_uevent_kobj);
+ memset(&sdfat_uevent_kobj, 0, sizeof(struct kobject));
+}
+
+void sdfat_uevent_ro_remount(struct super_block *sb)
+{
+ struct block_device *bdev = sb->s_bdev;
+ dev_t bd_dev = bdev ? bdev->bd_dev : 0;
+
+ char major[16], minor[16];
+ char *envp[] = { major, minor, NULL };
+
+ snprintf(major, sizeof(major), "MAJOR=%d", MAJOR(bd_dev));
+ snprintf(minor, sizeof(minor), "MINOR=%d", MINOR(bd_dev));
+
+ kobject_uevent_env(&sdfat_uevent_kobj, KOBJ_CHANGE, envp);
+
+ ST_LOG("[SDFAT](%s[%d:%d]): Uevent triggered\n",
+ sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
+}
+#endif
+
/*
* sdfat_fs_error reports a file system problem that might indicate fa data
* corruption/inconsistency. Depending on 'errors' mount option the
ST_LOG("[SDFAT](%s[%d:%d]): Filesystem has been set read-only\n",
sb->s_id, MAJOR(bd_dev), MINOR(bd_dev));
#endif
+ sdfat_uevent_ro_remount(sb);
}
}
EXPORT_SYMBOL(__sdfat_fs_error);
0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0,
};
+#define TIMEZONE_SEC(x) ((x) * 15 * SECS_PER_MIN)
/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */
-void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, struct timespec *ts,
- DATE_TIME_T *tp)
+void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
+ DATE_TIME_T *tp)
{
time_t year = tp->Year;
time_t ld; /* leap day */
+ (year * 365 + ld + accum_days_in_year[tp->Month]
+ (tp->Day - 1) + DAYS_DELTA_DECADE) * SECS_PER_DAY;
- if (!sbi->options.tz_utc)
+ ts->tv_nsec = 0;
+
+ /* Treat as local time */
+ if (!sbi->options.tz_utc && !tp->Timezone.valid) {
ts->tv_sec += sys_tz.tz_minuteswest * SECS_PER_MIN;
+ return;
+ }
- ts->tv_nsec = 0;
+ /* Treat as UTC time */
+ if (!tp->Timezone.valid)
+ return;
+
+ /* Treat as UTC time, but need to adjust timezone to UTC0 */
+ if (tp->Timezone.off <= 0x3F)
+ ts->tv_sec -= TIMEZONE_SEC(tp->Timezone.off);
+ else /* 0x40 <= (tp->Timezone & 0x7F) <=0x7F */
+ ts->tv_sec += TIMEZONE_SEC(0x80 - tp->Timezone.off);
}
+#define TIMEZONE_CUR_OFFSET() ((sys_tz.tz_minuteswest / (-15)) & 0x7F)
/* Convert linear UNIX date to a FAT time/date pair. */
-void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, struct timespec *ts,
- DATE_TIME_T *tp)
+void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
+ DATE_TIME_T *tp)
{
+ bool tz_valid = (sbi->fsi.vol_type == EXFAT) ? true : false;
time_t second = ts->tv_sec;
time_t day, month, year;
time_t ld; /* leap day */
- if (!sbi->options.tz_utc)
+ tp->Timezone.value = 0x00;
+
+ /* Treats as local time with proper time */
+ if (tz_valid || !sbi->options.tz_utc) {
second -= sys_tz.tz_minuteswest * SECS_PER_MIN;
+ if (tz_valid) {
+ tp->Timezone.valid = 1;
+ tp->Timezone.off = TIMEZONE_CUR_OFFSET();
+ }
+ }
/* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
if (second < UNIX_SECS_1980) {
TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tp)
{
- struct timespec ts = CURRENT_TIME_SEC;
+ sdfat_timespec_t ts = CURRENT_TIME_SEC;
DATE_TIME_T dt;
sdfat_time_unix2fat(sbi, &ts, &dt);
tp->hour = dt.Hour;
tp->min = dt.Minute;
tp->sec = dt.Second;
+ tp->tz.value = dt.Timezone.value;
return tp;
}
#include <linux/vmalloc.h>
#include <asm/current.h>
#include <asm/unaligned.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
+#include <linux/iversion.h>
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
#include <linux/aio.h>
#endif
/*************************************************************************
* FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
*************************************************************************/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)
+static inline void inode_set_iversion(struct inode *inode, u64 val)
+{
+ inode->i_version = val;
+}
+static inline u64 inode_peek_iversion(struct inode *inode)
+{
+ return inode->i_version;
+}
+#endif
+
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
/* EMPTY */
#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0) */
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
-#define CURRENT_TIME_SEC timespec_trunc(current_kernel_time(), NSEC_PER_SEC)
-#endif
-
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
static int sdfat_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int query_flags)
/*************************************************************************
* MORE FUNCTIONS WHICH HAS KERNEL VERSION DEPENDENCY
*************************************************************************/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
+#define CURRENT_TIME_SEC timespec64_trunc(current_kernel_time64(), NSEC_PER_SEC)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+#define CURRENT_TIME_SEC timespec_trunc(current_kernel_time(), NSEC_PER_SEC)
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) */
+ /* EMPTY */
+#endif
+
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
static void sdfat_writepage_end_io(struct bio *bio)
{
spin_lock(&dentry->d_lock);
if ((!dentry->d_inode) && (!__check_dstate_locked(dentry) &&
- (dentry->d_time != dentry->d_parent->d_inode->i_version))) {
+ (dentry->d_time !=
+ (unsigned long)inode_peek_iversion(dentry->d_parent->d_inode)))) {
ret = 0;
}
spin_unlock(&dentry->d_lock);
{
struct super_block *sb = dir->i_sb;
struct inode *inode;
- struct timespec ts;
+ sdfat_timespec_t ts;
FILE_ID_T fid;
loff_t i_pos;
int err;
__lock_d_revalidate(dentry);
- dir->i_version++;
+ inode_inc_iversion(dir);
dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
if (IS_DIRSYNC(dir))
(void) sdfat_sync_inode(dir);
err = PTR_ERR(inode);
goto out;
}
- inode->i_version++;
+ inode_inc_iversion(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
dput(alias);
out:
/* initialize d_time even though it is positive dentry */
- dentry->d_time = dir->i_version;
+ dentry->d_time = (unsigned long)inode_peek_iversion(dir);
__unlock_super(sb);
dentry = d_splice_alias(inode, dentry);
{
struct inode *inode = dentry->d_inode;
struct super_block *sb = dir->i_sb;
- struct timespec ts;
+ sdfat_timespec_t ts;
int err;
__lock_super(sb);
__lock_d_revalidate(dentry);
- dir->i_version++;
+ inode_inc_iversion(dir);
dir->i_mtime = dir->i_atime = ts;
if (IS_DIRSYNC(dir))
(void) sdfat_sync_inode(dir);
clear_nlink(inode);
inode->i_mtime = inode->i_atime = ts;
sdfat_detach(inode);
- dentry->d_time = dir->i_version;
+ dentry->d_time = (unsigned long)inode_peek_iversion(dir);
out:
__unlock_d_revalidate(dentry);
__unlock_super(sb);
{
struct super_block *sb = dir->i_sb;
struct inode *inode;
- struct timespec ts;
+ sdfat_timespec_t ts;
FILE_ID_T fid;
loff_t i_pos;
int err;
__lock_d_revalidate(dentry);
- dir->i_version++;
+ inode_inc_iversion(dir);
dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
if (IS_DIRSYNC(dir))
(void) sdfat_sync_inode(dir);
err = PTR_ERR(inode);
goto out;
}
- inode->i_version++;
+ inode_inc_iversion(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
{
struct super_block *sb = dir->i_sb;
struct inode *inode;
- struct timespec ts;
+ sdfat_timespec_t ts;
FILE_ID_T fid;
loff_t i_pos;
int err;
__lock_d_revalidate(dentry);
- dir->i_version++;
+ inode_inc_iversion(dir);
dir->i_ctime = dir->i_mtime = dir->i_atime = ts;
if (IS_DIRSYNC(dir))
(void) sdfat_sync_inode(dir);
err = PTR_ERR(inode);
goto out;
}
- inode->i_version++;
+ inode_inc_iversion(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime = ts;
/* timestamp is already written, so mark_inode_dirty() is unneeded. */
{
struct inode *inode = dentry->d_inode;
struct super_block *sb = dir->i_sb;
- struct timespec ts;
+ sdfat_timespec_t ts;
int err;
__lock_super(sb);
__lock_d_revalidate(dentry);
- dir->i_version++;
+ inode_inc_iversion(dir);
dir->i_mtime = dir->i_atime = ts;
if (IS_DIRSYNC(dir))
(void) sdfat_sync_inode(dir);
clear_nlink(inode);
inode->i_mtime = inode->i_atime = ts;
sdfat_detach(inode);
- dentry->d_time = dir->i_version;
+ dentry->d_time = (unsigned long)inode_peek_iversion(dir);
out:
__unlock_d_revalidate(dentry);
__unlock_super(sb);
{
struct inode *old_inode, *new_inode;
struct super_block *sb = old_dir->i_sb;
- struct timespec ts;
+ sdfat_timespec_t ts;
loff_t i_pos;
int err;
__lock_d_revalidate(old_dentry);
__lock_d_revalidate(new_dentry);
- new_dir->i_version++;
+ inode_inc_iversion(new_dir);
new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = ts;
if (IS_DIRSYNC(new_dir))
(void) sdfat_sync_inode(new_dir);
inc_nlink(new_dir);
}
- old_dir->i_version++;
+ inode_inc_iversion(old_dir);
old_dir->i_ctime = old_dir->i_mtime = ts;
if (IS_DIRSYNC(old_dir))
(void) sdfat_sync_inode(old_dir);
return 0;
}
+/*
+ * sdfat_block_truncate_page() zeroes out a mapping from file offset `from'
+ * up to the end of the block which corresponds to `from'.
+ * This is required during truncate to physically zeroout the tail end
+ * of that block so it doesn't yield old data if the file is later grown.
+ * Also, avoid causing failure from fsx for cases of "data past EOF"
+ */
+static int sdfat_block_truncate_page(struct inode *inode, loff_t from)
+{
+ return block_truncate_page(inode->i_mapping, from, sdfat_get_block);
+}
+
static int sdfat_setattr(struct dentry *dentry, struct iattr *attr)
{
&& (attr->ia_size > i_size_read(inode))) {
error = sdfat_cont_expand(inode, attr->ia_size);
if (error || attr->ia_valid == ATTR_SIZE)
- return error;
+ goto out;
attr->ia_valid &= ~ATTR_SIZE;
}
error = setattr_prepare(dentry, attr);
attr->ia_valid = ia_valid;
if (error)
- return error;
+ goto out;
if (((attr->ia_valid & ATTR_UID) &&
(!uid_eq(attr->ia_uid, sbi->options.fs_uid))) ||
(!gid_eq(attr->ia_gid, sbi->options.fs_gid))) ||
((attr->ia_valid & ATTR_MODE) &&
(attr->ia_mode & ~(S_IFREG | S_IFLNK | S_IFDIR | S_IRWXUGO)))) {
- return -EPERM;
+ error = -EPERM;
+ goto out;
}
/*
/* patch 1.2.0 : fixed the problem of size mismatch. */
if (attr->ia_valid & ATTR_SIZE) {
+ error = sdfat_block_truncate_page(inode, attr->ia_size);
+ if (error)
+ goto out;
+
old_size = i_size_read(inode);
/* TO CHECK evicting directory works correctly */
}
setattr_copy(inode, attr);
mark_inode_dirty(inode);
-
-
+out:
TMSG("%s exited with err(%d)\n", __func__, error);
return error;
}
SDFAT_I(inode)->target = NULL;
inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid;
- inode->i_version++;
+ inode_inc_iversion(inode);
inode->i_generation = get_seconds();
if (fsapi_read_inode(inode, &info) < 0) {
goto out;
}
inode->i_ino = iunique(sb, SDFAT_ROOT_INO);
- inode->i_version = 1;
+ inode_set_iversion(inode, 1);
err = sdfat_fill_inode(inode, fid);
if (err) {
iput(inode);
{
struct super_block *sb = inode->i_sb;
struct sdfat_sb_info *sbi = SDFAT_SB(sb);
- struct timespec ts;
+ sdfat_timespec_t ts;
FS_INFO_T *fsi = &(sbi->fsi);
DIR_ENTRY_T info;
inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid;
- inode->i_version++;
+ inode_inc_iversion(inode);
inode->i_generation = 0;
inode->i_mode = sdfat_make_mode(sbi, ATTR_SUBDIR, S_IRWXUGO);
inode->i_op = &sdfat_dir_inode_operations;
}
root_inode->i_ino = SDFAT_ROOT_INO;
- root_inode->i_version = 1;
+ inode_set_iversion(root_inode, 1);
err = sdfat_read_root(root_inode);
if (err) {
sdfat_kset = kset_create_and_add("sdfat", NULL, fs_kobj);
if (!sdfat_kset) {
- pr_err("[SDFAT] failed to create fs_kobj\n");
+ pr_err("[SDFAT] failed to create sdfat kset\n");
err = -ENOMEM;
goto error;
}
if (err)
goto error;
+ err = sdfat_uevent_init(sdfat_kset);
+ if (err)
+ goto error;
+
err = sdfat_init_inodecache();
if (err) {
pr_err("[SDFAT] failed to initialize inode cache\n");
return 0;
error:
+ sdfat_uevent_uninit();
sdfat_statistics_uninit();
if (sdfat_kset) {
static void __exit exit_sdfat_fs(void)
{
+ sdfat_uevent_uninit();
sdfat_statistics_uninit();
if (sdfat_kset) {
struct inode vfs_inode;
};
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
+typedef struct timespec64 sdfat_timespec_t;
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0) */
+typedef struct timespec sdfat_timespec_t;
+#endif
+
/*
* FIXME : needs on-disk-slot in-memory data
*/
#endif
/* sdfat/misc.c */
+#ifdef CONFIG_SDFAT_UEVENT
+extern int sdfat_uevent_init(struct kset *sdfat_kset);
+extern void sdfat_uevent_uninit(void);
+extern void sdfat_uevent_ro_remount(struct super_block *sb);
+#else
+static inline int sdfat_uevent_init(struct kset *sdfat_kset)
+{
+ return 0;
+}
+static inline void sdfat_uevent_uninit(void) {};
+static inline void sdfat_uevent_ro_remount(struct super_block *sb) {};
+#endif
extern void
__sdfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
__printf(3, 4) __cold;
#define sdfat_log_msg(sb, lv, fmt, args...) \
__sdfat_msg(sb, lv, 1, fmt, ## args)
extern void sdfat_log_version(void);
-extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, struct timespec *ts,
+extern void sdfat_time_fat2unix(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
DATE_TIME_T *tp);
-extern void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, struct timespec *ts,
+extern void sdfat_time_unix2fat(struct sdfat_sb_info *sbi, sdfat_timespec_t *ts,
DATE_TIME_T *tp);
extern TIMESTAMP_T *tm_now(struct sdfat_sb_info *sbi, TIMESTAMP_T *tm);
__le16 access_date; // aligned
__u8 create_time_ms;
__u8 modify_time_ms;
- __u8 access_time_ms;
- __u8 reserved2[9];
+ __u8 create_tz;
+ __u8 modify_tz;
+ __u8 access_tz;
+ __u8 reserved2[7];
} FILE_DENTRY_T;
/* EXFAT stream extension directory entry (32 bytes) */
/* PURPOSE : sdFAT File Manager */
/* */
/************************************************************************/
-#define SDFAT_VERSION "2.1.8-lineage"
+#define SDFAT_VERSION "2.3.0-lineage"