mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-23 18:14:24 +08:00
Made accessing reparse directories through internal plugins
When the bit 28 of a reparse tag is set on a directory, the reparse information should be ignored and the directory should be accessed the usual way (this setting is new to Windows 10). In such a situation access to the directory through an internal plugin rather than through an external one. The same policy applies to REPARSE_TAG_WCI which had been defined earlier without the bit 28 being set.
This commit is contained in:
parent
ad79372024
commit
4f450a35f5
@ -2403,22 +2403,23 @@ typedef struct {
|
||||
*
|
||||
* 1. The least significant 16 bits (i.e. bits 0 to 15) specify the type of
|
||||
* the reparse point.
|
||||
* 2. The 13 bits after this (i.e. bits 16 to 28) are reserved for future use.
|
||||
* 3. The most significant three bits are flags describing the reparse point.
|
||||
* 2. The 12 bits after this (i.e. bits 16 to 27) are reserved for future use.
|
||||
* 3. The most significant four bits are flags describing the reparse point.
|
||||
* They are defined as follows:
|
||||
* bit 28: Directory bit. If set, the directory is not a surrogate
|
||||
* and can be used the usual way.
|
||||
* bit 29: Name surrogate bit. If set, the filename is an alias for
|
||||
* another object in the system.
|
||||
* bit 30: High-latency bit. If set, accessing the first byte of data will
|
||||
* be slow. (E.g. the data is stored on a tape drive.)
|
||||
* bit 31: Microsoft bit. If set, the tag is owned by Microsoft. User
|
||||
* defined tags have to use zero here.
|
||||
* 4. However, on Windows 10 :
|
||||
* 4. Moreover, on Windows 10 :
|
||||
* Some flags may be used in bits 12 to 15 to further describe the
|
||||
* reparse point, and bit 28 may be set, probably to signal the
|
||||
* presence of these flags.
|
||||
* reparse point.
|
||||
*/
|
||||
typedef enum {
|
||||
IO_REPARSE_TAG_WITH_FLAGS = const_cpu_to_le32(0x10000000),
|
||||
IO_REPARSE_TAG_DIRECTORY = const_cpu_to_le32(0x10000000),
|
||||
IO_REPARSE_TAG_IS_ALIAS = const_cpu_to_le32(0x20000000),
|
||||
IO_REPARSE_TAG_IS_HIGH_LATENCY = const_cpu_to_le32(0x40000000),
|
||||
IO_REPARSE_TAG_IS_MICROSOFT = const_cpu_to_le32(0x80000000),
|
||||
|
@ -413,9 +413,7 @@ static const char *reparse_type_name(le32 tag)
|
||||
const char *name;
|
||||
le32 seltag;
|
||||
|
||||
seltag = tag;
|
||||
if (tag & IO_REPARSE_TAG_WITH_FLAGS)
|
||||
seltag &= IO_REPARSE_PLUGIN_SELECT;
|
||||
seltag = tag & IO_REPARSE_PLUGIN_SELECT;
|
||||
switch (seltag) {
|
||||
case IO_REPARSE_TAG_MOUNT_POINT :
|
||||
name = " (mount point)";
|
||||
|
@ -4568,6 +4568,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
register_internal_reparse_plugins();
|
||||
register_directory_plugins(ctx);
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
se = mount_fuse(parsed_options);
|
||||
|
@ -4304,6 +4304,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
register_internal_reparse_plugins();
|
||||
register_directory_plugins(ctx);
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
fh = mount_fuse(parsed_options);
|
||||
|
@ -36,6 +36,10 @@
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
@ -766,6 +770,108 @@ exit :
|
||||
|
||||
#ifndef DISABLE_PLUGINS
|
||||
|
||||
/*
|
||||
* Get attribute information for reparse directories
|
||||
*
|
||||
* Reparse directories have a reparse tag which should be ignored.
|
||||
*/
|
||||
|
||||
static int directory_getattr(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
struct stat *stbuf)
|
||||
{
|
||||
static ntfschar I30[] =
|
||||
{ const_cpu_to_le16('$'), const_cpu_to_le16('I'),
|
||||
const_cpu_to_le16('3'), const_cpu_to_le16('0') };
|
||||
ntfs_attr *na;
|
||||
int res;
|
||||
|
||||
res = -EOPNOTSUPP;
|
||||
if (ni && reparse && stbuf
|
||||
&& ((reparse->reparse_tag == IO_REPARSE_TAG_WCI)
|
||||
|| ((reparse->reparse_tag & IO_REPARSE_TAG_DIRECTORY)
|
||||
&& !(reparse->reparse_tag & IO_REPARSE_TAG_IS_ALIAS)))
|
||||
&& (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||
/* Directory */
|
||||
stbuf->st_mode = S_IFDIR | 0555;
|
||||
/* get index size, if not known */
|
||||
if (!test_nino_flag(ni, KnownSize)) {
|
||||
na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, I30, 4);
|
||||
if (na) {
|
||||
ni->data_size = na->data_size;
|
||||
ni->allocated_size = na->allocated_size;
|
||||
set_nino_flag(ni, KnownSize);
|
||||
ntfs_attr_close(na);
|
||||
}
|
||||
}
|
||||
stbuf->st_size = ni->data_size;
|
||||
stbuf->st_blocks = ni->allocated_size >> 9;
|
||||
stbuf->st_nlink = 1; /* Make find(1) work */
|
||||
res = 0;
|
||||
}
|
||||
/* Not a directory, or another error occurred */
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a reparse directory for reading
|
||||
*
|
||||
* Currently no reading context is created.
|
||||
*/
|
||||
|
||||
static int directory_opendir(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = -EOPNOTSUPP;
|
||||
if (ni && reparse && fi
|
||||
&& ((reparse->reparse_tag == IO_REPARSE_TAG_WCI)
|
||||
|| ((reparse->reparse_tag & IO_REPARSE_TAG_DIRECTORY)
|
||||
&& !(reparse->reparse_tag & IO_REPARSE_TAG_IS_ALIAS)))
|
||||
&& (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
|
||||
&& ((fi->flags & O_ACCMODE) == O_RDONLY))
|
||||
res = 0;
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* Release a reparse directory
|
||||
*
|
||||
* Should never be called, as no reading context was defined.
|
||||
*/
|
||||
|
||||
static int directory_release(ntfs_inode *ni __attribute__((unused)),
|
||||
const REPARSE_POINT *reparse __attribute__((unused)),
|
||||
struct fuse_file_info *fi __attribute__((unused)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read an open reparse directory
|
||||
*
|
||||
* Returns 0 or a negative error code
|
||||
*/
|
||||
|
||||
static int directory_readdir(ntfs_inode *ni, const REPARSE_POINT *reparse,
|
||||
s64 *pos, void *fillctx, ntfs_filldir_t filldir,
|
||||
struct fuse_file_info *fi __attribute__((unused)))
|
||||
{
|
||||
int res;
|
||||
|
||||
res = -EOPNOTSUPP;
|
||||
if (ni && reparse && pos && fillctx && filldir
|
||||
&& ((reparse->reparse_tag == IO_REPARSE_TAG_WCI)
|
||||
|| ((reparse->reparse_tag & IO_REPARSE_TAG_DIRECTORY)
|
||||
&& !(reparse->reparse_tag & IO_REPARSE_TAG_IS_ALIAS)))
|
||||
&& (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
|
||||
res = 0;
|
||||
if (ntfs_readdir(ni, pos, fillctx, filldir))
|
||||
res = -errno;
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag,
|
||||
const plugin_operations_t *ops, void *handle)
|
||||
{
|
||||
@ -773,14 +879,16 @@ int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag,
|
||||
int res;
|
||||
|
||||
res = -1;
|
||||
plugin = (plugin_list_t*)ntfs_malloc(sizeof(plugin_list_t));
|
||||
if (plugin) {
|
||||
plugin->tag = tag;
|
||||
plugin->ops = ops;
|
||||
plugin->handle = handle;
|
||||
plugin->next = ctx->plugins;
|
||||
ctx->plugins = plugin;
|
||||
res = 0;
|
||||
if (ctx) {
|
||||
plugin = (plugin_list_t*)ntfs_malloc(sizeof(plugin_list_t));
|
||||
if (plugin) {
|
||||
plugin->tag = tag;
|
||||
plugin->ops = ops;
|
||||
plugin->handle = handle;
|
||||
plugin->next = ctx->plugins;
|
||||
ctx->plugins = plugin;
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
@ -810,8 +918,8 @@ const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx,
|
||||
if (reparse) {
|
||||
tag = reparse->reparse_tag;
|
||||
seltag = tag;
|
||||
if (tag & IO_REPARSE_TAG_WITH_FLAGS)
|
||||
seltag &= IO_REPARSE_PLUGIN_SELECT;
|
||||
if (tag & IO_REPARSE_TAG_DIRECTORY)
|
||||
seltag &= IO_REPARSE_TAG_DIRECTORY;
|
||||
for (plugin=ctx->plugins; plugin && (plugin->tag != seltag);
|
||||
plugin = plugin->next) { }
|
||||
if (plugin) {
|
||||
@ -873,6 +981,23 @@ void close_reparse_plugins(ntfs_fuse_context_t *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
void register_directory_plugins(ntfs_fuse_context_t *ctx)
|
||||
{
|
||||
static const struct plugin_operations ops = {
|
||||
.getattr = directory_getattr,
|
||||
.release = directory_release,
|
||||
.opendir = directory_opendir,
|
||||
.readdir = directory_readdir,
|
||||
} ;
|
||||
|
||||
if (ctx) {
|
||||
register_reparse_plugin(ctx, IO_REPARSE_TAG_WCI,
|
||||
&ops, (void*)NULL);
|
||||
register_reparse_plugin(ctx, IO_REPARSE_TAG_DIRECTORY,
|
||||
&ops, (void*)NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
#ifdef HAVE_SETXATTR
|
||||
|
@ -211,7 +211,7 @@ const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx,
|
||||
ntfs_inode *ni, REPARSE_POINT **reparse);
|
||||
int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag,
|
||||
const plugin_operations_t *ops, void *handle);
|
||||
|
||||
void register_directory_plugins(ntfs_fuse_context_t *ctx);
|
||||
#endif /* DISABLE_PLUGINS */
|
||||
|
||||
#endif /* _NTFS_3G_COMMON_H */
|
||||
|
Loading…
Reference in New Issue
Block a user