From 02673bd04a2b91db74c219fcba5cabb9e7eff4fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Tue, 26 Jan 2021 10:06:17 +0100 Subject: [PATCH] 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). --- include/ntfs-3g/plugin.h | 30 ++++++++++- libntfs-3g/dir.c | 7 +-- src/lowntfs-3g.c | 106 ++++++++++++++++++++++++++++----------- src/ntfs-3g.c | 100 ++++++++++++++++++++++++++---------- 4 files changed, 181 insertions(+), 62 deletions(-) diff --git a/include/ntfs-3g/plugin.h b/include/ntfs-3g/plugin.h index a9d56a5f..88e733c4 100644 --- a/include/ntfs-3g/plugin.h +++ b/include/ntfs-3g/plugin.h @@ -1,7 +1,7 @@ /* * 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, s64 *pos, void *fillctx, ntfs_filldir_t filldir, 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; diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index 5e5baf62..a517ece9 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -1508,12 +1508,7 @@ static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, le32 securid, errno = EINVAL; return NULL; } - - if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) { - errno = EOPNOTSUPP; - return NULL; - } - + ni = ntfs_mft_record_alloc(dir_ni->vol, NULL); if (!ni) return NULL; diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index f78cb9c8..c9d4a062 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -4,7 +4,7 @@ * Copyright (c) 2005-2007 Yura Pakhuchiy * Copyright (c) 2005 Yuval Fledel * 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 * * This file is originated from the Linux-NTFS project. @@ -261,7 +261,7 @@ static const char *usage_msg = "\n" "Copyright (C) 2005-2007 Yura Pakhuchiy\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" "\n" "Usage: %s [-o option[,...]] \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)); #endif /* Create object specified in @type. */ - 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 (dir_ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef DISABLE_PLUGINS + const plugin_operations_t *ops; + 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 */ + ni = (ntfs_inode*)NULL; + 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); + 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) { /* @@ -2525,10 +2549,25 @@ static int ntfs_fuse_newlink(fuse_req_t req __attribute__((unused)), #else ntfs_fuse_fill_security_context(req, &security); #endif - { - if (ntfs_link(ni, dir_ni, uname, uname_len)) { - res = -errno; + { + if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) { +#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; +#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); if (e) { @@ -2712,9 +2751,20 @@ static int ntfs_fuse_rm(fuse_req_t req, fuse_ino_t parent, const char *name, goto exit; } } - if (ntfs_delete(ctx->vol, (char*)NULL, ni, dir_ni, - uname, uname_len)) - res = -errno; + if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef DISABLE_PLUGINS + 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 */ ni = dir_ni = NULL; exit: diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 2eb197a8..70effd7b 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -4,7 +4,7 @@ * Copyright (c) 2005-2007 Yura Pakhuchiy * Copyright (c) 2005 Yuval Fledel * 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 * * This file is originated from the Linux-NTFS project. @@ -196,7 +196,7 @@ static const char *usage_msg = "\n" "Copyright (C) 2005-2007 Yura Pakhuchiy\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" "\n" "Usage: %s [-o option[,...]] \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)); #endif /* Create object specified in @type. */ - switch (type) { - case S_IFCHR: - case S_IFBLK: - ni = ntfs_create_device(dir_ni, securid, + if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef DISABLE_PLUGINS + const plugin_operations_t *ops; + 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); - 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, + 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; + break; + default: + ni = ntfs_create(dir_ni, securid, + uname, uname_len, type); + break; + } } if (ni) { /* @@ -2309,10 +2330,24 @@ static int ntfs_fuse_link(const char *old_path, const char *new_path) else #endif { - if (ntfs_link(ni, dir_ni, uname, uname_len)) { - res = -errno; - goto exit; - } + if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef DISABLE_PLUGINS + 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); 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, S_IEXEC + S_IWRITE + S_ISVTX)) { #endif - if (ntfs_delete(ctx->vol, org_path, ni, dir_ni, - uname, uname_len)) - res = -errno; + if (dir_ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef DISABLE_PLUGINS + 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 */ ni = dir_ni = NULL; #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)