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.pull/2/head
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,
|
||||
const char *value, size_t size, int flags);
|
||||
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
|
||||
|
||||
|
|
|
@ -2792,3 +2792,82 @@ int ntfs_remove_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni)
|
|||
}
|
||||
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));
|
||||
withusermapping = (scx->mapping[MAPUSERS] != (struct MAPPING*)NULL);
|
||||
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)
|
||||
|| (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_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 {
|
||||
/* 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
|
||||
adjusted to the latest name.
|
||||
.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
|
||||
This option prevents files, directories and extended attributes to be
|
||||
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
|
||||
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)
|
||||
|| (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_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 {
|
||||
/* Regular or Interix (INTX) file. */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* 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
|
||||
*
|
||||
* 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 },
|
||||
{ "xattrmapping", OPT_XATTRMAPPING, FLGOPT_STRING },
|
||||
{ "efs_raw", OPT_EFS_RAW, FLGOPT_BOGUS },
|
||||
{ "posix_nlink", OPT_POSIX_NLINK, FLGOPT_BOGUS },
|
||||
{ (const char*)NULL, 0, 0 } /* end marker */
|
||||
} ;
|
||||
|
||||
|
@ -492,6 +493,9 @@ char *parse_mount_options(ntfs_fuse_context_t *ctx,
|
|||
ctx->efs_raw = TRUE;
|
||||
break;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
case OPT_POSIX_NLINK :
|
||||
ctx->posix_nlink = TRUE;
|
||||
break;
|
||||
case OPT_FSNAME : /* Filesystem name. */
|
||||
/*
|
||||
* We need this to be able to check whether filesystem
|
||||
|
|
|
@ -92,6 +92,7 @@ enum {
|
|||
OPT_USERMAPPING,
|
||||
OPT_XATTRMAPPING,
|
||||
OPT_EFS_RAW,
|
||||
OPT_POSIX_NLINK,
|
||||
} ;
|
||||
|
||||
/* Option flags */
|
||||
|
@ -153,6 +154,7 @@ typedef struct {
|
|||
BOOL no_detach;
|
||||
BOOL blkdev;
|
||||
BOOL mounted;
|
||||
BOOL posix_nlink;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
BOOL efs_raw;
|
||||
#ifdef XATTR_MAPPINGS
|
||||
|
|
Loading…
Reference in New Issue