mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-14 12:37:32 +00:00
Description for this pull request:
- Add ioctls to get and set file attribute that used in fatattr util. - Add zero_size_dir mount option not to allocate a cluster when creating directory. -----BEGIN PGP SIGNATURE----- iQJKBAABCgA0FiEE6NzKS6Uv/XAAGHgyZwv7A1FEIQgFAmVB3PcWHGxpbmtpbmpl b25Aa2VybmVsLm9yZwAKCRBnC/sDUUQhCPN6D/0eK9tVBSP4eZ7IKZ6OAjmjm+ED f4yrer/e44hRYw2kMu3zDjMOVyqsOOdzFy+Tu/dunEgWKyLR2LmPjkuIlyi0YZ8l bkkcO0wud6F4mp+p5w5V8Myyac1uzafTu9ChDqh61eNPI4lGRKaqI1apC1JzSDAM zPO2j3DZ9yd+bPjMkbFDFkzf8LMN2oqvV9rQLudLsIQICJoVfNwXY8wgioa1f00R YvRk8S2OFhpI7N8SXo/hvpgXySTI2tzfVQBvSigU7NZCObFx5SdvcRLmo6jtcMd3 /wykxae8xR+BE9x1eUiOz5fRsD4+7ebLPPxsqOxiF+S9Vlr6zgEelumrwP1cuVKo C/bqrjjiN2HAqJGLx/xE9F3KW4cQYzdhwl1p+06koVrTubTQE1Kp0idIcD+4yrMe 5/+R9n5T7LTdwGU8e70qD/65LMSj3r5ocZJvZHkXjWqe46k0sbti0E6KqCCn/9UV K7C7B6iW0082B2YDG8W1X5949UtwEHXyNuvn8a4rjwBX7ahcsZYlNJ9ucoW7gYms uqLXSFJVzJcp748xbCbqwqgS+u7gGyRxBT6ldruYEM/HnWRD16kdpCUNufcxpkKN +Z8pbMlxb5btm9WqduyMi1h1z0zPKsrJ//QS1kkUhjJEoMavF2k78iAN3IFpw/VJ 9v0Y7SfIik4v4kTMzw== =xztJ -----END PGP SIGNATURE----- Merge tag 'exfat-for-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat Pull exfat updates from Namjae Jeon: - Add ioctls to get and set file attribute that is used in the fatattr util - Add zero_size_dir mount option to avoid allocating a cluster when creating a directory * tag 'exfat-for-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat: exfat: support create zero-size directory exfat: support handle zero-size directory exfat: add ioctls for accessing attributes
This commit is contained in:
commit
dc737f11c2
7 changed files with 170 additions and 47 deletions
|
@ -287,7 +287,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx)
|
||||||
|
|
||||||
mutex_unlock(&EXFAT_SB(sb)->s_lock);
|
mutex_unlock(&EXFAT_SB(sb)->s_lock);
|
||||||
if (!dir_emit(ctx, nb->lfn, strlen(nb->lfn), inum,
|
if (!dir_emit(ctx, nb->lfn, strlen(nb->lfn), inum,
|
||||||
(de.attr & ATTR_SUBDIR) ? DT_DIR : DT_REG))
|
(de.attr & EXFAT_ATTR_SUBDIR) ? DT_DIR : DT_REG))
|
||||||
goto out;
|
goto out;
|
||||||
ctx->pos = cpos;
|
ctx->pos = cpos;
|
||||||
goto get_new;
|
goto get_new;
|
||||||
|
@ -359,7 +359,7 @@ unsigned int exfat_get_entry_type(struct exfat_dentry *ep)
|
||||||
if (ep->type == EXFAT_VOLUME)
|
if (ep->type == EXFAT_VOLUME)
|
||||||
return TYPE_VOLUME;
|
return TYPE_VOLUME;
|
||||||
if (ep->type == EXFAT_FILE) {
|
if (ep->type == EXFAT_FILE) {
|
||||||
if (le16_to_cpu(ep->dentry.file.attr) & ATTR_SUBDIR)
|
if (le16_to_cpu(ep->dentry.file.attr) & EXFAT_ATTR_SUBDIR)
|
||||||
return TYPE_DIR;
|
return TYPE_DIR;
|
||||||
return TYPE_FILE;
|
return TYPE_FILE;
|
||||||
}
|
}
|
||||||
|
@ -410,19 +410,21 @@ static void exfat_set_entry_type(struct exfat_dentry *ep, unsigned int type)
|
||||||
ep->type = EXFAT_VOLUME;
|
ep->type = EXFAT_VOLUME;
|
||||||
} else if (type == TYPE_DIR) {
|
} else if (type == TYPE_DIR) {
|
||||||
ep->type = EXFAT_FILE;
|
ep->type = EXFAT_FILE;
|
||||||
ep->dentry.file.attr = cpu_to_le16(ATTR_SUBDIR);
|
ep->dentry.file.attr = cpu_to_le16(EXFAT_ATTR_SUBDIR);
|
||||||
} else if (type == TYPE_FILE) {
|
} else if (type == TYPE_FILE) {
|
||||||
ep->type = EXFAT_FILE;
|
ep->type = EXFAT_FILE;
|
||||||
ep->dentry.file.attr = cpu_to_le16(ATTR_ARCHIVE);
|
ep->dentry.file.attr = cpu_to_le16(EXFAT_ATTR_ARCHIVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exfat_init_stream_entry(struct exfat_dentry *ep,
|
static void exfat_init_stream_entry(struct exfat_dentry *ep,
|
||||||
unsigned char flags, unsigned int start_clu,
|
unsigned int start_clu, unsigned long long size)
|
||||||
unsigned long long size)
|
|
||||||
{
|
{
|
||||||
exfat_set_entry_type(ep, TYPE_STREAM);
|
exfat_set_entry_type(ep, TYPE_STREAM);
|
||||||
ep->dentry.stream.flags = flags;
|
if (size == 0)
|
||||||
|
ep->dentry.stream.flags = ALLOC_FAT_CHAIN;
|
||||||
|
else
|
||||||
|
ep->dentry.stream.flags = ALLOC_NO_FAT_CHAIN;
|
||||||
ep->dentry.stream.start_clu = cpu_to_le32(start_clu);
|
ep->dentry.stream.start_clu = cpu_to_le32(start_clu);
|
||||||
ep->dentry.stream.valid_size = cpu_to_le64(size);
|
ep->dentry.stream.valid_size = cpu_to_le64(size);
|
||||||
ep->dentry.stream.size = cpu_to_le64(size);
|
ep->dentry.stream.size = cpu_to_le64(size);
|
||||||
|
@ -488,9 +490,7 @@ int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir,
|
||||||
if (!ep)
|
if (!ep)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
exfat_init_stream_entry(ep,
|
exfat_init_stream_entry(ep, start_clu, size);
|
||||||
(type == TYPE_FILE) ? ALLOC_FAT_CHAIN : ALLOC_NO_FAT_CHAIN,
|
|
||||||
start_clu, size);
|
|
||||||
exfat_update_bh(bh, IS_DIRSYNC(inode));
|
exfat_update_bh(bh, IS_DIRSYNC(inode));
|
||||||
brelse(bh);
|
brelse(bh);
|
||||||
|
|
||||||
|
|
|
@ -234,6 +234,8 @@ struct exfat_mount_options {
|
||||||
discard:1, /* Issue discard requests on deletions */
|
discard:1, /* Issue discard requests on deletions */
|
||||||
keep_last_dots:1; /* Keep trailing periods in paths */
|
keep_last_dots:1; /* Keep trailing periods in paths */
|
||||||
int time_offset; /* Offset of timestamps from UTC (in minutes) */
|
int time_offset; /* Offset of timestamps from UTC (in minutes) */
|
||||||
|
/* Support creating zero-size directory, default: false */
|
||||||
|
bool zero_size_dir;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -357,10 +359,10 @@ static inline int exfat_mode_can_hold_ro(struct inode *inode)
|
||||||
static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi,
|
static inline mode_t exfat_make_mode(struct exfat_sb_info *sbi,
|
||||||
unsigned short attr, mode_t mode)
|
unsigned short attr, mode_t mode)
|
||||||
{
|
{
|
||||||
if ((attr & ATTR_READONLY) && !(attr & ATTR_SUBDIR))
|
if ((attr & EXFAT_ATTR_READONLY) && !(attr & EXFAT_ATTR_SUBDIR))
|
||||||
mode &= ~0222;
|
mode &= ~0222;
|
||||||
|
|
||||||
if (attr & ATTR_SUBDIR)
|
if (attr & EXFAT_ATTR_SUBDIR)
|
||||||
return (mode & ~sbi->options.fs_dmask) | S_IFDIR;
|
return (mode & ~sbi->options.fs_dmask) | S_IFDIR;
|
||||||
|
|
||||||
return (mode & ~sbi->options.fs_fmask) | S_IFREG;
|
return (mode & ~sbi->options.fs_fmask) | S_IFREG;
|
||||||
|
@ -372,18 +374,18 @@ static inline unsigned short exfat_make_attr(struct inode *inode)
|
||||||
unsigned short attr = EXFAT_I(inode)->attr;
|
unsigned short attr = EXFAT_I(inode)->attr;
|
||||||
|
|
||||||
if (S_ISDIR(inode->i_mode))
|
if (S_ISDIR(inode->i_mode))
|
||||||
attr |= ATTR_SUBDIR;
|
attr |= EXFAT_ATTR_SUBDIR;
|
||||||
if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222))
|
if (exfat_mode_can_hold_ro(inode) && !(inode->i_mode & 0222))
|
||||||
attr |= ATTR_READONLY;
|
attr |= EXFAT_ATTR_READONLY;
|
||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void exfat_save_attr(struct inode *inode, unsigned short attr)
|
static inline void exfat_save_attr(struct inode *inode, unsigned short attr)
|
||||||
{
|
{
|
||||||
if (exfat_mode_can_hold_ro(inode))
|
if (exfat_mode_can_hold_ro(inode))
|
||||||
EXFAT_I(inode)->attr = attr & (ATTR_RWMASK | ATTR_READONLY);
|
EXFAT_I(inode)->attr = attr & (EXFAT_ATTR_RWMASK | EXFAT_ATTR_READONLY);
|
||||||
else
|
else
|
||||||
EXFAT_I(inode)->attr = attr & ATTR_RWMASK;
|
EXFAT_I(inode)->attr = attr & EXFAT_ATTR_RWMASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool exfat_is_last_sector_in_cluster(struct exfat_sb_info *sbi,
|
static inline bool exfat_is_last_sector_in_cluster(struct exfat_sb_info *sbi,
|
||||||
|
|
|
@ -64,15 +64,16 @@
|
||||||
#define CS_DEFAULT 2
|
#define CS_DEFAULT 2
|
||||||
|
|
||||||
/* file attributes */
|
/* file attributes */
|
||||||
#define ATTR_READONLY 0x0001
|
#define EXFAT_ATTR_READONLY 0x0001
|
||||||
#define ATTR_HIDDEN 0x0002
|
#define EXFAT_ATTR_HIDDEN 0x0002
|
||||||
#define ATTR_SYSTEM 0x0004
|
#define EXFAT_ATTR_SYSTEM 0x0004
|
||||||
#define ATTR_VOLUME 0x0008
|
#define EXFAT_ATTR_VOLUME 0x0008
|
||||||
#define ATTR_SUBDIR 0x0010
|
#define EXFAT_ATTR_SUBDIR 0x0010
|
||||||
#define ATTR_ARCHIVE 0x0020
|
#define EXFAT_ATTR_ARCHIVE 0x0020
|
||||||
|
|
||||||
#define ATTR_RWMASK (ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \
|
#define EXFAT_ATTR_RWMASK (EXFAT_ATTR_HIDDEN | EXFAT_ATTR_SYSTEM | \
|
||||||
ATTR_SUBDIR | ATTR_ARCHIVE)
|
EXFAT_ATTR_VOLUME | EXFAT_ATTR_SUBDIR | \
|
||||||
|
EXFAT_ATTR_ARCHIVE)
|
||||||
|
|
||||||
#define BOOTSEC_JUMP_BOOT_LEN 3
|
#define BOOTSEC_JUMP_BOOT_LEN 3
|
||||||
#define BOOTSEC_FS_NAME_LEN 8
|
#define BOOTSEC_FS_NAME_LEN 8
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
#include <linux/cred.h>
|
#include <linux/cred.h>
|
||||||
#include <linux/buffer_head.h>
|
#include <linux/buffer_head.h>
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
|
#include <linux/fsnotify.h>
|
||||||
|
#include <linux/security.h>
|
||||||
|
#include <linux/msdos_fs.h>
|
||||||
|
|
||||||
#include "exfat_raw.h"
|
#include "exfat_raw.h"
|
||||||
#include "exfat_fs.h"
|
#include "exfat_fs.h"
|
||||||
|
@ -144,7 +147,7 @@ int __exfat_truncate(struct inode *inode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ei->type == TYPE_FILE)
|
if (ei->type == TYPE_FILE)
|
||||||
ei->attr |= ATTR_ARCHIVE;
|
ei->attr |= EXFAT_ATTR_ARCHIVE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* update the directory entry
|
* update the directory entry
|
||||||
|
@ -315,6 +318,93 @@ int exfat_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* modified ioctls from fat/file.c by Welmer Almesberger
|
||||||
|
*/
|
||||||
|
static int exfat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr)
|
||||||
|
{
|
||||||
|
u32 attr;
|
||||||
|
|
||||||
|
inode_lock_shared(inode);
|
||||||
|
attr = exfat_make_attr(inode);
|
||||||
|
inode_unlock_shared(inode);
|
||||||
|
|
||||||
|
return put_user(attr, user_attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int exfat_ioctl_set_attributes(struct file *file, u32 __user *user_attr)
|
||||||
|
{
|
||||||
|
struct inode *inode = file_inode(file);
|
||||||
|
struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb);
|
||||||
|
int is_dir = S_ISDIR(inode->i_mode);
|
||||||
|
u32 attr, oldattr;
|
||||||
|
struct iattr ia;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = get_user(attr, user_attr);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
err = mnt_want_write_file(file);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
inode_lock(inode);
|
||||||
|
|
||||||
|
oldattr = exfat_make_attr(inode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mask attributes so we don't set reserved fields.
|
||||||
|
*/
|
||||||
|
attr &= (EXFAT_ATTR_READONLY | EXFAT_ATTR_HIDDEN | EXFAT_ATTR_SYSTEM |
|
||||||
|
EXFAT_ATTR_ARCHIVE);
|
||||||
|
attr |= (is_dir ? EXFAT_ATTR_SUBDIR : 0);
|
||||||
|
|
||||||
|
/* Equivalent to a chmod() */
|
||||||
|
ia.ia_valid = ATTR_MODE | ATTR_CTIME;
|
||||||
|
ia.ia_ctime = current_time(inode);
|
||||||
|
if (is_dir)
|
||||||
|
ia.ia_mode = exfat_make_mode(sbi, attr, 0777);
|
||||||
|
else
|
||||||
|
ia.ia_mode = exfat_make_mode(sbi, attr, 0666 | (inode->i_mode & 0111));
|
||||||
|
|
||||||
|
/* The root directory has no attributes */
|
||||||
|
if (inode->i_ino == EXFAT_ROOT_INO && attr != EXFAT_ATTR_SUBDIR) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out_unlock_inode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((attr | oldattr) & EXFAT_ATTR_SYSTEM) &&
|
||||||
|
!capable(CAP_LINUX_IMMUTABLE)) {
|
||||||
|
err = -EPERM;
|
||||||
|
goto out_unlock_inode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The security check is questionable... We single
|
||||||
|
* out the RO attribute for checking by the security
|
||||||
|
* module, just because it maps to a file mode.
|
||||||
|
*/
|
||||||
|
err = security_inode_setattr(file_mnt_idmap(file),
|
||||||
|
file->f_path.dentry, &ia);
|
||||||
|
if (err)
|
||||||
|
goto out_unlock_inode;
|
||||||
|
|
||||||
|
/* This MUST be done before doing anything irreversible... */
|
||||||
|
err = exfat_setattr(file_mnt_idmap(file), file->f_path.dentry, &ia);
|
||||||
|
if (err)
|
||||||
|
goto out_unlock_inode;
|
||||||
|
|
||||||
|
fsnotify_change(file->f_path.dentry, ia.ia_valid);
|
||||||
|
|
||||||
|
exfat_save_attr(inode, attr);
|
||||||
|
mark_inode_dirty(inode);
|
||||||
|
out_unlock_inode:
|
||||||
|
inode_unlock(inode);
|
||||||
|
mnt_drop_write_file(file);
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int exfat_ioctl_fitrim(struct inode *inode, unsigned long arg)
|
static int exfat_ioctl_fitrim(struct inode *inode, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct fstrim_range range;
|
struct fstrim_range range;
|
||||||
|
@ -345,8 +435,13 @@ static int exfat_ioctl_fitrim(struct inode *inode, unsigned long arg)
|
||||||
long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct inode *inode = file_inode(filp);
|
struct inode *inode = file_inode(filp);
|
||||||
|
u32 __user *user_attr = (u32 __user *)arg;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
case FAT_IOCTL_GET_ATTRIBUTES:
|
||||||
|
return exfat_ioctl_get_attributes(inode, user_attr);
|
||||||
|
case FAT_IOCTL_SET_ATTRIBUTES:
|
||||||
|
return exfat_ioctl_set_attributes(filp, user_attr);
|
||||||
case FITRIM:
|
case FITRIM:
|
||||||
return exfat_ioctl_fitrim(inode, arg);
|
return exfat_ioctl_fitrim(inode, arg);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -400,9 +400,9 @@ static int exfat_write_end(struct file *file, struct address_space *mapping,
|
||||||
if (err < len)
|
if (err < len)
|
||||||
exfat_write_failed(mapping, pos+len);
|
exfat_write_failed(mapping, pos+len);
|
||||||
|
|
||||||
if (!(err < 0) && !(ei->attr & ATTR_ARCHIVE)) {
|
if (!(err < 0) && !(ei->attr & EXFAT_ATTR_ARCHIVE)) {
|
||||||
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
|
||||||
ei->attr |= ATTR_ARCHIVE;
|
ei->attr |= EXFAT_ATTR_ARCHIVE;
|
||||||
mark_inode_dirty(inode);
|
mark_inode_dirty(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,7 +550,7 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
|
||||||
inode_inc_iversion(inode);
|
inode_inc_iversion(inode);
|
||||||
inode->i_generation = get_random_u32();
|
inode->i_generation = get_random_u32();
|
||||||
|
|
||||||
if (info->attr & ATTR_SUBDIR) { /* directory */
|
if (info->attr & EXFAT_ATTR_SUBDIR) { /* directory */
|
||||||
inode->i_generation &= ~1;
|
inode->i_generation &= ~1;
|
||||||
inode->i_mode = exfat_make_mode(sbi, info->attr, 0777);
|
inode->i_mode = exfat_make_mode(sbi, info->attr, 0777);
|
||||||
inode->i_op = &exfat_dir_inode_operations;
|
inode->i_op = &exfat_dir_inode_operations;
|
||||||
|
|
|
@ -351,14 +351,20 @@ static int exfat_find_empty_entry(struct inode *inode,
|
||||||
if (exfat_check_max_dentries(inode))
|
if (exfat_check_max_dentries(inode))
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
/* we trust p_dir->size regardless of FAT type */
|
|
||||||
if (exfat_find_last_cluster(sb, p_dir, &last_clu))
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate new cluster to this directory
|
* Allocate new cluster to this directory
|
||||||
*/
|
*/
|
||||||
exfat_chain_set(&clu, last_clu + 1, 0, p_dir->flags);
|
if (ei->start_clu != EXFAT_EOF_CLUSTER) {
|
||||||
|
/* we trust p_dir->size regardless of FAT type */
|
||||||
|
if (exfat_find_last_cluster(sb, p_dir, &last_clu))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
exfat_chain_set(&clu, last_clu + 1, 0, p_dir->flags);
|
||||||
|
} else {
|
||||||
|
/* This directory is empty */
|
||||||
|
exfat_chain_set(&clu, EXFAT_EOF_CLUSTER, 0,
|
||||||
|
ALLOC_NO_FAT_CHAIN);
|
||||||
|
}
|
||||||
|
|
||||||
/* allocate a cluster */
|
/* allocate a cluster */
|
||||||
ret = exfat_alloc_cluster(inode, 1, &clu, IS_DIRSYNC(inode));
|
ret = exfat_alloc_cluster(inode, 1, &clu, IS_DIRSYNC(inode));
|
||||||
|
@ -368,6 +374,11 @@ static int exfat_find_empty_entry(struct inode *inode,
|
||||||
if (exfat_zeroed_cluster(inode, clu.dir))
|
if (exfat_zeroed_cluster(inode, clu.dir))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
if (ei->start_clu == EXFAT_EOF_CLUSTER) {
|
||||||
|
ei->start_clu = clu.dir;
|
||||||
|
p_dir->dir = clu.dir;
|
||||||
|
}
|
||||||
|
|
||||||
/* append to the FAT chain */
|
/* append to the FAT chain */
|
||||||
if (clu.flags != p_dir->flags) {
|
if (clu.flags != p_dir->flags) {
|
||||||
/* no-fat-chain bit is disabled,
|
/* no-fat-chain bit is disabled,
|
||||||
|
@ -507,7 +518,7 @@ static int exfat_add_entry(struct inode *inode, const char *path,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == TYPE_DIR) {
|
if (type == TYPE_DIR && !sbi->options.zero_size_dir) {
|
||||||
ret = exfat_alloc_new_dir(inode, &clu);
|
ret = exfat_alloc_new_dir(inode, &clu);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -534,13 +545,16 @@ static int exfat_add_entry(struct inode *inode, const char *path,
|
||||||
info->type = type;
|
info->type = type;
|
||||||
|
|
||||||
if (type == TYPE_FILE) {
|
if (type == TYPE_FILE) {
|
||||||
info->attr = ATTR_ARCHIVE;
|
info->attr = EXFAT_ATTR_ARCHIVE;
|
||||||
info->start_clu = EXFAT_EOF_CLUSTER;
|
info->start_clu = EXFAT_EOF_CLUSTER;
|
||||||
info->size = 0;
|
info->size = 0;
|
||||||
info->num_subdirs = 0;
|
info->num_subdirs = 0;
|
||||||
} else {
|
} else {
|
||||||
info->attr = ATTR_SUBDIR;
|
info->attr = EXFAT_ATTR_SUBDIR;
|
||||||
info->start_clu = start_clu;
|
if (sbi->options.zero_size_dir)
|
||||||
|
info->start_clu = EXFAT_EOF_CLUSTER;
|
||||||
|
else
|
||||||
|
info->start_clu = start_clu;
|
||||||
info->size = clu_size;
|
info->size = clu_size;
|
||||||
info->num_subdirs = EXFAT_MIN_SUBDIR;
|
info->num_subdirs = EXFAT_MIN_SUBDIR;
|
||||||
}
|
}
|
||||||
|
@ -646,7 +660,7 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
|
||||||
info->type = exfat_get_entry_type(ep);
|
info->type = exfat_get_entry_type(ep);
|
||||||
info->attr = le16_to_cpu(ep->dentry.file.attr);
|
info->attr = le16_to_cpu(ep->dentry.file.attr);
|
||||||
info->size = le64_to_cpu(ep2->dentry.stream.valid_size);
|
info->size = le64_to_cpu(ep2->dentry.stream.valid_size);
|
||||||
if ((info->type == TYPE_FILE) && (info->size == 0)) {
|
if (info->size == 0) {
|
||||||
info->flags = ALLOC_NO_FAT_CHAIN;
|
info->flags = ALLOC_NO_FAT_CHAIN;
|
||||||
info->start_clu = EXFAT_EOF_CLUSTER;
|
info->start_clu = EXFAT_EOF_CLUSTER;
|
||||||
} else {
|
} else {
|
||||||
|
@ -889,6 +903,9 @@ static int exfat_check_dir_empty(struct super_block *sb,
|
||||||
|
|
||||||
dentries_per_clu = sbi->dentries_per_clu;
|
dentries_per_clu = sbi->dentries_per_clu;
|
||||||
|
|
||||||
|
if (p_dir->dir == EXFAT_EOF_CLUSTER)
|
||||||
|
return 0;
|
||||||
|
|
||||||
exfat_chain_dup(&clu, p_dir);
|
exfat_chain_dup(&clu, p_dir);
|
||||||
|
|
||||||
while (clu.dir != EXFAT_EOF_CLUSTER) {
|
while (clu.dir != EXFAT_EOF_CLUSTER) {
|
||||||
|
@ -1033,8 +1050,8 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
|
||||||
|
|
||||||
*epnew = *epold;
|
*epnew = *epold;
|
||||||
if (exfat_get_entry_type(epnew) == TYPE_FILE) {
|
if (exfat_get_entry_type(epnew) == TYPE_FILE) {
|
||||||
epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE);
|
epnew->dentry.file.attr |= cpu_to_le16(EXFAT_ATTR_ARCHIVE);
|
||||||
ei->attr |= ATTR_ARCHIVE;
|
ei->attr |= EXFAT_ATTR_ARCHIVE;
|
||||||
}
|
}
|
||||||
exfat_update_bh(new_bh, sync);
|
exfat_update_bh(new_bh, sync);
|
||||||
brelse(old_bh);
|
brelse(old_bh);
|
||||||
|
@ -1065,8 +1082,8 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
|
||||||
ei->entry = newentry;
|
ei->entry = newentry;
|
||||||
} else {
|
} else {
|
||||||
if (exfat_get_entry_type(epold) == TYPE_FILE) {
|
if (exfat_get_entry_type(epold) == TYPE_FILE) {
|
||||||
epold->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE);
|
epold->dentry.file.attr |= cpu_to_le16(EXFAT_ATTR_ARCHIVE);
|
||||||
ei->attr |= ATTR_ARCHIVE;
|
ei->attr |= EXFAT_ATTR_ARCHIVE;
|
||||||
}
|
}
|
||||||
exfat_update_bh(old_bh, sync);
|
exfat_update_bh(old_bh, sync);
|
||||||
brelse(old_bh);
|
brelse(old_bh);
|
||||||
|
@ -1114,8 +1131,8 @@ static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir,
|
||||||
|
|
||||||
*epnew = *epmov;
|
*epnew = *epmov;
|
||||||
if (exfat_get_entry_type(epnew) == TYPE_FILE) {
|
if (exfat_get_entry_type(epnew) == TYPE_FILE) {
|
||||||
epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE);
|
epnew->dentry.file.attr |= cpu_to_le16(EXFAT_ATTR_ARCHIVE);
|
||||||
ei->attr |= ATTR_ARCHIVE;
|
ei->attr |= EXFAT_ATTR_ARCHIVE;
|
||||||
}
|
}
|
||||||
exfat_update_bh(new_bh, IS_DIRSYNC(inode));
|
exfat_update_bh(new_bh, IS_DIRSYNC(inode));
|
||||||
brelse(mov_bh);
|
brelse(mov_bh);
|
||||||
|
@ -1256,7 +1273,8 @@ static int __exfat_rename(struct inode *old_parent_inode,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free the clusters if new_inode is a dir(as if exfat_rmdir) */
|
/* Free the clusters if new_inode is a dir(as if exfat_rmdir) */
|
||||||
if (new_entry_type == TYPE_DIR) {
|
if (new_entry_type == TYPE_DIR &&
|
||||||
|
new_ei->start_clu != EXFAT_EOF_CLUSTER) {
|
||||||
/* new_ei, new_clu_to_free */
|
/* new_ei, new_clu_to_free */
|
||||||
struct exfat_chain new_clu_to_free;
|
struct exfat_chain new_clu_to_free;
|
||||||
|
|
||||||
|
|
|
@ -165,6 +165,8 @@ static int exfat_show_options(struct seq_file *m, struct dentry *root)
|
||||||
seq_puts(m, ",sys_tz");
|
seq_puts(m, ",sys_tz");
|
||||||
else if (opts->time_offset)
|
else if (opts->time_offset)
|
||||||
seq_printf(m, ",time_offset=%d", opts->time_offset);
|
seq_printf(m, ",time_offset=%d", opts->time_offset);
|
||||||
|
if (opts->zero_size_dir)
|
||||||
|
seq_puts(m, ",zero_size_dir");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +211,7 @@ enum {
|
||||||
Opt_keep_last_dots,
|
Opt_keep_last_dots,
|
||||||
Opt_sys_tz,
|
Opt_sys_tz,
|
||||||
Opt_time_offset,
|
Opt_time_offset,
|
||||||
|
Opt_zero_size_dir,
|
||||||
|
|
||||||
/* Deprecated options */
|
/* Deprecated options */
|
||||||
Opt_utf8,
|
Opt_utf8,
|
||||||
|
@ -237,6 +240,7 @@ static const struct fs_parameter_spec exfat_parameters[] = {
|
||||||
fsparam_flag("keep_last_dots", Opt_keep_last_dots),
|
fsparam_flag("keep_last_dots", Opt_keep_last_dots),
|
||||||
fsparam_flag("sys_tz", Opt_sys_tz),
|
fsparam_flag("sys_tz", Opt_sys_tz),
|
||||||
fsparam_s32("time_offset", Opt_time_offset),
|
fsparam_s32("time_offset", Opt_time_offset),
|
||||||
|
fsparam_flag("zero_size_dir", Opt_zero_size_dir),
|
||||||
__fsparam(NULL, "utf8", Opt_utf8, fs_param_deprecated,
|
__fsparam(NULL, "utf8", Opt_utf8, fs_param_deprecated,
|
||||||
NULL),
|
NULL),
|
||||||
__fsparam(NULL, "debug", Opt_debug, fs_param_deprecated,
|
__fsparam(NULL, "debug", Opt_debug, fs_param_deprecated,
|
||||||
|
@ -305,6 +309,9 @@ static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
opts->time_offset = result.int_32;
|
opts->time_offset = result.int_32;
|
||||||
break;
|
break;
|
||||||
|
case Opt_zero_size_dir:
|
||||||
|
opts->zero_size_dir = true;
|
||||||
|
break;
|
||||||
case Opt_utf8:
|
case Opt_utf8:
|
||||||
case Opt_debug:
|
case Opt_debug:
|
||||||
case Opt_namecase:
|
case Opt_namecase:
|
||||||
|
@ -360,7 +367,7 @@ static int exfat_read_root(struct inode *inode)
|
||||||
inode->i_gid = sbi->options.fs_gid;
|
inode->i_gid = sbi->options.fs_gid;
|
||||||
inode_inc_iversion(inode);
|
inode_inc_iversion(inode);
|
||||||
inode->i_generation = 0;
|
inode->i_generation = 0;
|
||||||
inode->i_mode = exfat_make_mode(sbi, ATTR_SUBDIR, 0777);
|
inode->i_mode = exfat_make_mode(sbi, EXFAT_ATTR_SUBDIR, 0777);
|
||||||
inode->i_op = &exfat_dir_inode_operations;
|
inode->i_op = &exfat_dir_inode_operations;
|
||||||
inode->i_fop = &exfat_dir_operations;
|
inode->i_fop = &exfat_dir_operations;
|
||||||
|
|
||||||
|
@ -369,7 +376,7 @@ static int exfat_read_root(struct inode *inode)
|
||||||
ei->i_size_aligned = i_size_read(inode);
|
ei->i_size_aligned = i_size_read(inode);
|
||||||
ei->i_size_ondisk = i_size_read(inode);
|
ei->i_size_ondisk = i_size_read(inode);
|
||||||
|
|
||||||
exfat_save_attr(inode, ATTR_SUBDIR);
|
exfat_save_attr(inode, EXFAT_ATTR_SUBDIR);
|
||||||
ei->i_crtime = simple_inode_init_ts(inode);
|
ei->i_crtime = simple_inode_init_ts(inode);
|
||||||
exfat_truncate_inode_atime(inode);
|
exfat_truncate_inode_atime(inode);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue