mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-23 10:04:00 +08:00
Defined option "posix_nlink" to compute a Posix compliant st_nlink
When the mount option "posix_nlink" is used, the number of links returned by stat complies with Posix : the legacy 8.3 names are not taken into account, and the subdirectories are taken into account for directories. This causes some overhead for recomputing the number of links.
This commit is contained in:
parent
1bc996f52f
commit
d6558f1dea
@ -117,6 +117,7 @@ int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
|||||||
int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
|
||||||
const char *value, size_t size, int flags);
|
const char *value, size_t size, int flags);
|
||||||
int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni);
|
int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni);
|
||||||
|
int ntfs_dir_link_cnt(ntfs_inode *ni);
|
||||||
|
|
||||||
#if CACHE_INODE_SIZE
|
#if CACHE_INODE_SIZE
|
||||||
|
|
||||||
|
@ -2792,3 +2792,82 @@ int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||||||
}
|
}
|
||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Increment the count of subdirectories
|
||||||
|
* (excluding entries with a short name)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int nlink_increment(void *nlink_ptr,
|
||||||
|
const ntfschar *name __attribute__((unused)),
|
||||||
|
const int len __attribute__((unused)),
|
||||||
|
const int type,
|
||||||
|
const s64 pos __attribute__((unused)),
|
||||||
|
const MFT_REF mref __attribute__((unused)),
|
||||||
|
const unsigned int dt_type)
|
||||||
|
{
|
||||||
|
if ((dt_type == NTFS_DT_DIR) && (type != FILE_NAME_DOS))
|
||||||
|
(*((int*)nlink_ptr))++;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute the number of hard links according to Posix
|
||||||
|
* For a directory count the subdirectories whose name is not
|
||||||
|
* a short one, but count "." and ".."
|
||||||
|
* Otherwise count the names, excluding the short ones.
|
||||||
|
*
|
||||||
|
* if there is an error, a null count is returned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ntfs_dir_link_cnt(ntfs_inode *ni)
|
||||||
|
{
|
||||||
|
ntfs_attr_search_ctx *actx;
|
||||||
|
FILE_NAME_ATTR *fn;
|
||||||
|
s64 pos;
|
||||||
|
int err = 0;
|
||||||
|
int nlink = 0;
|
||||||
|
|
||||||
|
if (!ni) {
|
||||||
|
ntfs_log_error("Invalid argument.\n");
|
||||||
|
errno = EINVAL;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
if (ni->nr_extents == -1)
|
||||||
|
ni = ni->base_ni;
|
||||||
|
if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
|
||||||
|
/*
|
||||||
|
* Directory : scan the directory and count
|
||||||
|
* subdirectories whose name is not DOS-only.
|
||||||
|
* The directory names are ignored, but "." and ".."
|
||||||
|
* are taken into account.
|
||||||
|
*/
|
||||||
|
pos = 0;
|
||||||
|
err = ntfs_readdir(ni, &pos, &nlink, nlink_increment);
|
||||||
|
if (err)
|
||||||
|
nlink = 0;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Non-directory : search for FILE_NAME attributes,
|
||||||
|
* and count those which are not DOS-only ones.
|
||||||
|
*/
|
||||||
|
actx = ntfs_attr_get_search_ctx(ni, NULL);
|
||||||
|
if (!actx)
|
||||||
|
goto err_out;
|
||||||
|
while (!(err = ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0,
|
||||||
|
CASE_SENSITIVE, 0, NULL, 0, actx))) {
|
||||||
|
fn = (FILE_NAME_ATTR*)((u8*)actx->attr +
|
||||||
|
le16_to_cpu(actx->attr->value_offset));
|
||||||
|
if (fn->file_name_type != FILE_NAME_DOS)
|
||||||
|
nlink++;
|
||||||
|
}
|
||||||
|
if (err && (errno != ENOENT))
|
||||||
|
nlink = 0;
|
||||||
|
ntfs_attr_put_search_ctx(actx);
|
||||||
|
}
|
||||||
|
if (!nlink)
|
||||||
|
ntfs_log_perror("Failed to compute nlink of inode %lld",
|
||||||
|
(long long)ni->mft_no);
|
||||||
|
err_out :
|
||||||
|
return (nlink);
|
||||||
|
}
|
||||||
|
@ -708,6 +708,9 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
|
|||||||
memset(stbuf, 0, sizeof(struct stat));
|
memset(stbuf, 0, sizeof(struct stat));
|
||||||
withusermapping = (scx->mapping[MAPUSERS] != (struct MAPPING*)NULL);
|
withusermapping = (scx->mapping[MAPUSERS] != (struct MAPPING*)NULL);
|
||||||
stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
|
stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
|
||||||
|
if (ctx->posix_nlink
|
||||||
|
&& !(ni->flags & FILE_ATTR_REPARSE_POINT))
|
||||||
|
stbuf->st_nlink = ntfs_dir_link_cnt(ni);
|
||||||
if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||||
|| (ni->flags & FILE_ATTR_REPARSE_POINT)) {
|
|| (ni->flags & FILE_ATTR_REPARSE_POINT)) {
|
||||||
if (ni->flags & FILE_ATTR_REPARSE_POINT) {
|
if (ni->flags & FILE_ATTR_REPARSE_POINT) {
|
||||||
@ -770,7 +773,8 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
|
|||||||
}
|
}
|
||||||
stbuf->st_size = ni->data_size;
|
stbuf->st_size = ni->data_size;
|
||||||
stbuf->st_blocks = ni->allocated_size >> 9;
|
stbuf->st_blocks = ni->allocated_size >> 9;
|
||||||
stbuf->st_nlink = 1; /* Make find(1) work */
|
if (!ctx->posix_nlink)
|
||||||
|
stbuf->st_nlink = 1; /* Make find(1) work */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Regular or Interix (INTX) file. */
|
/* Regular or Interix (INTX) file. */
|
||||||
|
@ -250,6 +250,13 @@ they do not appear in Windows directory displays either.
|
|||||||
When a file is renamed or linked with a new name, the hidden flag is
|
When a file is renamed or linked with a new name, the hidden flag is
|
||||||
adjusted to the latest name.
|
adjusted to the latest name.
|
||||||
.TP
|
.TP
|
||||||
|
.B posix_nlink
|
||||||
|
Compute the count of hard links of a file or directory according to
|
||||||
|
the Posix specifications. When this option is not set, a count of 1
|
||||||
|
is set for directories, and the short name of files is accounted for.
|
||||||
|
Using the option entails some penalty as the count is not stored and
|
||||||
|
has to be computed.
|
||||||
|
.TP
|
||||||
.B windows_names
|
.B windows_names
|
||||||
This option prevents files, directories and extended attributes to be
|
This option prevents files, directories and extended attributes to be
|
||||||
created with a name not allowed by windows, because
|
created with a name not allowed by windows, because
|
||||||
|
@ -790,6 +790,9 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
|
stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
|
||||||
|
if (ctx->posix_nlink
|
||||||
|
&& !(ni->flags & FILE_ATTR_REPARSE_POINT))
|
||||||
|
stbuf->st_nlink = ntfs_dir_link_cnt(ni);
|
||||||
|
|
||||||
if (((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
if (((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||||
|| (ni->flags & FILE_ATTR_REPARSE_POINT))
|
|| (ni->flags & FILE_ATTR_REPARSE_POINT))
|
||||||
@ -852,7 +855,8 @@ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
|
|||||||
}
|
}
|
||||||
stbuf->st_size = ni->data_size;
|
stbuf->st_size = ni->data_size;
|
||||||
stbuf->st_blocks = ni->allocated_size >> 9;
|
stbuf->st_blocks = ni->allocated_size >> 9;
|
||||||
stbuf->st_nlink = 1; /* Make find(1) work */
|
if (!ctx->posix_nlink)
|
||||||
|
stbuf->st_nlink = 1; /* Make find(1) work */
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Regular or Interix (INTX) file. */
|
/* Regular or Interix (INTX) file. */
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* ntfs-3g_common.c - Common definitions for ntfs-3g and lowntfs-3g.
|
* ntfs-3g_common.c - Common definitions for ntfs-3g and lowntfs-3g.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010-2019 Jean-Pierre Andre
|
* Copyright (c) 2010-2020 Jean-Pierre Andre
|
||||||
* Copyright (c) 2010 Erik Larsson
|
* Copyright (c) 2010 Erik Larsson
|
||||||
*
|
*
|
||||||
* This program/include file is free software; you can redistribute it and/or
|
* This program/include file is free software; you can redistribute it and/or
|
||||||
@ -126,6 +126,7 @@ const struct DEFOPTION optionlist[] = {
|
|||||||
{ "usermapping", OPT_USERMAPPING, FLGOPT_STRING },
|
{ "usermapping", OPT_USERMAPPING, FLGOPT_STRING },
|
||||||
{ "xattrmapping", OPT_XATTRMAPPING, FLGOPT_STRING },
|
{ "xattrmapping", OPT_XATTRMAPPING, FLGOPT_STRING },
|
||||||
{ "efs_raw", OPT_EFS_RAW, FLGOPT_BOGUS },
|
{ "efs_raw", OPT_EFS_RAW, FLGOPT_BOGUS },
|
||||||
|
{ "posix_nlink", OPT_POSIX_NLINK, FLGOPT_BOGUS },
|
||||||
{ (const char*)NULL, 0, 0 } /* end marker */
|
{ (const char*)NULL, 0, 0 } /* end marker */
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
@ -492,6 +493,9 @@ char *parse_mount_options(ntfs_fuse_context_t *ctx,
|
|||||||
ctx->efs_raw = TRUE;
|
ctx->efs_raw = TRUE;
|
||||||
break;
|
break;
|
||||||
#endif /* HAVE_SETXATTR */
|
#endif /* HAVE_SETXATTR */
|
||||||
|
case OPT_POSIX_NLINK :
|
||||||
|
ctx->posix_nlink = TRUE;
|
||||||
|
break;
|
||||||
case OPT_FSNAME : /* Filesystem name. */
|
case OPT_FSNAME : /* Filesystem name. */
|
||||||
/*
|
/*
|
||||||
* We need this to be able to check whether filesystem
|
* We need this to be able to check whether filesystem
|
||||||
|
@ -92,6 +92,7 @@ enum {
|
|||||||
OPT_USERMAPPING,
|
OPT_USERMAPPING,
|
||||||
OPT_XATTRMAPPING,
|
OPT_XATTRMAPPING,
|
||||||
OPT_EFS_RAW,
|
OPT_EFS_RAW,
|
||||||
|
OPT_POSIX_NLINK,
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
/* Option flags */
|
/* Option flags */
|
||||||
@ -153,6 +154,7 @@ typedef struct {
|
|||||||
BOOL no_detach;
|
BOOL no_detach;
|
||||||
BOOL blkdev;
|
BOOL blkdev;
|
||||||
BOOL mounted;
|
BOOL mounted;
|
||||||
|
BOOL posix_nlink;
|
||||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||||
BOOL efs_raw;
|
BOOL efs_raw;
|
||||||
#ifdef XATTR_MAPPINGS
|
#ifdef XATTR_MAPPINGS
|
||||||
|
Loading…
Reference in New Issue
Block a user