diff --git a/include/ntfs-3g/plugin.h b/include/ntfs-3g/plugin.h index 7e7b2a7c..a9d56a5f 100644 --- a/include/ntfs-3g/plugin.h +++ b/include/ntfs-3g/plugin.h @@ -30,8 +30,9 @@ #ifndef _NTFS_PLUGIN_H #define _NTFS_PLUGIN_H -#include "inode.h" #include "layout.h" +#include "inode.h" +#include "dir.h" struct fuse_file_info; struct stat; @@ -71,10 +72,10 @@ typedef struct plugin_operations { struct fuse_file_info *fi); /* - * Release an open file + * Release an open file or directory * This is only called if fi->fh has been set to a non-null * value while opening. It may be used to free some context - * specific to the open file. + * specific to the open file or directory * The returned value is zero for success or a negative errno * value for failure. */ @@ -126,6 +127,30 @@ typedef struct plugin_operations { */ int (*truncate)(ntfs_inode *ni, const REPARSE_POINT *reparse, off_t size); + /* + * Open a directory + * The field fi->flags indicates the kind of opening. + * The field fi->fh may be used to store some information which + * will be available to subsequent readdir(). When used + * this field must be non-null and freed in release(). + * The returned value is zero for success and a negative errno + * value for failure. + */ + int (*opendir)(ntfs_inode *ni, const REPARSE_POINT *reparse, + struct fuse_file_info *fi); + + /* + * Get entries from a directory + * + * Use the filldir() function with fillctx argument to return + * the directory entries. + * Names "." and ".." are expected to be returned. + * The returned value is zero for success and a negative errno + * value for failure. + */ + int (*readdir)(ntfs_inode *ni, const REPARSE_POINT *reparse, + s64 *pos, void *fillctx, ntfs_filldir_t filldir, + struct fuse_file_info *fi); } plugin_operations_t; diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 748ba518..4bd211f6 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -203,6 +203,9 @@ typedef struct fill_item { typedef struct fill_context { struct fill_item *first; struct fill_item *last; +#ifndef DISABLE_PLUGINS + u64 fh; +#endif /* DISABLE_PLUGINS */ off_t off; fuse_req_t req; fuse_ino_t ino; @@ -1292,6 +1295,17 @@ static void ntfs_fuse_opendir(fuse_req_t req, fuse_ino_t ino, if (!ntfs_allowed_access(&security,ni,accesstype)) res = -EACCES; } + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef DISABLE_PLUGINS + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + fi->fh = 0; + res = CALL_REPARSE_PLUGIN(ni, opendir, fi); +#else /* DISABLE_PLUGINS */ + res = -EOPNOTSUPP; +#endif /* DISABLE_PLUGINS */ + } if (ntfs_inode_close(ni)) set_fuse_error(&res); if (!res) { @@ -1305,6 +1319,9 @@ static void ntfs_fuse_opendir(fuse_req_t req, fuse_ino_t ino, fill->filled = FALSE; fill->ino = ino; fill->off = 0; +#ifndef DISABLE_PLUGINS + fill->fh = fi->fh; +#endif /* DISABLE_PLUGINS */ } fi->fh = (long)fill; } @@ -1321,9 +1338,15 @@ static void ntfs_fuse_releasedir(fuse_req_t req, fuse_ino_t ino __attribute__((unused)), struct fuse_file_info *fi) { +#ifndef DISABLE_PLUGINS + struct fuse_file_info ufi; + ntfs_inode *ni; +#endif /* DISABLE_PLUGINS */ ntfs_fuse_fill_context_t *fill; ntfs_fuse_fill_item_t *current; + int res; + res = 0; fill = (ntfs_fuse_fill_context_t*)(long)fi->fh; if (fill && (fill->ino == ino)) { /* make sure to clear results */ @@ -1333,16 +1356,38 @@ static void ntfs_fuse_releasedir(fuse_req_t req, free(fill->first); fill->first = current; } +#ifndef DISABLE_PLUGINS + if (fill->fh) { + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + ni = ntfs_inode_open(ctx->vol, INODE(ino)); + if (ni) { + if (ni->flags & FILE_ATTR_REPARSE_POINT) { + memcpy(&ufi, fi, sizeof(ufi)); + ufi.fh = fill->fh; + res = CALL_REPARSE_PLUGIN(ni, release, + &ufi); + } + if (ntfs_inode_close(ni) && !res) + res = -errno; + } else + res = -errno; + } +#endif /* DISABLE_PLUGINS */ fill->ino = 0; free(fill); } - fuse_reply_err(req, 0); + fuse_reply_err(req, -res); } static void ntfs_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off __attribute__((unused)), struct fuse_file_info *fi __attribute__((unused))) { +#ifndef DISABLE_PLUGINS + struct fuse_file_info ufi; +#endif /* DISABLE_PLUGINS */ ntfs_fuse_fill_item_t *first; ntfs_fuse_fill_item_t *current; ntfs_fuse_fill_context_t *fill; @@ -1379,10 +1424,27 @@ static void ntfs_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, if (!ni) err = -errno; else { - if (ntfs_readdir(ni, &pos, fill, - (ntfs_filldir_t) + if (ni->flags + & FILE_ATTR_REPARSE_POINT) { +#ifndef DISABLE_PLUGINS + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + memcpy(&ufi, fi, sizeof(ufi)); + ufi.fh = fill->fh; + err = CALL_REPARSE_PLUGIN(ni, + readdir, &pos, fill, + (ntfs_filldir_t) + ntfs_fuse_filler, &ufi); +#else /* DISABLE_PLUGINS */ + err = -EOPNOTSUPP; +#endif /* DISABLE_PLUGINS */ + } else { + if (ntfs_readdir(ni, &pos, fill, + (ntfs_filldir_t) ntfs_fuse_filler)) - err = -errno; + err = -errno; + } fill->filled = TRUE; ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME); diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index e73eee33..9558d50b 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -1300,6 +1300,17 @@ static int ntfs_fuse_opendir(const char *path, ni,accesstype)) res = -EACCES; } + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef DISABLE_PLUGINS + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + fi->fh = 0; + res = CALL_REPARSE_PLUGIN(ni, opendir, fi); +#else /* DISABLE_PLUGINS */ + res = -EOPNOTSUPP; +#endif /* DISABLE_PLUGINS */ + } if (ntfs_inode_close(ni)) set_fuse_error(&res); } else @@ -1323,9 +1334,22 @@ static int ntfs_fuse_readdir(const char *path, void *buf, ni = ntfs_pathname_to_inode(ctx->vol, NULL, path); if (!ni) return -errno; - if (ntfs_readdir(ni, &pos, &fill_ctx, - (ntfs_filldir_t)ntfs_fuse_filler)) - err = -errno; + + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef DISABLE_PLUGINS + const plugin_operations_t *ops; + REPARSE_POINT *reparse; + + err = CALL_REPARSE_PLUGIN(ni, readdir, &pos, &fill_ctx, + (ntfs_filldir_t)ntfs_fuse_filler, fi); +#else /* DISABLE_PLUGINS */ + err = -EOPNOTSUPP; +#endif /* DISABLE_PLUGINS */ + } else { + if (ntfs_readdir(ni, &pos, &fill_ctx, + (ntfs_filldir_t)ntfs_fuse_filler)) + err = -errno; + } ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME); if (ntfs_inode_close(ni)) set_fuse_error(&err); @@ -3732,6 +3756,7 @@ static struct fuse_operations ntfs_3g_ops = { #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) .access = ntfs_fuse_access, .opendir = ntfs_fuse_opendir, + .releasedir = ntfs_fuse_release, #endif #ifdef HAVE_SETXATTR .getxattr = ntfs_fuse_getxattr,