Enabled actions on directories in reparse plugins

The plugins triggered by reparse points can now act on a directory
through link(2) unlink(2) and creat(2).
This commit is contained in:
Jean-Pierre André 2021-01-26 10:06:17 +01:00
parent 4b8a660006
commit 02673bd04a
4 changed files with 181 additions and 62 deletions

View File

@ -1,7 +1,7 @@
/* /*
* plugin.h : define interface for plugin development * plugin.h : define interface for plugin development
* *
* Copyright (c) 2015 Jean-Pierre Andre * Copyright (c) 2015-2021 Jean-Pierre Andre
* *
*/ */
@ -151,6 +151,34 @@ typedef struct plugin_operations {
int (*readdir)(ntfs_inode *ni, const REPARSE_POINT *reparse, int (*readdir)(ntfs_inode *ni, const REPARSE_POINT *reparse,
s64 *pos, void *fillctx, ntfs_filldir_t filldir, s64 *pos, void *fillctx, ntfs_filldir_t filldir,
struct fuse_file_info *fi); struct fuse_file_info *fi);
/*
* Create a new file of any type
*
* The returned value is a pointer to the inode created, or
* NULL if failed, with errno telling why.
*/
ntfs_inode *(*create)(ntfs_inode *dir_ni, const REPARSE_POINT *reparse,
le32 securid, ntfschar *name, int name_len,
mode_t type);
/*
* Link a new name to a file or directory
* Linking a directory is needed for renaming a directory
* The returned value is zero for success or a negative errno
* value for failure.
* If the returned value is zero, the modified time stamp
* will be updated after the call.
*/
int (*link)(ntfs_inode *dir_ni, const REPARSE_POINT *reparse,
ntfs_inode *ni, ntfschar *name, int name_len);
/*
* Unlink a name from a directory
* The argument pathname may be NULL
* The returned value is zero for success or a negative errno
* value for failure.
*/
int (*unlink)(ntfs_inode *dir_ni, const REPARSE_POINT *reparse,
const char *pathname,
ntfs_inode *ni, ntfschar *name, int name_len);
} plugin_operations_t; } plugin_operations_t;

View File

@ -1508,12 +1508,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid,
errno = EINVAL; errno = EINVAL;
return NULL; return NULL;
} }
if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
errno = EOPNOTSUPP;
return NULL;
}
ni = ntfs_mft_record_alloc(dir_ni->vol, NULL); ni = ntfs_mft_record_alloc(dir_ni->vol, NULL);
if (!ni) if (!ni)
return NULL; return NULL;

View File

