diff options
-rw-r--r-- | source3/Makefile.in | 2 | ||||
-rw-r--r-- | source3/modules/onefs.h | 31 | ||||
-rw-r--r-- | source3/modules/onefs_open.c | 53 | ||||
-rw-r--r-- | source3/modules/onefs_streams.c | 580 | ||||
-rw-r--r-- | source3/modules/vfs_onefs.c | 23 |
5 files changed, 674 insertions, 15 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 624156b256..a4b9bda564 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -651,7 +651,7 @@ VFS_ACL_XATTR_OBJ = modules/vfs_acl_xattr.o VFS_ACL_TDB_OBJ = modules/vfs_acl_tdb.o VFS_SMB_TRAFFIC_ANALYZER_OBJ = modules/vfs_smb_traffic_analyzer.o VFS_ONEFS_OBJ = modules/vfs_onefs.o modules/onefs_acl.o modules/onefs_system.o \ - modules/onefs_open.o + modules/onefs_open.o modules/onefs_streams.o PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h index 884f141661..6e5eae3085 100644 --- a/source3/modules/onefs.h +++ b/source3/modules/onefs.h @@ -67,6 +67,32 @@ NTSTATUS onefs_create_file(vfs_handle_struct *handle, int *pinfo, SMB_STRUCT_STAT *psbuf); +int onefs_close(vfs_handle_struct *handle, struct files_struct *fsp); + +int onefs_rename(vfs_handle_struct *handle, const char *oldname, + const char *newname); + +int onefs_stat(vfs_handle_struct *handle, const char *fname, + SMB_STRUCT_STAT *sbuf); + +int onefs_fstat(vfs_handle_struct *handle, struct files_struct *fsp, + SMB_STRUCT_STAT *sbuf); + +int onefs_lstat(vfs_handle_struct *handle, const char *path, + SMB_STRUCT_STAT *sbuf); + +int onefs_unlink(vfs_handle_struct *handle, const char *path); + +int onefs_chflags(vfs_handle_struct *handle, const char *path, + unsigned int flags); + +NTSTATUS onefs_streaminfo(vfs_handle_struct *handle, + struct files_struct *fsp, + const char *fname, + TALLOC_CTX *mem_ctx, + unsigned int *num_streams, + struct stream_struct **streams); + NTSTATUS onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc); @@ -75,14 +101,15 @@ NTSTATUS onefs_get_nt_acl(vfs_handle_struct *handle, const char* name, NTSTATUS onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd); - - /* * Utility functions */ NTSTATUS onefs_samba_sd_to_sd(uint32 security_info_sent, SEC_DESC *psd, struct ifs_security_descriptor *sd); +NTSTATUS onefs_split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname, + char **pbase, char **pstream); + /* * System Interfaces */ diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c index df0b75df95..c8415de521 100644 --- a/source3/modules/onefs_open.c +++ b/source3/modules/onefs_open.c @@ -88,6 +88,9 @@ static NTSTATUS onefs_open_file(files_struct *fsp, int local_flags = flags; bool file_existed = VALID_STAT(*psbuf); const char *wild; + char *base = NULL; + char *stream = NULL; + int base_fd = -1; fsp->fh->fd = -1; errno = EPERM; @@ -191,9 +194,25 @@ static NTSTATUS onefs_open_file(files_struct *fsp, if (!lp_oplocks(SNUM(conn))) oplock_request = 0; + /* Stream handling */ + if (is_ntfs_stream_name(path)) { + status = onefs_split_ntfs_stream_name(talloc_tos(), path, + &base, &stream); + } + /* It's a stream, so pass in the base_fd */ + if (stream != NULL) { + SMB_ASSERT(fsp->base_fsp); + + DEBUG(10,("Opening a stream: base=%s(%d), stream=%s", + base, fsp->base_fsp->fh->fd, stream)); + + base_fd = fsp->base_fsp->fh->fd; + } + fsp->fh->fd = onefs_sys_create_file(conn, - -1, - path, + base_fd, + stream != NULL ? stream : + (base != NULL ? base : path), access_mask, open_access_mask, share_access, @@ -427,6 +446,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn, bool def_acl = False; bool posix_open = False; bool new_file_created = False; + bool clear_ads = False; struct file_id id; mode_t new_unx_mode = (mode_t)0; mode_t unx_mode = (mode_t)0; @@ -584,12 +604,14 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn, * exist create. */ flags2 |= (O_CREAT | O_TRUNC); + clear_ads = true; break; case FILE_OVERWRITE_IF: /* If file exists replace/overwrite. If file doesn't * exist create. */ flags2 |= (O_CREAT | O_TRUNC); + clear_ads = true; break; case FILE_OPEN: @@ -615,6 +637,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn, return NT_STATUS_OBJECT_NAME_NOT_FOUND; } flags2 |= O_TRUNC; + clear_ads = true; break; case FILE_CREATE: @@ -1098,6 +1121,16 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn, SMB_ASSERT(lck != NULL); + /* Delete streams if create_disposition requires it */ + if (file_existed && clear_ads) { + status = delete_all_streams(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(lck); + fd_close(fsp); + return status; + } + } + /* note that we ignore failure for the following. It is basically a hack for NFS, and NFS will never set one of these only read them. Nobody but Samba can ever set a deny @@ -1586,6 +1619,8 @@ static NTSTATUS open_streams_for_delete(connection_struct *conn, goto fail; } + /* Open the base file */ + for (i=0; i<num_streams; i++) { char *streamname; @@ -1725,8 +1760,7 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn, } if ((conn->fs_capabilities & FILE_NAMED_STREAMS) - && is_ntfs_stream_name(fname) - && (!(create_options & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) { + && is_ntfs_stream_name(fname)) { char *base; uint32 base_create_disposition; @@ -1735,8 +1769,8 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn, goto fail; } - status = split_ntfs_stream_name(talloc_tos(), fname, - &base, NULL); + status = onefs_split_ntfs_stream_name(talloc_tos(), fname, + &base, NULL); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("onefs_create_file_unixpath: " "split_ntfs_stream_name failed: %s\n", @@ -1765,7 +1799,7 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn, FILE_SHARE_DELETE), /* share_access */ base_create_disposition, /* create_disposition*/ 0, /* create_options */ - 0, /* file_attributes */ + file_attributes, /* file_attributes */ NO_OPLOCK, /* oplock_request */ 0, /* allocation_size */ NULL, /* sd */ @@ -1779,11 +1813,6 @@ static NTSTATUS onefs_create_file_unixpath(connection_struct *conn, "failed: %s\n", base, nt_errstr(status))); goto fail; } - /* - * we don't need to low level fd: This might conflict with - * OneFS streams. - */ - fd_close(base_fsp); } /* Covert generic bits in the security descriptor. */ diff --git a/source3/modules/onefs_streams.c b/source3/modules/onefs_streams.c new file mode 100644 index 0000000000..55ce11ecf5 --- /dev/null +++ b/source3/modules/onefs_streams.c @@ -0,0 +1,580 @@ +/* + * Unix SMB/CIFS implementation. + * + * Support for OneFS Alternate Data Streams + * + * Copyright (C) Tim Prouty, 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "onefs.h" +#include <sys/isi_enc.h> + +/* + * OneFS stores streams without the explicit :$DATA at the end, so this strips + * it off. All onefs_stream functions must call through this instead of + * split_ntfs_stream_name directly. + */ +NTSTATUS onefs_split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname, + char **pbase, char **pstream) +{ + NTSTATUS status; + char *stream; + + status = split_ntfs_stream_name(mem_ctx, fname, pbase, pstream); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* Default $DATA stream. */ + if (pstream == NULL || *pstream == NULL) { + return NT_STATUS_OK; + } + + /* Strip off the $DATA. */ + stream = strrchr_m(*pstream, ':'); + SMB_ASSERT(stream); + stream[0] = '\0'; + + return NT_STATUS_OK; +} + +int onefs_close(vfs_handle_struct *handle, struct files_struct *fsp) +{ + int ret2, ret = 0; + + if (fsp->base_fsp) { + ret = SMB_VFS_NEXT_CLOSE(handle, fsp->base_fsp); + } + ret2 = SMB_VFS_NEXT_CLOSE(handle, fsp); + + return ret ? ret : ret2; +} + +/* + * Get the ADS directory fd for a file. + */ +static int get_stream_dir_fd(connection_struct *conn, const char *base, + int *base_fdp) +{ + int base_fd; + int dir_fd; + int saved_errno; + + /* If a valid base_fdp was given, use it. */ + if (base_fdp && *base_fdp >= 0) { + base_fd = *base_fdp; + } else { + base_fd = onefs_sys_create_file(conn, + -1, + base, + 0, + 0, + 0, + 0, + 0, + 0, + INTERNAL_OPEN_ONLY, + 0, + NULL, + 0, + NULL); + if (base_fd < 0) { + return -1; + } + } + + /* Open the ADS directory. */ + dir_fd = onefs_sys_create_file(conn, + base_fd, + ".", + 0, + FILE_READ_DATA, + 0, + 0, + 0, + 0, + INTERNAL_OPEN_ONLY, + 0, + NULL, + 0, + NULL); + + /* Close base_fd if it's not need or on error. */ + if (!base_fdp || dir_fd < 0) { + saved_errno = errno; + close(base_fd); + errno = saved_errno; + } + + /* Set the out base_fdp if successful and it was requested. */ + if (base_fdp && dir_fd >= 0) { + *base_fdp = base_fd; + } + + return dir_fd; +} + +int onefs_rename(vfs_handle_struct *handle, const char *oldname, + const char *newname) +{ + TALLOC_CTX *frame = NULL; + int ret = -1; + int dir_fd, saved_errno; + bool old_is_stream; + bool new_is_stream; + char *obase = NULL; + char *osname = NULL; + char *nbase = NULL; + char *nsname = NULL; + + old_is_stream = is_ntfs_stream_name(oldname); + new_is_stream = is_ntfs_stream_name(newname); + + if (!old_is_stream && !new_is_stream) { + return SMB_VFS_NEXT_RENAME(handle, oldname, newname); + } + + frame = talloc_stackframe(); + + if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), + oldname, &obase, + &osname))) { + errno = ENOMEM; + goto done; + } + + if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), + newname, &nbase, + &nsname))) { + errno = ENOMEM; + goto done; + } + + dir_fd = get_stream_dir_fd(handle->conn, obase, NULL); + if (dir_fd < -1) { + goto done; + } + + DEBUG(8,("onefs_rename called for %s : %s => %s : %s\n", + obase, osname, nbase, nsname)); + + /* Handle rename of stream to default stream specially. */ + if (nsname == NULL) { + ret = enc_renameat(dir_fd, osname, ENC_DEFAULT, AT_FDCWD, + nbase, ENC_DEFAULT); + } else { + ret = enc_renameat(dir_fd, osname, ENC_DEFAULT, dir_fd, nsname, + ENC_DEFAULT); + } + + done: + saved_errno = errno; + close(dir_fd); + errno = saved_errno; + TALLOC_FREE(frame); + return ret; +} + +/* + * Merge a base file's sbuf into the a streams's sbuf. + */ +static void merge_stat(SMB_STRUCT_STAT *stream_sbuf, + const SMB_STRUCT_STAT *base_sbuf) +{ + int dos_flags = (UF_DOS_NOINDEX | UF_DOS_ARCHIVE | + UF_DOS_HIDDEN | UF_DOS_RO | UF_DOS_SYSTEM); + stream_sbuf->st_mtime = base_sbuf->st_mtime; + stream_sbuf->st_ctime = base_sbuf->st_ctime; + stream_sbuf->st_atime = base_sbuf->st_atime; + stream_sbuf->st_flags &= ~dos_flags; + stream_sbuf->st_flags |= base_sbuf->st_flags & dos_flags; +} + +static int stat_stream(vfs_handle_struct *handle, const char *base, + const char *stream, SMB_STRUCT_STAT *sbuf, int flags) +{ + SMB_STRUCT_STAT base_sbuf; + int base_fd = -1, dir_fd, ret, saved_errno; + + dir_fd = get_stream_dir_fd(handle->conn, base, &base_fd); + if (dir_fd < 0) { + return -1; + } + + /* Stat the stream. */ + ret = enc_fstatat(dir_fd, stream, ENC_DEFAULT, sbuf, flags); + if (ret != -1) { + /* Now stat the base file and merge the results. */ + ret = sys_fstat(base_fd, &base_sbuf); + if (ret != -1) { + merge_stat(sbuf, &base_sbuf); + } + } + + saved_errno = errno; + close(dir_fd); + close(base_fd); + errno = saved_errno; + return ret; +} + +int onefs_stat(vfs_handle_struct *handle, const char *path, + SMB_STRUCT_STAT *sbuf) +{ + char *base = NULL; + char *stream = NULL; + + if (!is_ntfs_stream_name(path)) { + return SMB_VFS_NEXT_STAT(handle, path, sbuf); + } + + if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), path, + &base, &stream))) { + DEBUG(10, ("onefs_split_ntfs_stream_name failed\n")); + errno = ENOMEM; + return -1; + } + + /* If it's the ::$DATA stream just stat the base file name. */ + if (!stream) { + return SMB_VFS_NEXT_STAT(handle, base, sbuf); + } + + return stat_stream(handle, base, stream, sbuf, 0); +} + +int onefs_fstat(vfs_handle_struct *handle, struct files_struct *fsp, + SMB_STRUCT_STAT *sbuf) +{ + SMB_STRUCT_STAT base_sbuf; + int ret; + + /* Stat the stream, by calling next_fstat on the stream's fd. */ + ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf); + if (ret == -1) { + return ret; + } + + /* Stat the base file and merge the results. */ + if (fsp != NULL && fsp->base_fsp != NULL) { + ret = sys_fstat(fsp->base_fsp->fh->fd, &base_sbuf); + if (ret != -1) { + merge_stat(sbuf, &base_sbuf); + } + } + + return ret; +} + +int onefs_lstat(vfs_handle_struct *handle, const char *path, + SMB_STRUCT_STAT *sbuf) +{ + char *base = NULL; + char *stream = NULL; + + if (!is_ntfs_stream_name(path)) { + return SMB_VFS_NEXT_LSTAT(handle, path, sbuf); + } + + if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), path, + &base, &stream))) { + DEBUG(10, ("onefs_split_ntfs_stream_name failed\n")); + errno = ENOMEM; + return -1; + } + + /* If it's the ::$DATA stream just stat the base file name. */ + if (!stream) { + return SMB_VFS_NEXT_LSTAT(handle, base, sbuf); + } + + return stat_stream(handle, base, stream, sbuf, AT_SYMLINK_NOFOLLOW); +} + +int onefs_unlink(vfs_handle_struct *handle, const char *path) +{ + char *base = NULL; + char *stream = NULL; + int dir_fd, ret, saved_errno; + + if (!is_ntfs_stream_name(path)) { + return SMB_VFS_NEXT_UNLINK(handle, path); + } + + if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), path, + &base, &stream))) { + DEBUG(10, ("onefs_split_ntfs_stream_name failed\n")); + errno = ENOMEM; + return -1; + } + + /* If it's the ::$DATA stream just unlink the base file name. */ + if (!stream) { + return SMB_VFS_NEXT_UNLINK(handle, base); + } + + dir_fd = get_stream_dir_fd(handle->conn, base, NULL); + if (dir_fd < 0) { + return -1; + } + + ret = enc_unlinkat(dir_fd, stream, ENC_DEFAULT, 0); + + saved_errno = errno; + close(dir_fd); + errno = saved_errno; + return ret; +} + +int onefs_chflags(vfs_handle_struct *handle, const char *path, + unsigned int flags) +{ + char *base = NULL; + char *stream = NULL; + + if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), path, + &base, &stream))) { + DEBUG(10, ("onefs_split_ntfs_stream_name failed\n")); + errno = ENOMEM; + return -1; + } + + /* + * Only set the attributes on the base file. ifs_createfile handles + * file creation attribute semantics. + */ + return SMB_VFS_NEXT_CHFLAGS(handle, base, flags); +} + +/* + * Streaminfo enumeration functionality + */ +struct streaminfo_state { + TALLOC_CTX *mem_ctx; + vfs_handle_struct *handle; + unsigned int num_streams; + struct stream_struct *streams; + NTSTATUS status; +}; + +static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams, + struct stream_struct **streams, + const char *name, SMB_OFF_T size, + SMB_OFF_T alloc_size) +{ + struct stream_struct *tmp; + + tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct, + (*num_streams)+1); + if (tmp == NULL) { + return false; + } + + tmp[*num_streams].name = talloc_asprintf(mem_ctx, ":%s:%s", name, + "$DATA"); + if (tmp[*num_streams].name == NULL) { + return false; + } + + tmp[*num_streams].size = size; + tmp[*num_streams].alloc_size = alloc_size; + + *streams = tmp; + *num_streams += 1; + return true; +} + +static NTSTATUS walk_onefs_streams(connection_struct *conn, files_struct *fsp, + const char *fname, + struct streaminfo_state *state, + SMB_STRUCT_STAT *base_sbuf) +{ + NTSTATUS status = NT_STATUS_OK; + bool opened_base_fd = false; + int base_fd = -1; + int dir_fd = -1; + int stream_fd = -1; + int ret; + SMB_STRUCT_DIR *dirp = NULL; + SMB_STRUCT_DIRENT *dp = NULL; + files_struct fake_fs; + struct fd_handle fake_fh; + SMB_STRUCT_STAT stream_sbuf; + + ZERO_STRUCT(fake_fh); + ZERO_STRUCT(fake_fs); + + /* If the base file is already open, use its fd. */ + if ((fsp != NULL) && (fsp->fh->fd != -1)) { + base_fd = fsp->fh->fd; + } else { + opened_base_fd = true; + } + + dir_fd = get_stream_dir_fd(conn, fname, &base_fd); + if (dir_fd < 0) { + return map_nt_error_from_unix(errno); + } + + /* Open the ADS directory. */ + if ((dirp = fdopendir(dir_fd)) == NULL) { + DEBUG(0, ("Error on opendir %s. errno=%d (%s)\n", + fname, errno, strerror(errno))); + status = map_nt_error_from_unix(errno); + goto out; + } + + fake_fs.conn = conn; + fake_fs.fh = &fake_fh; + fake_fs.fsp_name = SMB_STRDUP(fname); + + /* Iterate over the streams in the ADS directory. */ + while ((dp = SMB_VFS_READDIR(conn, dirp)) != NULL) { + /* Skip the "." and ".." entries */ + if ((strcmp(dp->d_name, ".") == 0) || + (strcmp(dp->d_name, "..") == 0)) + continue; + + /* Open actual stream */ + if ((stream_fd = onefs_sys_create_file(conn, + base_fd, + dp->d_name, + 0, + 0, + 0, + 0, + 0, + 0, + INTERNAL_OPEN_ONLY, + 0, + NULL, + 0, + NULL)) == -1) { + DEBUG(0, ("Error opening stream %s:%s. " + "errno=%d (%s)\n", fname, dp->d_name, errno, + strerror(errno))); + continue; + } + + /* Figure out the stat info. */ + fake_fh.fd = stream_fd; + ret = SMB_VFS_FSTAT(&fake_fs, &stream_sbuf); + close(stream_fd); + + if (ret) { + DEBUG(0, ("Error fstating stream %s:%s. " + "errno=%d (%s)\n", fname, dp->d_name, errno, + strerror(errno))); + continue; + } + + merge_stat(&stream_sbuf, base_sbuf); + + if (!add_one_stream(state->mem_ctx, + &state->num_streams, &state->streams, + dp->d_name, stream_sbuf.st_size, + get_allocation_size(conn, NULL, + &stream_sbuf))) { + state->status = NT_STATUS_NO_MEMORY; + break; + } + } + +out: + /* Cleanup everything that was opened. */ + if (dirp != NULL) { + SMB_VFS_CLOSEDIR(conn, dirp); + } + if (dir_fd >= 0) { + close(dir_fd); + } + if (opened_base_fd) { + SMB_ASSERT(base_fd >= 0); + close(base_fd); + } + + SAFE_FREE(fake_fs.fsp_name); + return status; +} + +NTSTATUS onefs_streaminfo(vfs_handle_struct *handle, + struct files_struct *fsp, + const char *fname, + TALLOC_CTX *mem_ctx, + unsigned int *num_streams, + struct stream_struct **streams) +{ + SMB_STRUCT_STAT sbuf; + int ret; + NTSTATUS status; + struct streaminfo_state state; + + /* Get a valid stat. */ + if ((fsp != NULL) && (fsp->fh->fd != -1)) { + if (is_ntfs_stream_name(fsp->fsp_name)) { + return NT_STATUS_INVALID_PARAMETER; + } + ret = SMB_VFS_FSTAT(fsp, &sbuf); + } else { + if (is_ntfs_stream_name(fname)) { + return NT_STATUS_INVALID_PARAMETER; + } + ret = SMB_VFS_STAT(handle->conn, fname, &sbuf); + } + + if (ret == -1) { + return map_nt_error_from_unix(errno); + } + + state.streams = NULL; + state.num_streams = 0; + + /* Add the default stream. */ + if (S_ISREG(sbuf.st_mode)) { + if (!add_one_stream(mem_ctx, + &state.num_streams, &state.streams, + "", sbuf.st_size, + get_allocation_size(handle->conn, fsp, + &sbuf))) { + return NT_STATUS_NO_MEMORY; + } + } + + state.mem_ctx = mem_ctx; + state.handle = handle; + state.status = NT_STATUS_OK; + + /* If there are more streams, add them too. */ + if (sbuf.st_flags & UF_HASADS) { + + status = walk_onefs_streams(handle->conn, fsp, fname, + &state, &sbuf); + + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(state.streams); + return status; + } + + if (!NT_STATUS_IS_OK(state.status)) { + TALLOC_FREE(state.streams); + return state.status; + } + } + + *num_streams = state.num_streams; + *streams = state.streams; + return NT_STATUS_OK; +} diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c index b6faf52c9a..6b42c0f373 100644 --- a/source3/modules/vfs_onefs.c +++ b/source3/modules/vfs_onefs.c @@ -66,13 +66,36 @@ static int onefs_statvfs(vfs_handle_struct *handle, const char *path, return result; } +static uint32_t onefs_fs_capabilities(struct vfs_handle_struct *handle) +{ + return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS; +} + static vfs_op_tuple onefs_ops[] = { + {SMB_VFS_OP(onefs_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES, + SMB_VFS_LAYER_TRANSPARENT}, {SMB_VFS_OP(onefs_mkdir), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_create_file), SMB_VFS_OP_CREATE_FILE, SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(onefs_close), SMB_VFS_OP_CLOSE, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_rename), SMB_VFS_OP_RENAME, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_stat), SMB_VFS_OP_STAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_fstat), SMB_VFS_OP_FSTAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_lstat), SMB_VFS_OP_LSTAT, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_unlink), SMB_VFS_OP_UNLINK, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_chflags), SMB_VFS_OP_CHFLAGS, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(onefs_streaminfo), SMB_VFS_OP_STREAMINFO, + SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, |