@ -4,7 +4,7 @@
* Copyright (c) 2005-2007 Yura Pakhuchiy * Copyright (c) 2005-2007 Yura Pakhuchiy
* Copyright (c) 2005 Yuval Fledel * Copyright (c) 2005 Yuval Fledel
* Copyright (c) 2006-2009 Szabolcs Szakacsits * Copyright (c) 2006-2009 Szabolcs Szakacsits
* Copyright (c) 2007-2020 Jean-Pierre Andre * Copyright (c) 2007-2021 Jean-Pierre Andre
* Copyright (c) 2009 Erik Larsson * Copyright (c) 2009 Erik Larsson
* *
* This file is originated from the Linux-NTFS project. * This file is originated from the Linux-NTFS project.
@ -261,7 +261,7 @@ static const char *usage_msg =
"\n" "\n"
"Copyright (C) 2005-2007 Yura Pakhuchiy\n" "Copyright (C) 2005-2007 Yura Pakhuchiy\n"
"Copyright (C) 2006-2009 Szabolcs Szakacsits\n" "Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
"Copyright (C) 2007-2020 Jean-Pierre Andre\n" "Copyright (C) 2007-2021 Jean-Pierre Andre\n"
"Copyright (C) 2009 Erik Larsson\n" "Copyright (C) 2009 Erik Larsson\n"
"\n" "\n"
"Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n" "Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n"
@ -2336,26 +2336,50 @@ static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
perm & ~security.umask, S_ISDIR(type)); perm & ~security.umask, S_ISDIR(type));
#endif #endif
/* Create object specified in @type. */ /* Create object specified in @type. */
switch (type) { if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
case S_IFCHR: #ifndef DISABLE_PLUGINS
case S_IFBLK: const plugin_operations_t *ops;
ni = ntfs_create_device(dir_ni, securid, REPARSE_POINT *reparse;
uname, uname_len, type, dev);
break; reparse = (REPARSE_POINT*)NULL;
case S_IFLNK: ops = select_reparse_plugin(ctx, dir_ni, &reparse);
utarget_len = ntfs_mbstoucs(target, &utarget); if (ops && ops->create) {
if (utarget_len < 0) { ni = (*ops->create)(dir_ni, reparse,
res = -errno; securid, uname, uname_len, type);
goto exit; } else {
} ni = (ntfs_inode*)NULL;
ni = ntfs_create_symlink(dir_ni, securid, errno = EOPNOTSUPP;
uname, uname_len, }
utarget, utarget_len); free(reparse);
break; #else /* DISABLE_PLUGINS */
default: ni = (ntfs_inode*)NULL;
ni = ntfs_create(dir_ni, securid, uname, errno = EOPNOTSUPP;
uname_len, type); #endif /* DISABLE_PLUGINS */
break; } else {
switch (type) {
case S_IFCHR:
case S_IFBLK:
ni = ntfs_create_device(dir_ni, securid,
uname, uname_len,
type, dev);
break;
case S_IFLNK:
utarget_len = ntfs_mbstoucs(target,
&utarget);
if (utarget_len < 0) {
res = -errno;
goto exit;
}
ni = ntfs_create_symlink(dir_ni,
securid,
uname, uname_len,
utarget, utarget_len);
break;
default:
ni = ntfs_create(dir_ni, securid, uname,
uname_len, type);
break;
}
} }
if (ni) { if (ni) {
/* /*
@ -2525,10 +2549,25 @@ static int ntfs_fuse_newlink(fuse_req_t req __attribute__((unused)),
#else #else
ntfs_fuse_fill_security_context(req, &security); ntfs_fuse_fill_security_context(req, &security);
#endif #endif
{ {
if (ntfs_link(ni, dir_ni, uname, uname_len)) { if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
res = -errno; #ifndef DISABLE_PLUGINS
const plugin_operations_t *ops;
REPARSE_POINT *reparse;
res = CALL_REPARSE_PLUGIN(dir_ni, link,
ni, uname, uname_len);
if (res < 0)
goto exit;
#else /* DISABLE_PLUGINS */
res = -EOPNOTSUPP;
goto exit; goto exit;
#endif /* DISABLE_PLUGINS */
} else {
if (ntfs_link(ni, dir_ni, uname, uname_len)) {
res = -errno;
goto exit;
}
} }
ntfs_inode_update_mbsname(dir_ni, newname, ni->mft_no); ntfs_inode_update_mbsname(dir_ni, newname, ni->mft_no);
if (e) { if (e) {
@ -2712,9 +2751,20 @@ static int ntfs_fuse_rm(fuse_req_t req, fuse_ino_t parent, const char *name,
goto exit; goto exit;
} }
} }
if (ntfs_delete(ctx->vol, (char*)NULL, ni, dir_ni, if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
uname, uname_len)) #ifndef DISABLE_PLUGINS
res = -errno; const plugin_operations_t *ops;
REPARSE_POINT *reparse;
res = CALL_REPARSE_PLUGIN(dir_ni, unlink, (char*)NULL,
ni, uname, uname_len);
#else /* DISABLE_PLUGINS */
res = -EOPNOTSUPP;
#endif /* DISABLE_PLUGINS */
} else
if (ntfs_delete(ctx->vol, (char*)NULL, ni, dir_ni,
uname, uname_len))
res = -errno;
/* ntfs_delete() always closes ni and dir_ni */ /* ntfs_delete() always closes ni and dir_ni */
ni = dir_ni = NULL; ni = dir_ni = NULL;
exit: exit:

View File

@ -4,7 +4,7 @@
* Copyright (c) 2005-2007 Yura Pakhuchiy * Copyright (c) 2005-2007 Yura Pakhuchiy
* Copyright (c) 2005 Yuval Fledel * Copyright (c) 2005 Yuval Fledel
* Copyright (c) 2006-2009 Szabolcs Szakacsits * Copyright (c) 2006-2009 Szabolcs Szakacsits
* Copyright (c) 2007-2020 Jean-Pierre Andre * Copyright (c) 2007-2021 Jean-Pierre Andre
* Copyright (c) 2009 Erik Larsson * Copyright (c) 2009 Erik Larsson
* *
* This file is originated from the Linux-NTFS project. * This file is originated from the Linux-NTFS project.
@ -196,7 +196,7 @@ static const char *usage_msg =
"\n" "\n"
"Copyright (C) 2005-2007 Yura Pakhuchiy\n" "Copyright (C) 2005-2007 Yura Pakhuchiy\n"
"Copyright (C) 2006-2009 Szabolcs Szakacsits\n" "Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
"Copyright (C) 2007-2020 Jean-Pierre Andre\n" "Copyright (C) 2007-2021 Jean-Pierre Andre\n"
"Copyright (C) 2009 Erik Larsson\n" "Copyright (C) 2009 Erik Larsson\n"
"\n" "\n"
"Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n" "Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n"
@ -2067,26 +2067,47 @@ static int ntfs_fuse_create(const char *org_path, mode_t typemode, dev_t dev,
perm & ~security.umask, S_ISDIR(type)); perm & ~security.umask, S_ISDIR(type));
#endif #endif
/* Create object specified in @type. */ /* Create object specified in @type. */
switch (type) { if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
case S_IFCHR: #ifndef DISABLE_PLUGINS
case S_IFBLK: const plugin_operations_t *ops;
ni = ntfs_create_device(dir_ni, securid, REPARSE_POINT *reparse;
reparse = (REPARSE_POINT*)NULL;
ops = select_reparse_plugin(ctx, dir_ni, &reparse);
if (ops && ops->create) {
ni = (*ops->create)(dir_ni, reparse,
securid, uname, uname_len, type);
} else {
ni = (ntfs_inode*)NULL;
errno = EOPNOTSUPP;
}
free(reparse);
#else /* DISABLE_PLUGINS */
errno = EOPNOTSUPP;
#endif /* DISABLE_PLUGINS */
} else {
switch (type) {
case S_IFCHR:
case S_IFBLK:
ni = ntfs_create_device(dir_ni, securid,
uname, uname_len, type, dev); uname, uname_len, type, dev);
break; break;
case S_IFLNK: case S_IFLNK:
utarget_len = ntfs_mbstoucs(target, &utarget); utarget_len = ntfs_mbstoucs(target,
if (utarget_len < 0) { &utarget);
res = -errno; if (utarget_len < 0) {
goto exit; res = -errno;
} goto exit;
ni = ntfs_create_symlink(dir_ni, securid, }
uname, uname_len, ni = ntfs_create_symlink(dir_ni,
securid, uname, uname_len,
utarget, utarget_len); utarget, utarget_len);
break; break;
default: default:
ni = ntfs_create(dir_ni, securid, uname, ni = ntfs_create(dir_ni, securid,
uname_len, type); uname, uname_len, type);
break; break;
}
} }
if (ni) { if (ni) {
/* /*
@ -2309,10 +2330,24 @@ static int ntfs_fuse_link(const char *old_path, const char *new_path)
else else
#endif #endif
{ {
if (ntfs_link(ni, dir_ni, uname, uname_len)) { if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
res = -errno; #ifndef DISABLE_PLUGINS
goto exit; const plugin_operations_t *ops;
} REPARSE_POINT *reparse;
res = CALL_REPARSE_PLUGIN(dir_ni, link,
ni, uname, uname_len);
#else /* DISABLE_PLUGINS */
errno = EOPNOTSUPP;
res = -errno;
#endif /* DISABLE_PLUGINS */
if (res)
goto exit;
} else
if (ntfs_link(ni, dir_ni, uname, uname_len)) {
res = -errno;
goto exit;
}
set_archive(ni); set_archive(ni);
ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME); ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
@ -2384,9 +2419,20 @@ static int ntfs_fuse_rm(const char *org_path)
|| ntfs_allowed_dir_access(&security, org_path, dir_ni, ni, || ntfs_allowed_dir_access(&security, org_path, dir_ni, ni,
S_IEXEC + S_IWRITE + S_ISVTX)) { S_IEXEC + S_IWRITE + S_ISVTX)) {
#endif #endif
if (ntfs_delete(ctx->vol, org_path, ni, dir_ni, if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) {
uname, uname_len)) #ifndef DISABLE_PLUGINS
res = -errno; const plugin_operations_t *ops;
REPARSE_POINT *reparse;
res = CALL_REPARSE_PLUGIN(dir_ni, unlink,
org_path, ni, uname, uname_len);
#else /* DISABLE_PLUGINS */
res = -EOPNOTSUPP;
#endif /* DISABLE_PLUGINS */
} else
if (ntfs_delete(ctx->vol, org_path, ni, dir_ni,
uname, uname_len))
res = -errno;
/* ntfs_delete() always closes ni and dir_ni */ /* ntfs_delete() always closes ni and dir_ni */
ni = dir_ni = NULL; ni = dir_ni = NULL;
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS) #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)