diff options
Diffstat (limited to 'source3/modules')
-rw-r--r-- | source3/modules/onefs.h | 185 | ||||
-rw-r--r-- | source3/modules/onefs_acl.c | 979 | ||||
-rw-r--r-- | source3/modules/onefs_cbrl.c | 593 | ||||
-rw-r--r-- | source3/modules/onefs_config.c | 278 | ||||
-rw-r--r-- | source3/modules/onefs_config.h | 160 | ||||
-rw-r--r-- | source3/modules/onefs_dir.c | 622 | ||||
-rw-r--r-- | source3/modules/onefs_notify.c | 682 | ||||
-rw-r--r-- | source3/modules/onefs_open.c | 2200 | ||||
-rw-r--r-- | source3/modules/onefs_shadow_copy.c | 783 | ||||
-rw-r--r-- | source3/modules/onefs_shadow_copy.h | 32 | ||||
-rw-r--r-- | source3/modules/onefs_streams.c | 771 | ||||
-rw-r--r-- | source3/modules/onefs_system.c | 782 | ||||
-rw-r--r-- | source3/modules/perfcount_onefs.c | 481 | ||||
-rw-r--r-- | source3/modules/vfs_onefs.c | 299 | ||||
-rw-r--r-- | source3/modules/vfs_onefs_shadow_copy.c | 685 | ||||
-rw-r--r-- | source3/modules/wscript_build | 28 |
16 files changed, 0 insertions, 9560 deletions
diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h deleted file mode 100644 index b12a67e367..0000000000 --- a/source3/modules/onefs.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Support for OneFS - * - * Copyright (C) Steven Danneman, 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/>. - */ - -#ifndef _ONEFS_H -#define _ONEFS_H - -/* - * vfs interface handlers - */ -DIR *onefs_opendir(struct vfs_handle_struct *handle, - const char *fname, const char *mask, - uint32 attributes); - -struct dirent *onefs_readdir(struct vfs_handle_struct *handle, - DIR *dirp, SMB_STRUCT_STAT *sbuf); - -void onefs_seekdir(struct vfs_handle_struct *handle, DIR *dirp, - long offset); - -long onefs_telldir(struct vfs_handle_struct *handle, DIR *dirp); - -void onefs_rewinddir(struct vfs_handle_struct *handle, DIR *dirp); - -int onefs_closedir(struct vfs_handle_struct *handle, DIR *dir); - -void onefs_init_search_op(struct vfs_handle_struct *handle, - DIR *dirp); - -NTSTATUS onefs_create_file(vfs_handle_struct *handle, - struct smb_request *req, - uint16_t root_dir_fid, - struct smb_filename *smb_fname, - uint32_t access_mask, - uint32_t share_access, - uint32_t create_disposition, - uint32_t create_options, - uint32_t file_attributes, - uint32_t oplock_request, - uint64_t allocation_size, - struct security_descriptor *sd, - struct ea_list *ea_list, - files_struct **result, - int *pinfo); - -int onefs_close(vfs_handle_struct *handle, struct files_struct *fsp); - -int onefs_rename(vfs_handle_struct *handle, - const struct smb_filename *smb_fname_src, - const struct smb_filename *smb_fname_dst); - -int onefs_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname); - -int onefs_fstat(vfs_handle_struct *handle, struct files_struct *fsp, - SMB_STRUCT_STAT *sbuf); - -int onefs_lstat(vfs_handle_struct *handle, struct smb_filename *smb_fname); - -int onefs_unlink(vfs_handle_struct *handle, - const struct smb_filename *smb_fname); - -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); - -int onefs_vtimes_streams(vfs_handle_struct *handle, - const struct smb_filename *smb_fname, - int flags, struct timespec times[3]); - -NTSTATUS onefs_brl_lock_windows(vfs_handle_struct *handle, - struct byte_range_lock *br_lck, - struct lock_struct *plock, - bool blocking_lock, - struct blocking_lock_record *blr); - -bool onefs_brl_unlock_windows(vfs_handle_struct *handle, - struct messaging_context *msg_ctx, - struct byte_range_lock *br_lck, - const struct lock_struct *plock); - -bool onefs_brl_cancel_windows(vfs_handle_struct *handle, - struct byte_range_lock *br_lck, - struct lock_struct *plock, - struct blocking_lock_record *blr); - -bool onefs_strict_lock(vfs_handle_struct *handle, - files_struct *fsp, - struct lock_struct *plock); - -void onefs_strict_unlock(vfs_handle_struct *handle, - files_struct *fsp, - struct lock_struct *plock); - -NTSTATUS onefs_notify_watch(vfs_handle_struct *vfs_handle, - struct sys_notify_context *ctx, - struct notify_entry *e, - void (*callback)(struct sys_notify_context *ctx, - void *private_data, - struct notify_event *ev), - void *private_data, - void *handle_p); - -NTSTATUS onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - uint32 security_info, struct security_descriptor **ppdesc); - -NTSTATUS onefs_get_nt_acl(vfs_handle_struct *handle, const char* name, - uint32 security_info, struct security_descriptor **ppdesc); - -NTSTATUS onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - uint32 security_info_sent, - const struct security_descriptor *psd); - -/* - * Utility functions - */ -struct ifs_security_descriptor; -NTSTATUS onefs_samba_sd_to_sd(uint32_t security_info_sent, - const struct security_descriptor *psd, - struct ifs_security_descriptor *sd, int snum, - uint32_t *security_info_effective); - -NTSTATUS onefs_stream_prep_smb_fname(TALLOC_CTX *ctx, - const struct smb_filename *smb_fname_in, - struct smb_filename **smb_fname_out); - -int onefs_rdp_add_dir_state(connection_struct *conn, DIR *dirp); - -/* - * System Interfaces - */ -int onefs_sys_create_file(connection_struct *conn, - int base_fd, - const char *path, - uint32_t access_mask, - uint32_t open_access_mask, - uint32_t share_access, - uint32_t create_options, - int flags, - mode_t mode, - int oplock_request, - uint64_t id, - struct security_descriptor *sd, - uint32_t ntfs_flags, - int *granted_oplock); - -ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, - const DATA_BLOB *header, off_t offset, - size_t count); - -ssize_t onefs_sys_recvfile(int fromfd, int tofd, off_t offset, - size_t count); - -void init_stat_ex_from_onefs_stat(struct stat_ex *dst, const struct stat *src); - -int onefs_sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf); - -int onefs_sys_fstat(int fd, SMB_STRUCT_STAT *sbuf); - -int onefs_sys_fstat_at(int base_fd, const char *fname, SMB_STRUCT_STAT *sbuf, - int flags); - -int onefs_sys_lstat(const char *fname, SMB_STRUCT_STAT *sbuf); - - - -#endif /* _ONEFS_H */ diff --git a/source3/modules/onefs_acl.c b/source3/modules/onefs_acl.c deleted file mode 100644 index 749ddec3da..0000000000 --- a/source3/modules/onefs_acl.c +++ /dev/null @@ -1,979 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * Support for OneFS native NTFS ACLs - * - * Copyright (C) Steven Danneman, 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 "includes.h" -#include "smbd/smbd.h" -#include "onefs.h" -#include "onefs_config.h" - -#include <isi_acl/isi_acl_util.h> -#include <ifs/ifs_syscalls.h> -#include <sys/isi_acl.h> - -const struct enum_list enum_onefs_acl_wire_format[] = { - {ACL_FORMAT_RAW, "No Format"}, - {ACL_FORMAT_WINDOWS_SD, "Format Windows SD"}, - {ACL_FORMAT_ALWAYS, "Always Format SD"}, - {-1, NULL} -}; - -/** - * Turn SID into UID/GID and setup a struct ifs_identity - */ -static bool -onefs_sid_to_identity(const struct dom_sid *sid, struct ifs_identity *id, - bool is_group) -{ - enum ifs_identity_type type = IFS_ID_TYPE_LAST+1; - uid_t uid = 0; - gid_t gid = 0; - - if (!sid || dom_sid_equal(sid, &global_sid_NULL)) - type = IFS_ID_TYPE_NULL; - else if (dom_sid_equal(sid, &global_sid_World)) - type = IFS_ID_TYPE_EVERYONE; - else if (dom_sid_equal(sid, &global_sid_Creator_Owner)) - type = IFS_ID_TYPE_CREATOR_OWNER; - else if (dom_sid_equal(sid, &global_sid_Creator_Group)) - type = IFS_ID_TYPE_CREATOR_GROUP; - else if (is_group) { - if (!sid_to_gid(sid, &gid)) - return false; - type = IFS_ID_TYPE_GID; - } else { - if (sid_to_uid(sid, &uid)) - type = IFS_ID_TYPE_UID; - else if (sid_to_gid(sid, &gid)) - type = IFS_ID_TYPE_GID; - else - return false; - } - - if (aclu_initialize_identity(id, type, uid, gid, is_group)) { - DEBUG(3, ("Call to aclu_initialize_identity failed! id=%x, " - "type=%d, uid=%u, gid=%u, is_group=%d\n", - (unsigned int)id, type, uid, gid, is_group)); - return false; - } - - return true; -} - -/** - * Turn struct ifs_identity into SID - */ -static bool -onefs_identity_to_sid(struct ifs_identity *id, struct dom_sid *sid) -{ - if (!id || !sid) - return false; - - if (id->type >= IFS_ID_TYPE_LAST) - return false; - - switch (id->type) { - case IFS_ID_TYPE_UID: - uid_to_sid(sid, id->id.uid); - break; - case IFS_ID_TYPE_GID: - gid_to_sid(sid, id->id.gid); - break; - case IFS_ID_TYPE_EVERYONE: - sid_copy(sid, &global_sid_World); - break; - case IFS_ID_TYPE_NULL: - sid_copy(sid, &global_sid_NULL); - break; - case IFS_ID_TYPE_CREATOR_OWNER: - sid_copy(sid, &global_sid_Creator_Owner); - break; - case IFS_ID_TYPE_CREATOR_GROUP: - sid_copy(sid, &global_sid_Creator_Group); - break; - default: - DEBUG(0, ("Unknown identity type: %d\n", id->type)); - return false; - } - - return true; -} - -static bool -onefs_og_to_identity(struct dom_sid *sid, struct ifs_identity * ident, - bool is_group, int snum) -{ - const struct dom_sid *b_admin_sid = &global_sid_Builtin_Administrators; - - if (!onefs_sid_to_identity(sid, ident, is_group)) { - if (!lp_parm_bool(snum, PARM_ONEFS_TYPE, - PARM_UNMAPPABLE_SIDS_IGNORE, - PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT)) { - DEBUG(3, ("Unresolvable SID (%s) found.\n", - sid_string_dbg(sid))); - return false; - } - if (!onefs_sid_to_identity(b_admin_sid, ident, is_group)) { - return false; - } - DEBUG(3, ("Mapping unresolvable owner SID (%s) to Builtin " - "Administrators group.\n", - sid_string_dbg(sid))); - } - return true; -} - -static bool -sid_in_ignore_list(struct dom_sid * sid, int snum) -{ - const char ** sid_list = NULL; - struct dom_sid match; - - sid_list = lp_parm_string_list(snum, PARM_ONEFS_TYPE, - PARM_UNMAPPABLE_SIDS_IGNORE_LIST, - PARM_UNMAPPABLE_SIDS_IGNORE_LIST_DEFAULT); - - /* Fast path a NULL list */ - if (!sid_list || *sid_list == NULL) - return false; - - while (*sid_list) { - if (string_to_sid(&match, *sid_list)) - if (dom_sid_equal(sid, &match)) - return true; - sid_list++; - } - - return false; -} - -/** - * Convert a trustee to a struct identity - */ -static bool -onefs_samba_ace_to_ace(struct security_ace * samba_ace, struct ifs_ace * ace, - bool *mapped, int snum) -{ - struct ifs_identity ident = {.type=IFS_ID_TYPE_LAST, .id.uid=0}; - - SMB_ASSERT(ace); - SMB_ASSERT(mapped); - SMB_ASSERT(samba_ace); - - if (onefs_sid_to_identity(&samba_ace->trustee, &ident, false)) { - *mapped = true; - } else { - - SMB_ASSERT(ident.id.uid >= 0); - - /* Ignore the sid if it's in the list */ - if (sid_in_ignore_list(&samba_ace->trustee, snum)) { - DEBUG(3, ("Silently failing to set ACE for SID (%s) " - "because it is in the ignore sids list\n", - sid_string_dbg(&samba_ace->trustee))); - *mapped = false; - } else if ((samba_ace->type == SEC_ACE_TYPE_ACCESS_DENIED) && - lp_parm_bool(snum, PARM_ONEFS_TYPE, - PARM_UNMAPPABLE_SIDS_DENY_EVERYONE, - PARM_UNMAPPABLE_SIDS_DENY_EVERYONE_DEFAULT)) { - /* If the ace is deny translated to Everyone */ - DEBUG(3, ("Mapping unresolvable deny ACE SID (%s) " - "to Everyone.\n", - sid_string_dbg(&samba_ace->trustee))); - if (aclu_initialize_identity(&ident, - IFS_ID_TYPE_EVERYONE, 0, 0, False) != 0) { - DEBUG(2, ("aclu_initialize_identity() " - "failed making Everyone\n")); - return false; - } - *mapped = true; - } else if (lp_parm_bool(snum, PARM_ONEFS_TYPE, - PARM_UNMAPPABLE_SIDS_IGNORE, - PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT)) { - DEBUG(3, ("Silently failing to set ACE for SID (%s) " - "because it is unresolvable\n", - sid_string_dbg(&samba_ace->trustee))); - *mapped = false; - } else { - /* Fail for lack of a better option */ - return false; - } - } - - if (*mapped) { - if (aclu_initialize_ace(ace, samba_ace->type, - samba_ace->access_mask, samba_ace->flags, 0, - &ident)) - return false; - - if ((ace->trustee.type == IFS_ID_TYPE_CREATOR_OWNER || - ace->trustee.type == IFS_ID_TYPE_CREATOR_GROUP) && - nt4_compatible_acls()) - ace->flags |= SEC_ACE_FLAG_INHERIT_ONLY; - } - - return true; -} - -/** - * Convert a struct security_acl to a struct ifs_security_acl - */ -static bool -onefs_samba_acl_to_acl(struct security_acl *samba_acl, struct ifs_security_acl **acl, - bool * ignore_aces, int snum) -{ - int num_aces = 0; - struct ifs_ace *aces = NULL; - struct security_ace *samba_aces; - bool mapped; - int i, j; - - SMB_ASSERT(ignore_aces); - - if ((!acl) || (!samba_acl)) - return false; - - samba_aces = samba_acl->aces; - - if (samba_acl->num_aces > 0 && samba_aces) { - /* Setup ACES */ - num_aces = samba_acl->num_aces; - aces = SMB_MALLOC_ARRAY(struct ifs_ace, num_aces); - - for (i = 0, j = 0; j < num_aces; i++, j++) { - if (!onefs_samba_ace_to_ace(&samba_aces[j], - &aces[i], &mapped, snum)) - goto err_free; - - if (!mapped) - i--; - } - num_aces = i; - } - - /* If aces are given but we cannot apply them due to the reasons - * above we do not change the SD. However, if we are told to - * explicitly set an SD with 0 aces we honor this operation */ - *ignore_aces = samba_acl->num_aces > 0 && num_aces < 1; - - if (*ignore_aces == false) - if (aclu_initialize_acl(acl, aces, num_aces)) - goto err_free; - - /* Currently aclu_initialize_acl should copy the aces over, allowing - * us to immediately free */ - free(aces); - return true; - -err_free: - free(aces); - return false; -} - -/** - * Convert a struct ifs_security_acl to a struct security_acl - */ -static bool -onefs_acl_to_samba_acl(struct ifs_security_acl *acl, struct security_acl **samba_acl) -{ - struct security_ace *samba_aces = NULL; - struct security_acl *tmp_samba_acl = NULL; - int i, num_aces = 0; - - if (!samba_acl) - return false; - - /* NULL ACL */ - if (!acl) { - *samba_acl = NULL; - return true; - } - - /* Determine number of aces in ACL */ - if (!acl->aces) - num_aces = 0; - else - num_aces = acl->num_aces; - - /* Allocate the ace list. */ - if (num_aces > 0) { - if ((samba_aces = SMB_MALLOC_ARRAY(struct security_ace, num_aces)) == NULL) - { - DEBUG(0, ("Unable to malloc space for %d aces.\n", - num_aces)); - return false; - } - memset(samba_aces, '\0', (num_aces) * sizeof(struct security_ace)); - } - - for (i = 0; i < num_aces; i++) { - struct dom_sid sid; - - if (!onefs_identity_to_sid(&acl->aces[i].trustee, &sid)) - goto err_free; - - init_sec_ace(&samba_aces[i], &sid, acl->aces[i].type, - acl->aces[i].access_mask, acl->aces[i].flags); - } - - if ((tmp_samba_acl = make_sec_acl(talloc_tos(), acl->revision, num_aces, - samba_aces)) == NULL) { - DEBUG(0, ("Unable to malloc space for acl.\n")); - goto err_free; - } - - *samba_acl = tmp_samba_acl; - SAFE_FREE(samba_aces); - return true; -err_free: - SAFE_FREE(samba_aces); - return false; -} - -/** - * @brief Reorder ACLs into the "correct" order for Windows Explorer. - * - * Windows Explorer expects ACLs to be in a standard order (inherited first, - * then deny, then permit.) When ACLs are composed from POSIX file permissions - * bits, they may not match these expectations, generating an annoying warning - * dialog for the user. This function will, if configured appropriately, - * reorder the ACLs for these "synthetic" (POSIX-derived) descriptors to prevent - * this. The list is changed within the security descriptor passed in. - * - * @param fsp files_struct with service configs; must not be NULL - * @param sd security descriptor being normalized; - * sd->dacl->aces is rewritten in-place, so must not be NULL - * @return true on success, errno will be set on error - * - * @bug Although Windows Explorer likes the reordering, they seem to cause - * problems with Excel and Word sending back the reordered ACLs to us and - * changing policy; see Isilon bug 30165. - */ -static bool -onefs_canon_acl(files_struct *fsp, struct ifs_security_descriptor *sd) -{ - int error = 0; - int cur; - struct ifs_ace *new_aces = NULL; - int new_aces_count = 0; - SMB_STRUCT_STAT sbuf; - - if (sd == NULL || sd->dacl == NULL || sd->dacl->num_aces == 0) - return true; - - /* - * Find out if this is a windows bit, and if the smb policy wants us to - * lie about the sd. - */ - SMB_ASSERT(fsp != NULL); - switch (lp_parm_enum(SNUM(fsp->conn), PARM_ONEFS_TYPE, - PARM_ACL_WIRE_FORMAT, enum_onefs_acl_wire_format, - PARM_ACL_WIRE_FORMAT_DEFAULT)) { - case ACL_FORMAT_RAW: - return true; - - case ACL_FORMAT_WINDOWS_SD: - error = SMB_VFS_FSTAT(fsp, &sbuf); - if (error) - return false; - - if ((sbuf.st_ex_flags & SF_HASNTFSACL) != 0) { - DEBUG(10, ("Did not canonicalize ACLs because a " - "Windows ACL set was found for file %s\n", - fsp_str_dbg(fsp))); - return true; - } - break; - - case ACL_FORMAT_ALWAYS: - break; - - default: - SMB_ASSERT(false); - return false; - } - - new_aces = SMB_MALLOC_ARRAY(struct ifs_ace, sd->dacl->num_aces); - if (new_aces == NULL) - return false; - - /* - * By walking down the list 3 separate times, we can avoid the need - * to create multiple temp buffers and extra copies. - */ - - /* Explict deny aces first */ - for (cur = 0; cur < sd->dacl->num_aces; cur++) { - if (!(sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE) && - (sd->dacl->aces[cur].type == IFS_ACE_TYPE_ACCESS_DENIED)) - new_aces[new_aces_count++] = sd->dacl->aces[cur]; - } - - /* Explict allow aces second */ - for (cur = 0; cur < sd->dacl->num_aces; cur++) { - if (!(sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE) && - !(sd->dacl->aces[cur].type == IFS_ACE_TYPE_ACCESS_DENIED)) - new_aces[new_aces_count++] = sd->dacl->aces[cur]; - } - - /* Inherited deny/allow aces third */ - for (cur = 0; cur < sd->dacl->num_aces; cur++) { - if ((sd->dacl->aces[cur].flags & IFS_ACE_FLAG_INHERITED_ACE)) - new_aces[new_aces_count++] = sd->dacl->aces[cur]; - } - - SMB_ASSERT(new_aces_count == sd->dacl->num_aces); - DEBUG(10, ("Performed canonicalization of ACLs for file %s\n", - fsp_str_dbg(fsp))); - - /* - * At this point you would think we could just do this: - * SAFE_FREE(sd->dacl->aces); - * sd->dacl->aces = new_aces; - * However, in some cases the existing aces pointer does not point - * to the beginning of an allocated block. So we have to do a more - * expensive memcpy() - */ - memcpy(sd->dacl->aces, new_aces, - sizeof(struct ifs_ace) * new_aces_count); - - SAFE_FREE(new_aces); - return true; -} - - -/** - * This enum is a helper for onefs_fget_nt_acl() to communicate with - * onefs_init_ace(). - */ -enum mode_ident { USR, GRP, OTH }; - -/** - * Initializes an ACE for addition to a synthetic ACL. - */ -static struct ifs_ace onefs_init_ace(struct connection_struct *conn, - mode_t mode, - bool isdir, - enum mode_ident ident) -{ - struct ifs_ace result; - enum ifs_ace_rights r,w,x; - - r = isdir ? UNIX_DIRECTORY_ACCESS_R : UNIX_ACCESS_R; - w = isdir ? UNIX_DIRECTORY_ACCESS_W : UNIX_ACCESS_W; - x = isdir ? UNIX_DIRECTORY_ACCESS_X : UNIX_ACCESS_X; - - result.type = IFS_ACE_TYPE_ACCESS_ALLOWED; - result.ifs_flags = 0; - result.flags = isdir ? IFS_ACE_FLAG_CONTAINER_INHERIT : - IFS_ACE_FLAG_OBJECT_INHERIT; - result.flags |= IFS_ACE_FLAG_INHERIT_ONLY; - - switch (ident) { - case USR: - result.access_mask = - ((mode & S_IRUSR) ? r : 0 ) | - ((mode & S_IWUSR) ? w : 0 ) | - ((mode & S_IXUSR) ? x : 0 ); - if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_CREATOR_OWNER_GETS_FULL_CONTROL, - PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT)) - result.access_mask |= GENERIC_ALL_ACCESS; - result.trustee.type = IFS_ID_TYPE_CREATOR_OWNER; - break; - case GRP: - result.access_mask = - ((mode & S_IRGRP) ? r : 0 ) | - ((mode & S_IWGRP) ? w : 0 ) | - ((mode & S_IXGRP) ? x : 0 ); - result.trustee.type = IFS_ID_TYPE_CREATOR_GROUP; - break; - case OTH: - result.access_mask = - ((mode & S_IROTH) ? r : 0 ) | - ((mode & S_IWOTH) ? w : 0 ) | - ((mode & S_IXOTH) ? x : 0 ); - result.trustee.type = IFS_ID_TYPE_EVERYONE; - break; - } - - return result; -} - -/** - * This adds inheritable ACEs to the end of the DACL, with the ACEs - * being derived from the mode bits. This is useful for clients that have the - * MoveSecurityAttributes regkey set to 0 or are in Simple File Sharing Mode. - * - * On these clients, when copying files from one folder to another inside the - * same volume/share, the DACL is explicitely cleared. Without inheritable - * aces on the target folder the mode bits of the copied file are set to 000. - * - * See Isilon Bug 27990 - * - * Note: This function allocates additional memory onto sd->dacl->aces, that - * must be freed by the caller. - */ -static bool add_sfs_aces(files_struct *fsp, struct ifs_security_descriptor *sd) -{ - int error; - SMB_STRUCT_STAT sbuf; - - error = SMB_VFS_FSTAT(fsp, &sbuf); - if (error) { - DEBUG(0, ("Failed to stat %s in simple files sharing " - "compatibility mode. errno=%d\n", - fsp_str_dbg(fsp), errno)); - return false; - } - - /* Only continue if this is a synthetic ACL and a directory. */ - if (S_ISDIR(sbuf.st_ex_mode) && - (sbuf.st_ex_flags & SF_HASNTFSACL) == 0) { - struct ifs_ace new_aces[6]; - struct ifs_ace *old_aces; - int i, num_aces_to_add = 0; - mode_t file_mode = 0, dir_mode = 0; - - /* Use existing samba logic to derive the mode bits. */ - file_mode = unix_mode(fsp->conn, 0, fsp->fsp_name, NULL); - dir_mode = unix_mode(fsp->conn, FILE_ATTRIBUTE_DIRECTORY, fsp->fsp_name, NULL); - - /* Initialize ACEs. */ - new_aces[0] = onefs_init_ace(fsp->conn, file_mode, false, USR); - new_aces[1] = onefs_init_ace(fsp->conn, file_mode, false, GRP); - new_aces[2] = onefs_init_ace(fsp->conn, file_mode, false, OTH); - new_aces[3] = onefs_init_ace(fsp->conn, dir_mode, true, USR); - new_aces[4] = onefs_init_ace(fsp->conn, dir_mode, true, GRP); - new_aces[5] = onefs_init_ace(fsp->conn, dir_mode, true, OTH); - - for (i = 0; i < 6; i++) - if (new_aces[i].access_mask != 0) - num_aces_to_add++; - - /* Expand the ACEs array */ - if (num_aces_to_add != 0) { - old_aces = sd->dacl->aces; - - sd->dacl->aces = SMB_MALLOC_ARRAY(struct ifs_ace, - sd->dacl->num_aces + num_aces_to_add); - if (!sd->dacl->aces) { - DEBUG(0, ("Unable to malloc space for " - "new_aces: %d.\n", - sd->dacl->num_aces + num_aces_to_add)); - return false; - } - memcpy(sd->dacl->aces, old_aces, - sizeof(struct ifs_ace) * sd->dacl->num_aces); - - /* Add the new ACEs to the DACL. */ - for (i = 0; i < 6; i++) { - if (new_aces[i].access_mask != 0) { - sd->dacl->aces[sd->dacl->num_aces] = - new_aces[i]; - sd->dacl->num_aces++; - } - } - } - } - return true; -} - -/** - * Isilon-specific function for getting an NTFS ACL from an open file. - * - * @param[out] ppdesc SecDesc to allocate and fill in - * - * @return NTSTATUS based off errno on error - */ -NTSTATUS -onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - uint32 security_info, struct security_descriptor **ppdesc) -{ - int error; - uint32_t sd_size = 0; - size_t size = 0; - struct ifs_security_descriptor *sd = NULL; - struct dom_sid owner_sid, group_sid; - struct dom_sid *ownerp, *groupp; - struct security_acl *dacl, *sacl; - struct security_descriptor *pdesc; - bool alloced = false; - bool new_aces_alloced = false; - bool fopened = false; - NTSTATUS status = NT_STATUS_OK; - - START_PROFILE(syscall_get_sd); - - *ppdesc = NULL; - - DEBUG(5, ("Getting sd for file %s. security_info=%u\n", - fsp_str_dbg(fsp), security_info)); - - if (lp_parm_bool(SNUM(fsp->conn), PARM_ONEFS_TYPE, - PARM_IGNORE_SACLS, PARM_IGNORE_SACLS_DEFAULT)) { - DEBUG(5, ("Ignoring SACL on %s.\n", fsp_str_dbg(fsp))); - security_info &= ~SECINFO_SACL; - } - - if (fsp->fh->fd == -1) { - if ((fsp->fh->fd = onefs_sys_create_file(handle->conn, - -1, - fsp->fsp_name->base_name, - 0, - 0, - 0, - 0, - 0, - 0, - INTERNAL_OPEN_ONLY, - 0, - NULL, - 0, - NULL)) == -1) { - DEBUG(0, ("Error opening file %s. errno=%d (%s)\n", - fsp_str_dbg(fsp), errno, strerror(errno))); - status = map_nt_error_from_unix(errno); - goto out; - } - fopened = true; - } - - /* Get security descriptor */ - sd_size = 0; - do { - /* Allocate memory for get_security_descriptor */ - if (sd_size > 0) { - sd = SMB_REALLOC(sd, sd_size); - if (!sd) { - DEBUG(0, ("Unable to malloc %u bytes of space " - "for security descriptor.\n", sd_size)); - status = map_nt_error_from_unix(errno); - goto out; - } - - alloced = true; - } - - error = ifs_get_security_descriptor(fsp->fh->fd, security_info, - sd_size, &sd_size, sd); - if (error && (errno != EMSGSIZE)) { - DEBUG(0, ("Failed getting size of security descriptor! " - "errno=%d\n", errno)); - status = map_nt_error_from_unix(errno); - goto out; - } - } while (error); - - DEBUG(5, ("Got sd, size=%u:\n", sd_size)); - - if (lp_parm_bool(SNUM(fsp->conn), - PARM_ONEFS_TYPE, - PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE, - PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT) && - sd->dacl) { - if(!(new_aces_alloced = add_sfs_aces(fsp, sd))) - goto out; - } - - if (!(onefs_canon_acl(fsp, sd))) { - status = map_nt_error_from_unix(errno); - goto out; - } - - DEBUG(5, ("Finished canonicalizing ACL\n")); - - ownerp = NULL; - groupp = NULL; - dacl = NULL; - sacl = NULL; - - /* Copy owner into ppdesc */ - if (security_info & SECINFO_OWNER) { - if (!onefs_identity_to_sid(sd->owner, &owner_sid)) { - status = NT_STATUS_INVALID_PARAMETER; - goto out; - } - - ownerp = &owner_sid; - } - - /* Copy group into ppdesc */ - if (security_info & SECINFO_GROUP) { - if (!onefs_identity_to_sid(sd->group, &group_sid)) { - status = NT_STATUS_INVALID_PARAMETER; - goto out; - } - - groupp = &group_sid; - } - - /* Copy DACL into ppdesc */ - if (security_info & SECINFO_DACL) { - if (!onefs_acl_to_samba_acl(sd->dacl, &dacl)) { - status = NT_STATUS_INVALID_PARAMETER; - goto out; - } - } - - /* Copy SACL into ppdesc */ - if (security_info & SECINFO_SACL) { - if (!onefs_acl_to_samba_acl(sd->sacl, &sacl)) { - status = NT_STATUS_INVALID_PARAMETER; - goto out; - } - } - - /* AUTO_INHERIT_REQ bits are not returned over the wire so strip them - * off. Eventually we should stop storing these in the kernel - * all together. See Isilon bug 40364 */ - sd->control &= ~(IFS_SD_CTRL_DACL_AUTO_INHERIT_REQ | - IFS_SD_CTRL_SACL_AUTO_INHERIT_REQ); - - pdesc = make_sec_desc(talloc_tos(), sd->revision, sd->control, - ownerp, groupp, sacl, dacl, &size); - - if (!pdesc) { - DEBUG(0, ("Problem with make_sec_desc. Memory?\n")); - status = map_nt_error_from_unix(errno); - goto out; - } - - *ppdesc = pdesc; - - DEBUG(5, ("Finished retrieving/canonicalizing SD!\n")); - /* FALLTHROUGH */ -out: - - END_PROFILE(syscall_get_sd); - - if (alloced && sd) { - if (new_aces_alloced && sd->dacl->aces) - SAFE_FREE(sd->dacl->aces); - - SAFE_FREE(sd); - } - - if (fopened) { - close(fsp->fh->fd); - fsp->fh->fd = -1; - } - - return status; -} - -/** - * Isilon-specific function for getting an NTFS ACL from a file path. - * - * Since onefs_fget_nt_acl() needs to open a filepath if the fd is invalid, - * we just mock up a files_struct with the path and bad fd and call into it. - * - * @param[out] ppdesc SecDesc to allocate and fill in - * - * @return NTSTATUS based off errno on error - */ -NTSTATUS -onefs_get_nt_acl(vfs_handle_struct *handle, const char* name, - uint32 security_info, struct security_descriptor **ppdesc) -{ - files_struct finfo; - struct fd_handle fh; - NTSTATUS status; - - ZERO_STRUCT(finfo); - ZERO_STRUCT(fh); - - finfo.fnum = -1; - finfo.conn = handle->conn; - finfo.fh = &fh; - finfo.fh->fd = -1; - status = create_synthetic_smb_fname(talloc_tos(), name, NULL, NULL, - &finfo.fsp_name); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - status = onefs_fget_nt_acl(handle, &finfo, security_info, ppdesc); - - TALLOC_FREE(finfo.fsp_name); - return status; -} - -/** - * Isilon-specific function for setting up an ifs_security_descriptor, given a - * samba struct security_descriptor - * - * @param[out] sd ifs_security_descriptor to fill in - * - * @return NTSTATUS_OK if successful - */ -NTSTATUS onefs_samba_sd_to_sd(uint32_t security_info_sent, - const struct security_descriptor *psd, - struct ifs_security_descriptor *sd, int snum, - uint32_t *security_info_effective) -{ - struct ifs_security_acl *daclp, *saclp; - struct ifs_identity owner, group, *ownerp, *groupp; - bool ignore_aces; - - ownerp = NULL; - groupp = NULL; - daclp = NULL; - saclp = NULL; - - *security_info_effective = security_info_sent; - - /* Setup owner */ - if (security_info_sent & SECINFO_OWNER) { - if (!onefs_og_to_identity(psd->owner_sid, &owner, false, snum)) - return NT_STATUS_ACCESS_DENIED; - - SMB_ASSERT(owner.id.uid >= 0); - - ownerp = &owner; - } - - /* Setup group */ - if (security_info_sent & SECINFO_GROUP) { - if (!onefs_og_to_identity(psd->group_sid, &group, true, snum)) - return NT_STATUS_ACCESS_DENIED; - - SMB_ASSERT(group.id.gid >= 0); - - groupp = &group; - } - - /* Setup DACL */ - if ((security_info_sent & SECINFO_DACL) && (psd->dacl)) { - if (!onefs_samba_acl_to_acl(psd->dacl, &daclp, &ignore_aces, - snum)) - return NT_STATUS_ACCESS_DENIED; - - if (ignore_aces == true) - *security_info_effective &= ~SECINFO_DACL; - } - - /* Setup SACL */ - if (security_info_sent & SECINFO_SACL) { - - if (lp_parm_bool(snum, PARM_ONEFS_TYPE, - PARM_IGNORE_SACLS, PARM_IGNORE_SACLS_DEFAULT)) { - DEBUG(5, ("Ignoring SACL.\n")); - *security_info_effective &= ~SECINFO_SACL; - } else { - if (psd->sacl) { - if (!onefs_samba_acl_to_acl(psd->sacl, - &saclp, &ignore_aces, snum)) - return NT_STATUS_ACCESS_DENIED; - - if (ignore_aces == true) { - *security_info_effective &= - ~SECINFO_SACL; - } - } - } - } - - /* Setup ifs_security_descriptor */ - DEBUG(5,("Setting up SD\n")); - if (aclu_initialize_sd(sd, psd->type, ownerp, groupp, - (daclp ? &daclp : NULL), (saclp ? &saclp : NULL), false)) - return NT_STATUS_ACCESS_DENIED; - - DEBUG(10, ("sec_info_sent: 0x%x, sec_info_effective: 0x%x.\n", - security_info_sent, *security_info_effective)); - - return NT_STATUS_OK; -} - -/** - * Isilon-specific function for setting an NTFS ACL on an open file. - * - * @return NT_STATUS_UNSUCCESSFUL for userspace errors, NTSTATUS based off - * errno on syscall errors - */ -NTSTATUS -onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - uint32_t sec_info_sent, const struct security_descriptor *psd) -{ - struct ifs_security_descriptor sd = {}; - int fd = -1; - bool fopened = false; - NTSTATUS status; - uint32_t sec_info_effective = 0; - - START_PROFILE(syscall_set_sd); - - DEBUG(5,("Setting SD on file %s.\n", fsp_str_dbg(fsp))); - - status = onefs_samba_sd_to_sd(sec_info_sent, psd, &sd, - SNUM(handle->conn), &sec_info_effective); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("SD initialization failure: %s\n", nt_errstr(status))); - goto out; - } - - fd = fsp->fh->fd; - if (fd == -1) { - DEBUG(10,("Reopening file %s.\n", fsp_str_dbg(fsp))); - if ((fd = onefs_sys_create_file(handle->conn, - -1, - fsp->fsp_name->base_name, - 0, - 0, - 0, - 0, - 0, - 0, - INTERNAL_OPEN_ONLY, - 0, - NULL, - 0, - NULL)) == -1) { - DEBUG(0, ("Error opening file %s. errno=%d (%s)\n", - fsp_str_dbg(fsp), errno, strerror(errno))); - status = map_nt_error_from_unix(errno); - goto out; - } - fopened = true; - } - - errno = 0; - if (ifs_set_security_descriptor(fd, sec_info_effective, &sd)) { - DEBUG(0, ("Error setting security descriptor = %s\n", - strerror(errno))); - status = map_nt_error_from_unix(errno); - goto out; - } - - DEBUG(5, ("Security descriptor set correctly!\n")); - status = NT_STATUS_OK; - - /* FALLTHROUGH */ -out: - END_PROFILE(syscall_set_sd); - - if (fopened) - close(fd); - - aclu_free_sd(&sd, false); - return status; -} diff --git a/source3/modules/onefs_cbrl.c b/source3/modules/onefs_cbrl.c deleted file mode 100644 index 2f20d04ddb..0000000000 --- a/source3/modules/onefs_cbrl.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Support for OneFS system interfaces. - * - * Copyright (C) Zack Kirsch, 2009 - * - * 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 "includes.h" -#include "smbd/smbd.h" -#include "onefs.h" - -#include <ifs/ifs_syscalls.h> -#include <sys/isi_cifs_brl.h> -#include <isi_ecs/isi_ecs_cbrl.h> - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_LOCKING - -static uint64_t onefs_get_new_id(void) { - static uint64_t id = 0; - - id++; - - return id; -} - -enum onefs_cbrl_lock_state {ONEFS_CBRL_NONE, ONEFS_CBRL_ASYNC, ONEFS_CBRL_DONE, - ONEFS_CBRL_ERROR}; - -struct onefs_cbrl_blr_state { - uint64_t id; - enum onefs_cbrl_lock_state state; -}; - -static char *onefs_cbrl_blr_state_str(const struct blocking_lock_record *blr) -{ - static fstring result; - struct onefs_cbrl_blr_state *bs; - - SMB_ASSERT(blr); - - bs = (struct onefs_cbrl_blr_state *)blr->blr_private; - - if (bs == NULL) { - fstrcpy(result, "NULL CBRL BLR state - Posix lock?"); - return result; - } - - switch (bs->state) { - case ONEFS_CBRL_NONE: - fstr_sprintf(result, "CBRL BLR id=%llu: state=NONE", bs->id); - break; - case ONEFS_CBRL_ASYNC: - fstr_sprintf(result, "CBRL BLR id=%llu: state=ASYNC", bs->id); - break; - case ONEFS_CBRL_DONE: - fstr_sprintf(result, "CBRL BLR id=%llu: state=DONE", bs->id); - break; - case ONEFS_CBRL_ERROR: - fstr_sprintf(result, "CBRL BLR id=%llu: state=ERROR", bs->id); - break; - default: - fstr_sprintf(result, "CBRL BLR id=%llu: unknown state %d", - bs->id, bs->state); - break; - } - - return result; -} - -static void onefs_cbrl_enumerate_blq(const char *fn) -{ - struct smbd_server_connection *sconn = smbd_server_conn; - struct blocking_lock_record *blr; - - if (DEBUGLVL(10)) - return; - - DEBUG(10, ("CBRL BLR records (%s):\n", fn)); - - if (sconn->using_smb2) { - struct smbd_smb2_request *smb2req; - for (smb2req = sconn->smb2.requests; smb2req; smb2req = nextreq) { - blr = get_pending_smb2req_blr(smb2req); - if (blr) { - DEBUGADD(10, ("%s\n", onefs_cbrl_blr_state_str(blr))); - } - } - } else { - for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = blr->next) - DEBUGADD(10, ("%s\n", onefs_cbrl_blr_state_str(blr))); - } -} - -static struct blocking_lock_record *onefs_cbrl_find_blr(uint64_t id) -{ - struct smbd_server_connection *sconn = smbd_server_conn; - struct blocking_lock_record *blr; - struct onefs_cbrl_blr_state *bs; - - onefs_cbrl_enumerate_blq("onefs_cbrl_find_blr"); - - if (sconn->using_smb2) { - struct smbd_smb2_request *smb2req; - for (smb2req = sconn->smb2.requests; smb2req; smb2req = nextreq) { - blr = get_pending_smb2req_blr(smb2req); - if (!blr) { - continue; - } - bs = (struct onefs_cbrl_blr_state *)blr->blr_private; - if (bs == NULL) { - continue; - } - if (bs->id == id) { - DEBUG(10, ("found %s\n", - onefs_cbrl_blr_state_str(blr))); - break; - } - } - } else { - for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = blr->next) { - bs = (struct onefs_cbrl_blr_state *)blr->blr_private; - - /* We don't control all of the BLRs on the BLQ. */ - if (bs == NULL) - continue; - - if (bs->id == id) { - DEBUG(10, ("found %s\n", - onefs_cbrl_blr_state_str(blr))); - break; - } - } - } - - if (blr == NULL) { - DEBUG(5, ("Could not find CBRL BLR for id %llu\n", id)); - return NULL; - } - - return blr; -} - -static void onefs_cbrl_async_success(uint64_t id) -{ - struct blocking_lock_record *blr; - struct onefs_cbrl_blr_state *bs; - uint16 num_locks; - - DEBUG(10, ("CBRL async success!\n")); - - /* Find BLR with id. Its okay not to find one (race with cancel) */ - blr = onefs_cbrl_find_blr(id); - if (blr == NULL) - return; - - bs = (struct onefs_cbrl_blr_state *)blr->blr_private; - SMB_ASSERT(bs); - SMB_ASSERT(bs->state == ONEFS_CBRL_ASYNC); - - blr->lock_num++; - - num_locks = SVAL(blr->req->vwv+7, 0); - - if (blr->lock_num == num_locks) - bs->state = ONEFS_CBRL_DONE; - else - bs->state = ONEFS_CBRL_NONE; - - /* Self contend our own level 2 oplock. The kernel handles - * contention of other opener's level 2 oplocks. */ - contend_level2_oplocks_begin(blr->fsp, - LEVEL2_CONTEND_WINDOWS_BRL); - - /* Process the queue, to try the next lock or finish up. */ - process_blocking_lock_queue(smbd_server_conn); -} - -static void onefs_cbrl_async_failure(uint64_t id) -{ - struct blocking_lock_record *blr; - struct onefs_cbrl_blr_state *bs; - - DEBUG(10, ("CBRL async failure!\n")); - - /* Find BLR with id. Its okay not to find one (race with cancel) */ - blr = onefs_cbrl_find_blr(id); - if (blr == NULL) - return; - - bs = (struct onefs_cbrl_blr_state *)blr->blr_private; - SMB_ASSERT(bs); - - SMB_ASSERT(bs->state == ONEFS_CBRL_ASYNC); - bs->state = ONEFS_CBRL_ERROR; - - /* Process the queue. It will end up trying to retake the same lock, - * see the error in onefs_cbrl_lock_windows() and fail. */ - process_blocking_lock_queue(smbd_server_conn); -} - -static struct cbrl_event_ops cbrl_ops = - {.cbrl_async_success = onefs_cbrl_async_success, - .cbrl_async_failure = onefs_cbrl_async_failure}; - -static void onefs_cbrl_events_handler(struct event_context *ev, - struct fd_event *fde, - uint16_t flags, - void *private_data) -{ - DEBUG(10, ("onefs_cbrl_events_handler\n")); - - if (cbrl_event_dispatcher(&cbrl_ops)) { - DEBUG(0, ("cbrl_event_dispatcher failed: %s\n", - strerror(errno))); - } -} - -static void onefs_init_cbrl(void) -{ - static bool init_done = false; - static int cbrl_event_fd; - static struct fd_event *cbrl_fde; - - if (init_done) - return; - - DEBUG(10, ("onefs_init_cbrl\n")); - - /* Register the event channel for CBRL. */ - cbrl_event_fd = cbrl_event_register(); - if (cbrl_event_fd == -1) { - DEBUG(0, ("cbrl_event_register failed: %s\n", - strerror(errno))); - return; - } - - DEBUG(10, ("cbrl_event_fd = %d\n", cbrl_event_fd)); - - /* Register the CBRL event_fd with samba's event system */ - cbrl_fde = event_add_fd(server_event_context(), - NULL, - cbrl_event_fd, - EVENT_FD_READ, - onefs_cbrl_events_handler, - NULL); - - init_done = true; - return; -} - -/** - * Blocking PID. As far as I can tell, the blocking_pid is only used to tell - * whether a posix lock or a CIFS lock blocked us. If it was a posix lock, - * Samba polls every 10 seconds, which we don't want. -zkirsch - */ -#define ONEFS_BLOCKING_PID 0xABCDABCD - -/** - * @param[in] br_lck Contains the fsp. - * @param[in] plock Lock request. - * @param[in] blocking_lock Only used for figuring out the error. - * @param[in,out] blr The BLR for the already-deferred operation. - */ -NTSTATUS onefs_brl_lock_windows(vfs_handle_struct *handle, - struct byte_range_lock *br_lck, - struct lock_struct *plock, - bool blocking_lock, - struct blocking_lock_record *blr) -{ - int fd = br_lck->fsp->fh->fd; - uint64_t id = 0; - enum cbrl_lock_type type; - bool async = false; - bool pending = false; - bool pending_async = false; - int error; - struct onefs_cbrl_blr_state *bs; - NTSTATUS status; - - START_PROFILE(syscall_brl_lock); - - SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK); - SMB_ASSERT(plock->lock_type != UNLOCK_LOCK); - - onefs_cbrl_enumerate_blq("onefs_brl_lock_windows"); - - /* Will only initialize the first time its called. */ - onefs_init_cbrl(); - - switch (plock->lock_type) { - case WRITE_LOCK: - type = CBRL_LK_EX; - break; - case READ_LOCK: - type = CBRL_LK_SH; - break; - case PENDING_WRITE_LOCK: - /* Called when a blocking lock request is added - do an - * async lock. */ - type = CBRL_LK_EX; - pending = true; - async = true; - break; - case PENDING_READ_LOCK: - /* Called when a blocking lock request is added - do an - * async lock. */ - type = CBRL_LK_SH; - pending = true; - async = true; - break; - default: - /* UNLOCK_LOCK: should only be used for a POSIX_LOCK */ - smb_panic("Invalid plock->lock_type passed in to " - "onefs_brl_lock_windows"); - } - - /* Figure out if we're actually doing the lock or a no-op. We need to - * do a no-op when process_blocking_lock_queue calls back into us. - * - * We know process_* is calling into us if a blr is passed in and - * pending is false. */ - if (!pending && blr) { - /* Check the BLR state. */ - bs = (struct onefs_cbrl_blr_state *)blr->blr_private; - SMB_ASSERT(bs); - - /* ASYNC still in progress: The process_* calls will keep - * calling even if we haven't gotten the lock. Keep erroring - * without calling ifs_cbrl, or getting/setting an id. */ - if (bs->state == ONEFS_CBRL_ASYNC) { - goto failure; - } - else if (bs->state == ONEFS_CBRL_ERROR) { - END_PROFILE(syscall_brl_lock); - return NT_STATUS_NO_MEMORY; - } - - SMB_ASSERT(bs->state == ONEFS_CBRL_NONE); - async = true; - } - - if (async) { - SMB_ASSERT(blocking_lock); - SMB_ASSERT(blr); - id = onefs_get_new_id(); - } - - DEBUG(10, ("Calling ifs_cbrl(LOCK)...\n")); - error = ifs_cbrl(fd, CBRL_OP_LOCK, type, plock->start, - plock->size, async, id, plock->context.smbpid, plock->context.tid, - plock->fnum); - if (!error) { - goto success; - } else if (errno == EWOULDBLOCK) { - SMB_ASSERT(!async); - } else if (errno == EINPROGRESS) { - SMB_ASSERT(async); - - if (pending) { - /* Talloc a new BLR private state. */ - blr->blr_private = talloc(blr, struct onefs_cbrl_blr_state); - pending_async = true; - } - - /* Store the new id in the BLR private state. */ - bs = (struct onefs_cbrl_blr_state *)blr->blr_private; - bs->id = id; - bs->state = ONEFS_CBRL_ASYNC; - } else { - DEBUG(0, ("onefs_brl_lock_windows failure: error=%d (%s).\n", - errno, strerror(errno))); - } - -failure: - - END_PROFILE(syscall_brl_lock); - - /* Failure - error or async. */ - plock->context.smbpid = (uint32) ONEFS_BLOCKING_PID; - - if (pending_async) - status = NT_STATUS_OK; - else - status = brl_lock_failed(br_lck->fsp, plock, blocking_lock); - - DEBUG(10, ("returning %s.\n", nt_errstr(status))); - return status; - -success: - /* Self contend our own level 2 oplock. The kernel handles - * contention of other opener's level 2 oplocks. */ - contend_level2_oplocks_begin(br_lck->fsp, - LEVEL2_CONTEND_WINDOWS_BRL); - - END_PROFILE(syscall_brl_lock); - - /* Success. */ - onefs_cbrl_enumerate_blq("onefs_brl_unlock_windows"); - DEBUG(10, ("returning NT_STATUS_OK.\n")); - return NT_STATUS_OK; -} - -bool onefs_brl_unlock_windows(vfs_handle_struct *handle, - struct messaging_context *msg_ctx, - struct byte_range_lock *br_lck, - const struct lock_struct *plock) -{ - int error; - int fd = br_lck->fsp->fh->fd; - - START_PROFILE(syscall_brl_unlock); - - SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK); - SMB_ASSERT(plock->lock_type == UNLOCK_LOCK); - - DEBUG(10, ("Calling ifs_cbrl(UNLOCK)...\n")); - error = ifs_cbrl(fd, CBRL_OP_UNLOCK, CBRL_LK_SH, - plock->start, plock->size, false, 0, plock->context.smbpid, - plock->context.tid, plock->fnum); - - END_PROFILE(syscall_brl_unlock); - - if (error) { - DEBUG(10, ("returning false.\n")); - return false; - } - - /* For symmetry purposes, end our oplock contention even though its - * currently a no-op. */ - contend_level2_oplocks_end(br_lck->fsp, LEVEL2_CONTEND_WINDOWS_BRL); - - DEBUG(10, ("returning true.\n")); - return true; - - /* Problem with storing things in TDB: I won't know what BRL to unlock in the TDB. - * - I could fake it? - * - I could send Samba a message with which lock is being unlocked? - * - I could *easily* make the "id" something you always pass in to - * lock, unlock or cancel -- it identifies a lock. Makes sense! - */ -} - -/* Default implementation only calls this on PENDING locks. */ -bool onefs_brl_cancel_windows(vfs_handle_struct *handle, - struct byte_range_lock *br_lck, - struct lock_struct *plock, - struct blocking_lock_record *blr) -{ - int error; - int fd = br_lck->fsp->fh->fd; - struct onefs_cbrl_blr_state *bs; - - START_PROFILE(syscall_brl_cancel); - - SMB_ASSERT(plock); - SMB_ASSERT(plock->lock_flav == WINDOWS_LOCK); - SMB_ASSERT(blr); - - onefs_cbrl_enumerate_blq("onefs_brl_cancel_windows"); - - bs = ((struct onefs_cbrl_blr_state *)blr->blr_private); - SMB_ASSERT(bs); - - if (bs->state == ONEFS_CBRL_DONE || bs->state == ONEFS_CBRL_ERROR) { - /* No-op. */ - DEBUG(10, ("State=%d, returning true\n", bs->state)); - END_PROFILE(syscall_brl_cancel); - return true; - } - - SMB_ASSERT(bs->state == ONEFS_CBRL_NONE || - bs->state == ONEFS_CBRL_ASYNC); - - /* A real cancel. */ - DEBUG(10, ("Calling ifs_cbrl(CANCEL)...\n")); - error = ifs_cbrl(fd, CBRL_OP_CANCEL, CBRL_LK_UNSPEC, plock->start, - plock->size, false, bs->id, plock->context.smbpid, - plock->context.tid, plock->fnum); - - END_PROFILE(syscall_brl_cancel); - - if (error) { - DEBUG(10, ("returning false\n")); - bs->state = ONEFS_CBRL_ERROR; - return false; - } - - bs->state = ONEFS_CBRL_DONE; - onefs_cbrl_enumerate_blq("onefs_brl_cancel_windows"); - DEBUG(10, ("returning true\n")); - return true; -} - -bool onefs_strict_lock(vfs_handle_struct *handle, - files_struct *fsp, - struct lock_struct *plock) -{ - int error; - - START_PROFILE(syscall_strict_lock); - - SMB_ASSERT(plock->lock_type == READ_LOCK || - plock->lock_type == WRITE_LOCK); - - if (!lp_locking(handle->conn->params) || - !lp_strict_locking(handle->conn->params)) { - END_PROFILE(syscall_strict_lock); - return True; - } - - if (plock->lock_flav == POSIX_LOCK) { - END_PROFILE(syscall_strict_lock); - return SMB_VFS_NEXT_STRICT_LOCK(handle, fsp, plock); - } - - if (plock->size == 0) { - END_PROFILE(syscall_strict_lock); - return True; - } - - error = ifs_cbrl(fsp->fh->fd, CBRL_OP_LOCK, - plock->lock_type == READ_LOCK ? CBRL_LK_RD : CBRL_LK_WR, - plock->start, plock->size, 0, 0, plock->context.smbpid, - plock->context.tid, plock->fnum); - - END_PROFILE(syscall_strict_lock); - - return (error == 0); -} - -void onefs_strict_unlock(vfs_handle_struct *handle, - files_struct *fsp, - struct lock_struct *plock) -{ - START_PROFILE(syscall_strict_unlock); - - SMB_ASSERT(plock->lock_type == READ_LOCK || - plock->lock_type == WRITE_LOCK); - - if (!lp_locking(handle->conn->params) || - !lp_strict_locking(handle->conn->params)) { - END_PROFILE(syscall_strict_unlock); - return; - } - - if (plock->lock_flav == POSIX_LOCK) { - SMB_VFS_NEXT_STRICT_UNLOCK(handle, fsp, plock); - END_PROFILE(syscall_strict_unlock); - return; - } - - if (plock->size == 0) { - END_PROFILE(syscall_strict_unlock); - return; - } - - if (fsp->fh) { - ifs_cbrl(fsp->fh->fd, CBRL_OP_UNLOCK, - plock->lock_type == READ_LOCK ? CBRL_LK_RD : CBRL_LK_WR, - plock->start, plock->size, 0, 0, plock->context.smbpid, - plock->context.tid, plock->fnum); - } - - END_PROFILE(syscall_strict_unlock); -} - -/* TODO Optimization: Abstract out brl_get_locks() in the Windows case. - * We'll malloc some memory or whatever (can't return NULL), but not actually - * touch the TDB. */ - -/* XXX brl_locktest: CBRL does not support calling this, but its only for - * strict locking. Add empty VOP? */ - -/* XXX brl_lockquery: CBRL does not support calling this for WINDOWS LOCKS, but - * its only called for POSIX LOCKS. Add empty VOP? */ - -/* XXX brl_close_fnum: CBRL will do this automatically. I think this is a NO-OP - * for us, we could add an empty VOP. */ - diff --git a/source3/modules/onefs_config.c b/source3/modules/onefs_config.c deleted file mode 100644 index 8b34d7cd45..0000000000 --- a/source3/modules/onefs_config.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Support for OneFS - * - * Copyright (C) Todd Stecher, 2009 - * Copyright (C) Tim Prouty, 2009 - * - * 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 "includes.h" -#include "smbd/smbd.h" -#include "onefs_config.h" - -#include <ifs/ifs_syscalls.h> - -#define ONEFS_DATA_FASTBUF 10 - -struct onefs_vfs_share_config vfs_share_config[ONEFS_DATA_FASTBUF]; -struct onefs_vfs_share_config *pvfs_share_config; - -static void onefs_load_faketimestamp_config(struct connection_struct *conn, - struct onefs_vfs_share_config *cfg) -{ - const char **parm; - int snum = SNUM(conn); - - parm = lp_parm_string_list(snum, PARM_ONEFS_TYPE, PARM_ATIME_NOW, - PARM_ATIME_NOW_DEFAULT); - - if (parm) { - cfg->init_flags |= ONEFS_VFS_CONFIG_FAKETIMESTAMPS; - set_namearray(&cfg->atime_now_list,*parm); - } - - parm = lp_parm_string_list(snum, PARM_ONEFS_TYPE, PARM_CTIME_NOW, - PARM_CTIME_NOW_DEFAULT); - - if (parm) { - cfg->init_flags |= ONEFS_VFS_CONFIG_FAKETIMESTAMPS; - set_namearray(&cfg->ctime_now_list,*parm); - } - - parm = lp_parm_string_list(snum, PARM_ONEFS_TYPE, PARM_MTIME_NOW, - PARM_MTIME_NOW_DEFAULT); - - if (parm) { - cfg->init_flags |= ONEFS_VFS_CONFIG_FAKETIMESTAMPS; - set_namearray(&cfg->mtime_now_list,*parm); - } - - parm = lp_parm_string_list(snum, PARM_ONEFS_TYPE, PARM_ATIME_STATIC, - PARM_ATIME_STATIC_DEFAULT); - - if (parm) { - cfg->init_flags |= ONEFS_VFS_CONFIG_FAKETIMESTAMPS; - set_namearray(&cfg->atime_static_list,*parm); - } - - parm = lp_parm_string_list(snum, PARM_ONEFS_TYPE, PARM_MTIME_STATIC, - PARM_MTIME_STATIC_DEFAULT); - - if (parm) { - cfg->init_flags |= ONEFS_VFS_CONFIG_FAKETIMESTAMPS; - set_namearray(&cfg->mtime_static_list,*parm); - } - - cfg->atime_slop = lp_parm_int(snum, PARM_ONEFS_TYPE, PARM_ATIME_SLOP, - PARM_ATIME_SLOP_DEFAULT); - cfg->ctime_slop = lp_parm_int(snum, PARM_ONEFS_TYPE, PARM_CTIME_SLOP, - PARM_CTIME_SLOP_DEFAULT); - cfg->mtime_slop = lp_parm_int(snum, PARM_ONEFS_TYPE, PARM_MTIME_SLOP, - PARM_MTIME_SLOP_DEFAULT); -} - -/** - * Set onefs-specific vfs global config parameters. - * - * Since changes in these parameters require calling syscalls, we only want to - * call them when the configuration actually changes. - */ -static void onefs_load_global_config(connection_struct *conn) -{ - static struct onefs_vfs_global_config global_config; - bool dot_snap_child_accessible; - bool dot_snap_child_visible; - bool dot_snap_root_accessible; - bool dot_snap_root_visible; - bool dot_snap_tilde; - bool reconfig_dso = false; - bool reconfig_tilde = false; - - /* Check if this is the first time setting the config options. */ - if (!(global_config.init_flags & ONEFS_VFS_CONFIG_INITIALIZED)) { - global_config.init_flags |= ONEFS_VFS_CONFIG_INITIALIZED; - - /* Set process encoding */ - onefs_sys_config_enc(); - - reconfig_dso = true; - reconfig_tilde = true; - } - - /* Get the dot snap options from the conf. */ - dot_snap_child_accessible = - lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_DOT_SNAP_CHILD_ACCESSIBLE, - PARM_DOT_SNAP_CHILD_ACCESSIBLE_DEFAULT); - dot_snap_child_visible = - lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_DOT_SNAP_CHILD_VISIBLE, - PARM_DOT_SNAP_CHILD_VISIBLE_DEFAULT); - dot_snap_root_accessible = - lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_DOT_SNAP_ROOT_ACCESSIBLE, - PARM_DOT_SNAP_ROOT_ACCESSIBLE_DEFAULT); - dot_snap_root_visible = - lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_DOT_SNAP_ROOT_VISIBLE, - PARM_DOT_SNAP_ROOT_VISIBLE_DEFAULT); - dot_snap_tilde = - lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_DOT_SNAP_TILDE, - PARM_DOT_SNAP_TILDE_DEFAULT); - - /* Check if any of the dot snap options need updating. */ - if (dot_snap_child_accessible != - global_config.dot_snap_child_accessible) { - global_config.dot_snap_child_accessible = - dot_snap_child_accessible; - reconfig_dso = true; - } - if (dot_snap_child_visible != - global_config.dot_snap_child_visible) { - global_config.dot_snap_child_visible = - dot_snap_child_visible; - reconfig_dso = true; - } - if (dot_snap_root_accessible != - global_config.dot_snap_root_accessible) { - global_config.dot_snap_root_accessible = - dot_snap_root_accessible; - reconfig_dso = true; - } - if (dot_snap_root_visible != - global_config.dot_snap_root_visible) { - global_config.dot_snap_root_visible = - dot_snap_root_visible; - reconfig_dso = true; - } - if (dot_snap_tilde != global_config.dot_snap_tilde) { - global_config.dot_snap_tilde = dot_snap_tilde; - reconfig_tilde = true; - } - - /* If a dot snap option has changed update the process. */ - if (reconfig_dso) { - onefs_sys_config_snap_opt(&global_config); - } - - /* If the dot snap tilde option has changed update the process. */ - if (reconfig_tilde) { - onefs_sys_config_tilde(&global_config); - } -} - -int onefs_load_config(connection_struct *conn) -{ - int snum = SNUM(conn); - int share_count = lp_numservices(); - - /* Share config */ - if (!pvfs_share_config) { - - if (share_count <= ONEFS_DATA_FASTBUF) - pvfs_share_config = vfs_share_config; - else { - pvfs_share_config = - SMB_MALLOC_ARRAY(struct onefs_vfs_share_config, - share_count); - if (!pvfs_share_config) { - errno = ENOMEM; - return -1; - } - - memset(pvfs_share_config, 0, - (sizeof(struct onefs_vfs_share_config) * - share_count)); - } - } - - if ((pvfs_share_config[snum].init_flags & - ONEFS_VFS_CONFIG_INITIALIZED) == 0) { - pvfs_share_config[snum].init_flags = - ONEFS_VFS_CONFIG_INITIALIZED; - onefs_load_faketimestamp_config(conn, - &pvfs_share_config[snum]); - } - - /* Global config */ - onefs_load_global_config(conn); - - return 0; -} - -bool onefs_get_config(int snum, int config_type, - struct onefs_vfs_share_config *cfg) -{ - if ((pvfs_share_config != NULL) && - (pvfs_share_config[snum].init_flags & config_type)) - *cfg = pvfs_share_config[snum]; - else - return false; - - return true; -} - - -/** - * Set the per-process encoding, ignoring errors. - */ -void onefs_sys_config_enc(void) -{ - int ret; - - ret = enc_set_proc(ENC_UTF8); - if (ret) { - DEBUG(0, ("Setting process encoding failed: %s\n", - strerror(errno))); - } -} - -/** - * Set the per-process .snpashot directory options, ignoring errors. - */ -void onefs_sys_config_snap_opt(struct onefs_vfs_global_config *global_config) -{ - struct ifs_dotsnap_options dso; - int ret; - - dso.per_proc = 1; - dso.sub_accessible = global_config->dot_snap_child_accessible; - dso.sub_visible = global_config->dot_snap_child_visible; - dso.root_accessible = global_config->dot_snap_root_accessible; - dso.root_visible = global_config->dot_snap_root_visible; - - ret = ifs_set_dotsnap_options(&dso); - if (ret) { - DEBUG(0, ("Setting snapshot visibility/accessibility " - "failed: %s\n", strerror(errno))); - } -} - -/** - * Set the per-process flag saying whether or not to accept ~snapshot - * as an alternative name for .snapshot directories. - */ -void onefs_sys_config_tilde(struct onefs_vfs_global_config *global_config) -{ - int ret; - - ret = ifs_tilde_snapshot(global_config->dot_snap_tilde); - if (ret) { - DEBUG(0, ("Setting snapshot tilde failed: %s\n", - strerror(errno))); - } -} diff --git a/source3/modules/onefs_config.h b/source3/modules/onefs_config.h deleted file mode 100644 index f0f48e6379..0000000000 --- a/source3/modules/onefs_config.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * OneFS vfs module configuration and defaults - * - * Copyright (C) Steven Danneman, 2008 - * Copyright (C) Tim Prouty, 2009 - * - * 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/>. - */ - -#ifndef _ONEFS_CONFIG_H -#define _ONEFS_CONFIG_H - -/** -* Specifies when ACLs presented to Windows should be canonicalized -* into the ordering which Explorer expects. -*/ -enum onefs_acl_wire_format -{ - ACL_FORMAT_RAW, /**< Never canonicalize */ - ACL_FORMAT_WINDOWS_SD, /**< Only canonicalize synthetic ACLs */ - ACL_FORMAT_ALWAYS /**< Always canonicalize */ -}; - -#define PARM_ONEFS_TYPE "onefs" -#define PARM_ACL_WIRE_FORMAT "acl wire format" -#define PARM_ACL_WIRE_FORMAT_DEFAULT ACL_FORMAT_WINDOWS_SD -#define PARM_ALLOW_EXECUTE_ALWAYS "allow execute always" -#define PARM_ALLOW_EXECUTE_ALWAYS_DEFAULT false -#define PARM_ATIME_NOW "atime now files" -#define PARM_ATIME_NOW_DEFAULT NULL -#define PARM_ATIME_STATIC "atime static files" -#define PARM_ATIME_STATIC_DEFAULT NULL -#define PARM_ATIME_SLOP "atime now slop" -#define PARM_ATIME_SLOP_DEFAULT 0 -#define PARM_ATOMIC_SENDFILE "atomic sendfile" -#define PARM_ATOMIC_SENDFILE_DEFAULT true -#define PARM_CREATOR_OWNER_GETS_FULL_CONTROL "creator owner gets full control" -#define PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT true -#define PARM_CTIME_NOW "ctime now files" -#define PARM_CTIME_NOW_DEFAULT NULL -#define PARM_CTIME_SLOP "ctime now slop" -#define PARM_CTIME_SLOP_DEFAULT 0 -#define PARM_DOT_SNAP_CHILD_ACCESSIBLE "dot snap child accessible" -#define PARM_DOT_SNAP_CHILD_ACCESSIBLE_DEFAULT true -#define PARM_DOT_SNAP_CHILD_VISIBLE "dot snap child visible" -#define PARM_DOT_SNAP_CHILD_VISIBLE_DEFAULT false -#define PARM_DOT_SNAP_ROOT_ACCESSIBLE "dot snap root accessible" -#define PARM_DOT_SNAP_ROOT_ACCESSIBLE_DEFAULT true -#define PARM_DOT_SNAP_ROOT_VISIBLE "dot snap root visible" -#define PARM_DOT_SNAP_ROOT_VISIBLE_DEFAULT true -#define PARM_DOT_SNAP_TILDE "dot snap tilde" -#define PARM_DOT_SNAP_TILDE_DEFAULT true -#define PARM_IGNORE_SACLS "ignore sacls" -#define PARM_IGNORE_SACLS_DEFAULT false -#define PARM_IGNORE_STREAMS "ignore streams" -#define PARM_IGNORE_STREAMS_DEFAULT false -#define PARM_MTIME_NOW "mtime now files" -#define PARM_MTIME_NOW_DEFAULT NULL -#define PARM_MTIME_STATIC "mtime static files" -#define PARM_MTIME_STATIC_DEFAULT NULL -#define PARM_MTIME_SLOP "mtime now slop" -#define PARM_MTIME_SLOP_DEFAULT 0 -#define PARM_USE_READDIRPLUS "use readdirplus" -#define PARM_USE_READDIRPLUS_DEFAULT true -#define PARM_SENDFILE_LARGE_READS "sendfile large reads" -#define PARM_SENDFILE_LARGE_READS_DEFAULT false -#define PARM_SENDFILE_SAFE "sendfile safe" -#define PARM_SENDFILE_SAFE_DEFAULT true -#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE "simple file sharing compatibility mode" -#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT false -#define PARM_UNMAPPABLE_SIDS_DENY_EVERYONE "unmappable sids deny everyone" -#define PARM_UNMAPPABLE_SIDS_DENY_EVERYONE_DEFAULT false -#define PARM_UNMAPPABLE_SIDS_IGNORE "ignore unmappable sids" -#define PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT false -#define PARM_UNMAPPABLE_SIDS_IGNORE_LIST "unmappable sids ignore list" -#define PARM_UNMAPPABLE_SIDS_IGNORE_LIST_DEFAULT NULL - -#define IS_CTIME_NOW_PATH(conn,cfg,path) ((conn) && is_in_path((path),\ - (cfg)->ctime_now_list,(conn)->case_sensitive)) -#define IS_MTIME_NOW_PATH(conn,cfg,path) ((conn) && is_in_path((path),\ - (cfg)->mtime_now_list,(conn)->case_sensitive)) -#define IS_ATIME_NOW_PATH(conn,cfg,path) ((conn) && is_in_path((path),\ - (cfg)->atime_now_list,(conn)->case_sensitive)) -#define IS_MTIME_STATIC_PATH(conn,cfg,path) ((conn) && is_in_path((path),\ - (cfg)->mtime_static_list,(conn)->case_sensitive)) -#define IS_ATIME_STATIC_PATH(conn,cfg,path) ((conn) && is_in_path((path),\ - (cfg)->atime_static_list,(conn)->case_sensitive)) - -/* - * Store some commonly evaluated parameters to avoid loadparm pain. - */ - -#define ONEFS_VFS_CONFIG_INITIALIZED 0x00010000 - -#define ONEFS_VFS_CONFIG_FAKETIMESTAMPS 0x00000001 - -struct onefs_vfs_share_config -{ - uint32_t init_flags; - - /* data for fake timestamps */ - int atime_slop; - int ctime_slop; - int mtime_slop; - - /* Per-share list of files to fake the create time for. */ - name_compare_entry *ctime_now_list; - - /* Per-share list of files to fake the modification time for. */ - name_compare_entry *mtime_now_list; - - /* Per-share list of files to fake the access time for. */ - name_compare_entry *atime_now_list; - - /* Per-share list of files to fake the modification time for. */ - name_compare_entry *mtime_static_list; - - /* The access time will equal the create time. */ - /* The modification time will equal the create time.*/ - - /* Per-share list of files to fake the access time for. */ - name_compare_entry *atime_static_list; -}; - -struct onefs_vfs_global_config -{ - uint32_t init_flags; - - /* Snapshot options */ - bool dot_snap_child_accessible; - bool dot_snap_child_visible; - bool dot_snap_root_accessible; - bool dot_snap_root_visible; - bool dot_snap_tilde; -}; - -int onefs_load_config(connection_struct *conn); - -bool onefs_get_config(int snum, int config_type, - struct onefs_vfs_share_config *cfg); - -void onefs_sys_config_enc(void); - -void onefs_sys_config_snap_opt(struct onefs_vfs_global_config *global_config); - -void onefs_sys_config_tilde(struct onefs_vfs_global_config *global_config); - -#endif /* _ONEFS_CONFIG_H */ diff --git a/source3/modules/onefs_dir.c b/source3/modules/onefs_dir.c deleted file mode 100644 index 1a0f4819fe..0000000000 --- a/source3/modules/onefs_dir.c +++ /dev/null @@ -1,622 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * Support for OneFS bulk directory enumeration API - * - * Copyright (C) Steven Danneman, 2009 - * - * 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 "includes.h" -#include "smbd/smbd.h" -#include "onefs.h" -#include "onefs_config.h" - -#include <ifs/ifs_syscalls.h> -#include <isi_util/isi_dir.h> - -/* The OneFS filesystem provides a readdirplus() syscall, equivalent to the - * NFSv3 PDU, which retrieves bulk directory listings with stat information - * in a single syscall. - * - * This file hides this bulk interface underneath Samba's very POSIX like - * opendir/readdir/telldir VFS interface. This is done to provide a - * significant performance improvement when listing the contents of large - * directories, which also require file meta information. ie a typical - * Windows Explorer request. - */ - -#define RDP_RESUME_KEY_START 0x1 - -#define RDP_BATCH_SIZE 128 -#define RDP_DIRENTRIES_SIZE ((size_t)(RDP_BATCH_SIZE * sizeof(struct dirent))) - -static char *rdp_direntries = NULL; -static struct stat *rdp_stats = NULL; -static uint64_t *rdp_cookies = NULL; - -struct rdp_dir_state { - struct rdp_dir_state *next, *prev; - DIR *dirp; - char *direntries_cursor; /* cursor to last returned direntry in cache */ - size_t stat_count; /* number of entries stored in the cache */ - size_t stat_cursor; /* cursor to last returned stat in the cache */ - uint64_t resume_cookie; /* cookie from the last entry returned from the - cache */ -}; - -static struct rdp_dir_state *dirstatelist = NULL; - -DIR *rdp_last_dirp = NULL; - -/** - * Given a DIR pointer, return our internal state. - * - * This function also tells us whether the given DIR is the same as we saw - * during the last call. Because we use a single globally allocated buffer - * for readdirplus entries we must check every call into this API to see if - * it's for the same directory listing, or a new one. If it's the same we can - * maintain our current cached entries, otherwise we must go to the kernel. - * - * @return 0 on success, 1 on failure - */ -static int -rdp_retrieve_dir_state(DIR *dirp, struct rdp_dir_state **dir_state, - bool *same_as_last) -{ - struct rdp_dir_state *dsp; - - /* Is this directory the same as the last call */ - *same_as_last = (dirp == rdp_last_dirp); - - for(dsp = dirstatelist; dsp; dsp = dsp->next) - if (dsp->dirp == dirp) { - *dir_state = dsp; - return 0; - } - - /* Couldn't find existing dir_state for the given directory - * pointer. */ - return 1; -} - -/** - * Initialize the global readdirplus buffers. - * - * These same buffers are used for all calls into readdirplus. - * - * @return 0 on success, errno value on failure - */ -static int -rdp_init(struct rdp_dir_state *dsp) -{ - /* Unfortunately, there is no good way to free these buffers. If we - * allocated and freed for every DIR handle performance would be - * adversely affected. For now these buffers will be leaked and only - * freed when the smbd process dies. */ - if (!rdp_direntries) { - rdp_direntries = SMB_MALLOC(RDP_DIRENTRIES_SIZE); - if (!rdp_direntries) - return ENOMEM; - } - - if (!rdp_stats) { - rdp_stats = - SMB_MALLOC(RDP_BATCH_SIZE * sizeof(struct stat)); - if (!rdp_stats) - return ENOMEM; - } - - if (!rdp_cookies) { - rdp_cookies = SMB_MALLOC(RDP_BATCH_SIZE * sizeof(uint64_t)); - if (!rdp_cookies) - return ENOMEM; - } - - dsp->direntries_cursor = rdp_direntries + RDP_DIRENTRIES_SIZE; - dsp->stat_count = RDP_BATCH_SIZE; - dsp->stat_cursor = RDP_BATCH_SIZE; - dsp->resume_cookie = RDP_RESUME_KEY_START; - - return 0; -} - -/** - * Call into readdirplus() to refill our global dirent cache. - * - * This function also resets all cursors back to the beginning of the cache. - * All stat buffers are retrieved by following symlinks. - * - * @return number of entries retrieved, -1 on error - */ -static int -rdp_fill_cache(struct rdp_dir_state *dsp) -{ - int nread, dirfd; - - dirfd = dirfd(dsp->dirp); - if (dirfd < 0) { - DEBUG(1, ("Could not retrieve fd for DIR\n")); - return -1; - } - - /* Resize the stat_count to grab as many entries as possible */ - dsp->stat_count = RDP_BATCH_SIZE; - - DEBUG(9, ("Calling readdirplus() with DIR %p, dirfd: %d, " - "resume_cookie %#llx, size_to_read: %zu, " - "direntries_size: %zu, stat_count: %u\n", - dsp->dirp, dirfd, dsp->resume_cookie, RDP_BATCH_SIZE, - RDP_DIRENTRIES_SIZE, dsp->stat_count)); - - nread = readdirplus(dirfd, - RDP_FOLLOW, - &dsp->resume_cookie, - RDP_BATCH_SIZE, - rdp_direntries, - RDP_DIRENTRIES_SIZE, - &dsp->stat_count, - rdp_stats, - rdp_cookies); - if (nread < 0) { - DEBUG(1, ("Error calling readdirplus(): %s\n", - strerror(errno))); - return -1; - } - - DEBUG(9, ("readdirplus() returned %u entries from DIR %p\n", - dsp->stat_count, dsp->dirp)); - - dsp->direntries_cursor = rdp_direntries; - dsp->stat_cursor = 0; - - return nread; -} - -/** - * Create a dir_state to track an open directory that we're enumerating. - * - * This utility function is globally accessible for use by other parts of the - * onefs.so module to initialize a dir_state when a directory is opened through - * a path other than the VFS layer. - * - * @return 0 on success and errno on failure - * - * @note: Callers of this function MUST cleanup the dir_state through a proper - * call to VFS_CLOSEDIR(). - */ -int -onefs_rdp_add_dir_state(connection_struct *conn, DIR *dirp) -{ - int ret = 0; - struct rdp_dir_state *dsp = NULL; - - /* No-op if readdirplus is disabled */ - if (!lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT)) - { - return 0; - } - - /* Create a struct dir_state */ - dsp = SMB_MALLOC_P(struct rdp_dir_state); - if (!dsp) { - DEBUG(0, ("Error allocating struct rdp_dir_state.\n")); - return ENOMEM; - } - - /* Initialize the dir_state structure and add it to the list */ - ret = rdp_init(dsp); - if (ret) { - DEBUG(0, ("Error initializing readdirplus() buffers: %s\n", - strerror(ret))); - return ret; - } - - /* Set the DIR in the dsp */ - dsp->dirp = dirp; - - DLIST_ADD(dirstatelist, dsp); - - return 0; -} - -/** - * Open a directory for enumeration. - * - * Create a state struct to track the state of this directory for the life - * of this open. - * - * @param[in] handle vfs handle given in most VFS calls - * @param[in] fname filename of the directory to open - * @param[in] mask unused - * @param[in] attr unused - * - * @return DIR pointer, NULL if directory does not exist, NULL on error - */ -DIR * -onefs_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, - uint32 attr) -{ - int ret = 0; - DIR *ret_dirp; - - /* Fallback to default system routines if readdirplus is disabled */ - if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE, - PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT)) - { - return SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr); - } - - /* Open the directory */ - ret_dirp = SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr); - if (!ret_dirp) { - DEBUG(3, ("Unable to open directory: %s\n", fname)); - return NULL; - } - - /* Create the dir_state struct and add it to the list */ - ret = onefs_rdp_add_dir_state(handle->conn, ret_dirp); - if (ret) { - DEBUG(0, ("Error adding dir_state to the list\n")); - return NULL; - } - - DEBUG(9, ("Opened handle on directory: \"%s\", DIR %p\n", - fname, ret_dirp)); - - return ret_dirp; -} - -/** - * Retrieve one direntry and optional stat buffer from our readdir cache. - * - * Increment the internal resume cookie, and refresh the cache from the - * kernel if necessary. - * - * The cache cursor tracks the last entry which was successfully returned - * to a caller of onefs_readdir(). When a new entry is requested, this - * function first increments the cursor, then returns that entry. - * - * @param[in] handle vfs handle given in most VFS calls - * @param[in] dirp system DIR handle to retrieve direntries from - * @param[in/out] sbuf optional stat buffer to fill, this can be NULL - * - * @return dirent structure, NULL if at the end of the directory, NULL on error - */ -struct dirent * -onefs_readdir(vfs_handle_struct *handle, DIR *dirp, - SMB_STRUCT_STAT *sbuf) -{ - struct rdp_dir_state *dsp = NULL; - struct dirent *ret_direntp; - bool same_as_last, filled_cache = false; - int ret = -1; - - /* Set stat invalid in-case we error out */ - if (sbuf) - SET_STAT_INVALID(*sbuf); - - /* Fallback to default system routines if readdirplus is disabled */ - if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE, - PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT)) - { - return readdir(dirp); - } - - /* Retrieve state based off DIR handle */ - ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last); - if (ret) { - DEBUG(1, ("Could not retrieve dir_state struct for " - "DIR pointer.\n")); - ret_direntp = NULL; - goto end; - } - - /* DIR is the same, current buffer and cursors are valid. - * Check if there are any entries left in our current cache. */ - if (same_as_last) { - if (dsp->stat_cursor == dsp->stat_count - 1) { - /* Cache is empty, refill from kernel */ - ret = rdp_fill_cache(dsp); - if (ret <= 0) { - ret_direntp = NULL; - goto end; - } - filled_cache = true; - } - } else { - /* DIR is different from last call, reset all buffers and - * cursors, and refill the global cache from the new DIR */ - ret = rdp_fill_cache(dsp); - if (ret <= 0) { - ret_direntp = NULL; - goto end; - } - filled_cache = true; - DEBUG(8, ("Switched global rdp cache to new DIR entry.\n")); - } - - /* If we just filled the cache we treat that action as the cursor - * increment as the resume cookie used belonged to the previous - * directory entry. If the cache has not changed we first increment - * our cursor, then return the next entry */ - if (!filled_cache) { - dsp->direntries_cursor += - ((struct dirent *)dsp->direntries_cursor)->d_reclen; - dsp->stat_cursor++; - } - - /* The resume_cookie stored here purposely differs based on whether we - * just filled the cache. The resume cookie stored must always provide - * the next direntry, in case the cache is reloaded on every - * onefs_readdir() */ - dsp->resume_cookie = rdp_cookies[dsp->stat_cursor]; - - /* Return an entry from cache */ - ret_direntp = ((struct dirent *)dsp->direntries_cursor); - if (sbuf) { - struct stat onefs_sbuf; - - onefs_sbuf = rdp_stats[dsp->stat_cursor]; - init_stat_ex_from_onefs_stat(sbuf, &onefs_sbuf); - - /* readdirplus() sets st_ino field to 0, if it was - * unable to retrieve stat information for that - * particular directory entry. */ - if (sbuf->st_ex_ino == 0) - SET_STAT_INVALID(*sbuf); - } - - DEBUG(9, ("Read from DIR %p, direntry: \"%s\", resume cookie: %#llx, " - "cache cursor: %zu, cache count: %zu\n", - dsp->dirp, ret_direntp->d_name, dsp->resume_cookie, - dsp->stat_cursor, dsp->stat_count)); - - /* FALLTHROUGH */ -end: - /* Set rdp_last_dirp at the end of every VFS call where the cache was - * reloaded */ - rdp_last_dirp = dirp; - return ret_direntp; -} - -/** - * Set the location of the next direntry to be read via onefs_readdir(). - * - * This function should only pass in locations retrieved from onefs_telldir(). - * - * @param[in] handle vfs handle given in most VFS calls - * @param[in] dirp system DIR handle to set offset on - * @param[in] offset into the directory to resume reading from - * - * @return no return value - */ -void -onefs_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset) -{ - struct rdp_dir_state *dsp = NULL; - bool same_as_last; - uint64_t resume_cookie = 0; - int ret = -1; - - /* Fallback to default system routines if readdirplus is disabled */ - if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE, - PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT)) - { - return seekdir(dirp, offset); - } - - /* Validate inputs */ - if (offset < 0) { - DEBUG(1, ("Invalid offset %ld passed.\n", offset)); - return; - } - - /* Retrieve state based off DIR handle */ - ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last); - if (ret) { - DEBUG(1, ("Could not retrieve dir_state struct for " - "DIR pointer.\n")); - /* XXX: we can't return an error, should we ABORT rather than - * return without actually seeking? */ - return; - } - - /* Convert offset to resume_cookie */ - resume_cookie = rdp_offset31_to_cookie63(offset); - - DEBUG(9, ("Seek DIR %p, offset: %ld, resume_cookie: %#llx\n", - dsp->dirp, offset, resume_cookie)); - - /* TODO: We could check if the resume_cookie is already in the cache - * through a linear search. This would allow us to avoid the cost of - * flushing the cache. Frequently, the seekdir offset will only be - * one entry before the current cache cursor. However, usually - * VFS_SEEKDIR() is only called at the end of a TRAND2_FIND read and - * we'll flush the cache at the beginning of the next PDU anyway. Some - * analysis should be done to see if this enhancement would provide - * better performance. */ - - /* Set the resume cookie and indicate that the cache should be reloaded - * on next read */ - dsp->resume_cookie = resume_cookie; - rdp_last_dirp = NULL; - - return; -} - -/** - * Returns the location of the next direntry to be read via onefs_readdir(). - * - * This value can be passed into onefs_seekdir(). - * - * @param[in] handle vfs handle given in most VFS calls - * @param[in] dirp system DIR handle to set offset on - * - * @return offset into the directory to resume reading from - */ -long -onefs_telldir(vfs_handle_struct *handle, DIR *dirp) -{ - struct rdp_dir_state *dsp = NULL; - bool same_as_last; - long offset; - int ret = -1; - - /* Fallback to default system routines if readdirplus is disabled */ - if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE, - PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT)) - { - return telldir(dirp); - } - - /* Retrieve state based off DIR handle */ - ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last); - if (ret) { - DEBUG(1, ("Could not retrieve dir_state struct for " - "DIR pointer.\n")); - return -1; - } - - /* Convert resume_cookie to offset */ - offset = rdp_cookie63_to_offset31(dsp->resume_cookie); - if (offset < 0) { - DEBUG(1, ("Unable to convert resume_cookie: %#llx to a " - "suitable 32-bit offset value. Error: %s\n", - dsp->resume_cookie, strerror(errno))); - return -1; - } - - DEBUG(9, ("Seek DIR %p, offset: %ld, resume_cookie: %#llx\n", - dsp->dirp, offset, dsp->resume_cookie)); - - return offset; -} - -/** - * Set the next direntry to be read via onefs_readdir() to the beginning of the - * directory. - * - * @param[in] handle vfs handle given in most VFS calls - * @param[in] dirp system DIR handle to set offset on - * - * @return no return value - */ -void -onefs_rewinddir(vfs_handle_struct *handle, DIR *dirp) -{ - struct rdp_dir_state *dsp = NULL; - bool same_as_last; - int ret = -1; - - /* Fallback to default system routines if readdirplus is disabled */ - if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE, - PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT)) - { - return rewinddir(dirp); - } - - /* Retrieve state based off DIR handle */ - ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last); - if (ret) { - DEBUG(1, ("Could not retrieve dir_state struct for " - "DIR pointer.\n")); - return; - } - - /* Reset location and resume key to beginning */ - ret = rdp_init(dsp); - if (ret) { - DEBUG(0, ("Error re-initializing rdp cursors: %s\n", - strerror(ret))); - return; - } - - DEBUG(9, ("Rewind DIR: %p, to resume_cookie: %#llx\n", dsp->dirp, - dsp->resume_cookie)); - - return; -} - -/** - * Close DIR pointer and remove all state for that directory open. - * - * @param[in] handle vfs handle given in most VFS calls - * @param[in] dirp system DIR handle to set offset on - * - * @return -1 on failure, setting errno - */ -int -onefs_closedir(vfs_handle_struct *handle, DIR *dirp) -{ - struct rdp_dir_state *dsp = NULL; - bool same_as_last; - int ret_val = -1; - int ret = -1; - - /* Fallback to default system routines if readdirplus is disabled */ - if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE, - PARM_USE_READDIRPLUS, PARM_USE_READDIRPLUS_DEFAULT)) - { - return SMB_VFS_NEXT_CLOSEDIR(handle, dirp); - } - - /* Retrieve state based off DIR handle */ - ret = rdp_retrieve_dir_state(dirp, &dsp, &same_as_last); - if (ret) { - DEBUG(1, ("Could not retrieve dir_state struct for " - "DIR pointer.\n")); - errno = ENOENT; - return -1; - } - - /* Close DIR pointer */ - ret_val = SMB_VFS_NEXT_CLOSEDIR(handle, dsp->dirp); - - DEBUG(9, ("Closed handle on DIR %p\n", dsp->dirp)); - - /* Tear down state struct */ - DLIST_REMOVE(dirstatelist, dsp); - SAFE_FREE(dsp); - - /* Set lastp to NULL, as cache is no longer valid */ - rdp_last_dirp = NULL; - - return ret_val; -} - -/** - * Initialize cache data at the beginning of every SMB search operation - * - * Since filesystem operations, such as delete files or meta data - * updates can occur to files in the directory we're searching - * between FIND_FIRST and FIND_NEXT calls we must refresh the cache - * from the kernel on every new search SMB. - * - * @param[in] handle vfs handle given in most VFS calls - * @param[in] dirp system DIR handle for the current search - * - * @return nothing - */ -void -onefs_init_search_op(vfs_handle_struct *handle, DIR *dirp) -{ - /* Setting the rdp_last_dirp to NULL will cause the next readdir - * operation to refill the cache. */ - rdp_last_dirp = NULL; - - return; -} diff --git a/source3/modules/onefs_notify.c b/source3/modules/onefs_notify.c deleted file mode 100644 index bbdade6015..0000000000 --- a/source3/modules/onefs_notify.c +++ /dev/null @@ -1,682 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * Support for change notify using OneFS's file event notification system - * - * Copyright (C) Andrew Tridgell, 2006 - * Copyright (C) Steven Danneman, 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/>. - */ - -/* Implement handling of change notify requests on files and directories using - * Isilon OneFS's "ifs event" file notification system. - * - * The structure of this file is based off the implementation of change notify - * using the inotify system calls in smbd/notify_inotify.c */ - -/* TODO: We could reduce the number of file descriptors used by merging - * multiple watch requests on the same directory into the same - * onefs_notify_watch_context. To do this we'd need mux/demux routines that - * when receiving an event on that watch context would check it against the - * CompletionFilter and WatchTree of open SMB requests, and return notify - * events back to the proper SMB requests */ - -#include "includes.h" -#include "smbd/smbd.h" -#include "onefs.h" - -#include <ifs/ifs_types.h> -#include <ifs/ifs_syscalls.h> -#include <isi_util/syscalls.h> - -#include <sys/event.h> - -#define ONEFS_IFS_EVENT_MAX_NUM 8 -#define ONEFS_IFS_EVENT_MAX_BYTES (ONEFS_IFS_EVENT_MAX_NUM * \ - sizeof(struct ifs_event)) - -struct onefs_notify_watch_context { - struct sys_notify_context *ctx; - int watch_fd; - ino_t watch_lin; - const char *path; - int ifs_event_fd; - uint32_t ifs_filter; /* the ifs event mask */ - uint32_t smb_filter; /* the windows completion filter */ - void (*callback)(struct sys_notify_context *ctx, - void *private_data, - struct notify_event *ev); - void *private_data; -}; - -/** - * Conversion map from a SMB completion filter to an IFS event mask. - */ -static const struct { - uint32_t smb_filter; - uint32_t ifs_filter; -} onefs_notify_conv[] = { - {FILE_NOTIFY_CHANGE_FILE_NAME, - NOTE_CREATE | NOTE_DELETE | NOTE_RENAME_FROM | NOTE_RENAME_TO}, - {FILE_NOTIFY_CHANGE_DIR_NAME, - NOTE_CREATE | NOTE_DELETE | NOTE_RENAME_FROM | NOTE_RENAME_TO}, - {FILE_NOTIFY_CHANGE_ATTRIBUTES, - NOTE_CREATE | NOTE_DELETE | NOTE_RENAME_FROM | NOTE_RENAME_TO | - NOTE_ATTRIB}, - {FILE_NOTIFY_CHANGE_SIZE, - NOTE_SIZE | NOTE_EXTEND}, - {FILE_NOTIFY_CHANGE_LAST_WRITE, - NOTE_WRITE | NOTE_ATTRIB}, - /* OneFS doesn't set atime by default, but we can somewhat fake it by - * notifying for other events that imply ACCESS */ - {FILE_NOTIFY_CHANGE_LAST_ACCESS, - NOTE_WRITE | NOTE_ATTRIB}, - /* We don't have an ifs_event for the setting of create time, but we - * can fake by notifying when a "new" file is created via rename */ - {FILE_NOTIFY_CHANGE_CREATION, - NOTE_RENAME_TO}, - {FILE_NOTIFY_CHANGE_SECURITY, - NOTE_SECURITY}, - /* Unsupported bits - FILE_NOTIFY_CHANGE_EA (no EAs in OneFS) - FILE_NOTIFY_CHANGE_STREAM_NAME (no ifs_event equivalent) - FILE_NOTIFY_CHANGE_STREAM_SIZE (no ifs_event equivalent) - FILE_NOTIFY_CHANGE_STREAM_WRITE (no ifs_event equivalent) */ -}; - -#define ONEFS_NOTIFY_UNSUPPORTED (FILE_NOTIFY_CHANGE_LAST_ACCESS | \ - FILE_NOTIFY_CHANGE_CREATION | \ - FILE_NOTIFY_CHANGE_EA | \ - FILE_NOTIFY_CHANGE_STREAM_NAME | \ - FILE_NOTIFY_CHANGE_STREAM_SIZE | \ - FILE_NOTIFY_CHANGE_STREAM_WRITE) - -/** - * Convert Windows/SMB filter/flags to IFS event filter. - * - * @param[in] smb_filter Windows Completion Filter sent in the SMB - * - * @return ifs event filter mask - */ -static uint32_t -onefs_notify_smb_filter_to_ifs_filter(uint32_t smb_filter) -{ - int i; - uint32_t ifs_filter = 0x0; - - for (i=0;i<ARRAY_SIZE(onefs_notify_conv);i++) { - if (onefs_notify_conv[i].smb_filter & smb_filter) { - ifs_filter |= onefs_notify_conv[i].ifs_filter; - } - } - - return ifs_filter; -} - -/** - * Convert IFS filter/flags to a Windows notify action. - * - * Returns Win notification actions, types (1-5). - * - * @param[in] smb_filter Windows Completion Filter sent in the SMB - * @param[in] ifs_filter Returned from the kernel in the ifs_event - * - * @return 0 if there are no more relevant flags. - */ -static int -onefs_notify_ifs_filter_to_smb_action(uint32_t smb_filter, uint32_t ifs_filter) -{ - /* Handle Windows special cases, before modifying events bitmask */ - - /* Special case 1: win32api->MoveFile needs to send a modified - * notification on the new file, if smb_filter == ATTRIBUTES. - * Here we handle the case where two separate ATTR & NAME notifications - * have been registered. We handle the case where both bits are set in - * the same registration in onefs_notify_dispatch() */ - if ((smb_filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) && - !(smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && - (ifs_filter & NOTE_FILE) && (ifs_filter & NOTE_RENAME_TO)) - { - return NOTIFY_ACTION_MODIFIED; - } - - /* Special case 2: Writes need to send a modified - * notification on the file, if smb_filter = ATTRIBUTES. */ - if ((smb_filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) && - (ifs_filter & NOTE_FILE) && (ifs_filter & NOTE_WRITE)) - { - return NOTIFY_ACTION_MODIFIED; - } - - /* Loop because some events may be filtered out. Eventually all - * relevant events will be taken care of and returned. */ - while (1) { - if (ifs_filter & NOTE_CREATE) { - ifs_filter &= ~NOTE_CREATE; - if ((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && - (ifs_filter & NOTE_FILE)) - return NOTIFY_ACTION_ADDED; - if ((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) && - (ifs_filter & NOTE_DIRECTORY)) - return NOTIFY_ACTION_ADDED; - } - else if (ifs_filter & NOTE_DELETE) { - ifs_filter &= ~NOTE_DELETE; - if ((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && - (ifs_filter & NOTE_FILE)) - return NOTIFY_ACTION_REMOVED; - if ((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) && - (ifs_filter & NOTE_DIRECTORY)) - return NOTIFY_ACTION_REMOVED; - } - else if (ifs_filter & NOTE_WRITE) { - ifs_filter &= ~NOTE_WRITE; - if ((smb_filter & FILE_NOTIFY_CHANGE_LAST_WRITE) || - (smb_filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)) - return NOTIFY_ACTION_MODIFIED; - } - else if ((ifs_filter & NOTE_SIZE) || (ifs_filter & NOTE_EXTEND)) { - ifs_filter &= ~NOTE_SIZE; - ifs_filter &= ~NOTE_EXTEND; - - /* TODO: Do something on NOTE_DIR? */ - if ((smb_filter & FILE_NOTIFY_CHANGE_SIZE) && - (ifs_filter & NOTE_FILE)) - return NOTIFY_ACTION_MODIFIED; - } - else if (ifs_filter & NOTE_ATTRIB) { - ifs_filter &= ~NOTE_ATTRIB; - /* NOTE_ATTRIB needs to be converted to a - * LAST_WRITE as well, because we need to send - * LAST_WRITE when the mtime changes. Looking into - * better alternatives as this causes extra LAST_WRITE - * notifications. We also return LAST_ACCESS as a - * modification to attribs implies this. */ - if ((smb_filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) || - (smb_filter & FILE_NOTIFY_CHANGE_LAST_WRITE) || - (smb_filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)) - return NOTIFY_ACTION_MODIFIED; - } - else if (ifs_filter & NOTE_LINK) { - ifs_filter &= ~NOTE_LINK; - /* NOTE_LINK will send out NO notifications */ - } - else if (ifs_filter & NOTE_REVOKE) { - ifs_filter &= ~NOTE_REVOKE; - /* NOTE_REVOKE will send out NO notifications */ - } - else if (ifs_filter & NOTE_RENAME_FROM) { - ifs_filter &= ~NOTE_RENAME_FROM; - - if (((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && - (ifs_filter & NOTE_FILE)) || - ((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) && - (ifs_filter & NOTE_DIRECTORY))) { - /* Check if this is a RENAME, not a MOVE */ - if (ifs_filter & NOTE_RENAME_SAMEDIR) { - /* Remove the NOTE_RENAME_SAMEDIR, IFF - * RENAME_TO is not in this event */ - if (!(ifs_filter & NOTE_RENAME_TO)) - ifs_filter &= - ~NOTE_RENAME_SAMEDIR; - return NOTIFY_ACTION_OLD_NAME; - } - return NOTIFY_ACTION_REMOVED; - } - } - else if (ifs_filter & NOTE_RENAME_TO) { - ifs_filter &= ~NOTE_RENAME_TO; - - if (((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && - (ifs_filter & NOTE_FILE)) || - ((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) && - (ifs_filter & NOTE_DIRECTORY))) { - /* Check if this is a RENAME, not a MOVE */ - if (ifs_filter & NOTE_RENAME_SAMEDIR) { - /* Remove the NOTE_RENAME_SAMEDIR, IFF - * RENAME_FROM is not in this event */ - if (!(ifs_filter & NOTE_RENAME_FROM)) - ifs_filter &= - ~NOTE_RENAME_SAMEDIR; - return NOTIFY_ACTION_NEW_NAME; - } - return NOTIFY_ACTION_ADDED; - } - /* RAW-NOTIFY shows us that a rename triggers a - * creation time change */ - if ((smb_filter & FILE_NOTIFY_CHANGE_CREATION) && - (ifs_filter & NOTE_FILE)) - return NOTIFY_ACTION_MODIFIED; - } - else if (ifs_filter & NOTE_SECURITY) { - ifs_filter &= ~NOTE_SECURITY; - - if (smb_filter & FILE_NOTIFY_CHANGE_SECURITY) - return NOTIFY_ACTION_MODIFIED; - } else { - /* No relevant flags found */ - return 0; - } - } -} - -/** - * Retrieve a directory path of a changed file, relative to the watched dir - * - * @param[in] wc watch context for the returned event - * @param[in] e ifs_event notification returned from the kernel - * @param[out] path name relative to the watched dir. This is talloced - * off of wc and needs to be freed by the caller. - * - * @return true on success - * - * TODO: This function currently doesn't handle path names with multiple - * encodings. enc_get_lin_path() should be used in the future to convert - * each path segment's encoding to UTF-8 - */ -static bool -get_ifs_event_path(struct onefs_notify_watch_context *wc, struct ifs_event *e, - char **path) -{ - char *path_buf = NULL; - size_t pathlen = 0; - int error = 0; - - SMB_ASSERT(path); - - /* Lookup the path from watch_dir through our parent dir */ - if (e->namelen > 0) { - error = lin_get_path(wc->watch_lin, - e->parent_lin, - HEAD_SNAPID, - e->parent_parent_lin, - e->parent_name_hash, - &pathlen, &path_buf); - if (!error) { - /* Only add slash if a path exists in path_buf from - * lin_get_path call. Windows does not expect a - * leading '/' */ - if (pathlen > 0) - *path = talloc_asprintf(wc, "%s/%s", - path_buf, e->name); - else - *path = talloc_asprintf(wc, "%s", e->name); - SAFE_FREE(path_buf); - } - } - - /* If ifs_event didn't return a name, or we errored out of our intial - * path lookup, try again using the lin of the changed file */ - if (!(*path)) { - error = lin_get_path(wc->watch_lin, - e->lin, - HEAD_SNAPID, - e->parent_lin, - e->name_hash, - &pathlen, &path_buf); - if (error) { - /* It's possible that both the lin and the parent lin - * are invalid (or not given) -- we will skip these - * events. */ - DEBUG(3,("Path lookup failed. LINS are invalid: " - "e->lin: 0x%llu, e->parent_lin: 0x%llu, " - "e->parent_parent_lin: 0x%llu\n", - e->lin, e->parent_lin, e->parent_parent_lin)); - SAFE_FREE(path_buf); - return false; - } else { - *path = talloc_asprintf(wc, "%s", path_buf); - DEBUG(5, ("Using path from event LIN = %s\n", - path_buf)); - SAFE_FREE(path_buf); - } - } - - /* Replacement of UNIX slashes with WIN slashes is handled at a - * higher layer. */ - - return true; -} - -/** - * Dispatch one OneFS notify event to the general Samba code - * - * @param[in] wc watch context for the returned event - * @param[in] e event returned from the kernel - * - * @return nothing - */ -static void -onefs_notify_dispatch(struct onefs_notify_watch_context *wc, - struct ifs_event *e) -{ - char *path = NULL; - struct notify_event ne; - - DEBUG(5, ("Retrieved ifs event from kernel: lin=%#llx, ifs_events=%#x, " - "parent_lin=%#llx, namelen=%d, name=\"%s\"\n", - e->lin, e->events, e->parent_lin, e->namelen, e->name)); - - /* Check validity of event returned from kernel */ - if (e->lin == 0) { - /* The lin == 0 specifies 1 of 2 cases: - * 1) We are out of events. The kernel has a limited - * amount (somewhere near 90000) - * 2) Split nodes have merged back and had data written - * to them -- thus we've missed some of those events. */ - DEBUG(3, ("We've missed some kernel ifs events!\n")); - - /* Alert higher level to the problem so it returns catch-all - * response to the client */ - ne.path = NULL; - ne.action = 0; - wc->callback(wc->ctx, wc->private_data, &ne); - } - - if (e->lin == wc->watch_lin) { - /* Windows doesn't report notifications on root - * watched directory */ - /* TODO: This should be abstracted out to the general layer - * instead of being handled in every notify provider */ - DEBUG(5, ("Skipping notification on root of the watched " - "path.\n")); - return; - } - - /* Retrieve the full path for the ifs event name */ - if(!get_ifs_event_path(wc, e, &path)) { - DEBUG(3, ("Failed to convert the ifs_event lins to a path. " - "Skipping this event\n")); - return; - } - - if (!strncmp(path, ".ifsvar", 7)) { - /* Skip notifications on file if its in ifs configuration - * directory */ - goto clean; - } - - ne.path = path; - - /* Convert ifs event mask to an smb action mask */ - ne.action = onefs_notify_ifs_filter_to_smb_action(wc->smb_filter, - e->events); - - DEBUG(5, ("Converted smb_filter=%#x, ifs_events=%#x, to " - "ne.action = %d, for ne.path = %s\n", - wc->smb_filter, e->events, ne.action, ne.path)); - - if (!ne.action) - goto clean; - - /* Return notify_event to higher level */ - wc->callback(wc->ctx, wc->private_data, &ne); - - /* SMB expects a file rename/move to generate three actions, a - * rename_from/delete on the from file, a rename_to/create on the to - * file, and a modify for the rename_to file. If we have two separate - * notifications registered for ATTRIBUTES and FILENAME, this case will - * be handled by separate ifs_events in - * onefs_notify_ifs_filter_to_smb_action(). If both bits are registered - * in the same notification, we must send an extra MODIFIED action - * here. */ - if ((wc->smb_filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) && - (wc->smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) && - (e->events & NOTE_FILE) && (e->events & NOTE_RENAME_TO)) - { - ne.action = NOTIFY_ACTION_MODIFIED; - wc->callback(wc->ctx, wc->private_data, &ne); - } - - /* FALLTHROUGH */ -clean: - talloc_free(path); - return; -} - -/** - * Callback when the kernel has some events for us - * - * Read events off ifs event fd and pass them to our dispatch function - * - * @param ev context of all tevents registered in the smbd - * @param fde tevent struct specific to one ifs event channel - * @param flags tevent flags passed when we added our ifs event channel fd to - * the main loop - * @param private_data onefs_notify_watch_context specific to this ifs event - * channel - * - * @return nothing - */ -static void -onefs_notify_handler(struct event_context *ev, - struct fd_event *fde, - uint16_t flags, - void *private_data) -{ - struct onefs_notify_watch_context *wc = NULL; - struct ifs_event ifs_events[ONEFS_IFS_EVENT_MAX_NUM]; - ssize_t nread = 0; - int count = 0; - int i = 0; - - wc = talloc_get_type(private_data, struct onefs_notify_watch_context); - - /* Read as many ifs events from the notify channel as we can */ - nread = sys_read(wc->ifs_event_fd, &ifs_events, - ONEFS_IFS_EVENT_MAX_BYTES); - if (nread == 0) { - DEBUG(0,("No data found while reading ifs event fd?!\n")); - return; - } - if (nread < 0) { - DEBUG(0,("Failed to read ifs event data: %s\n", - strerror(errno))); - return; - } - - count = nread / sizeof(struct ifs_event); - - DEBUG(5, ("Got %d notification events in %d bytes.\n", count, nread)); - - /* Dispatch ifs_events one-at-a-time to higher level */ - for (i=0; i < count; i++) { - onefs_notify_dispatch(wc, &ifs_events[i]); - } -} - -/** - * Destroy the ifs event channel - * - * This is called from talloc_free() when the generic Samba notify layer frees - * the onefs_notify_watch_context. - * - * @param[in] wc pointer to watch context which is being destroyed - * - * return 0 on success -*/ -static int -onefs_watch_destructor(struct onefs_notify_watch_context *wc) -{ - /* The ifs_event_fd will re de-registered from the event loop by - * another destructor triggered from the freeing of this wc */ - close(wc->ifs_event_fd); - return 0; -} - -/** - * Register a single change notify watch request. - * - * Open an event listener on a directory to watch for modifications. This - * channel is closed by a destructor when the caller calls talloc_free() - * on *handle. - * - * @param[in] vfs_handle handle given to most VFS operations - * @param[in] ctx context (conn and tevent) for this connection - * @param[in] e filter and path of client's notify request - * @param[in] callback function to call when file notification event is received - * from the kernel, passing that event up to Samba's - * generalized change notify layer - * @param[in] private_data opaque data given to us by the general change notify - * layer which must be returned in the callback function - * @param[out] handle_p handle returned to generalized change notify layer used - * to close the event channel when notification is - * cancelled - * - * @return NT_STATUS_OK unless error - */ -NTSTATUS -onefs_notify_watch(vfs_handle_struct *vfs_handle, - struct sys_notify_context *ctx, - struct notify_entry *e, - void (*callback)(struct sys_notify_context *ctx, - void *private_data, - struct notify_event *ev), - void *private_data, - void *handle_p) -{ - int ifs_event_fd = -1; - uint32_t ifs_filter = 0; - uint32_t smb_filter = e->filter; - bool watch_tree = !!e->subdir_filter; - struct onefs_notify_watch_context *wc = NULL; - void **handle = (void **)handle_p; - SMB_STRUCT_STAT sbuf; - NTSTATUS status = NT_STATUS_UNSUCCESSFUL; - - /* Fallback to default Samba implementation if kernel CN is disabled */ - if (!lp_kernel_change_notify(vfs_handle->conn->params)) { - (*handle) = NULL; - return NT_STATUS_OK; - } - - /* The OneFS open path should always give us a valid fd on a directory*/ - SMB_ASSERT(e->dir_fd >= 0); - - /* Always set e->filter to 0 so we don't fallback on the default change - * notify backend. It's not cluster coherent or cross-protocol so we - * can't guarantee correctness using it. */ - e->filter = 0; - e->subdir_filter = 0; - - /* Snapshots do not currently allow event listeners. See Isilon - * bug 33476 for an example of .snapshot debug spew that can occur. */ - if (e->dir_id.extid != HEAD_SNAPID) - return NT_STATUS_INVALID_PARAMETER; - - /* Convert Completion Filter mask to IFS Event mask */ - ifs_filter = onefs_notify_smb_filter_to_ifs_filter(smb_filter); - - if (smb_filter & ONEFS_NOTIFY_UNSUPPORTED) { - /* One or more of the filter bits could not be fully handled by - * the ifs_event system. To be correct, if we cannot service a - * bit in the completion filter we should return - * NT_STATUS_NOT_IMPLEMENTED to let the client know that they - * won't be receiving all the notify events that they asked for. - * Unfortunately, WinXP clients cache this error message, stop - * trying to send any notify requests at all, and instead return - * NOT_IMPLEMENTED to all requesting apps without ever sending a - * message to us. Thus we lie, and say we can service all bits, - * but simply don't return actions for the filter bits we can't - * detect or fully implement. */ - DEBUG(3,("One or more of the Windows completion filter bits " - "for \"%s\" could not be fully handled by the " - "ifs_event system. The failed bits are " - "smb_filter=%#x\n", - e->path, smb_filter & ONEFS_NOTIFY_UNSUPPORTED)); - } - - if (ifs_filter == 0) { - /* None of the filter bits given are supported by the ifs_event - * system. Don't create a kernel notify channel, but mock - * up a fake handle for the caller. */ - DEBUG(3,("No bits in the Windows completion filter could be " - "translated to ifs_event mask for \"%s\", " - "smb_filter=%#x\n", e->path, smb_filter)); - (*handle) = NULL; - return NT_STATUS_OK; - } - - /* Register an ifs event channel for this watch request */ - ifs_event_fd = ifs_create_listener(watch_tree ? - EVENT_RECURSIVE : - EVENT_CHILDREN, - ifs_filter, - e->dir_fd); - if (ifs_event_fd < 0) { - DEBUG(0,("Failed to create listener for %s with \"%s\". " - "smb_filter=0x%x, ifs_filter=0x%x, watch_tree=%u\n", - strerror(errno), e->path, smb_filter, ifs_filter, - watch_tree)); - return map_nt_error_from_unix(errno); - } - - /* Create a watch context to track this change notify request */ - wc = talloc(ctx, struct onefs_notify_watch_context); - if (wc == NULL) { - status = NT_STATUS_NO_MEMORY; - goto err; - } - - /* Get LIN for directory */ - if (onefs_sys_fstat(e->dir_fd, &sbuf)) { - DEBUG(0, ("stat on directory fd failed: %s\n", - strerror(errno))); - status = map_nt_error_from_unix(errno); - goto err; - } - - if (sbuf.st_ex_ino == 0) { - DEBUG(0, ("0 LIN found!\n")); - goto err; - } - - wc->ctx = ctx; - wc->watch_fd = e->dir_fd; - wc->watch_lin = sbuf.st_ex_ino; - wc->ifs_event_fd = ifs_event_fd; - wc->ifs_filter = ifs_filter; - wc->smb_filter = smb_filter; - wc->callback = callback; - wc->private_data = private_data; - wc->path = talloc_strdup(wc, e->path); - if (wc->path == NULL) { - status = NT_STATUS_NO_MEMORY; - goto err; - } - - (*handle) = wc; - - /* The caller frees the handle to stop watching */ - talloc_set_destructor(wc, onefs_watch_destructor); - - /* Add a tevent waiting for the ifs event fd to be readable */ - event_add_fd(ctx->ev, wc, wc->ifs_event_fd, EVENT_FD_READ, - onefs_notify_handler, wc); - - DEBUG(10, ("Watching for changes on \"%s\" smb_filter=0x%x, " - "ifs_filter=0x%x, watch_tree=%d, ifs_event_fd=%d, " - "dir_fd=%d, dir_lin=0x%llx\n", - e->path, smb_filter, ifs_filter, watch_tree, - ifs_event_fd, e->dir_fd, sbuf.st_ex_ino)); - - return NT_STATUS_OK; - -err: - talloc_free(wc); - SMB_ASSERT(ifs_event_fd >= 0); - close(ifs_event_fd); - return status; -} diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c deleted file mode 100644 index a77d6f3e7e..0000000000 --- a/source3/modules/onefs_open.c +++ /dev/null @@ -1,2200 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * This file began with some code from source3/smbd/open.c and has been - * modified it work with ifs_createfile. - * - * ifs_createfile is a CIFS-specific syscall for opening/files and - * directories. It adds support for: - * - Full in-kernel access checks using a windows access_mask - * - Cluster-coherent share mode locks - * - Cluster-coherent oplocks - * - Streams - * - Setting security descriptors at create time - * - Setting dos_attributes at create time - * - * Copyright (C) Andrew Tridgell 1992-1998 - * Copyright (C) Jeremy Allison 2001-2004 - * Copyright (C) Volker Lendecke 2005 - * 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 "includes.h" -#include "smbd/smbd.h" -#include "onefs.h" -#include "onefs_config.h" -#include "oplock_onefs.h" -#include "smbd/globals.h" - -extern const struct generic_mapping file_generic_mapping; - -struct onefs_fsp_data { - uint64_t oplock_callback_id; -}; - -static NTSTATUS onefs_create_file_unixpath(connection_struct *conn, - struct smb_request *req, - struct smb_filename *smb_fname, - uint32_t access_mask, - uint32_t share_access, - uint32_t create_disposition, - uint32_t create_options, - uint32_t file_attributes, - uint32_t oplock_request, - uint64_t allocation_size, - uint32_t private_flags, - struct security_descriptor *sd, - struct ea_list *ea_list, - files_struct **result, - int *pinfo, - struct onefs_fsp_data *fsp_data); - -/**************************************************************************** - Open a file. -****************************************************************************/ - -static NTSTATUS onefs_open_file(files_struct *fsp, - connection_struct *conn, - struct smb_request *req, - const char *parent_dir, - struct smb_filename *smb_fname, - int flags, - mode_t unx_mode, - uint32 access_mask, - uint32 open_access_mask, - int oplock_request, - uint64 id, - uint32 share_access, - uint32 create_options, - uint32_t new_dos_attributes, - struct security_descriptor *sd, - int *granted_oplock) -{ - struct smb_filename *smb_fname_onefs = NULL; - NTSTATUS status = NT_STATUS_OK; - int accmode = (flags & O_ACCMODE); - int local_flags = flags; - bool file_existed = VALID_STAT(smb_fname->st); - const char *wild; - int base_fd = -1; - - fsp->fh->fd = -1; - errno = EPERM; - - /* Check permissions */ - - /* - * This code was changed after seeing a client open request - * containing the open mode of (DENY_WRITE/read-only) with - * the 'create if not exist' bit set. The previous code - * would fail to open the file read only on a read-only share - * as it was checking the flags parameter directly against O_RDONLY, - * this was failing as the flags parameter was set to O_RDONLY|O_CREAT. - * JRA. - */ - - if (!CAN_WRITE(conn)) { - /* It's a read-only share - fail if we wanted to write. */ - if(accmode != O_RDONLY) { - DEBUG(3, ("Permission denied opening %s\n", - smb_fname_str_dbg(smb_fname))); - return NT_STATUS_ACCESS_DENIED; - } else if(flags & O_CREAT) { - /* We don't want to write - but we must make sure that - O_CREAT doesn't create the file if we have write - access into the directory. - */ - flags &= ~O_CREAT; - local_flags &= ~O_CREAT; - } - } - - /* - * This little piece of insanity is inspired by the - * fact that an NT client can open a file for O_RDONLY, - * but set the create disposition to FILE_EXISTS_TRUNCATE. - * If the client *can* write to the file, then it expects to - * truncate the file, even though it is opening for readonly. - * Quicken uses this stupid trick in backup file creation... - * Thanks *greatly* to "David W. Chapman Jr." <dwcjr@inethouston.net> - * for helping track this one down. It didn't bite us in 2.0.x - * as we always opened files read-write in that release. JRA. - */ - - if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) { - DEBUG(10,("onefs_open_file: truncate requested on read-only " - "open for file %s\n", smb_fname_str_dbg(smb_fname))); - local_flags = (flags & ~O_ACCMODE)|O_RDWR; - } - -#if defined(O_NONBLOCK) && defined(S_ISFIFO) - /* - * We would block on opening a FIFO with no one else on the - * other end. Do what we used to do and add O_NONBLOCK to the - * open flags. JRA. - */ - - if (file_existed && S_ISFIFO(smb_fname->st.st_ex_mode)) { - local_flags |= O_NONBLOCK; - } -#endif - - /* Don't create files with Microsoft wildcard characters. */ - if (fsp->base_fsp) { - /* - * wildcard characters are allowed in stream names - * only test the basefilename - */ - wild = fsp->base_fsp->fsp_name->base_name; - } else { - wild = smb_fname->base_name; - } - if ((local_flags & O_CREAT) && !file_existed && - ms_has_wild(wild)) { - /* - * XXX: may need to remvoe this return... - * - * We dont think this check needs to exist. All it does is - * block creating files with Microsoft wildcards, which is - * fine if the creation originated from NFS or locally and - * then was copied via Samba. - */ - DEBUG(1, ("onefs_open_file: creating file with wildcard: %s\n", - smb_fname_str_dbg(smb_fname))); - return NT_STATUS_OBJECT_NAME_INVALID; - } - - /* Actually do the open */ - -#ifdef O_NOFOLLOW - /* - * Never follow symlinks on a POSIX client. The - * client should be doing this. - */ - - if (fsp->posix_open || !lp_symlinks(SNUM(conn))) { - flags |= O_NOFOLLOW; - } -#endif - /* Setup a onefs-style smb_fname struct. */ - status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname, - &smb_fname_onefs); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - /* If it's a stream pass in the base_fd */ - if ((conn->fs_capabilities & FILE_NAMED_STREAMS) && - is_ntfs_stream_smb_fname(smb_fname_onefs)) { - SMB_ASSERT(fsp->base_fsp); - - DEBUG(10, ("Opening a stream: base=%s(%d), stream=%s\n", - smb_fname_onefs->base_name, fsp->base_fsp->fh->fd, - smb_fname_onefs->stream_name)); - - base_fd = fsp->base_fsp->fh->fd; - } - - fsp->fh->fd = onefs_sys_create_file(conn, - base_fd, - smb_fname_onefs->stream_name != NULL ? - smb_fname_onefs->stream_name : - smb_fname_onefs->base_name, - access_mask, - open_access_mask, - share_access, - create_options, - flags, - unx_mode, - oplock_request, - id, - sd, - new_dos_attributes, - granted_oplock); - TALLOC_FREE(smb_fname_onefs); - - if (fsp->fh->fd == -1) { - if (errno == EMFILE) { - static time_t last_warned = 0L; - - if (time((time_t *) NULL) > last_warned) { - DEBUG(0, ("Too many open files, unable " - "to open more! smbd's max " - "open files = %d, also check " - "sysctl kern.maxfiles and " - "sysctl kern.maxfilesperproc\n", - lp_max_open_files())); - last_warned = time((time_t *) NULL); - } - } - - status = map_nt_error_from_unix(errno); - DEBUG(3, ("Error opening file %s (%s) (local_flags=%d) " - "(flags=%d)\n", smb_fname_str_dbg(smb_fname), - strerror(errno), local_flags, flags)); - return status; - } - - if ((local_flags & O_CREAT) && !file_existed) { - - /* Inherit the ACL if required */ - if (lp_inherit_perms(SNUM(conn))) { - inherit_access_posix_acl(conn, parent_dir, - smb_fname->base_name, unx_mode); - } - - /* Change the owner if required. */ - if (lp_inherit_owner(SNUM(conn))) { - change_file_owner_to_parent(conn, parent_dir, - fsp); - } - - notify_fname(conn, NOTIFY_ACTION_ADDED, - FILE_NOTIFY_CHANGE_FILE_NAME, smb_fname->base_name); - } - - if (!file_existed) { - int ret; - - if (fsp->fh->fd == -1) { - ret = SMB_VFS_STAT(conn, smb_fname); - } else { - ret = SMB_VFS_FSTAT(fsp, &smb_fname->st); - /* If we have an fd, this stat should succeed. */ - if (ret == -1) { - DEBUG(0, ("Error doing fstat on open file %s " - "(%s)\n", - smb_fname_str_dbg(smb_fname), - strerror(errno) )); - } - } - - /* For a non-io open, this stat failing means file not found. JRA */ - if (ret == -1) { - status = map_nt_error_from_unix(errno); - fd_close(fsp); - return status; - } - } - - /* - * POSIX allows read-only opens of directories. We don't - * want to do this (we use a different code path for this) - * so catch a directory open and return an EISDIR. JRA. - */ - - if(S_ISDIR(smb_fname->st.st_ex_mode)) { - fd_close(fsp); - errno = EISDIR; - return NT_STATUS_FILE_IS_A_DIRECTORY; - } - - fsp->mode = smb_fname->st.st_ex_mode; - fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st); - fsp->vuid = req ? req->vuid : UID_FIELD_INVALID; - fsp->file_pid = req ? req->smbpid : 0; - fsp->can_lock = True; - fsp->can_read = (access_mask & (FILE_READ_DATA)) ? True : False; - if (!CAN_WRITE(conn)) { - fsp->can_write = False; - } else { - fsp->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? - True : False; - } - fsp->print_file = NULL; - fsp->modified = False; - fsp->sent_oplock_break = NO_BREAK_SENT; - fsp->is_directory = False; - if (conn->aio_write_behind_list && - is_in_path(smb_fname->base_name, conn->aio_write_behind_list, - conn->case_sensitive)) { - fsp->aio_write_behind = True; - } - - fsp->wcp = NULL; /* Write cache pointer. */ - - DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n", - conn->session_info->unix_info->unix_name, - smb_fname_str_dbg(smb_fname), - BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write), - conn->num_files_open)); - - errno = 0; - return NT_STATUS_OK; -} - -/**************************************************************************** - Handle the 1 second delay in returning a SHARING_VIOLATION error. -****************************************************************************/ - -static void defer_open(struct share_mode_lock *lck, - struct timeval request_time, - struct timeval timeout, - struct smb_request *req, - struct deferred_open_record *state) -{ - int i; - - /* Paranoia check */ - - for (i=0; i<lck->num_share_modes; i++) { - struct share_mode_entry *e = &lck->share_modes[i]; - - if (!is_deferred_open_entry(e)) { - continue; - } - - if (procid_is_me(&e->pid) && (e->op_mid == req->mid)) { - DEBUG(0, ("Trying to defer an already deferred " - "request: mid=%llu, exiting\n", - (unsigned long long)req->mid)); - exit_server("attempt to defer a deferred request"); - } - } - - /* End paranoia check */ - - DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred " - "open entry for mid %llu\n", - (unsigned int)request_time.tv_sec, - (unsigned int)request_time.tv_usec, - (unsigned long long)req->mid)); - - if (!push_deferred_open_message_smb(req, request_time, timeout, - state->id, (char *)state, sizeof(*state))) { - exit_server("push_deferred_open_message_smb failed"); - } - add_deferred_open(lck, req->mid, request_time, state->id); -} - -static void schedule_defer_open(struct share_mode_lock *lck, - struct timeval request_time, - struct smb_request *req) -{ - struct deferred_open_record state; - - /* This is a relative time, added to the absolute - request_time value to get the absolute timeout time. - Note that if this is the second or greater time we enter - this codepath for this particular request mid then - request_time is left as the absolute time of the *first* - time this request mid was processed. This is what allows - the request to eventually time out. */ - - struct timeval timeout; - - /* Normally the smbd we asked should respond within - * OPLOCK_BREAK_TIMEOUT seconds regardless of whether - * the client did, give twice the timeout as a safety - * measure here in case the other smbd is stuck - * somewhere else. */ - - /* - * On OneFS, the kernel will always send an oplock_revoked message - * before this timeout is hit. - */ - timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*10, 0); - - /* Nothing actually uses state.delayed_for_oplocks - but it's handy to differentiate in debug messages - between a 30 second delay due to oplock break, and - a 1 second delay for share mode conflicts. */ - - state.delayed_for_oplocks = True; - state.failed = false; - state.id = lck->id; - - if (!request_timed_out(request_time, timeout)) { - defer_open(lck, request_time, timeout, req, &state); - } else { - /* A delayed-for-oplocks deferred open timing out should only - * happen if there is a bug or extreme load, since we set the - * timeout to 300 seconds. */ - DEBUG(0, ("Deferred open timeout! request_time=%d.%d, " - "mid=%d\n", request_time.tv_sec, request_time.tv_usec, - req->mid)); - } -} - -/**************************************************************************** - Open a file with a share mode. Passed in an already created files_struct. -****************************************************************************/ -NTSTATUS onefs_open_file_ntcreate(connection_struct *conn, - struct smb_request *req, - struct smb_filename *smb_fname, - uint32 access_mask, - uint32 share_access, - uint32 create_disposition, - uint32 create_options, - uint32 new_dos_attributes, - int oplock_request, - uint32_t private_flags, - struct security_descriptor *sd, - files_struct *fsp, - int *pinfo, - struct onefs_fsp_data *fsp_data) -{ - int flags=0; - int flags2=0; - bool file_existed = VALID_STAT(smb_fname->st); - 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; - int info; - uint32 existing_dos_attributes = 0; - struct timeval request_time = timeval_zero(); - struct share_mode_lock *lck = NULL; - uint32 open_access_mask = access_mask; - NTSTATUS status; - int ret_flock; - char *parent_dir; - int granted_oplock; - uint64_t oplock_callback_id = 0; - uint32 createfile_attributes = 0; - - ZERO_STRUCT(id); - - if (conn->printer) { - /* - * Printers are handled completely differently. - * Most of the passed parameters are ignored. - */ - - if (pinfo) { - *pinfo = FILE_WAS_CREATED; - } - - DEBUG(10, ("onefs_open_file_ntcreate: printer open fname=%s\n", - smb_fname_str_dbg(smb_fname))); - - return print_spool_open(fsp, smb_fname->base_name, - req->vuid); - } - - if (!parent_dirname(talloc_tos(), smb_fname->base_name, &parent_dir, - NULL)) { - return NT_STATUS_NO_MEMORY; - } - - if (new_dos_attributes & FILE_FLAG_POSIX_SEMANTICS) { - posix_open = True; - unx_mode = (mode_t)(new_dos_attributes & ~FILE_FLAG_POSIX_SEMANTICS); - new_dos_attributes = 0; - } else { - /* We add FILE_ATTRIBUTE_ARCHIVE to this as this mode is only used if the file is - * created new. */ - unx_mode = unix_mode(conn, new_dos_attributes | FILE_ATTRIBUTE_ARCHIVE, - smb_fname, parent_dir); - } - - DEBUG(10,("onefs_open_file_ntcreate: fname=%s, dos_attrs=0x%x " - "access_mask=0x%x share_access=0x%x " - "create_disposition = 0x%x create_options=0x%x " - "unix mode=0%o oplock_request=0x%x\n", - smb_fname_str_dbg(smb_fname), new_dos_attributes, - access_mask, share_access, create_disposition, - create_options, unx_mode, oplock_request)); - - /* - * Any non-stat-only open has the potential to contend oplocks, which - * means to avoid blocking in the kernel (which is unacceptable), the - * open must be deferred. In order to defer opens, req must not be - * NULL. The known cases of calling with a NULL req: - * - * 1. Open the base file of a stream: Always done stat-only - * - * 2. open_file_fchmod(), which is called from 3 places: - * A. try_chown: Posix acls only. Never called on onefs. - * B. set_ea_dos_attributes: Can't be called from onefs, because - * SMB_VFS_SETXATTR return ENOSYS. - * C. file_set_dos_mode: This would only happen if the "dos - * filemode" smb.conf parameter is set to yes. We ship with - * it off, but if a customer were to turn it on it would be - * bad. - */ - if (req == NULL && !is_stat_open(access_mask) && - !is_ntfs_stream_smb_fname(smb_fname)) { - smb_panic("NULL req on a non-stat-open!"); - } - - if ((req == NULL) && ((oplock_request & INTERNAL_OPEN_ONLY) == 0)) { - DEBUG(0, ("No smb request but not an internal only open!\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - /* - * Only non-internal opens can be deferred at all - */ - - if (req) { - void *ptr; - if (get_deferred_open_message_state(req, - &request_time, - &ptr)) { - struct deferred_open_record *state = (struct deferred_open_record *)ptr; - - /* Remember the absolute time of the original - request with this mid. We'll use it later to - see if this has timed out. */ - - /* Remove the deferred open entry under lock. */ - remove_deferred_open_entry(state->id, req->mid); - - /* Ensure we don't reprocess this message. */ - remove_deferred_open_message_smb(req->mid); - - /* - * When receiving a semlock_async_failure message, the - * deferred open will be marked as "failed". Returning - * INTERNAL_ERROR. - */ - if (state->failed) { - DEBUG(0, ("onefs_open_file_ntcreate: " - "semlock_async_failure detected!\n")); - return NT_STATUS_INTERNAL_ERROR; - } - } - } - - status = check_name(conn, smb_fname->base_name); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (!posix_open) { - new_dos_attributes &= SAMBA_ATTRIBUTES_MASK; - if (file_existed) { - existing_dos_attributes = dos_mode(conn, smb_fname); - } - } - - /* Setup dos_attributes to be set by ifs_createfile */ - if (lp_store_dos_attributes(SNUM(conn))) { - createfile_attributes = (new_dos_attributes | FILE_ATTRIBUTE_ARCHIVE) & - ~(FILE_ATTRIBUTE_NONINDEXED | FILE_ATTRIBUTE_COMPRESSED); - } - - /* Ignore oplock requests if oplocks are disabled. */ - if (!lp_oplocks(SNUM(conn)) || - IS_VETO_OPLOCK_PATH(conn, smb_fname->base_name)) { - /* Mask off everything except the private Samba bits. */ - oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK; - } - - /* this is for OS/2 long file names - say we don't support them */ - if (!lp_posix_pathnames() && strstr(smb_fname->base_name,".+,;=[].")) { - /* OS/2 Workplace shell fix may be main code stream in a later - * release. */ - DEBUG(5,("onefs_open_file_ntcreate: OS/2 long filenames are " - "not supported.\n")); - if (use_nt_status()) { - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - return NT_STATUS_DOS(ERRDOS, ERRcannotopen); - } - - switch( create_disposition ) { - /* - * Currently we're using FILE_SUPERSEDE as the same as - * FILE_OVERWRITE_IF but they really are - * different. FILE_SUPERSEDE deletes an existing file - * (requiring delete access) then recreates it. - */ - case FILE_SUPERSEDE: - /** - * @todo: Clear all file attributes? - * http://www.osronline.com/article.cfm?article=302 - * create if not exist, trunc if exist - * - * If file exists replace/overwrite. If file doesn't - * 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: - /* If file exists open. If file doesn't exist error. */ - if (!file_existed) { - DEBUG(5,("onefs_open_file_ntcreate: FILE_OPEN " - "requested for file %s and file " - "doesn't exist.\n", - smb_fname_str_dbg(smb_fname))); - errno = ENOENT; - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - break; - - case FILE_OVERWRITE: - /* If file exists overwrite. If file doesn't exist - * error. */ - if (!file_existed) { - DEBUG(5, ("onefs_open_file_ntcreate: " - "FILE_OVERWRITE requested for file " - "%s and file doesn't exist.\n", - smb_fname_str_dbg(smb_fname))); - errno = ENOENT; - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } - flags2 |= O_TRUNC; - clear_ads = true; - break; - - case FILE_CREATE: - /* If file exists error. If file doesn't exist - * create. */ - if (file_existed) { - DEBUG(5, ("onefs_open_file_ntcreate: " - "FILE_CREATE requested for file %s " - "and file already exists.\n", - smb_fname_str_dbg(smb_fname))); - if (S_ISDIR(smb_fname->st.st_ex_mode)) { - errno = EISDIR; - } else { - errno = EEXIST; - } - return map_nt_error_from_unix(errno); - } - flags2 |= (O_CREAT|O_EXCL); - break; - - case FILE_OPEN_IF: - /* If file exists open. If file doesn't exist - * create. */ - flags2 |= O_CREAT; - break; - - default: - return NT_STATUS_INVALID_PARAMETER; - } - - /* Match attributes on file exists and overwrite. */ - if (!posix_open && file_existed && - ((create_disposition == FILE_OVERWRITE) || - (create_disposition == FILE_OVERWRITE_IF))) { - if (!open_match_attributes(conn, existing_dos_attributes, - new_dos_attributes, - smb_fname->st.st_ex_mode, - unx_mode, &new_unx_mode)) { - DEBUG(5, ("onefs_open_file_ntcreate: attributes " - "missmatch for file %s (%x %x) (0%o, 0%o)\n", - smb_fname_str_dbg(smb_fname), - existing_dos_attributes, - new_dos_attributes, - (unsigned int)smb_fname->st.st_ex_mode, - (unsigned int)unx_mode )); - errno = EACCES; - return NT_STATUS_ACCESS_DENIED; - } - } - - /* - * OneFS understands MAXIMUM_ALLOWED_ACCESS, so only hack the - * access_mask, but leave the MAA for the actual open in - * open_access_mask. - */ - open_access_mask = access_mask; - if (open_access_mask & MAXIMUM_ALLOWED_ACCESS) { - access_mask |= FILE_GENERIC_ALL; - } - - /* Convert GENERIC bits to specific bits. */ - se_map_generic(&access_mask, &file_generic_mapping); - se_map_generic(&open_access_mask, &file_generic_mapping); - - if ((flags2 & O_TRUNC) || (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) { - /* This will cause oplock breaks. */ - open_access_mask |= FILE_WRITE_DATA; - } - - DEBUG(10, ("onefs_open_file_ntcreate: fname=%s, after mapping " - "open_access_mask=%#x, access_mask=0x%x\n", - smb_fname_str_dbg(smb_fname), open_access_mask, - access_mask)); - - /* - * Note that we ignore the append flag as append does not - * mean the same thing under DOS and Unix. - */ - - if ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) || - (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) { - - /* - * DENY_DOS opens are always underlying read-write on the - * file handle, no matter what the requested access mask - * says. Stock samba just sets the flags, but since - * ifs_createfile uses the access_mask, it must be updated as - * well. This allows BASE-DENY* to pass. - */ - if (create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS) { - - DEBUG(10,("onefs_open_file_ntcreate: deny_dos: " - "Adding O_RDWR to flags " - "(0x%x) and some READ bits to " - "open_access_mask (0x%x)\n", - flags, open_access_mask)); - - flags = O_RDWR; - open_access_mask |= (FILE_READ_ATTRIBUTES | - FILE_READ_DATA | FILE_READ_EA | FILE_EXECUTE); - - } else if (access_mask & (FILE_READ_ATTRIBUTES | - FILE_READ_DATA | - FILE_READ_EA | - FILE_EXECUTE)) { - flags = O_RDWR; - } else { - flags = O_WRONLY; - } - } else { - flags = O_RDONLY; - } - - /* Currently we only look at FILE_WRITE_THROUGH for create options. */ -#if defined(O_SYNC) - if ((create_options & FILE_WRITE_THROUGH) && - lp_strict_sync(SNUM(conn))) { - flags2 |= O_SYNC; - } -#endif /* O_SYNC */ - - if (posix_open && (access_mask & FILE_APPEND_DATA)) { - flags2 |= O_APPEND; - } - - if (!posix_open && !CAN_WRITE(conn)) { - /* - * We should really return a permission denied error if either - * O_CREAT or O_TRUNC are set, but for compatibility with - * older versions of Samba we just AND them out. - */ - flags2 &= ~(O_CREAT|O_TRUNC); - - /* Deny DELETE_ACCESS explicitly if the share is read only. */ - if (access_mask & DELETE_ACCESS) { - return map_nt_error_from_unix(EACCES); - } - } - - /* Ensure we can't write on a read-only share or file. */ - if (flags != O_RDONLY && file_existed && - (!CAN_WRITE(conn) || IS_DOS_READONLY(existing_dos_attributes))) { - DEBUG(5, ("onefs_open_file_ntcreate: write access requested " - "for file %s on read only %s\n", - smb_fname_str_dbg(smb_fname), - !CAN_WRITE(conn) ? "share" : "file" )); - errno = EACCES; - return NT_STATUS_ACCESS_DENIED; - } - - DEBUG(10, ("fsp = %p\n", fsp)); - - fsp->share_access = share_access; - fsp->fh->private_options = private_flags; - fsp->access_mask = open_access_mask; /* We change this to the - * requested access_mask after - * the open is done. */ - fsp->posix_open = posix_open; - - /* Ensure no SAMBA_PRIVATE bits can be set. */ - fsp->oplock_type = (oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK); - - if (timeval_is_zero(&request_time)) { - request_time = fsp->open_time; - } - - if (file_existed) { - struct timespec old_write_time = smb_fname->st.st_ex_mtime; - id = vfs_file_id_from_sbuf(conn, &smb_fname->st); - - lck = get_share_mode_lock(talloc_tos(), id, - conn->connectpath, - smb_fname, &old_write_time); - - if (lck == NULL) { - DEBUG(0, ("Could not get share mode lock\n")); - return NT_STATUS_SHARING_VIOLATION; - } - - if (lck->delete_on_close) { - /* DELETE_PENDING is not deferred for a second */ - TALLOC_FREE(lck); - return NT_STATUS_DELETE_PENDING; - } - } - - SMB_ASSERT(!file_existed || (lck != NULL)); - - /* - * Ensure we pay attention to default ACLs on directories. May be - * neccessary depending on ACL policies. - */ - if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) && - (def_acl = directory_has_default_acl(conn, parent_dir))) { - unx_mode = 0777; - } - - DEBUG(4,("calling onefs_open_file with flags=0x%X flags2=0x%X " - "mode=0%o, access_mask = 0x%x, open_access_mask = 0x%x\n", - (unsigned int)flags, (unsigned int)flags2, - (unsigned int)unx_mode, (unsigned int)access_mask, - (unsigned int)open_access_mask)); - - /* - * Since the open is guaranteed to be stat only if req == NULL, a - * callback record is only needed if req != NULL. - */ - if (req) { - SMB_ASSERT(fsp_data); - oplock_callback_id = onefs_oplock_wait_record(req->sconn, - req->mid); - if (oplock_callback_id == 0) { - return NT_STATUS_NO_MEMORY; - } - } else { - /* - * It is also already asserted it's either a stream or a - * stat-only open at this point. - */ - SMB_ASSERT(fsp->oplock_type == NO_OPLOCK); - - /* The kernel and Samba's version of stat-only differs - * slightly: The kernel doesn't think its stat-only if we're - * truncating. We'd better have a req in order to defer the - * open. */ - SMB_ASSERT(!((flags|flags2) & O_TRUNC)); - } - - /* Do the open. */ - status = onefs_open_file(fsp, - conn, - req, - parent_dir, - smb_fname, - flags|flags2, - unx_mode, - access_mask, - open_access_mask, - fsp->oplock_type, - oplock_callback_id, - share_access, - create_options, - createfile_attributes, - sd, - &granted_oplock); - - if (!NT_STATUS_IS_OK(status)) { - - /* OneFS Oplock Handling */ - if (errno == EINPROGRESS) { - - /* If we get EINPROGRESS, the kernel will send us an - * asynchronous semlock event back. Ensure we can defer - * the open, by asserting req. */ - SMB_ASSERT(req); - - if (lck == NULL) { - /* - * We hit the race that when we did the stat - * on the file it did not exist, and someone - * has created it in between the stat and the - * open_file() call. Defer our open waiting, - * to break the oplock of the first opener. - */ - - struct timespec old_write_time; - - DEBUG(3, ("Someone created file %s with an " - "oplock after we looked: Retrying\n", - smb_fname_str_dbg(smb_fname))); - /* - * We hit the race that when we did the stat - * on the file it did not exist, and someone - * has created it in between the stat and the - * open_file() call. Just retry immediately. - */ - id = vfs_file_id_from_sbuf(conn, - &smb_fname->st); - if (!(lck = get_share_mode_lock(talloc_tos(), - id, conn->connectpath, smb_fname, - &old_write_time))) { - /* - * Emergency exit - */ - DEBUG(0, ("onefs_open_file_ntcreate: " - "Could not get share mode " - "lock for %s\n", - smb_fname_str_dbg(smb_fname))); - status = NT_STATUS_SHARING_VIOLATION; - - /* XXXZLK: This will cause us to get a - * semlock event when we aren't - * expecting one. */ - goto cleanup_destroy; - } - - schedule_defer_open(lck, request_time, req); - goto cleanup; - } - /* Waiting for an oplock */ - DEBUG(5,("Async createfile because a client has an " - "oplock on %s\n", - smb_fname_str_dbg(smb_fname))); - - SMB_ASSERT(req); - schedule_defer_open(lck, request_time, req); - goto cleanup; - } - - /* Check for a sharing violation */ - if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { - uint32 can_access_mask; - bool can_access = True; - - /* If we raced on open we may not have a valid file_id - * or stat buf. Get them again. */ - if (SMB_VFS_STAT(conn, fname, psbuf) == -1) { - DEBUG(0,("Error doing stat on file %s " - "(%s)\n", fname, strerror(errno))); - status = NT_STATUS_SHARING_VIOLATION; - goto cleanup_destroy; - } - id = vfs_file_id_from_sbuf(conn, psbuf); - - /* Check if this can be done with the deny_dos and fcb - * calls. */ - - /* Try to find dup fsp if possible. */ - if (private_flags & - (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS| - NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) { - - if (req == NULL) { - DEBUG(0, ("DOS open without an SMB " - "request!\n")); - status = NT_STATUS_INTERNAL_ERROR; - goto cleanup_destroy; - } - - /* Use the client requested access mask here, - * not the one we open with. */ - status = fcb_or_dos_open(req, - conn, - fsp, - smb_fname, - id, - req->smbpid, - req->vuid, - access_mask, - share_access, - create_options); - - if (NT_STATUS_IS_OK(status)) { - if (pinfo) { - *pinfo = FILE_WAS_OPENED; - } - status = NT_STATUS_OK; - goto cleanup; - } - } - - /* - * This next line is a subtlety we need for - * MS-Access. If a file open will fail due to share - * permissions and also for security (access) reasons, - * we need to return the access failed error, not the - * share error. We can't open the file due to kernel - * oplock deadlock (it's possible we failed above on - * the open_mode_check()) so use a userspace check. - */ - - if (flags & O_RDWR) { - can_access_mask = FILE_READ_DATA|FILE_WRITE_DATA; - } else if (flags & O_WRONLY) { - can_access_mask = FILE_WRITE_DATA; - } else { - can_access_mask = FILE_READ_DATA; - } - - if (((can_access_mask & FILE_WRITE_DATA) && - !CAN_WRITE(conn)) || - !NT_STATUS_IS_OK(smbd_check_access_rights(conn, - smb_fname, can_access_mask))) { - can_access = False; - } - - /* - * If we're returning a share violation, ensure we - * cope with the braindead 1 second delay. - */ - if (!(oplock_request & INTERNAL_OPEN_ONLY) && - lp_defer_sharing_violations()) { - struct timeval timeout; - struct deferred_open_record state; - int timeout_usecs; - - /* this is a hack to speed up torture tests - in 'make test' */ - timeout_usecs = lp_parm_int(SNUM(conn), - "smbd","sharedelay", - SHARING_VIOLATION_USEC_WAIT); - - /* This is a relative time, added to the - absolute request_time value to get the - absolute timeout time. Note that if this - is the second or greater time we enter this - codepath for this particular request mid - then request_time is left as the absolute - time of the *first* time this request mid - was processed. This is what allows the - request to eventually time out. */ - - timeout = timeval_set(0, timeout_usecs); - - /* Nothing actually uses - state.delayed_for_oplocks but it's handy to - differentiate in debug messages between a - 30 second delay due to oplock break, and a - 1 second delay for share mode conflicts. */ - - state.delayed_for_oplocks = False; - state.id = id; - state.failed = false; - - /* - * We hit the race that when we did the stat - * on the file it did not exist, and someone - * has created it in between the stat and the - * open_file() call. Retrieve the share_mode - * lock on the newly opened file so we can - * defer our request. - */ - if (lck == NULL) { - struct timespec old_write_time; - old_write_time = get_mtimespec(psbuf); - - lck = get_share_mode_lock(talloc_tos(), - id, conn->connectpath, fname, - &old_write_time); - if (lck == NULL) { - DEBUG(0, - ("onefs_open_file_ntcreate:" - " Could not get share " - "mode lock for %s\n", - fname)); - /* This will cause us to return - * immediately skipping the - * the 1 second delay, which - * isn't a big deal */ - status = NT_STATUS_SHARING_VIOLATION; - goto cleanup_destroy; - } - } - - if ((req != NULL) && - !request_timed_out(request_time, timeout)) - { - defer_open(lck, request_time, timeout, - req, &state); - } - } - - if (can_access) { - /* - * We have detected a sharing violation here - * so return the correct error code - */ - status = NT_STATUS_SHARING_VIOLATION; - } else { - status = NT_STATUS_ACCESS_DENIED; - } - - goto cleanup_destroy; - } - - /* - * Normal error, for example EACCES - */ - cleanup_destroy: - if (oplock_callback_id != 0) { - destroy_onefs_callback_record(oplock_callback_id); - } - cleanup: - TALLOC_FREE(lck); - return status; - } - - fsp->oplock_type = granted_oplock; - - if (oplock_callback_id != 0) { - onefs_set_oplock_callback(oplock_callback_id, fsp); - fsp_data->oplock_callback_id = oplock_callback_id; - } else { - SMB_ASSERT(fsp->oplock_type == NO_OPLOCK); - } - - if (!file_existed) { - struct timespec old_write_time = smb_fname->st.st_ex_mtime; - /* - * Deal with the race condition where two smbd's detect the - * file doesn't exist and do the create at the same time. One - * of them will win and set a share mode, the other (ie. this - * one) should check if the requested share mode for this - * create is allowed. - */ - - /* - * Now the file exists and fsp is successfully opened, - * fsp->file_id is valid and should replace the - * dev=0, inode=0 from a non existent file. Spotted by - * Nadav Danieli <nadavd@exanet.com>. JRA. - */ - - id = fsp->file_id; - - lck = get_share_mode_lock(talloc_tos(), id, - conn->connectpath, - smb_fname, &old_write_time); - - if (lck == NULL) { - DEBUG(0, ("onefs_open_file_ntcreate: Could not get " - "share mode lock for %s\n", - smb_fname_str_dbg(smb_fname))); - fd_close(fsp); - return NT_STATUS_SHARING_VIOLATION; - } - - if (lck->delete_on_close) { - status = NT_STATUS_DELETE_PENDING; - } - - if (!NT_STATUS_IS_OK(status)) { - struct deferred_open_record state; - - fd_close(fsp); - - state.delayed_for_oplocks = False; - state.id = id; - - /* Do it all over again immediately. In the second - * round we will find that the file existed and handle - * the DELETE_PENDING and FCB cases correctly. No need - * to duplicate the code here. Essentially this is a - * "goto top of this function", but don't tell - * anybody... */ - - if (req != NULL) { - defer_open(lck, request_time, timeval_zero(), - req, &state); - } - TALLOC_FREE(lck); - return status; - } - - /* - * We exit this block with the share entry *locked*..... - */ - - } - - SMB_ASSERT(lck != NULL); - - /* Delete streams if create_disposition requires it */ - if (file_existed && clear_ads && - !is_ntfs_stream_smb_fname(smb_fname)) { - status = delete_all_streams(conn, smb_fname->base_name); - 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 - mode and we have already checked our more authoritative - locking database for permission to set this deny mode. If - the kernel refuses the operations then the kernel is wrong. - note that GPFS supports it as well - jmcd */ - - if (fsp->fh->fd != -1) { - ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, share_access, access_mask); - if(ret_flock == -1 ){ - - TALLOC_FREE(lck); - fd_close(fsp); - return NT_STATUS_SHARING_VIOLATION; - } - } - - /* - * At this point onwards, we can guarentee that the share entry - * is locked, whether we created the file or not, and that the - * deny mode is compatible with all current opens. - */ - - /* - * According to Samba4, SEC_FILE_READ_ATTRIBUTE is always granted, - */ - fsp->access_mask = access_mask | FILE_READ_ATTRIBUTES; - - if (file_existed) { - /* stat opens on existing files don't get oplocks. */ - if (is_stat_open(open_access_mask)) { - fsp->oplock_type = NO_OPLOCK; - } - - if (!(flags2 & O_TRUNC)) { - info = FILE_WAS_OPENED; - } else { - info = FILE_WAS_OVERWRITTEN; - } - } else { - info = FILE_WAS_CREATED; - } - - if (pinfo) { - *pinfo = info; - } - - /* - * Setup the oplock info in both the shared memory and - * file structs. - */ - - if ((fsp->oplock_type != NO_OPLOCK) && - (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) { - if (!set_file_oplock(fsp, fsp->oplock_type)) { - /* Could not get the kernel oplock */ - fsp->oplock_type = NO_OPLOCK; - } - } - - if (fsp->oplock_type == LEVEL_II_OPLOCK && - (!lp_level2_oplocks(SNUM(conn)) || - !(global_client_caps & CAP_LEVEL_II_OPLOCKS))) { - - DEBUG(5, ("Downgrading level2 oplock on open " - "because level2 oplocks = off\n")); - - release_file_oplock(fsp); - } - - if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || - info == FILE_WAS_SUPERSEDED) { - new_file_created = True; - } - - set_share_mode(lck, fsp, get_current_uid(conn), - req ? req->mid : 0, - fsp->oplock_type); - - /* Handle strange delete on close create semantics. */ - if (create_options & FILE_DELETE_ON_CLOSE) { - status = can_set_delete_on_close(fsp, new_dos_attributes); - - if (!NT_STATUS_IS_OK(status)) { - /* Remember to delete the mode we just added. */ - del_share_mode(lck, fsp); - TALLOC_FREE(lck); - fd_close(fsp); - return status; - } - /* Note that here we set the *inital* delete on close flag, - not the regular one. The magic gets handled in close. */ - fsp->initial_delete_on_close = True; - } - - /* - * Take care of inherited ACLs on created files - if default ACL not - * selected. - * May be necessary depending on acl policies. - */ - if (!posix_open && !file_existed && !def_acl && - !(VALID_STAT(smb_fname->st) && - (smb_fname->st.st_ex_flags & SF_HASNTFSACL))) { - - int saved_errno = errno; /* We might get ENOSYS in the next - * call.. */ - - if (SMB_VFS_FCHMOD_ACL(fsp, unx_mode) == -1 && - errno == ENOSYS) { - errno = saved_errno; /* Ignore ENOSYS */ - } - - } else if (new_unx_mode) { - - int ret = -1; - - /* Attributes need changing. File already existed. */ - - { - int saved_errno = errno; /* We might get ENOSYS in the - * next call.. */ - ret = SMB_VFS_FCHMOD_ACL(fsp, new_unx_mode); - - if (ret == -1 && errno == ENOSYS) { - errno = saved_errno; /* Ignore ENOSYS */ - } else { - DEBUG(5, ("onefs_open_file_ntcreate: reset " - "attributes of file %s to 0%o\n", - smb_fname_str_dbg(smb_fname), - (unsigned int)new_unx_mode)); - ret = 0; /* Don't do the fchmod below. */ - } - } - - if ((ret == -1) && - (SMB_VFS_FCHMOD(fsp, new_unx_mode) == -1)) - DEBUG(5, ("onefs_open_file_ntcreate: failed to reset " - "attributes of file %s to 0%o\n", - smb_fname_str_dbg(smb_fname), - (unsigned int)new_unx_mode)); - } - - /* If this is a successful open, we must remove any deferred open - * records. */ - if (req != NULL) { - del_deferred_open_entry(lck, req->mid); - } - TALLOC_FREE(lck); - - return NT_STATUS_OK; -} - - -/**************************************************************************** - Open a directory from an NT SMB call. -****************************************************************************/ -static NTSTATUS onefs_open_directory(connection_struct *conn, - struct smb_request *req, - struct smb_filename *smb_dname, - uint32 access_mask, - uint32 share_access, - uint32 create_disposition, - uint32 create_options, - uint32 file_attributes, - struct security_descriptor *sd, - files_struct **result, - int *pinfo) -{ - files_struct *fsp = NULL; - struct share_mode_lock *lck = NULL; - NTSTATUS status; - struct timespec mtimespec; - int info = 0; - char *parent_dir; - bool posix_open = false; - uint32 create_flags = 0; - uint32 mode = lp_dir_mask(SNUM(conn)); - - DEBUG(5, ("onefs_open_directory: opening directory %s, " - "access_mask = 0x%x, " - "share_access = 0x%x create_options = 0x%x, " - "create_disposition = 0x%x, file_attributes = 0x%x\n", - smb_fname_str_dbg(smb_dname), (unsigned int)access_mask, - (unsigned int)share_access, (unsigned int)create_options, - (unsigned int)create_disposition, - (unsigned int)file_attributes)); - - if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS) && - (conn->fs_capabilities & FILE_NAMED_STREAMS) && - is_ntfs_stream_smb_fname(smb_dname)) { - DEBUG(2, ("onefs_open_directory: %s is a stream name!\n", - smb_fname_str_dbg(smb_dname))); - return NT_STATUS_NOT_A_DIRECTORY; - } - - switch (create_disposition) { - case FILE_OPEN: - /* If directory exists open. If directory doesn't - * exist error. */ - create_flags = 0; - info = FILE_WAS_OPENED; - break; - case FILE_CREATE: - /* If directory exists error. If directory doesn't - * exist create. */ - create_flags = O_CREAT | O_EXCL; - info = FILE_WAS_CREATED; - break; - case FILE_OPEN_IF: - /* If directory exists open. If directory doesn't - * exist create. */ - - /* Note: in order to return whether the directory was - * opened or created, we first try to open and then try - * to create. */ - create_flags = 0; - info = FILE_WAS_OPENED; - break; - case FILE_SUPERSEDE: - case FILE_OVERWRITE: - case FILE_OVERWRITE_IF: - default: - DEBUG(5, ("onefs_open_directory: invalid " - "create_disposition 0x%x for directory %s\n", - (unsigned int)create_disposition, - smb_fname_str_dbg(smb_dname))); - return NT_STATUS_INVALID_PARAMETER; - } - - /* - * Check for write access to the share. Done in mkdir_internal() in - * mainline samba. - */ - if (!CAN_WRITE(conn) && (create_flags & O_CREAT)) { - return NT_STATUS_ACCESS_DENIED; - } - - /* Get parent dirname */ - if (!parent_dirname(talloc_tos(), smb_dname->base_name, &parent_dir, - NULL)) { - return NT_STATUS_NO_MEMORY; - } - - if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { - posix_open = true; - mode = (mode_t)(file_attributes & ~FILE_FLAG_POSIX_SEMANTICS); - file_attributes = 0; - } else { - mode = unix_mode(conn, FILE_ATTRIBUTE_DIRECTORY, smb_dname, parent_dir); - } - - /* - * The NONINDEXED and COMPRESSED bits seem to always be cleared on - * directories, no matter if you specify that they should be set. - */ - file_attributes &= - ~(FILE_ATTRIBUTE_NONINDEXED | FILE_ATTRIBUTE_COMPRESSED); - - status = file_new(req, conn, &fsp); - if(!NT_STATUS_IS_OK(status)) { - return status; - } - - /* - * Actual open with retry magic to handle FILE_OPEN_IF which is - * unique because the kernel won't tell us if the file was opened or - * created. - */ - retry_open: - fsp->fh->fd = onefs_sys_create_file(conn, - -1, - smb_dname->base_name, - access_mask, - access_mask, - share_access, - create_options, - create_flags | O_DIRECTORY, - mode, - 0, - 0, - sd, - file_attributes, - NULL); - - if (fsp->fh->fd == -1) { - DEBUG(3, ("Error opening %s. Errno=%d (%s).\n", - smb_fname_str_dbg(smb_dname), errno, - strerror(errno))); - SMB_ASSERT(errno != EINPROGRESS); - - if (create_disposition == FILE_OPEN_IF) { - if (errno == ENOENT) { - /* Try again, creating it this time. */ - create_flags = O_CREAT | O_EXCL; - info = FILE_WAS_CREATED; - goto retry_open; - } else if (errno == EEXIST) { - /* Uggh. Try again again. */ - create_flags = 0; - info = FILE_WAS_OPENED; - goto retry_open; - } - } - - /* Error cases below: */ - file_free(req, fsp); - - if ((errno == ENOENT) && (create_disposition == FILE_OPEN)) { - DEBUG(5, ("onefs_open_directory: FILE_OPEN requested " - "for directory %s and it doesn't " - "exist.\n", smb_fname_str_dbg(smb_dname))); - return NT_STATUS_OBJECT_NAME_NOT_FOUND; - } else if ((errno == EEXIST) && - (create_disposition == FILE_CREATE)) { - DEBUG(5, ("onefs_open_directory: FILE_CREATE " - "requested for directory %s and it " - "already exists.\n", - smb_fname_str_dbg(smb_dname))); - return NT_STATUS_OBJECT_NAME_COLLISION; - } else if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { - /* Catch sharing violations. */ - return NT_STATUS_SHARING_VIOLATION; - } - - return map_nt_error_from_unix(errno); - } - - if (info == FILE_WAS_CREATED) { - - /* Pulled from mkdir_internal() */ - if (SMB_VFS_LSTAT(conn, smb_dname) == -1) { - DEBUG(2, ("Could not stat directory '%s' just " - "created: %s\n", - smb_fname_str_dbg(smb_dname), - strerror(errno))); - return map_nt_error_from_unix(errno); - } - - if (!S_ISDIR(smb_dname->st.st_ex_mode)) { - DEBUG(0, ("Directory just '%s' created is not a " - "directory\n", - smb_fname_str_dbg(smb_dname))); - return NT_STATUS_ACCESS_DENIED; - } - - if (!posix_open) { - /* - * Check if high bits should have been set, then (if - * bits are missing): add them. Consider bits - * automagically set by UNIX, i.e. SGID bit from - * parent dir. - */ - if (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) && - (mode & ~smb_dname->st.st_ex_mode)) { - SMB_VFS_CHMOD(conn, smb_dname->base_name, - (smb_dname->st.st_ex_mode | - (mode & ~smb_dname->st.st_ex_mode))); - } - } - - /* Change the owner if required. */ - if (lp_inherit_owner(SNUM(conn))) { - change_dir_owner_to_parent(conn, parent_dir, - smb_dname->base_name, - &smb_dname->st); - } - - notify_fname(conn, NOTIFY_ACTION_ADDED, - FILE_NOTIFY_CHANGE_DIR_NAME, - smb_dname->base_name); - } - - /* Stat the fd for Samba bookkeeping. */ - if(SMB_VFS_FSTAT(fsp, &smb_dname->st) != 0) { - fd_close(fsp); - file_free(req, fsp); - return map_nt_error_from_unix(errno); - } - - /* Setup the files_struct for it. */ - fsp->mode = smb_dname->st.st_ex_mode; - fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_dname->st); - fsp->vuid = req ? req->vuid : UID_FIELD_INVALID; - fsp->file_pid = req ? req->smbpid : 0; - fsp->can_lock = False; - fsp->can_read = False; - fsp->can_write = False; - - fsp->share_access = share_access; - fsp->fh->private_options = 0; - /* - * According to Samba4, SEC_FILE_READ_ATTRIBUTE is always granted, - */ - fsp->access_mask = access_mask | FILE_READ_ATTRIBUTES; - fsp->print_file = NULL; - fsp->modified = False; - fsp->oplock_type = NO_OPLOCK; - fsp->sent_oplock_break = NO_BREAK_SENT; - fsp->is_directory = True; - fsp->posix_open = posix_open; - - status = fsp_set_smb_fname(fsp, smb_dname); - if (!NT_STATUS_IS_OK(status)) { - fd_close(fsp); - file_free(req, fsp); - return status; - } - - mtimespec = smb_dname->st.st_ex_mtime; - - /* - * Still set the samba share mode lock for correct delete-on-close - * semantics and to make smbstatus more useful. - */ - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, - conn->connectpath, smb_dname, &mtimespec); - - if (lck == NULL) { - DEBUG(0, ("onefs_open_directory: Could not get share mode " - "lock for %s\n", smb_fname_str_dbg(smb_dname))); - fd_close(fsp); - file_free(req, fsp); - return NT_STATUS_SHARING_VIOLATION; - } - - if (lck->delete_on_close) { - TALLOC_FREE(lck); - fd_close(fsp); - file_free(req, fsp); - return NT_STATUS_DELETE_PENDING; - } - - set_share_mode(lck, fsp, get_current_uid(conn), - req ? req->mid : 0, NO_OPLOCK); - - /* - * For directories the delete on close bit at open time seems - * always to be honored on close... See test 19 in Samba4 BASE-DELETE. - */ - if (create_options & FILE_DELETE_ON_CLOSE) { - status = can_set_delete_on_close(fsp, 0); - if (!NT_STATUS_IS_OK(status) && - !NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) { - TALLOC_FREE(lck); - fd_close(fsp); - file_free(req, fsp); - return status; - } - - if (NT_STATUS_IS_OK(status)) { - /* Note that here we set the *inital* delete on close flag, - not the regular one. The magic gets handled in close. */ - fsp->initial_delete_on_close = True; - } - } - - TALLOC_FREE(lck); - - if (pinfo) { - *pinfo = info; - } - - *result = fsp; - return NT_STATUS_OK; -} - -/* - * Wrapper around onefs_open_file_ntcreate and onefs_open_directory. - */ -static NTSTATUS onefs_create_file_unixpath(connection_struct *conn, - struct smb_request *req, - struct smb_filename *smb_fname, - uint32_t access_mask, - uint32_t share_access, - uint32_t create_disposition, - uint32_t create_options, - uint32_t file_attributes, - uint32_t oplock_request, - uint64_t allocation_size, - uint32_t private_flags, - struct security_descriptor *sd, - struct ea_list *ea_list, - files_struct **result, - int *pinfo, - struct onefs_fsp_data *fsp_data) -{ - int info = FILE_WAS_OPENED; - files_struct *base_fsp = NULL; - files_struct *fsp = NULL; - NTSTATUS status; - - DEBUG(10,("onefs_create_file_unixpath: access_mask = 0x%x " - "file_attributes = 0x%x, share_access = 0x%x, " - "create_disposition = 0x%x create_options = 0x%x " - "oplock_request = 0x%x private_flags = 0x%x " - "ea_list = 0x%p, sd = 0x%p, " - "fname = %s\n", - (unsigned int)access_mask, - (unsigned int)file_attributes, - (unsigned int)share_access, - (unsigned int)create_disposition, - (unsigned int)create_options, - (unsigned int)oplock_request, - (unsigned int)private_flags, - ea_list, sd, smb_fname_str_dbg(smb_fname))); - - if (create_options & FILE_OPEN_BY_FILE_ID) { - status = NT_STATUS_NOT_SUPPORTED; - goto fail; - } - - if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) { - status = NT_STATUS_INVALID_PARAMETER; - goto fail; - } - - if (req == NULL) { - SMB_ASSERT((oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK) == - NO_OPLOCK); - oplock_request |= INTERNAL_OPEN_ONLY; - } - - if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_IGNORE_SACLS, PARM_IGNORE_SACLS_DEFAULT)) { - access_mask &= ~SYSTEM_SECURITY_ACCESS; - } - - if ((conn->fs_capabilities & FILE_NAMED_STREAMS) - && (access_mask & DELETE_ACCESS) - && !is_ntfs_stream_smb_fname(smb_fname)) { - /* - * We can't open a file with DELETE access if any of the - * streams is open without FILE_SHARE_DELETE - */ - status = open_streams_for_delete(conn, smb_fname->base_name); - - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - } - - if ((conn->fs_capabilities & FILE_NAMED_STREAMS) - && is_ntfs_stream_smb_fname(smb_fname)) { - uint32 base_create_disposition; - struct smb_filename *smb_fname_base = NULL; - - if (create_options & FILE_DIRECTORY_FILE) { - status = NT_STATUS_NOT_A_DIRECTORY; - goto fail; - } - - switch (create_disposition) { - case FILE_OPEN: - base_create_disposition = FILE_OPEN; - break; - default: - base_create_disposition = FILE_OPEN_IF; - break; - } - - /* Create an smb_filename with stream_name == NULL. */ - status = create_synthetic_smb_fname(talloc_tos(), - smb_fname->base_name, - NULL, NULL, - &smb_fname_base); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - if (SMB_VFS_STAT(conn, smb_fname_base) == -1) { - DEBUG(10, ("Unable to stat stream: %s\n", - smb_fname_str_dbg(smb_fname_base))); - } - - status = onefs_create_file_unixpath( - conn, /* conn */ - NULL, /* req */ - smb_fname_base, /* fname */ - SYNCHRONIZE_ACCESS, /* access_mask */ - (FILE_SHARE_READ | - FILE_SHARE_WRITE | - FILE_SHARE_DELETE), /* share_access */ - base_create_disposition, /* create_disposition*/ - 0, /* create_options */ - file_attributes, /* file_attributes */ - NO_OPLOCK, /* oplock_request */ - 0, /* allocation_size */ - 0, /* private_flags */ - NULL, /* sd */ - NULL, /* ea_list */ - &base_fsp, /* result */ - NULL, /* pinfo */ - NULL); /* fsp_data */ - - TALLOC_FREE(smb_fname_base); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("onefs_create_file_unixpath for base %s " - "failed: %s\n", smb_fname->base_name, - nt_errstr(status))); - goto fail; - } - - /* - * Testing against windows xp/2003/vista shows that oplocks - * can actually be requested and granted on streams (see the - * RAW-OPLOCK-STREAM1 smbtorture test). - */ - if ((oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK) != - NO_OPLOCK) { - DEBUG(5, ("Oplock(%d) being requested on a stream! " - "Ignoring oplock request: fname=%s\n", - oplock_request & ~SAMBA_PRIVATE_OPLOCK_MASK, - smb_fname_str_dbg(smb_fname))); - /* Request NO_OPLOCK instead. */ - oplock_request &= SAMBA_PRIVATE_OPLOCK_MASK; - } - } - - /* Covert generic bits in the security descriptor. */ - if (sd != NULL) { - security_acl_map_generic(sd->dacl, &file_generic_mapping); - security_acl_map_generic(sd->sacl, &file_generic_mapping); - } - - /* - * If it's a request for a directory open, deal with it separately. - */ - - if (create_options & FILE_DIRECTORY_FILE) { - - if (create_options & FILE_NON_DIRECTORY_FILE) { - status = NT_STATUS_INVALID_PARAMETER; - goto fail; - } - - /* Can't open a temp directory. IFS kit test. */ - if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS) && - (file_attributes & FILE_ATTRIBUTE_TEMPORARY)) { - status = NT_STATUS_INVALID_PARAMETER; - goto fail; - } - - /* - * We will get a create directory here if the Win32 - * app specified a security descriptor in the - * CreateDirectory() call. - */ - - status = onefs_open_directory( - conn, /* conn */ - req, /* req */ - smb_fname, /* fname */ - access_mask, /* access_mask */ - share_access, /* share_access */ - create_disposition, /* create_disposition*/ - create_options, /* create_options */ - file_attributes, /* file_attributes */ - sd, /* sd */ - &fsp, /* result */ - &info); /* pinfo */ - } else { - - /* - * Ordinary file case. - */ - - status = file_new(req, conn, &fsp); - if(!NT_STATUS_IS_OK(status)) { - goto fail; - } - - /* - * We're opening the stream element of a base_fsp - * we already opened. Set up the base_fsp pointer. - */ - if (base_fsp) { - fsp->base_fsp = base_fsp; - } - - status = onefs_open_file_ntcreate( - conn, /* conn */ - req, /* req */ - smb_fname, /* fname */ - access_mask, /* access_mask */ - share_access, /* share_access */ - create_disposition, /* create_disposition*/ - create_options, /* create_options */ - file_attributes, /* file_attributes */ - oplock_request, /* oplock_request */ - sd, /* sd */ - fsp, /* result */ - &info, /* pinfo */ - fsp_data); /* fsp_data */ - - if(!NT_STATUS_IS_OK(status)) { - file_free(req, fsp); - fsp = NULL; - } - - if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { - - /* A stream open never opens a directory */ - - if (base_fsp) { - status = NT_STATUS_FILE_IS_A_DIRECTORY; - goto fail; - } - - /* - * Fail the open if it was explicitly a non-directory - * file. - */ - - if (create_options & FILE_NON_DIRECTORY_FILE) { - status = NT_STATUS_FILE_IS_A_DIRECTORY; - goto fail; - } - - create_options |= FILE_DIRECTORY_FILE; - - status = onefs_open_directory( - conn, /* conn */ - req, /* req */ - smb_fname, /* fname */ - access_mask, /* access_mask */ - share_access, /* share_access */ - create_disposition, /* create_disposition*/ - create_options, /* create_options */ - file_attributes, /* file_attributes */ - sd, /* sd */ - &fsp, /* result */ - &info); /* pinfo */ - } - } - - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - fsp->base_fsp = base_fsp; - - SMB_ASSERT(fsp); - - if ((ea_list != NULL) && (info == FILE_WAS_CREATED)) { - status = set_ea(conn, fsp, smb_fname, ea_list); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - } - - if (!fsp->is_directory && S_ISDIR(smb_fname->st.st_ex_mode)) { - status = NT_STATUS_ACCESS_DENIED; - goto fail; - } - - /* Save the requested allocation size. */ - if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) { - if (allocation_size - && (allocation_size > smb_fname->st.st_ex_size)) { - fsp->initial_allocation_size = smb_roundup( - fsp->conn, allocation_size); - if (fsp->is_directory) { - /* Can't set allocation size on a directory. */ - status = NT_STATUS_ACCESS_DENIED; - goto fail; - } - if (vfs_allocate_file_space( - fsp, fsp->initial_allocation_size) == -1) { - status = NT_STATUS_DISK_FULL; - goto fail; - } - } else { - fsp->initial_allocation_size = smb_roundup( - fsp->conn, (uint64_t)smb_fname->st.st_ex_size); - } - } - - DEBUG(10, ("onefs_create_file_unixpath: info=%d\n", info)); - - *result = fsp; - if (pinfo != NULL) { - *pinfo = info; - } - if ((fsp->fh != NULL) && (fsp->fh->fd != -1)) { - SMB_VFS_FSTAT(fsp, &smb_fname->st); - } - return NT_STATUS_OK; - - fail: - DEBUG(10, ("onefs_create_file_unixpath: %s\n", nt_errstr(status))); - - if (fsp != NULL) { - if (base_fsp && fsp->base_fsp == base_fsp) { - /* - * The close_file below will close - * fsp->base_fsp. - */ - base_fsp = NULL; - } - close_file(req, fsp, ERROR_CLOSE); - fsp = NULL; - } - if (base_fsp != NULL) { - close_file(req, base_fsp, ERROR_CLOSE); - base_fsp = NULL; - } - return status; -} - -static void destroy_onefs_fsp_data(void *p_data) -{ - struct onefs_fsp_data *fsp_data = (struct onefs_fsp_data *)p_data; - - destroy_onefs_callback_record(fsp_data->oplock_callback_id); -} - -/** - * SMB_VFS_CREATE_FILE interface to onefs. - */ -NTSTATUS onefs_create_file(vfs_handle_struct *handle, - struct smb_request *req, - uint16_t root_dir_fid, - struct smb_filename *smb_fname, - uint32_t access_mask, - uint32_t share_access, - uint32_t create_disposition, - uint32_t create_options, - uint32_t file_attributes, - uint32_t oplock_request, - uint64_t allocation_size, - uint32_t private_flags, - struct security_descriptor *sd, - struct ea_list *ea_list, - files_struct **result, - int *pinfo) -{ - connection_struct *conn = handle->conn; - struct onefs_fsp_data fsp_data = {}; - int info = FILE_WAS_OPENED; - files_struct *fsp = NULL; - NTSTATUS status; - - DEBUG(10,("onefs_create_file: access_mask = 0x%x " - "file_attributes = 0x%x, share_access = 0x%x, " - "create_disposition = 0x%x create_options = 0x%x " - "oplock_request = 0x%x private_flags = 0x%x" - "root_dir_fid = 0x%x, ea_list = 0x%p, sd = 0x%p, " - "fname = %s\n", - (unsigned int)access_mask, - (unsigned int)file_attributes, - (unsigned int)share_access, - (unsigned int)create_disposition, - (unsigned int)create_options, - (unsigned int)oplock_request, - (unsigned int)private_flags, - (unsigned int)root_dir_fid, - ea_list, sd, smb_fname_str_dbg(smb_fname))); - - /* Get the file name if root_dir_fid was specified. */ - if (root_dir_fid != 0) { - struct smb_filename *smb_fname_out = NULL; - status = get_relative_fid_filename(conn, req, root_dir_fid, - smb_fname, &smb_fname_out); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - smb_fname = smb_fname_out; - } - - /* All file access must go through check_name() */ - status = check_name(conn, smb_fname->base_name); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - if (is_ntfs_stream_smb_fname(smb_fname)) { - if (!(conn->fs_capabilities & FILE_NAMED_STREAMS)) { - status = NT_STATUS_OBJECT_NAME_NOT_FOUND; - goto fail; - } - - if (is_ntfs_default_stream_smb_fname(smb_fname)) { - int ret; - smb_fname->stream_name = NULL; - /* We have to handle this error here. */ - if (create_options & FILE_DIRECTORY_FILE) { - status = NT_STATUS_NOT_A_DIRECTORY; - goto fail; - } - if (lp_posix_pathnames()) { - ret = SMB_VFS_LSTAT(conn, smb_fname); - } else { - ret = SMB_VFS_STAT(conn, smb_fname); - } - - if (ret == 0 && VALID_STAT_OF_DIR(smb_fname->st)) { - status = NT_STATUS_FILE_IS_A_DIRECTORY; - goto fail; - } - } - } - - status = onefs_create_file_unixpath( - conn, /* conn */ - req, /* req */ - smb_fname, /* fname */ - access_mask, /* access_mask */ - share_access, /* share_access */ - create_disposition, /* create_disposition*/ - create_options, /* create_options */ - file_attributes, /* file_attributes */ - oplock_request, /* oplock_request */ - allocation_size, /* allocation_size */ - private_flags, - sd, /* sd */ - ea_list, /* ea_list */ - &fsp, /* result */ - &info, /* pinfo */ - &fsp_data); /* psbuf */ - - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - DEBUG(10, ("onefs_create_file: info=%d\n", info)); - - /* - * Setup private onefs_fsp_data. Currently the private data struct is - * only used to store the oplock_callback_id so that when the file is - * closed, the onefs_callback_record can be properly cleaned up in the - * oplock_onefs sub-system. - */ - if (fsp) { - struct onefs_fsp_data *fsp_data_tmp = NULL; - fsp_data_tmp = (struct onefs_fsp_data *) - VFS_ADD_FSP_EXTENSION(handle, fsp, struct onefs_fsp_data, - &destroy_onefs_fsp_data); - - if (fsp_data_tmp == NULL) { - status = NT_STATUS_NO_MEMORY; - goto fail; - } - - *fsp_data_tmp = fsp_data; - } - - *result = fsp; - if (pinfo != NULL) { - *pinfo = info; - } - return NT_STATUS_OK; - - fail: - DEBUG(10, ("onefs_create_file: %s\n", nt_errstr(status))); - - if (fsp != NULL) { - close_file(req, fsp, ERROR_CLOSE); - fsp = NULL; - } - return status; -} diff --git a/source3/modules/onefs_shadow_copy.c b/source3/modules/onefs_shadow_copy.c deleted file mode 100644 index 29ee9e1a22..0000000000 --- a/source3/modules/onefs_shadow_copy.c +++ /dev/null @@ -1,783 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * OneFS shadow copy implementation that utilizes the file system's native - * snapshot support. This file does all of the heavy lifting. - * - * Copyright (C) Dave Richards, 2007 - * Copyright (C) Tim Prouty, 2009 - * - * 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 "smbd/smbd.h" -#include <ifs/ifs_syscalls.h> -#include <sys/types.h> -#include <sys/isi_enc.h> -#include <sys/module.h> -#include <sys/stat.h> -#include <sys/syscall.h> -#include <sys/time.h> -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <search.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "onefs_shadow_copy.h" - -/* Copied from ../include/proto.h */ -void become_root(void); -void unbecome_root(void); - -#define SNAPSHOT_DIRECTORY ".snapshot" - -#define MAX_VERSIONS 64 - -/** - * A snapshot object. - * - * During snapshot enumeration, snapshots are represented by snapshot objects - * and are stored in a snapshot set. The snapshot object represents one - * snapshot within the set. An important thing to note about the set is that - * the key of the snapshot object is the tv_sec component of the is_time - * member. What this means is that we only store one snapshot for each - * second. If multiple snapshots were created within the same second, we'll - * keep the earliest one and ignore the rest. Thus, not all snapshots are - * necessarily retained. - */ -struct osc_snapshot { - char * is_name; - struct timespec is_time; - struct osc_snapshot * is_next; -}; - -/** - * A snapshot context object. - * - * Snapshot contexts are used to pass information throughout the snapshot - * enumeration routines. As a result, snapshot contexts are stored on the - * stack and are both created and destroyed within a single API function. - */ -struct osc_snapshot_ctx { - void * osc_set; - struct timespec osc_mtime; -}; - -/** - * A directory context. - * - * Directory contexts are the underlying data structured used to enumerate - * snapshot versions. An opendir()-, readdir()- and closedir()-like interface - * is provided that utilizes directory contexts. At the API level, directory - * contexts are passed around as void pointers. Directory contexts are - * allocated on the heap and their lifetime is dictated by the calling - * routine. - */ -struct osc_directory_ctx { - size_t idc_pos; - size_t idc_len; - size_t idc_size; - char ** idc_version; -}; - -/** - * Return a file descriptor to the STF names directory. - * - * Opens the STF names directory and returns a file descriptor to it. - * Subsequent calls return the same value (avoiding the need to re-open the - * directory repeatedly). Caveat caller: don't close the file descriptor or - * you will be shot! - */ -static int -osc_get_names_directory_fd(void) -{ - static int fd = -1; - - if (fd == -1) { - become_root(); - fd = pctl2_lin_open(STF_NAMES_LIN, HEAD_SNAPID, O_RDONLY); - unbecome_root(); - } - - return fd; -} - -/** - * Compare two time values. - * - * Accepts two struct timespecs and compares the tv_sec components of these - * values. It returns -1 if the first value preceeds the second, 0 if they - * are equal and +1 if the first values succeeds the second. - */ -static int -osc_time_compare(const struct timespec *tsp1, const struct timespec *tsp2) -{ - return (tsp1->tv_sec < tsp2->tv_sec) ? -1 : - (tsp1->tv_sec > tsp2->tv_sec) ? +1 : 0; -} - -/** - * Compare two timespec values. - * - * Compares two timespec values. It returns -1 if the first value preceeds - * the second, 0 if they are equal and +1 if the first values succeeds the - * second. - */ -static int -osc_timespec_compare(const struct timespec *tsp1, const struct timespec *tsp2) -{ - return (tsp1->tv_sec < tsp2->tv_sec) ? -1 : - (tsp1->tv_sec > tsp2->tv_sec) ? +1 : - (tsp1->tv_nsec < tsp2->tv_nsec) ? -1 : - (tsp1->tv_nsec > tsp2->tv_nsec) ? +1 : 0; -} - -/** - * Determine whether a timespec value is zero. - * - * Return 1 if the struct timespec provided is zero and 0 otherwise. - */ -static int -osc_timespec_is_zero(const struct timespec *tsp) -{ - return (tsp->tv_sec == 0) && - (tsp->tv_nsec == 0); -} - -/** - * Create a snapshot object. - * - * Allocates and initializes a new snapshot object. In addition to allocating - * space for the snapshot object itself, space is allocated for the snapshot - * name. Both the name and time are then copied to the new object. - */ -static struct osc_snapshot * -osc_snapshot_create(const char *name, const struct timespec *tsp) -{ - struct osc_snapshot *isp; - - isp = malloc(sizeof *isp); - if (isp == NULL) - goto out; - - isp->is_name = malloc(strlen(name) + 1); - if (isp->is_name == NULL) { - free(isp); - isp = NULL; - goto out; - } - - strcpy(isp->is_name, name); - isp->is_time = *tsp; - isp->is_next = NULL; - - out: - return isp; -} - -/** - * Destroy a snapshot object. - * - * Frees both the name and the snapshot object itself. Appropriate NULL - * checking is performed because counting on free to do so is immoral. - */ -static void -osc_snapshot_destroy(struct osc_snapshot *isp) -{ - if (isp != NULL) { - if (isp->is_name != NULL) - free(isp->is_name); - free(isp); - } -} - -/** - * Destroy all snapshots in the snapshot list. - * - * Calls osc_snapshot_destroy() on each snapshot in the list. - */ -static void -osc_snapshot_destroy_list(struct osc_snapshot *isp) -{ - struct osc_snapshot *tmp; - - while (isp != NULL) { - tmp = isp; - isp = isp->is_next; - osc_snapshot_destroy(tmp); - } -} - -/** - * Compare two snapshot objects. - * - * Compare two snapshot objects. It is really just a wrapper for - * osc_time_compare(), which compare the time value of the two snapshots. - * N.B. time value in this context refers only to the tv_sec component. - */ -static int -osc_snapshot_compare(const void *vp1, const void *vp2) -{ - const struct osc_snapshot *isp1 = vp1; - const struct osc_snapshot *isp2 = vp2; - - return -osc_time_compare(&isp1->is_time, &isp2->is_time); -} - -/** - * Insert a snapshot into the snapshot set. - * - * Inserts a new snapshot into the snapshot set. The key for snapshots is - * their creation time (it's actually the seconds portion of the creation - * time). If a duplicate snapshot is found in the set, the new snapshot is - * added to a linked list of snapshots for that second. - */ -static void -osc_snapshot_insert(struct osc_snapshot_ctx *oscp, const char *name, - const struct timespec *tsp, int *errorp) -{ - struct osc_snapshot *isp1; - struct osc_snapshot **ispp; - - isp1 = osc_snapshot_create(name, tsp); - if (isp1 == NULL) { - *errorp = 1; - return; - } - - ispp = tsearch(isp1, &oscp->osc_set, osc_snapshot_compare); - if (ispp != NULL) { - struct osc_snapshot *isp2 = *ispp; - - /* If this is the only snapshot for this second, we're done. */ - if (isp2 == isp1) - return; - - /* Collision: add the new snapshot to the list. */ - isp1->is_next = isp2->is_next; - isp2->is_next = isp1; - - } else - *errorp = 1; - -} - -/** - * Process the next snapshot. - * - * Called for (almost) every entry in a .snapshot directory, ("." and ".." are - * ignored in osc_process_snapshot_directory()). All other entries are passed - * to osc_process_snapshot(), however. These entries can fall into one of two - * categories: snapshot names and snapshot aliases. We only care about - * snapshot names (as aliases are just redundant entries). Once it verifies - * that name represents a valid snapshot name, it calls fstat() to get the - * creation time of the snapshot and then calls osc_snapshot_insert() to add - * this entry to the snapshot set. - */ -static void -osc_process_snapshot(struct osc_snapshot_ctx *oscp, const char *name, - int *errorp) -{ - int fd; - struct stf_stat stf_stat; - struct stat stbuf; - - fd = osc_get_names_directory_fd(); - if (fd == -1) - goto out; - - fd = enc_openat(fd, name, ENC_DEFAULT, O_RDONLY); - if (fd == -1) - goto out; - - memset(&stf_stat, 0, sizeof stf_stat); - if (ifs_snap_stat(fd, &stf_stat) == -1) - goto out; - - if (stf_stat.sf_type != SF_STF) - goto out; - - if (fstat(fd, &stbuf) == -1) - goto out; - - osc_snapshot_insert(oscp, name, &stbuf.st_birthtimespec, errorp); - - out: - if (fd != -1) - close(fd); -} - -/** - * Process a snapshot directory. - * - * Opens the snapshot directory and calls osc_process_snapshot() for each - * entry. (Well ok, "." and ".." are ignored.) The goal here is to add all - * snapshots in the directory to the snapshot set. - */ -static void -osc_process_snapshot_directory(struct osc_snapshot_ctx *oscp, int *errorp) -{ - int fd; - struct stat stbuf; - DIR *dirp; - struct dirent *dp; - - fd = osc_get_names_directory_fd(); - if (fd == -1) - goto out; - - if (fstat(fd, &stbuf) == -1) - goto out; - - dirp = opendir(SNAPSHOT_DIRECTORY); - if (dirp == NULL) - goto out; - - for (;;) { - dp = readdir(dirp); - if (dp == NULL) - break; - - if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || - (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) - continue; - - osc_process_snapshot(oscp, dp->d_name, errorp); - if (*errorp) - break; - } - - closedir(dirp); - - if (!*errorp) - oscp->osc_mtime = stbuf.st_mtimespec; - - out: - return; -} - -/** - * Initialize a snapshot context object. - * - * Clears all members of the context object. - */ -static void -osc_snapshot_ctx_init(struct osc_snapshot_ctx *oscp) -{ - memset(oscp, 0, sizeof *oscp); -} - -/** - * Desoy a snapshot context object. - * - * Frees all snapshots associated with the snapshot context and then calls - * osc_snapshot_ctx_init() to re-initialize the context object. - */ -static void -osc_snapshot_ctx_clean(struct osc_snapshot_ctx *oscp) -{ - struct osc_snapshot *tmp; - - while (oscp->osc_set != NULL) { - tmp = *(void **)oscp->osc_set; - tdelete(tmp, &oscp->osc_set, osc_snapshot_compare); - osc_snapshot_destroy_list(tmp); - } - - osc_snapshot_ctx_init(oscp); -} - -/** - * Return the "global" snapshot context. - * - * We maintain a single open snapshot context. Return a pointer to it. - */ -static struct osc_snapshot_ctx * -osc_get_snapshot_ctx(void) -{ - static struct osc_snapshot_ctx osc = { 0, { 0, 0 } }; - - return &osc; -} - -/** - * Determine whether a snapshot context is still valid. - * - * "Valid" in this context means "reusable". We can re-use a previous - * snapshot context iff we successfully built a previous snapshot context - * and no snapshots have been created or deleted since we did so. - * A "names" directory exists within our snapshot - * implementation in which all snapshot names are entered. Each time a - * snapshot is created or deleted, an entry must be added or removed. - * When this happens the modification time on the "names" directory - * changes. Therefore, a snapshot context is valid iff the context - * pointer is non-NULL, the cached modification time is non-zero - * (zero means uninitialized), and the modification time of the "names" - * directory matches the cached value. - */ -static int -osc_snapshot_ctx_is_valid(struct osc_snapshot_ctx *oscp) -{ - int fd; - struct stat stbuf; - - if (oscp == NULL) - return 0; - - if (osc_timespec_is_zero(&oscp->osc_mtime)) - return 0; - - fd = osc_get_names_directory_fd(); - if (fd == -1) - return 0; - - if (fstat(fd, &stbuf) == -1) - return 0; - - if (osc_timespec_compare(&oscp->osc_mtime, &stbuf.st_mtimespec) != 0) - return 0; - - return 1; -} - -/** - * Create and initialize a directory context. - * - * Allocates a directory context from the heap and initializes it. - */ -static struct osc_directory_ctx * -osc_directory_ctx_create(void) -{ - struct osc_directory_ctx *idcp; - - idcp = malloc(sizeof *idcp); - if (idcp != NULL) - memset(idcp, 0, sizeof *idcp); - - return idcp; -} - -/** - * Destroy a directory context. - * - * Frees any versions associated with the directory context and then frees the - * context itself. - */ -static void -osc_directory_ctx_destroy(struct osc_directory_ctx *idcp) -{ - int i; - - if (idcp == NULL) - return; - - for (i = 0; i < idcp->idc_len; i++) - free(idcp->idc_version[i]); - - free(idcp); -} - -/** - * Expand the size of a directory context's version list. - * - * If osc_directory_ctx_append_version() detects that the version list is too - * small to accomodate a new version string, it called - * osc_directory_ctx_expand_version_list() to expand the version list. - */ -static void -osc_directory_ctx_expand_version_list(struct osc_snapshot_ctx *oscp, - struct osc_directory_ctx *idcp, int *errorp) -{ - size_t size; - char **cpp; - - size = idcp->idc_size * 2 ?: 1; - - cpp = realloc(idcp->idc_version, size * sizeof (char *)); - if (cpp == NULL) { - *errorp = 1; - return; - } - - idcp->idc_size = size; - idcp->idc_version = cpp; -} - -/** - * Append a new version to a directory context. - * - * Appends a snapshot version to the - * directory context's version list. - */ -static void -osc_directory_ctx_append_version(struct osc_snapshot_ctx *oscp, - struct osc_directory_ctx *idcp, const struct timespec *tsp, int *errorp) -{ - char *cp; - struct tm *tmp; - char text[64]; - - if (idcp->idc_len >= MAX_VERSIONS) - return; - - if (idcp->idc_len >= idcp->idc_size) { - osc_directory_ctx_expand_version_list(oscp, idcp, errorp); - if (*errorp) - return; - } - - tmp = gmtime(&tsp->tv_sec); - if (tmp == NULL) { - *errorp = 1; - return; - } - - snprintf(text, sizeof text, - "@GMT-%04u.%02u.%02u-%02u.%02u.%02u", - tmp->tm_year + 1900, - tmp->tm_mon + 1, - tmp->tm_mday, - tmp->tm_hour, - tmp->tm_min, - tmp->tm_sec); - - cp = malloc(strlen(text) + 1); - if (cp == NULL) { - *errorp = 1; - return; - } - - strcpy(cp, text); - - idcp->idc_version[idcp->idc_len++] = cp; -} - -/** - * Make a directory context from a snapshot context. - * - * Once a snapshot context has been completely filled-in, - * osc_make_directory_ctx() is used to build a directory context from it. The - * idea here is to create version for each snapshot in the snapshot set. - */ -static void -osc_make_directory_ctx(struct osc_snapshot_ctx *oscp, - struct osc_directory_ctx *idcp, int *errorp) -{ - static void - walk(const void *vp, VISIT v, int level) - { - const struct osc_snapshot *isp; - - if ((v != postorder && v != leaf) || *errorp) - return; - - isp = *(const struct osc_snapshot **)(u_long)vp; - - osc_directory_ctx_append_version(oscp, idcp, &isp->is_time, - errorp); - } - - twalk(oscp->osc_set, walk); -} - -/** - * Open a version directory. - * - * Opens a version directory. What this really means is that - * osc_version_opendir() returns a handle to a directory context, which can be - * used to retrieve version strings. - */ -void * -osc_version_opendir(void) -{ - int error = 0; - struct osc_directory_ctx *idcp; - struct osc_snapshot_ctx *oscp; - - idcp = osc_directory_ctx_create(); - if (idcp == NULL) - goto error_out; - - oscp = osc_get_snapshot_ctx(); - - if (!osc_snapshot_ctx_is_valid(oscp)) { - osc_snapshot_ctx_clean(oscp); - osc_process_snapshot_directory(oscp, &error); - if (error) - goto error_out; - } - - osc_make_directory_ctx(oscp, idcp, &error); - if (error) - goto error_out; - - goto out; - - error_out: - if (idcp != NULL) { - osc_directory_ctx_destroy(idcp); - idcp = NULL; - } - - out: - return (void *)idcp; -} - -/** - * Read the next version directory entry. - * - * Returns the name of the next version in the version directory, or NULL if - * we're at the end of the directory. What this really does is return the - * next version from the version list stored in the directory context. - */ -char * -osc_version_readdir(void *vp) -{ - struct osc_directory_ctx *idcp = vp; - - if (idcp == NULL) - return NULL; - - if (idcp->idc_pos >= idcp->idc_len) - return NULL; - - return idcp->idc_version[idcp->idc_pos++]; -} - -/** - * Close the version directory. - * - * Destroys the underlying directory context. - */ -void -osc_version_closedir(void *vp) -{ - struct osc_directory_ctx *idcp = vp; - - if (idcp != NULL) - osc_directory_ctx_destroy(idcp); -} - -/** - * Canonicalize a path. - * - * Converts paths of the form @GMT-.. to paths of the form ../.snapshot/.. - * It's not the prettiest routine I've ever written, but what the heck? - */ -char * -osc_canonicalize_path(const char *path, char *snap_component) -{ - int error = 0; - struct osc_snapshot_ctx *oscp; - struct tm tm; - int n; - struct osc_snapshot is; - struct osc_snapshot **ispp; - struct osc_snapshot *isp; - char *cpath = NULL; - char *cpath2 = NULL; - const char *snap_component_orig = snap_component; - struct stat sb; - - oscp = osc_get_snapshot_ctx(); - - if (!osc_snapshot_ctx_is_valid(oscp)) { - osc_snapshot_ctx_clean(oscp); - osc_process_snapshot_directory(oscp, &error); - if (error) - goto out; - } - - memset(&tm, 0, sizeof tm); - n = sscanf(snap_component, - "@GMT-%4u.%2u.%2u-%2u.%2u.%2u", - &tm.tm_year, - &tm.tm_mon, - &tm.tm_mday, - &tm.tm_hour, - &tm.tm_min, - &tm.tm_sec); - if (n != 6) - goto out; - - tm.tm_year -= 1900; - tm.tm_mon -= 1; - - is.is_name = NULL; - is.is_time.tv_sec = timegm(&tm); - is.is_time.tv_nsec = 0; - - ispp = tfind(&is, &oscp->osc_set, osc_snapshot_compare); - if (ispp == NULL) - goto out; - isp = *ispp; - - /* Determine the path after "@GMT-..." */ - while (*snap_component != '/' && *snap_component != '\0') - snap_component++; - - while (*snap_component == '/') - snap_component++; - - cpath = malloc(strlen(SNAPSHOT_DIRECTORY) + strlen(isp->is_name) + - strlen(path) + 3); - - if (cpath == NULL) - goto out; - - /* - * Use the first snapshot that has a successful stat for the requested - * path. - */ - while (true) { - - sprintf(cpath, "%s/%s", SNAPSHOT_DIRECTORY, isp->is_name); - - /* Append path before "@GMT-..." */ - if (snap_component_orig != path) { - strcat(cpath, "/"); - strncat(cpath, path, snap_component_orig - path); - } - - /* Append path after "@GMT-..." */ - if (*snap_component != '\0') { - strcat(cpath, "/"); - strcat(cpath, snap_component); - } - - /* If there is a valid snapshot for this file, we're done. */ - if (stat(cpath, &sb) == 0) - break; - - /* Try the next snapshot. If this was the last one, give up. */ - isp = isp->is_next; - if (isp == NULL) - break; - - /* If the realloc fails, give up. */ - cpath2 = realloc(cpath, strlen(SNAPSHOT_DIRECTORY) + - strlen(isp->is_name) + strlen(path) + 3); - if (cpath2 == NULL) - break; - cpath = cpath2; - } - - out: - return cpath; -} diff --git a/source3/modules/onefs_shadow_copy.h b/source3/modules/onefs_shadow_copy.h deleted file mode 100644 index 6415a4be1a..0000000000 --- a/source3/modules/onefs_shadow_copy.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * - * OneFS shadow copy implementation that utilizes the file system's native - * snapshot support. - * - * Copyright (C) Dave Richards, 2007 - * Copyright (C) Tim Prouty, 2009 - * - * 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/>. - */ - -#ifndef ONEFS_SHADOW_COPY_H -#define ONEFS_SHADOW_COPY_H - -void *osc_version_opendir(void); -char *osc_version_readdir(void *vp); -void osc_version_closedir(void *vp); -char *osc_canonicalize_path(const char *path, char *snap_component); - -#endif /* ONEFS_SHADOW_COPY_H */ diff --git a/source3/modules/onefs_streams.c b/source3/modules/onefs_streams.c deleted file mode 100644 index 0a1d98c809..0000000000 --- a/source3/modules/onefs_streams.c +++ /dev/null @@ -1,771 +0,0 @@ -/* - * 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 "includes.h" -#include "smbd/smbd.h" -#include "onefs.h" -#include "onefs_config.h" - -#include <sys/isi_enc.h> - -NTSTATUS onefs_stream_prep_smb_fname(TALLOC_CTX *ctx, - const struct smb_filename *smb_fname_in, - struct smb_filename **smb_fname_out) -{ - char *stream_name = NULL; - NTSTATUS status; - - /* - * Only attempt to strip off the trailing :$DATA if there is an actual - * stream there. If it is the default stream, the smb_fname_out will - * just have a NULL stream so the base file is opened. - */ - if (smb_fname_in->stream_name && - !is_ntfs_default_stream_smb_fname(smb_fname_in)) { - char *str_tmp = smb_fname_in->stream_name; - - /* First strip off the leading ':' */ - if (str_tmp[0] == ':') { - str_tmp++; - } - - /* Create a new copy of the stream_name. */ - stream_name = talloc_strdup(ctx, str_tmp); - if (stream_name == NULL) { - return NT_STATUS_NO_MEMORY; - } - - /* Strip off the :$DATA if one exists. */ - str_tmp = strrchr_m(stream_name, ':'); - if (str_tmp) { - if (strcasecmp_m(str_tmp, ":$DATA") != 0) { - return NT_STATUS_INVALID_PARAMETER; - } - str_tmp[0] = '\0'; - } - } - - /* - * If there was a stream that wasn't the default stream the leading - * colon and trailing :$DATA has now been stripped off. Create a new - * smb_filename to pass back. - */ - status = create_synthetic_smb_fname(ctx, smb_fname_in->base_name, - stream_name, &smb_fname_in->st, - smb_fname_out); - TALLOC_FREE(stream_name); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(5, ("Failed to prep stream name for %s: %s\n", - *smb_fname_out ? - smb_fname_str_dbg(*smb_fname_out) : "NULL", - nt_errstr(status))); - } - return status; -} - -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; - - DEBUG(10, ("Getting stream directory fd: %s (%d)\n", base, - base_fdp ? *base_fdp : -1)); - - /* 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) { - DEBUG(5, ("Failed getting base fd: %s\n", - strerror(errno))); - 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; - } - - if (dir_fd < 0) { - DEBUG(5, ("Failed getting stream directory fd: %s\n", - strerror(errno))); - } - - return dir_fd; -} - -int onefs_rename(vfs_handle_struct *handle, - const struct smb_filename *smb_fname_src, - const struct smb_filename *smb_fname_dst) -{ - struct smb_filename *smb_fname_src_onefs = NULL; - struct smb_filename *smb_fname_dst_onefs = NULL; - NTSTATUS status; - int saved_errno; - int dir_fd = -1; - int ret = -1; - - START_PROFILE(syscall_rename_at); - - if (!is_ntfs_stream_smb_fname(smb_fname_src) && - !is_ntfs_stream_smb_fname(smb_fname_dst)) { - ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, - smb_fname_dst); - goto done; - } - - /* For now don't allow renames from or to the default stream. */ - if (is_ntfs_default_stream_smb_fname(smb_fname_src) || - is_ntfs_default_stream_smb_fname(smb_fname_dst)) { - DEBUG(3, ("Unable to rename to/from a default stream: %s -> " - "%s\n", smb_fname_str_dbg(smb_fname_src), - smb_fname_str_dbg(smb_fname_dst))); - errno = ENOSYS; - goto done; - } - - /* prep stream smb_filename structs. */ - status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname_src, - &smb_fname_src_onefs); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - goto done; - } - status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname_dst, - &smb_fname_dst_onefs); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - goto done; - } - - dir_fd = get_stream_dir_fd(handle->conn, smb_fname_src->base_name, - NULL); - if (dir_fd < -1) { - goto done; - } - - DEBUG(8, ("onefs_rename called for %s => %s\n", - smb_fname_str_dbg(smb_fname_src_onefs), - smb_fname_str_dbg(smb_fname_dst_onefs))); - - /* Handle rename of stream to default stream specially. */ - if (smb_fname_dst_onefs->stream_name == NULL) { - ret = enc_renameat(dir_fd, smb_fname_src_onefs->stream_name, - ENC_DEFAULT, AT_FDCWD, - smb_fname_dst_onefs->base_name, - ENC_DEFAULT); - } else { - ret = enc_renameat(dir_fd, smb_fname_src_onefs->stream_name, - ENC_DEFAULT, dir_fd, - smb_fname_dst_onefs->stream_name, - ENC_DEFAULT); - } - - done: - END_PROFILE(syscall_rename_at); - TALLOC_FREE(smb_fname_src_onefs); - TALLOC_FREE(smb_fname_dst_onefs); - - saved_errno = errno; - if (dir_fd >= 0) { - close(dir_fd); - } - errno = saved_errno; - 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_ex_mtime = base_sbuf->st_ex_mtime; - stream_sbuf->st_ex_ctime = base_sbuf->st_ex_ctime; - stream_sbuf->st_ex_atime = base_sbuf->st_ex_atime; - stream_sbuf->st_ex_flags &= ~dos_flags; - stream_sbuf->st_ex_flags |= base_sbuf->st_ex_flags & dos_flags; -} - -/* fake timestamps */ -static void onefs_adjust_stat_time(struct connection_struct *conn, - const char *fname, SMB_STRUCT_STAT *sbuf) -{ - struct onefs_vfs_share_config cfg; - struct timeval tv_now = {0, 0}; - bool static_mtime = False; - bool static_atime = False; - - if (!onefs_get_config(SNUM(conn), - ONEFS_VFS_CONFIG_FAKETIMESTAMPS, &cfg)) { - return; - } - - if (IS_MTIME_STATIC_PATH(conn, &cfg, fname)) { - sbuf->st_ex_mtime = sbuf->st_ex_btime; - static_mtime = True; - } - if (IS_ATIME_STATIC_PATH(conn, &cfg, fname)) { - sbuf->st_ex_atime = sbuf->st_ex_btime; - static_atime = True; - } - - if (IS_CTIME_NOW_PATH(conn, &cfg, fname)) { - if (cfg.ctime_slop < 0) { - sbuf->st_ex_btime.tv_sec = INT_MAX - 1; - } else { - GetTimeOfDay(&tv_now); - sbuf->st_ex_btime.tv_sec = tv_now.tv_sec + - cfg.ctime_slop; - } - } - - if (!static_mtime && IS_MTIME_NOW_PATH(conn,&cfg,fname)) { - if (cfg.mtime_slop < 0) { - sbuf->st_ex_mtime.tv_sec = INT_MAX - 1; - } else { - if (tv_now.tv_sec == 0) - GetTimeOfDay(&tv_now); - sbuf->st_ex_mtime.tv_sec = tv_now.tv_sec + - cfg.mtime_slop; - } - } - if (!static_atime && IS_ATIME_NOW_PATH(conn,&cfg,fname)) { - if (cfg.atime_slop < 0) { - sbuf->st_ex_atime.tv_sec = INT_MAX - 1; - } else { - if (tv_now.tv_sec == 0) - GetTimeOfDay(&tv_now); - sbuf->st_ex_atime.tv_sec = tv_now.tv_sec + - cfg.atime_slop; - } - } -} - -static int stat_stream(struct connection_struct *conn, 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(conn, base, &base_fd); - if (dir_fd < 0) { - return -1; - } - - /* Stat the stream. */ - ret = onefs_sys_fstat_at(dir_fd, stream, sbuf, flags); - if (ret != -1) { - DEBUG(10, ("stat of stream '%s' failed: %s\n", stream, - strerror(errno))); - } else { - /* Now stat the base file and merge the results. */ - ret = onefs_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, struct smb_filename *smb_fname) -{ - struct smb_filename *smb_fname_onefs = NULL; - NTSTATUS status; - int ret; - - status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname, - &smb_fname_onefs); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return -1; - } - - /* - * If the smb_fname has no stream or is :$DATA, then just stat the - * base stream. Otherwise stat the stream. - */ - if (!is_ntfs_stream_smb_fname(smb_fname_onefs)) { - ret = onefs_sys_stat(smb_fname_onefs->base_name, - &smb_fname->st); - } else { - ret = stat_stream(handle->conn, smb_fname_onefs->base_name, - smb_fname_onefs->stream_name, &smb_fname->st, - 0); - } - - onefs_adjust_stat_time(handle->conn, smb_fname->base_name, - &smb_fname->st); - - TALLOC_FREE(smb_fname_onefs); - - return ret; -} - -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 = onefs_sys_fstat(fsp->fh->fd, sbuf); - if (ret == -1) { - return ret; - } - - /* Stat the base file and merge the results. */ - if (fsp != NULL && fsp->base_fsp != NULL) { - ret = onefs_sys_fstat(fsp->base_fsp->fh->fd, &base_sbuf); - if (ret != -1) { - merge_stat(sbuf, &base_sbuf); - } - } - - onefs_adjust_stat_time(handle->conn, fsp->fsp_name->base_name, sbuf); - return ret; -} - -int onefs_lstat(vfs_handle_struct *handle, struct smb_filename *smb_fname) -{ - struct smb_filename *smb_fname_onefs = NULL; - NTSTATUS status; - int ret; - - status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname, - &smb_fname_onefs); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return -1; - } - - /* - * If the smb_fname has no stream or is :$DATA, then just stat the - * base stream. Otherwise stat the stream. - */ - if (!is_ntfs_stream_smb_fname(smb_fname_onefs)) { - ret = onefs_sys_lstat(smb_fname_onefs->base_name, - &smb_fname->st); - } else { - ret = stat_stream(handle->conn, smb_fname_onefs->base_name, - smb_fname_onefs->stream_name, &smb_fname->st, - AT_SYMLINK_NOFOLLOW); - } - - onefs_adjust_stat_time(handle->conn, smb_fname->base_name, - &smb_fname->st); - - TALLOC_FREE(smb_fname_onefs); - - return ret; -} - -int onefs_unlink(vfs_handle_struct *handle, - const struct smb_filename *smb_fname) -{ - struct smb_filename *smb_fname_onefs = NULL; - int ret; - int dir_fd, saved_errno; - NTSTATUS status; - - /* Not a stream. */ - if (!is_ntfs_stream_smb_fname(smb_fname)) { - return SMB_VFS_NEXT_UNLINK(handle, smb_fname); - } - - status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname, - &smb_fname_onefs); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return -1; - } - - /* Default stream (the ::$DATA was just stripped off). */ - if (!is_ntfs_stream_smb_fname(smb_fname_onefs)) { - ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_onefs); - goto out; - } - - dir_fd = get_stream_dir_fd(handle->conn, smb_fname_onefs->base_name, - NULL); - if (dir_fd < 0) { - ret = -1; - goto out; - } - - ret = enc_unlinkat(dir_fd, smb_fname_onefs->stream_name, ENC_DEFAULT, - 0); - - saved_errno = errno; - close(dir_fd); - errno = saved_errno; - out: - TALLOC_FREE(smb_fname_onefs); - return ret; -} - -int onefs_vtimes_streams(vfs_handle_struct *handle, - const struct smb_filename *smb_fname, - int flags, struct timespec times[3]) -{ - struct smb_filename *smb_fname_onefs = NULL; - int ret; - int dirfd; - int saved_errno; - NTSTATUS status; - - START_PROFILE(syscall_ntimes); - - if (!is_ntfs_stream_smb_fname(smb_fname)) { - ret = vtimes(smb_fname->base_name, times, flags); - return ret; - } - - status = onefs_stream_prep_smb_fname(talloc_tos(), smb_fname, - &smb_fname_onefs); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return -1; - } - - /* Default stream (the ::$DATA was just stripped off). */ - if (!is_ntfs_stream_smb_fname(smb_fname_onefs)) { - ret = vtimes(smb_fname_onefs->base_name, times, flags); - goto out; - } - - dirfd = get_stream_dir_fd(handle->conn, smb_fname->base_name, NULL); - if (dirfd < -1) { - ret = -1; - goto out; - } - - ret = enc_vtimesat(dirfd, smb_fname_onefs->stream_name, ENC_DEFAULT, - times, flags); - - saved_errno = errno; - close(dirfd); - errno = saved_errno; - - out: - END_PROFILE(syscall_ntimes); - TALLOC_FREE(smb_fname_onefs); - return ret; -} - -/* - * 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, off_t size, - off_t alloc_size) -{ - struct stream_struct *tmp; - - tmp = talloc_realloc(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; - DIR *dirp = NULL; - 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; - } - - /* Initialize the dir state struct and add it to the list. - * This is a layer violation, and really should be handled by a - * VFS_FDOPENDIR() call which would properly setup the dir state. - * But since this is all within the onefs.so module, we cheat for - * now and call directly into the readdirplus code. - * NOTE: This state MUST be freed by a proper VFS_CLOSEDIR() call. */ - ret = onefs_rdp_add_dir_state(conn, dirp); - if (ret) { - DEBUG(0, ("Error adding dir_state to the list\n")); - status = map_nt_error_from_unix(errno); - goto out; - } - - fake_fs.conn = conn; - fake_fs.fh = &fake_fh; - status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, NULL, - &fake_fs.fsp_name); - if (!NT_STATUS_IS_OK(status)) { - goto out; - } - - /* Iterate over the streams in the ADS directory. */ - while ((dp = SMB_VFS_READDIR(conn, dirp, NULL)) != 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_ex_size, - SMB_VFS_GET_ALLOC_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); - } - - TALLOC_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)) { - ret = SMB_VFS_FSTAT(fsp, &sbuf); - } else { - struct smb_filename *smb_fname = NULL; - - status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - return status; - } - ret = SMB_VFS_STAT(handle->conn, smb_fname); - - sbuf = smb_fname->st; - - TALLOC_FREE(smb_fname); - } - - if (ret == -1) { - return map_nt_error_from_unix(errno); - } - - state.streams = *pstreams; - state.num_streams = *pnum_streams; - - if (lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE, - PARM_IGNORE_STREAMS, PARM_IGNORE_STREAMS_DEFAULT)) { - goto out; - } - - state.mem_ctx = mem_ctx; - state.handle = handle; - state.status = NT_STATUS_OK; - - /* If there are more streams, add them too. */ - if (sbuf.st_ex_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; - } - } - out: - *num_streams = state.num_streams; - *streams = state.streams; - return SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname, mem_ctx, pnum_streams, pstreams); -} diff --git a/source3/modules/onefs_system.c b/source3/modules/onefs_system.c deleted file mode 100644 index 07272cc86b..0000000000 --- a/source3/modules/onefs_system.c +++ /dev/null @@ -1,782 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Support for OneFS system interfaces. - * - * 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 "includes.h" -#include "smbd/smbd.h" -#include "onefs.h" -#include "onefs_config.h" -#include "oplock_onefs.h" - -#include <ifs/ifs_syscalls.h> -#include <isi_acl/isi_acl_util.h> -#include <sys/isi_acl.h> - -/* - * Initialize the sm_lock struct before passing it to ifs_createfile. - */ -static void smlock_init(connection_struct *conn, struct sm_lock *sml, - bool isexe, uint32_t access_mask, uint32_t share_access, - uint32_t create_options) -{ - sml->sm_type.doc = false; - sml->sm_type.isexe = isexe; - sml->sm_type.statonly = is_stat_open(access_mask); - sml->sm_type.access_mask = access_mask; - sml->sm_type.share_access = share_access; - - /* - * private_options was previously used for DENY_DOS/DENY_FCB checks in - * the kernel, but are now properly handled by fcb_or_dos_open. In - * these cases, ifs_createfile will return a sharing violation, which - * gives fcb_or_dos_open the chance to open a duplicate file handle. - */ - sml->sm_type.private_options = 0; - - /* 1 second delay is handled in onefs_open.c by deferring the open */ - sml->sm_timeout = timeval_set(0, 0); -} - -static void smlock_dump(int debuglevel, const struct sm_lock *sml) -{ - if (sml == NULL) { - DEBUG(debuglevel, ("sml == NULL\n")); - return; - } - - DEBUG(debuglevel, - ("smlock: doc=%s, isexec=%s, statonly=%s, access_mask=0x%x, " - "share_access=0x%x, private_options=0x%x timeout=%d/%d\n", - sml->sm_type.doc ? "True" : "False", - sml->sm_type.isexe ? "True" : "False", - sml->sm_type.statonly ? "True" : "False", - sml->sm_type.access_mask, - sml->sm_type.share_access, - sml->sm_type.private_options, - (int)sml->sm_timeout.tv_sec, - (int)sml->sm_timeout.tv_usec)); -} - -/** - * External interface to ifs_createfile - */ -int onefs_sys_create_file(connection_struct *conn, - int base_fd, - const char *path, - uint32_t access_mask, - uint32_t open_access_mask, - uint32_t share_access, - uint32_t create_options, - int flags, - mode_t mode, - int oplock_request, - uint64_t id, - struct security_descriptor *sd, - uint32_t dos_flags, - int *granted_oplock) -{ - struct sm_lock sml, *psml = NULL; - enum oplock_type onefs_oplock; - enum oplock_type onefs_granted_oplock = OPLOCK_NONE; - struct ifs_security_descriptor ifs_sd = {}, *pifs_sd = NULL; - uint32_t sec_info_effective = 0; - int ret_fd = -1; - uint32_t onefs_dos_attributes; - struct ifs_createfile_flags cf_flags = CF_FLAGS_NONE; - char *mapped_name = NULL; - NTSTATUS result; - - START_PROFILE(syscall_createfile); - - /* Translate the name to UNIX before calling ifs_createfile */ - mapped_name = talloc_strdup(talloc_tos(), path); - if (mapped_name == NULL) { - errno = ENOMEM; - goto out; - } - result = SMB_VFS_TRANSLATE_NAME(conn, &mapped_name, - vfs_translate_to_unix); - if (!NT_STATUS_IS_OK(result)) { - goto out; - } - - /* Setup security descriptor and get secinfo. */ - if (sd != NULL) { - NTSTATUS status; - uint32_t sec_info_sent = 0; - - sec_info_sent = (get_sec_info(sd) & IFS_SEC_INFO_KNOWN_MASK); - - status = onefs_samba_sd_to_sd(sec_info_sent, sd, &ifs_sd, - SNUM(conn), &sec_info_effective); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("SD initialization failure: %s\n", - nt_errstr(status))); - errno = EINVAL; - goto out; - } - - pifs_sd = &ifs_sd; - } - - /* Stripping off private bits will be done for us. */ - onefs_oplock = onefs_samba_oplock_to_oplock(oplock_request); - - if (!lp_oplocks(SNUM(conn))) { - SMB_ASSERT(onefs_oplock == OPLOCK_NONE); - } - - /* Convert samba dos flags to UF_DOS_* attributes. */ - onefs_dos_attributes = dos_attributes_to_stat_dos_flags(dos_flags); - - /** - * Deal with kernel creating Default ACLs. (Isilon bug 47447.) - * - * 1) "nt acl support = no", default_acl = no - * 2) "inherit permissions = yes", default_acl = no - */ - if (lp_nt_acl_support(SNUM(conn)) && !lp_inherit_perms(SNUM(conn))) - cf_flags = cf_flags_or(cf_flags, CF_FLAGS_DEFAULT_ACL); - - /* - * Some customer workflows require the execute bit to be ignored. - */ - if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_ALLOW_EXECUTE_ALWAYS, - PARM_ALLOW_EXECUTE_ALWAYS_DEFAULT) && - (open_access_mask & FILE_EXECUTE)) { - - DEBUG(3, ("Stripping execute bit from %s: (0x%x)\n", mapped_name, - open_access_mask)); - - /* Strip execute. */ - open_access_mask &= ~FILE_EXECUTE; - - /* - * Add READ_DATA, so we're not left with desired_access=0. An - * execute call should imply the client will read the data. - */ - open_access_mask |= FILE_READ_DATA; - - DEBUGADD(3, ("New stripped access mask: 0x%x\n", - open_access_mask)); - } - - DEBUG(10,("onefs_sys_create_file: base_fd = %d, fname = %s " - "open_access_mask = 0x%x, flags = 0x%x, mode = 0%o, " - "desired_oplock = %s, id = 0x%x, secinfo = 0x%x, sd = %p, " - "dos_attributes = 0x%x, path = %s, " - "default_acl=%s\n", base_fd, mapped_name, - (unsigned int)open_access_mask, - (unsigned int)flags, - (unsigned int)mode, - onefs_oplock_str(onefs_oplock), - (unsigned int)id, - sec_info_effective, sd, - (unsigned int)onefs_dos_attributes, mapped_name, - cf_flags_and_bool(cf_flags, CF_FLAGS_DEFAULT_ACL) ? - "true" : "false")); - - /* Initialize smlock struct for files/dirs but not internal opens */ - if (!(oplock_request & INTERNAL_OPEN_ONLY)) { - smlock_init(conn, &sml, is_executable(mapped_name), access_mask, - share_access, create_options); - psml = &sml; - } - - smlock_dump(10, psml); - - ret_fd = ifs_createfile(base_fd, mapped_name, - (enum ifs_ace_rights)open_access_mask, flags & ~O_ACCMODE, mode, - onefs_oplock, id, psml, sec_info_effective, pifs_sd, - onefs_dos_attributes, cf_flags, &onefs_granted_oplock); - - DEBUG(10,("onefs_sys_create_file(%s): ret_fd = %d, " - "onefs_granted_oplock = %s\n", - ret_fd < 0 ? strerror(errno) : "success", ret_fd, - onefs_oplock_str(onefs_granted_oplock))); - - if (granted_oplock) { - *granted_oplock = - onefs_oplock_to_samba_oplock(onefs_granted_oplock); - } - - out: - END_PROFILE(syscall_createfile); - aclu_free_sd(pifs_sd, false); - TALLOC_FREE(mapped_name); - - return ret_fd; -} - -/** - * FreeBSD based sendfile implementation that allows for atomic semantics. - */ -static ssize_t onefs_sys_do_sendfile(int tofd, int fromfd, - const DATA_BLOB *header, off_t offset, size_t count, bool atomic) -{ - size_t total=0; - struct sf_hdtr hdr; - struct iovec hdtrl; - size_t hdr_len = 0; - int flags = 0; - - if (atomic) { - flags = SF_ATOMIC; - } - - hdr.headers = &hdtrl; - hdr.hdr_cnt = 1; - hdr.trailers = NULL; - hdr.trl_cnt = 0; - - /* Set up the header iovec. */ - if (header) { - hdtrl.iov_base = (void *)header->data; - hdtrl.iov_len = hdr_len = header->length; - } else { - hdtrl.iov_base = NULL; - hdtrl.iov_len = 0; - } - - total = count; - while (total + hdtrl.iov_len) { - off_t nwritten; - int ret; - - /* - * FreeBSD sendfile returns 0 on success, -1 on error. - * Remember, the tofd and fromfd are reversed..... :-). - * nwritten includes the header data sent. - */ - - do { - ret = sendfile(fromfd, tofd, offset, total, &hdr, - &nwritten, flags); -#if defined(EWOULDBLOCK) - } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)); -#else - } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); -#endif - - /* On error we're done. */ - if (ret == -1) { - return -1; - } - - /* - * If this was an ATOMIC sendfile, nwritten doesn't - * necessarily indicate an error. It could mean count > than - * what sendfile can handle atomically (usually 64K) or that - * there was a short read due to the file being truncated. - */ - if (nwritten == 0) { - return atomic ? 0 : -1; - } - - /* - * An atomic sendfile should never send partial data! - */ - if (atomic && nwritten != total + hdtrl.iov_len) { - DEBUG(0,("Atomic sendfile() sent partial data: " - "%llu of %d\n", nwritten, - total + hdtrl.iov_len)); - return -1; - } - - /* - * If this was a short (signal interrupted) write we may need - * to subtract it from the header data, or null out the header - * data altogether if we wrote more than hdtrl.iov_len bytes. - * We change nwritten to be the number of file bytes written. - */ - - if (hdtrl.iov_base && hdtrl.iov_len) { - if (nwritten >= hdtrl.iov_len) { - nwritten -= hdtrl.iov_len; - hdtrl.iov_base = NULL; - hdtrl.iov_len = 0; - } else { - hdtrl.iov_base = - (void *)((caddr_t)hdtrl.iov_base + nwritten); - hdtrl.iov_len -= nwritten; - nwritten = 0; - } - } - total -= nwritten; - offset += nwritten; - } - return count + hdr_len; -} - -/** - * Handles the subtleties of using sendfile with CIFS. - */ -ssize_t onefs_sys_sendfile(connection_struct *conn, int tofd, int fromfd, - const DATA_BLOB *header, off_t offset, - size_t count) -{ - bool atomic = false; - ssize_t ret = 0; - - START_PROFILE_BYTES(syscall_sendfile, count); - - if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_ATOMIC_SENDFILE, - PARM_ATOMIC_SENDFILE_DEFAULT)) { - atomic = true; - } - - /* Try the sendfile */ - ret = onefs_sys_do_sendfile(tofd, fromfd, header, offset, count, - atomic); - - /* If the sendfile wasn't atomic, we're done. */ - if (!atomic) { - DEBUG(10, ("non-atomic sendfile read %ul bytes\n", ret)); - END_PROFILE(syscall_sendfile); - return ret; - } - - /* - * Atomic sendfile takes care to not write anything to the socket - * until all of the requested bytes have been read from the file. - * There are two atomic cases that need to be handled. - * - * 1. The file was truncated causing less data to be read than was - * requested. In this case, we return back to the caller to - * indicate 0 bytes were written to the socket. This should - * prompt the caller to fallback to the standard read path: read - * the data, create a header that indicates how many bytes were - * actually read, and send the header/data back to the client. - * - * This saves us from standard sendfile behavior of sending a - * header promising more data then will actually be sent. The - * only two options are to close the socket and kill the client - * connection, or write a bunch of 0s. Closing the client - * connection is bad because there could actually be multiple - * sessions multiplexed from the same client that are all dropped - * because of a truncate. Writing the remaining data as 0s also - * isn't good, because the client will have an incorrect version - * of the file. If the file is written back to the server, the 0s - * will be written back. Fortunately, atomic sendfile allows us - * to avoid making this choice in most cases. - * - * 2. One downside of atomic sendfile, is that there is a limit on - * the number of bytes that can be sent atomically. The kernel - * has a limited amount of mbuf space that it can read file data - * into without exhausting the system's mbufs, so a buffer of - * length xfsize is used. The xfsize at the time of writing this - * is 64K. xfsize bytes are read from the file, and subsequently - * written to the socket. This makes it impossible to do the - * sendfile atomically for a byte count > xfsize. - * - * To cope with large requests, atomic sendfile returns -1 with - * errno set to E2BIG. Since windows maxes out at 64K writes, - * this is currently only a concern with non-windows clients. - * Posix extensions allow the full 24bit bytecount field to be - * used in ReadAndX, and clients such as smbclient and the linux - * cifs client can request up to 16MB reads! There are a few - * options for handling large sendfile requests. - * - * a. Fall back to the standard read path. This is unacceptable - * because it would require prohibitively large mallocs. - * - * b. Fall back to using samba's fake_send_file which emulates - * the kernel sendfile in userspace. This still has the same - * problem of sending the header before all of the data has - * been read, so it doesn't buy us anything, and has worse - * performance than the kernel's zero-copy sendfile. - * - * c. Use non-atomic sendfile syscall to attempt a zero copy - * read, and hope that there isn't a short read due to - * truncation. In the case of a short read, there are two - * options: - * - * 1. Kill the client connection - * - * 2. Write zeros to the socket for the remaining bytes - * promised in the header. - * - * It is safer from a data corruption perspective to kill the - * client connection, so this is our default behavior, but if - * this causes problems this can be configured to write zeros - * via smb.conf. - */ - - /* Handle case 1: short read -> truncated file. */ - if (ret == 0) { - END_PROFILE(syscall_sendfile); - return ret; - } - - /* Handle case 2: large read. */ - if (ret == -1 && errno == E2BIG) { - - if (!lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_SENDFILE_LARGE_READS, - PARM_SENDFILE_LARGE_READS_DEFAULT)) { - DEBUG(3, ("Not attempting non-atomic large sendfile: " - "%lu bytes\n", count)); - END_PROFILE(syscall_sendfile); - return 0; - } - - if (count < 0x10000) { - DEBUG(0, ("Count < 2^16 and E2BIG was returned! %lu\n", - count)); - } - - DEBUG(10, ("attempting non-atomic large sendfile: %lu bytes\n", - count)); - - /* Try a non-atomic sendfile. */ - ret = onefs_sys_do_sendfile(tofd, fromfd, header, offset, - count, false); - /* Real error: kill the client connection. */ - if (ret == -1) { - DEBUG(1, ("error on non-atomic large sendfile " - "(%lu bytes): %s\n", count, - strerror(errno))); - END_PROFILE(syscall_sendfile); - return ret; - } - - /* Short read: kill the client connection. */ - if (ret != count + header->length) { - DEBUG(1, ("short read on non-atomic large sendfile " - "(%lu of %lu bytes): %s\n", ret, count, - strerror(errno))); - - /* - * Returning ret here would cause us to drop into the - * codepath that calls sendfile_short_send, which - * sends the client a bunch of zeros instead. - * Returning -1 kills the connection. - */ - if (lp_parm_bool(SNUM(conn), PARM_ONEFS_TYPE, - PARM_SENDFILE_SAFE, - PARM_SENDFILE_SAFE_DEFAULT)) { - END_PROFILE(syscall_sendfile); - return -1; - } - - END_PROFILE(syscall_sendfile); - return ret; - } - - DEBUG(10, ("non-atomic large sendfile successful\n")); - } - - /* There was error in the atomic sendfile. */ - if (ret == -1) { - DEBUG(1, ("error on %s sendfile (%lu bytes): %s\n", - atomic ? "atomic" : "non-atomic", - count, strerror(errno))); - } - - END_PROFILE(syscall_sendfile); - return ret; -} - -/** - * Only talloc the spill buffer once (reallocing when necessary). - */ -static char *get_spill_buffer(size_t new_count) -{ - static int cur_count = 0; - static char *spill_buffer = NULL; - - /* If a sufficiently sized buffer exists, just return. */ - if (new_count <= cur_count) { - SMB_ASSERT(spill_buffer); - return spill_buffer; - } - - /* Allocate the first time. */ - if (cur_count == 0) { - SMB_ASSERT(!spill_buffer); - spill_buffer = talloc_array(NULL, char, new_count); - if (spill_buffer) { - cur_count = new_count; - } - return spill_buffer; - } - - /* A buffer exists, but it's not big enough, so realloc. */ - SMB_ASSERT(spill_buffer); - spill_buffer = talloc_realloc(NULL, spill_buffer, char, new_count); - if (spill_buffer) { - cur_count = new_count; - } - return spill_buffer; -} - -/** - * recvfile does zero-copy writes given an fd to write to, and a socket with - * some data to write. If recvfile read more than it was able to write, it - * spills the data into a buffer. After first reading any additional data - * from the socket into the buffer, the spill buffer is then written with a - * standard pwrite. - */ -ssize_t onefs_sys_recvfile(int fromfd, int tofd, off_t offset, - size_t count) -{ - char *spill_buffer = NULL; - bool socket_drained = false; - int ret; - off_t total_rbytes = 0; - off_t total_wbytes = 0; - off_t rbytes; - off_t wbytes; - - START_PROFILE_BYTES(syscall_recvfile, count); - - DEBUG(10,("onefs_recvfile: from = %d, to = %d, offset=%llu, count = " - "%lu\n", fromfd, tofd, offset, count)); - - if (count == 0) { - END_PROFILE(syscall_recvfile); - return 0; - } - - /* - * Setup up a buffer for recvfile to spill data that has been read - * from the socket but not written. - */ - spill_buffer = get_spill_buffer(count); - if (spill_buffer == NULL) { - ret = -1; - goto out; - } - - /* - * Keep trying recvfile until: - * - There is no data left to read on the socket, or - * - bytes read != bytes written, or - * - An error is returned that isn't EINTR/EAGAIN - */ - do { - /* Keep track of bytes read/written for recvfile */ - rbytes = 0; - wbytes = 0; - - DEBUG(10, ("calling recvfile loop, offset + total_wbytes = " - "%llu, count - total_rbytes = %llu\n", - offset + total_wbytes, count - total_rbytes)); - - ret = recvfile(tofd, fromfd, offset + total_wbytes, - count - total_wbytes, &rbytes, &wbytes, 0, - spill_buffer); - - DEBUG(10, ("recvfile ret = %d, errno = %d, rbytes = %llu, " - "wbytes = %llu\n", ret, ret >= 0 ? 0 : errno, - rbytes, wbytes)); - - /* Update our progress so far */ - total_rbytes += rbytes; - total_wbytes += wbytes; - - } while ((count - total_rbytes) && (rbytes == wbytes) && - (ret == -1 && (errno == EINTR || errno == EAGAIN))); - - DEBUG(10, ("total_rbytes = %llu, total_wbytes = %llu\n", - total_rbytes, total_wbytes)); - - /* Log if recvfile didn't write everything it read. */ - if (total_rbytes != total_wbytes) { - DEBUG(3, ("partial recvfile: total_rbytes=%llu but " - "total_wbytes=%llu, diff = %llu\n", total_rbytes, - total_wbytes, total_rbytes - total_wbytes)); - SMB_ASSERT(total_rbytes > total_wbytes); - } - - /* - * If there is still data on the socket, read it off. - */ - while (total_rbytes < count) { - - DEBUG(3, ("shallow recvfile (%s), reading %llu\n", - strerror(errno), count - total_rbytes)); - - /* - * Read the remaining data into the spill buffer. recvfile - * may already have some data in the spill buffer, so start - * filling the buffer at total_rbytes - total_wbytes. - */ - ret = sys_read(fromfd, - spill_buffer + (total_rbytes - total_wbytes), - count - total_rbytes); - - if (ret <= 0) { - if (ret == 0) { - DEBUG(0, ("shallow recvfile read: EOF\n")); - } else { - DEBUG(0, ("shallow recvfile read failed: %s\n", - strerror(errno))); - } - /* Socket is dead, so treat as if it were drained. */ - socket_drained = true; - goto out; - } - - /* Data was read so update the rbytes */ - total_rbytes += ret; - } - - if (total_rbytes != count) { - smb_panic("Unread recvfile data still on the socket!"); - } - - /* - * Now write any spilled data + the extra data read off the socket. - */ - while (total_wbytes < count) { - - DEBUG(3, ("partial recvfile, writing %llu\n", count - total_wbytes)); - - ret = sys_pwrite(tofd, spill_buffer, count - total_wbytes, - offset + total_wbytes); - - if (ret == -1) { - DEBUG(0, ("partial recvfile write failed: %s\n", - strerror(errno))); - goto out; - } - - /* Data was written so update the wbytes */ - total_wbytes += ret; - } - - /* Success! */ - ret = total_wbytes; - -out: - - END_PROFILE(syscall_recvfile); - - /* Make sure we always try to drain the socket. */ - if (!socket_drained && count - total_rbytes) { - int saved_errno = errno; - - if (drain_socket(fromfd, count - total_rbytes) != - count - total_rbytes) { - /* Socket is dead! */ - DEBUG(0, ("drain socket failed: %d\n", errno)); - } - errno = saved_errno; - } - - return ret; -} - -void init_stat_ex_from_onefs_stat(struct stat_ex *dst, const struct stat *src) -{ - ZERO_STRUCT(*dst); - - dst->st_ex_dev = src->st_dev; - dst->st_ex_ino = src->st_ino; - dst->st_ex_mode = src->st_mode; - dst->st_ex_nlink = src->st_nlink; - dst->st_ex_uid = src->st_uid; - dst->st_ex_gid = src->st_gid; - dst->st_ex_rdev = src->st_rdev; - dst->st_ex_size = src->st_size; - dst->st_ex_atime = src->st_atimespec; - dst->st_ex_mtime = src->st_mtimespec; - dst->st_ex_ctime = src->st_ctimespec; - dst->st_ex_btime = src->st_birthtimespec; - dst->st_ex_blksize = src->st_blksize; - dst->st_ex_blocks = src->st_blocks; - - dst->st_ex_flags = src->st_flags; - - dst->vfs_private = src->st_snapid; -} - -int onefs_sys_stat(const char *fname, SMB_STRUCT_STAT *sbuf) -{ - int ret; - struct stat onefs_sbuf; - - ret = stat(fname, &onefs_sbuf); - - if (ret == 0) { - /* we always want directories to appear zero size */ - if (S_ISDIR(onefs_sbuf.st_mode)) { - onefs_sbuf.st_size = 0; - } - init_stat_ex_from_onefs_stat(sbuf, &onefs_sbuf); - } - return ret; -} - -int onefs_sys_fstat(int fd, SMB_STRUCT_STAT *sbuf) -{ - int ret; - struct stat onefs_sbuf; - - ret = fstat(fd, &onefs_sbuf); - - if (ret == 0) { - /* we always want directories to appear zero size */ - if (S_ISDIR(onefs_sbuf.st_mode)) { - onefs_sbuf.st_size = 0; - } - init_stat_ex_from_onefs_stat(sbuf, &onefs_sbuf); - } - return ret; -} - -int onefs_sys_fstat_at(int base_fd, const char *fname, SMB_STRUCT_STAT *sbuf, - int flags) -{ - int ret; - struct stat onefs_sbuf; - - ret = enc_fstatat(base_fd, fname, ENC_DEFAULT, &onefs_sbuf, flags); - - if (ret == 0) { - /* we always want directories to appear zero size */ - if (S_ISDIR(onefs_sbuf.st_mode)) { - onefs_sbuf.st_size = 0; - } - init_stat_ex_from_onefs_stat(sbuf, &onefs_sbuf); - } - return ret; -} - -int onefs_sys_lstat(const char *fname, SMB_STRUCT_STAT *sbuf) -{ - int ret; - struct stat onefs_sbuf; - - ret = lstat(fname, &onefs_sbuf); - - if (ret == 0) { - /* we always want directories to appear zero size */ - if (S_ISDIR(onefs_sbuf.st_mode)) { - onefs_sbuf.st_size = 0; - } - init_stat_ex_from_onefs_stat(sbuf, &onefs_sbuf); - } - return ret; -} - diff --git a/source3/modules/perfcount_onefs.c b/source3/modules/perfcount_onefs.c deleted file mode 100644 index fcc0620159..0000000000 --- a/source3/modules/perfcount_onefs.c +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Support for OneFS protocol statistics / perfcounters - * - * Copyright (C) Todd Stecher 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 "includes.h" -#include "smbd/smbd.h" -#include <sys/isi_stats_protocol.h> -#include <sys/isi_stats_client.h> -#include <sys/isi_stats_cifs.h> - -extern struct current_user current_user; - -struct onefs_op_counter { - struct isp_op_delta iod; - struct onefs_op_counter *next; - struct onefs_op_counter *prev; -}; - -struct onefs_stats_context { - bool alloced; - struct isp_op_delta iod; - - /* ANDX commands stats stored here */ - struct onefs_op_counter *ops_chain; -}; - -const char *onefs_stat_debug(struct isp_op_delta *iod); - -struct onefs_stats_context g_context; - -static void onefs_smb_statistics_end(struct smb_perfcount_data *pcd); - -struct isp_op_delta *onefs_stats_get_op_delta(struct onefs_stats_context *ctxt) -{ - /* operate on head of chain */ - if (ctxt->ops_chain) { -#ifdef ONEFS_PERF_DEBUG - DEBUG(0,("************* CHAINED *****\n")); -#endif - return &ctxt->ops_chain->iod; - } else - return &ctxt->iod; -} - -/* statistics operations */ -static void onefs_smb_statistics_start(struct smb_perfcount_data *pcd) -{ - -#ifdef ONEFS_PERF_DEBUG - if (g_context.iod.op) { - DEBUG(0,("**************** OP Collision! %s(%d) \n", - onefs_stat_debug(&g_context.iod), g_context.iod.op)); - } - -#endif - - ISP_OP_BEG(&g_context.iod, ISP_PROTO_CIFS, 0); - - if (g_context.iod.enabled) - pcd->context = &g_context; - else - pcd->context = NULL; - - -} - -static void onefs_smb_statistics_add(struct smb_perfcount_data *pcd) -{ - struct onefs_op_counter *oc; - struct onefs_stats_context *ctxt = pcd->context; - - /* not enabled */ - if (pcd->context == NULL) - return; - - oc = SMB_MALLOC_P(struct onefs_op_counter); - - if (oc == NULL) - return; - -#ifdef ONEFS_PERF_DEBUG - DEBUG(0,("*********** add chained op \n")); -#endif - - DLIST_ADD(ctxt->ops_chain, oc); - ISP_OP_BEG(&oc->iod, ISP_PROTO_CIFS, 0); -} - -static void onefs_smb_statistics_set_op(struct smb_perfcount_data *pcd, int op) -{ - struct onefs_stats_context *ctxt = pcd->context; - struct isp_op_delta *iod; - - /* not enabled */ - if (pcd->context == NULL) - return; - - iod = onefs_stats_get_op_delta(ctxt); - iod->op = isp_cifs_op_id(op); - -#ifdef ONEFS_PERF_DEBUG - DEBUG(0,("***********SET op %s(%d)\n", onefs_stat_debug(iod), op)); -#endif - /* no reply required */ - if (op == SMBntcancel) - onefs_smb_statistics_end(pcd); - -} - -static void onefs_smb_statistics_set_subop(struct smb_perfcount_data *pcd, - int subop) -{ - struct onefs_stats_context *ctxt = pcd->context; - struct isp_op_delta *iod; - - /* not enabled */ - if (pcd->context == NULL) - return; - - iod = onefs_stats_get_op_delta(ctxt); - iod->op = isp_cifs_sub_op_id(iod->op, subop); - -#ifdef ONEFS_PERF_DEBUG - DEBUG(0,("******************** SET subop %s(%d)\n", - onefs_stat_debug(iod), subop)); -#endif - - /* - * finalize this one - we don't need to know when it - * is set, but its useful as a counter - */ - if (subop == NT_TRANSACT_NOTIFY_CHANGE) - onefs_smb_statistics_end(pcd); -} - -static void onefs_smb_statistics_set_ioctl(struct smb_perfcount_data *pcd, - int io_ctl) -{ - struct onefs_stats_context *ctxt = pcd->context; - struct isp_op_delta *iod; - - /* not enabled */ - if (pcd->context == NULL) - return; - - /* we only monitor shadow copy */ - if (io_ctl != FSCTL_GET_SHADOW_COPY_DATA) - return; - - iod = onefs_stats_get_op_delta(ctxt); - iod->op = isp_cifs_sub_op_id(iod->op, ISP_CIFS_NTRN_IOCTL_FGSCD); -#ifdef ONEFS_PERF_DEBUG - DEBUG(0,("******************** SET ioctl %s(%d)\n", - onefs_stat_debug(iod), io_ctl)); -#endif -} - -static void onefs_smb_statistics_set_msglen_in(struct smb_perfcount_data *pcd, - uint64_t in_bytes) -{ - struct onefs_stats_context *ctxt = pcd->context; - struct isp_op_delta *iod; - - /* not enabled */ - if (pcd->context == NULL) - return; - - iod = onefs_stats_get_op_delta(ctxt); - iod->in_bytes = in_bytes; -} - -static void onefs_smb_statistics_set_msglen_out(struct smb_perfcount_data *pcd, - uint64_t out_bytes) -{ - struct onefs_stats_context *ctxt = pcd->context; - - /* not enabled */ - if (pcd->context == NULL) - return; - - if (ctxt->ops_chain) - ctxt->ops_chain->iod.out_bytes = out_bytes; - - ctxt->iod.out_bytes = out_bytes; -} - -static int onefs_copy_perfcount_context(struct onefs_stats_context *ctxt, - struct onefs_stats_context **dest) -{ - struct onefs_stats_context *new_ctxt; - - /* make an alloc'd copy of the data */ - new_ctxt = SMB_MALLOC_P(struct onefs_stats_context); - if (!new_ctxt) { - return -1; - } - - memcpy(new_ctxt, ctxt, sizeof(struct onefs_stats_context)); - new_ctxt->alloced = True; - *dest = new_ctxt; - return 0; -} - -static void onefs_smb_statistics_copy_context(struct smb_perfcount_data *pcd, - struct smb_perfcount_data *dest) -{ - struct onefs_stats_context *ctxt = pcd->context; - struct onefs_stats_context *new_ctxt; - int ret; - - /* not enabled */ - if (pcd->context == NULL) - return; - -#ifdef ONEFS_PERF_DEBUG - DEBUG(0,("******** COPYING op %s(%d)\n", - onefs_stat_debug(&ctxt->iod), ctxt->iod.op)); -#endif - - ret = onefs_copy_perfcount_context(ctxt, &new_ctxt); - if (ret) - return; - - /* instrumentation */ - if (ctxt == &g_context) - ZERO_STRUCT(g_context); - - dest->context = new_ctxt; -} - -/* - * For perf reasons, we usually use the global - sometimes, though, - * when an operation is deferred, we need to alloc a copy. - */ -static void onefs_smb_statistics_defer_op(struct smb_perfcount_data *pcd, - struct smb_perfcount_data *def_pcd) -{ - struct onefs_stats_context *ctxt = pcd->context; - struct onefs_stats_context *deferred_ctxt; - int ret; - - /* not enabled */ - if (pcd->context == NULL) - return; - - /* already allocated ? */ - if (ctxt->alloced) - { - def_pcd->context = ctxt; - pcd->context = NULL; - return; - } - -#ifdef ONEFS_PERF_DEBUG - DEBUG(0,("******** DEFERRING op %s(%d)\n", - onefs_stat_debug(&ctxt->iod), ctxt->iod.op)); -#endif - - ret = onefs_copy_perfcount_context(ctxt, &deferred_ctxt); - if (ret) - return; - - def_pcd->context = (void*) deferred_ctxt; - - /* instrumentation */ - if (ctxt == &g_context) - ZERO_STRUCT(g_context); - - if (pcd != def_pcd) - pcd->context = NULL; -} - -static void onefs_smb_statistics_end(struct smb_perfcount_data *pcd) -{ - struct onefs_stats_context *ctxt = pcd->context; - struct onefs_op_counter *tmp; - uint64_t uid; - - static in_addr_t rem_addr = 0; - static in_addr_t loc_addr = 0; - - /* not enabled */ - if (pcd->context == NULL) - return; - - uid = current_user.ut.uid ? current_user.ut.uid : ISC_UNKNOWN_CLIENT_ID; - - /* get address info once, doesn't change for process */ - if (rem_addr == 0) { - -#error Isilon, please remove this after testing the code below - - char *addr; - - addr = talloc_sub_basic(talloc_tos(), "", "", "%I"); - if (addr != NULL) { - rem_addr = interpret_addr(addr); - TALLOC_FREE(addr); - } else { - rem_addr = ISC_MASKED_ADDR; - } - - addr = talloc_sub_basic(talloc_tos(), "", "", "%i"); - if (addr != NULL) { - loc_addr = interpret_addr(addr); - TALLOC_FREE(addr); - } else { - loc_addr = ISC_MASKED_ADDR; - } - } - - /* - * bug here - we aren't getting the outlens right, - * when dealing w/ chained requests. - */ - for (tmp = ctxt->ops_chain; tmp; tmp = tmp->next) { - tmp->iod.out_bytes = ctxt->iod.out_bytes; - isc_cookie_init(&tmp->iod.cookie, rem_addr, loc_addr, uid); - ISP_OP_END(&tmp->iod); -#ifdef ONEFS_PERF_DEBUG - DEBUG(0,("******** Finalized CHAIN op %s uid %llu in:%llu" - ", out:%llu\n", - onefs_stat_debug(&tmp->iod), uid, - tmp->iod.in_bytes, tmp->iod.out_bytes)); -#endif - SAFE_FREE(DLIST_PREV(tmp)); - } - - isc_cookie_init(&ctxt->iod.cookie, rem_addr, loc_addr, uid); - ISP_OP_END(&ctxt->iod); -#ifdef ONEFS_PERF_DEBUG - DEBUG(0,("******** Finalized op %s uid %llu in:%llu, out:%llu\n", - onefs_stat_debug(&ctxt->iod), uid, - ctxt->iod.in_bytes, ctxt->iod.out_bytes)); -#endif - - if (ctxt->alloced) - SAFE_FREE(ctxt); - else - ZERO_STRUCTP(ctxt); - - pcd->context = NULL; -} - - -static struct smb_perfcount_handlers onefs_pc_handlers = { - onefs_smb_statistics_start, - onefs_smb_statistics_add, - onefs_smb_statistics_set_op, - onefs_smb_statistics_set_subop, - onefs_smb_statistics_set_ioctl, - onefs_smb_statistics_set_msglen_in, - onefs_smb_statistics_set_msglen_out, - onefs_smb_statistics_copy_context, - onefs_smb_statistics_defer_op, - onefs_smb_statistics_end -}; - -NTSTATUS perfcount_onefs_init(void) -{ - return smb_register_perfcounter(SMB_PERFCOUNTER_INTERFACE_VERSION, - "pc_onefs", &onefs_pc_handlers); -} - -#ifdef ONEFS_PERF_DEBUG -/* debug helper */ -struct op_debug { - int type; - const char *name; -}; - -struct op_debug op_debug_table[] = { - { 0x00, "mkdir"}, { 0x01, "rmdir"}, { 0x02, "open"}, { 0x03, "create"}, - { 0x04, "close"}, { 0x05, "flush"}, { 0x06, "unlink"}, { 0x07, "mv"}, - { 0x08, "getatr"}, { 0x09, "setatr"}, { 0x0a, "read"}, { 0x0b, "write"}, - { 0x0c, "lock"}, { 0x0d, "unlock"}, { 0x0e, "ctemp"}, { 0x0f, "mknew"}, - { 0x10, "chkpth"}, { 0x11, "exit"}, { 0x12, "lseek"}, { 0x13, "lockread"}, - { 0x14, "writeunlock"}, { 0x1a, "readbraw"}, { 0x1b, "readbmpx"}, - { 0x1c, "readbs"}, { 0x1d, "writebraw"}, { 0x1e, "writebmpx"}, - { 0x1f, "writebs"}, { 0x20, "writec"}, { 0x22, "setattre"}, - { 0x23, "getattre"}, { 0x24, "lockingx"}, { 0x25, "trans"}, - { 0x26, "transs"}, { 0x27, "ioctl"}, { 0x28, "ioctls"}, { 0x29, "copy"}, - { 0x2a, "move"}, { 0x2b, "echo"}, { 0x2c, "writeclose"}, { 0x2d, "openx"}, - { 0x2e, "readx"}, { 0x2f, "writex"}, { 0x34, "findclose"}, - { 0x35, "findnclose"}, { 0x70, "tcon"}, { 0x71, "tdis"}, - { 0x72, "negprot"}, { 0x73, "sesssetupx"}, { 0x74, "ulogoffx"}, - { 0x75, "tconx"}, { 0x80, "dskattr"}, { 0x81, "search"}, - { 0x82, "ffirst"}, { 0x83, "funique"}, { 0x84, "fclose"}, - { 0x400, "nttrans"},{ 0x500, "nttranss"}, - { 0xa2, "ntcreatex"}, { 0xa4, "ntcancel"}, { 0xa5, "ntrename"}, - { 0xc0, "splopen"}, { 0xc1, "splwr"}, { 0xc2, "splclose"}, - { 0xc3, "splretq"}, { 0xd0, "sends"}, { 0xd1, "sendb"}, - { 0xd2, "fwdname"}, { 0xd3, "cancelf"}, { 0xd4, "getmac"}, - { 0xd5, "sendstrt"}, { 0xd6, "sendend"}, { 0xd7, "sendtxt"}, - { ISP_CIFS_INVALID_OP, "unknown"}, - { ISP_CIFS_TRNS2 + 0x00, "trans2:open"}, - { ISP_CIFS_TRNS2 + 0x01, "trans2:findfirst"}, - { ISP_CIFS_TRNS2 + 0x02, "trans2:findnext"}, - { ISP_CIFS_TRNS2 + 0x03, "trans2:qfsinfo"}, - { ISP_CIFS_TRNS2 + 0x04, "trans2:setfsinfo"}, - { ISP_CIFS_TRNS2 + 0x05, "trans2:qpathinfo"}, - { ISP_CIFS_TRNS2 + 0x06, "trans2:setpathinfo"}, - { ISP_CIFS_TRNS2 + 0x07, "trans2:qfileinfo"}, - { ISP_CIFS_TRNS2 + 0x08, "trans2:setfileinfo"}, - { ISP_CIFS_TRNS2 + 0x0a, "trans2:ioctl"}, - { ISP_CIFS_TRNS2 + 0x0b, "trans2:findnotifyfirst"}, - { ISP_CIFS_TRNS2 + 0x0c, "trans2:findnotifynext"}, - { ISP_CIFS_TRNS2 + 0x0d, "trans2:mkdir"}, - { ISP_CIFS_TRNS2 + 0x10, "trans2:get_dfs_ref"}, - { ISP_CIFS_TRNS2 + ISP_CIFS_SUBOP_UNKNOWN, "trans2:unknown"}, - { ISP_CIFS_TRNSS2 +0x00, "transs2:open"}, - { ISP_CIFS_TRNSS2 +0x01, "transs2:findfirst"}, - { ISP_CIFS_TRNSS2 +0x02, "transs2:findnext"}, - { ISP_CIFS_TRNSS2 +0x03, "transs2:qfsinfo"}, - { ISP_CIFS_TRNSS2 +0x04, "transs2:setfsinfo"}, - { ISP_CIFS_TRNSS2 +0x05, "transs2:qpathinfo"}, - { ISP_CIFS_TRNSS2 +0x06, "transs2:setpathinfo"}, - { ISP_CIFS_TRNSS2 +0x07, "transs2:qfileinfo"}, - { ISP_CIFS_TRNSS2 +0x08, "transs2:setfileinfo"}, - { ISP_CIFS_TRNSS2 +0x0a, "transs2:ioctl"}, - { ISP_CIFS_TRNSS2 +0x0b, "transs2:findnotifyfirst"}, - { ISP_CIFS_TRNSS2 +0x0c, "transs2:findnotifynext"}, - { ISP_CIFS_TRNSS2 +0x0d, "transs2:mkdir"}, - { ISP_CIFS_TRNSS2 +0x10, "transs2:get_dfs_referral"}, - { ISP_CIFS_TRNSS2 + ISP_CIFS_SUBOP_UNKNOWN, "transs2:unknown"}, - { ISP_CIFS_NTRNS + 0x1, "nttrans:create"}, - { ISP_CIFS_NTRNS + 0x2, "nttrans:ioctl"}, - { ISP_CIFS_NTRNS + 0x3, "nttrans:set_security_desc"}, - { ISP_CIFS_NTRNS + 0x4, "nttrans:notify_change"}, - { ISP_CIFS_NTRNS + 0x5, "nttrans:rename"}, - { ISP_CIFS_NTRNS + 0x6, "nttrans:qry_security_desc"}, - { ISP_CIFS_NTRNS + 0x7, "nttrans:get_user_quota"}, - { ISP_CIFS_NTRNS + 0x8, "nttrans:set_user_quota"}, - { ISP_CIFS_NTRNS + ISP_CIFS_NTRN_IOCTL_FGSCD, - "nttrans:ioctl:get_shadow_copy_data"}, - { ISP_CIFS_NTRNS + ISP_CIFS_SUBOP_UNKNOWN, - "nttrans:unknown"}, - { ISP_CIFS_NTRNSS + 0x1, "nttranss:create"}, - { ISP_CIFS_NTRNSS + 0x2, "nttranss:ioctl"}, - { ISP_CIFS_NTRNSS + 0x3, "nttranss:set_security_desc"}, - { ISP_CIFS_NTRNSS + 0x4, "nttranss:notify_change"}, - { ISP_CIFS_NTRNSS + 0x5, "nttranss:rename"}, - { ISP_CIFS_NTRNSS + 0x6, "nttranss:qry_security_desc"}, - { ISP_CIFS_NTRNSS + 0x7, "nttranss:get_user_quota"}, - { ISP_CIFS_NTRNSS + 0x8, "nttranss:set_user_quota"}, - { ISP_CIFS_NTRNSS + ISP_CIFS_NTRN_IOCTL_FGSCD, - "nttranss:ioctl:get_shadow_copy_data"}, - { ISP_CIFS_NTRNSS + ISP_CIFS_SUBOP_UNKNOWN, - "nttranss:unknown"}, -}; - -int op_debug_table_count = sizeof(op_debug_table) / sizeof(op_debug_table[0]); - -const char *onefs_stat_debug(struct isp_op_delta *iod) -{ - int i; - const char *unk = "unknown"; - for (i=0; i < op_debug_table_count;i++) { - if (iod->op == op_debug_table[i].type) - return op_debug_table[i].name; - } - - return unk; -} -#endif diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c deleted file mode 100644 index 619e3874a3..0000000000 --- a/source3/modules/vfs_onefs.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * Support for OneFS - * - * 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 "includes.h" -#include "smbd/smbd.h" -#include "onefs.h" -#include "onefs_config.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_VFS - -static int onefs_connect(struct vfs_handle_struct *handle, const char *service, - const char *user) -{ - int ret = SMB_VFS_NEXT_CONNECT(handle, service, user); - - if (ret < 0) { - return ret; - } - - ret = onefs_load_config(handle->conn); - if (ret) { - SMB_VFS_NEXT_DISCONNECT(handle); - DEBUG(3, ("Load config failed: %s\n", strerror(errno))); - return ret; - } - - return 0; -} - -static int onefs_mkdir(vfs_handle_struct *handle, const char *path, - mode_t mode) -{ - /* SMB_VFS_MKDIR should never be called in vfs_onefs */ - SMB_ASSERT(false); - return SMB_VFS_NEXT_MKDIR(handle, path, mode); -} - -static int onefs_open(vfs_handle_struct *handle, - struct smb_filename *smb_fname, - files_struct *fsp, int flags, mode_t mode) -{ - /* SMB_VFS_OPEN should never be called in vfs_onefs */ - SMB_ASSERT(false); - return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode); -} - -static ssize_t onefs_sendfile(vfs_handle_struct *handle, int tofd, - files_struct *fromfsp, const DATA_BLOB *header, - off_t offset, size_t count) -{ - ssize_t result; - - START_PROFILE_BYTES(syscall_sendfile, count); - result = onefs_sys_sendfile(handle->conn, tofd, fromfsp->fh->fd, - header, offset, count); - END_PROFILE(syscall_sendfile); - return result; -} - -static ssize_t onefs_recvfile(vfs_handle_struct *handle, int fromfd, - files_struct *tofsp, off_t offset, - size_t count) -{ - ssize_t result; - - START_PROFILE_BYTES(syscall_recvfile, count); - result = onefs_sys_recvfile(fromfd, tofsp->fh->fd, offset, count); - END_PROFILE(syscall_recvfile); - return result; -} - -static uint64_t onefs_get_alloc_size(struct vfs_handle_struct *handle, - files_struct *fsp, - const SMB_STRUCT_STAT *sbuf) -{ - uint64_t result; - - START_PROFILE(syscall_get_alloc_size); - - if(S_ISDIR(sbuf->st_ex_mode)) { - result = 0; - goto out; - } - - /* Just use the file size since st_blocks is unreliable on OneFS. */ - result = get_file_size_stat(sbuf); - - if (fsp && fsp->initial_allocation_size) - result = MAX(result,fsp->initial_allocation_size); - - result = smb_roundup(handle->conn, result); - - out: - END_PROFILE(syscall_get_alloc_size); - return result; -} - -static struct file_id onefs_file_id_create(struct vfs_handle_struct *handle, - const SMB_STRUCT_STAT *sbuf) -{ - struct file_id key; - - /* the ZERO_STRUCT ensures padding doesn't break using the key as a - * blob */ - ZERO_STRUCT(key); - - key.devid = sbuf->st_ex_dev; - key.inode = sbuf->st_ex_ino; - key.extid = sbuf->vfs_private; - - return key; -} - -static int onefs_statvfs(vfs_handle_struct *handle, const char *path, - vfs_statvfs_struct *statbuf) -{ - struct statvfs statvfs_buf; - int result; - - DEBUG(5, ("Calling SMB_STAT_VFS \n")); - result = statvfs(path, &statvfs_buf); - ZERO_STRUCTP(statbuf); - - if (!result) { - statbuf->OptimalTransferSize = statvfs_buf.f_iosize; - statbuf->BlockSize = statvfs_buf.f_bsize; - statbuf->TotalBlocks = statvfs_buf.f_blocks; - statbuf->BlocksAvail = statvfs_buf.f_bfree; - statbuf->UserBlocksAvail = statvfs_buf.f_bavail; - statbuf->TotalFileNodes = statvfs_buf.f_files; - statbuf->FreeFileNodes = statvfs_buf.f_ffree; - statbuf->FsIdentifier = - (((uint64_t)statvfs_buf.f_fsid.val[0]<<32) & - 0xffffffff00000000LL) | - (uint64_t)statvfs_buf.f_fsid.val[1]; - } - return result; -} - -static int onefs_get_real_filename(vfs_handle_struct *handle, const char *path, - const char *name, TALLOC_CTX *mem_ctx, - char **found_name) -{ - struct stat sb; - struct connection_struct *conn = handle->conn; - struct stat_extra se; - int result; - char *unmangled_name = NULL; - char *full_name = NULL; - - /* First demangle the name if necessary. */ - if (!conn->case_sensitive && mangle_is_mangled(name, conn->params) && - mangle_lookup_name_from_8_3(mem_ctx, name, &unmangled_name, - conn->params)) { - /* Name is now unmangled. */ - name = unmangled_name; - } - - /* Do the case insensitive stat. */ - ZERO_STRUCT(se); - se.se_version = ESTAT_CURRENT_VERSION; - se.se_flags = ESTAT_CASE_INSENSITIVE | ESTAT_SYMLINK_NOFOLLOW; - - if (*path != '\0') { - if (!(full_name = talloc_asprintf(mem_ctx, "%s/%s", path, name))) { - errno = ENOMEM; - DEBUG(2, ("talloc_asprintf failed\n")); - result = -1; - goto done; - } - } - - if ((result = estat(full_name ? full_name : name, &sb, &se)) != 0) { - DEBUG(2, ("error calling estat: %s\n", strerror(errno))); - goto done; - } - - *found_name = talloc_strdup(mem_ctx, se.se_realname); - if (*found_name == NULL) { - errno = ENOMEM; - result = -1; - goto done; - } - -done: - TALLOC_FREE(full_name); - TALLOC_FREE(unmangled_name); - return result; -} - -static int onefs_ntimes(vfs_handle_struct *handle, - const struct smb_filename *smb_fname, - struct smb_file_time *ft) -{ - int flags = 0; - struct timespec times[3]; - - if (!null_timespec(ft->atime)) { - flags |= VT_ATIME; - times[0] = ft->atime; - DEBUG(6,("**** onefs_ntimes: actime: %s.%d\n", - time_to_asc(convert_timespec_to_time_t(ft->atime)), - ft->atime.tv_nsec)); - } - - if (!null_timespec(ft->mtime)) { - flags |= VT_MTIME; - times[1] = ft->mtime; - DEBUG(6,("**** onefs_ntimes: modtime: %s.%d\n", - time_to_asc(convert_timespec_to_time_t(ft->mtime)), - ft->mtime.tv_nsec)); - } - - if (!null_timespec(ft->create_time)) { - flags |= VT_BTIME; - times[2] = ft->create_time; - DEBUG(6,("**** onefs_ntimes: createtime: %s.%d\n", - time_to_asc(convert_timespec_to_time_t(ft->create_time)), - ft->create_time.tv_nsec)); - } - - return onefs_vtimes_streams(handle, smb_fname, flags, times); -} - -static uint32_t onefs_fs_capabilities(struct vfs_handle_struct *handle, enum timestamp_set_resolution *p_ts_res) -{ - uint32_t result = 0; - - if (!lp_parm_bool(SNUM(handle->conn), PARM_ONEFS_TYPE, - PARM_IGNORE_STREAMS, PARM_IGNORE_STREAMS_DEFAULT)) { - result |= FILE_NAMED_STREAMS; - } - - result |= SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res); - *p_ts_res = TIMESTAMP_SET_MSEC; - return result; -} - -static struct vfs_fn_pointers onefs_fns = { - .connect_fn = onefs_connect, - .fs_capabilities_fn = onefs_fs_capabilities, - .opendir_fn = onefs_opendir, - .readdir_fn = onefs_readdir, - .seekdir_fn = onefs_seekdir, - .telldir_fn = onefs_telldir, - .rewind_dir_fn = onefs_rewinddir, - .mkdir_fn = onefs_mkdir, - .closedir_fn = onefs_closedir, - .init_search_op_fn = onefs_init_search_op, - .open_fn = onefs_open, - .create_file_fn = onefs_create_file, - .close_fn = onefs_close, - .sendfile_fn = onefs_sendfile, - .recvfile_fn = onefs_recvfile, - .rename_fn = onefs_rename, - .stat_fn = onefs_stat, - .fstat_fn = onefs_fstat, - .lstat_fn = onefs_lstat, - .get_alloc_size_fn = onefs_get_alloc_size, - .unlink_fn = onefs_unlink, - .ntimes_fn = onefs_ntimes, - .file_id_create_fn = onefs_file_id_create, - .streaminfo_fn = onefs_streaminfo, - .brl_lock_windows_fn = onefs_brl_lock_windows, - .brl_unlock_windows_fn = onefs_brl_unlock_windows, - .brl_cancel_windows_fn = onefs_brl_cancel_windows, - .strict_lock_fn = onefs_strict_lock, - .strict_unlock_fn = onefs_strict_unlock, - .notify_watch_fn = onefs_notify_watch, - .fget_nt_acl_fn = onefs_fget_nt_acl, - .get_nt_acl_fn = onefs_get_nt_acl, - .fset_nt_acl_fn = onefs_fset_nt_acl, - .statvfs_fn = onefs_statvfs, - .get_real_filename_fn = onefs_get_real_filename, -}; - -NTSTATUS vfs_onefs_init(void) -{ - return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "onefs", - &onefs_fns); -} diff --git a/source3/modules/vfs_onefs_shadow_copy.c b/source3/modules/vfs_onefs_shadow_copy.c deleted file mode 100644 index ac61852d3d..0000000000 --- a/source3/modules/vfs_onefs_shadow_copy.c +++ /dev/null @@ -1,685 +0,0 @@ -/* - * OneFS shadow copy implementation that utilizes the file system's native - * snapshot support. This is based on the original shadow copy module from - * 2004. - * - * Copyright (C) Stefan Metzmacher 2003-2004 - * Copyright (C) Tim Prouty 2009 - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "includes.h" -#include "smbd/smbd.h" -#include "onefs_shadow_copy.h" - -static int vfs_onefs_shadow_copy_debug_level = DBGC_VFS; - -#undef DBGC_CLASS -#define DBGC_CLASS vfs_onefs_shadow_copy_debug_level - -#define SHADOW_COPY_PREFIX "@GMT-" -#define SHADOW_COPY_SAMPLE "@GMT-2004.02.18-15.44.00" - -bool -shadow_copy_match_name(const char *name, char **snap_component) -{ - uint32 i = 0; - char delim[] = SHADOW_COPY_PREFIX; - char* start; - - start = strstr( name, delim ); - - /* - * The name could have SHADOW_COPY_PREFIX in it so we need to keep - * trying until we get something that is the full length of the - * SHADOW_COPY_SAMPLE. - */ - while (start != NULL) { - - DEBUG(10,("Processing %s\n", name)); - - /* size / correctness check */ - *snap_component = start; - for ( i = sizeof(SHADOW_COPY_PREFIX); - i < sizeof(SHADOW_COPY_SAMPLE); i++) { - if (start[i] == '/') { - if (i == sizeof(SHADOW_COPY_SAMPLE) - 1) - return true; - else - break; - } else if (start[i] == '\0') - return (i == sizeof(SHADOW_COPY_SAMPLE) - 1); - } - - start = strstr( start, delim ); - } - - return false; -} - -static int -onefs_shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle, - files_struct *fsp, - SHADOW_COPY_DATA *shadow_copy_data, - bool labels) -{ - void *p = osc_version_opendir(); - char *snap_component = NULL; - shadow_copy_data->num_volumes = 0; - shadow_copy_data->labels = NULL; - - if (!p) { - DEBUG(0, ("shadow_copy_get_shadow_copy_data: osc_opendir() " - "failed for [%s]\n",fsp->conn->connectpath)); - return -1; - } - - while (true) { - SHADOW_COPY_LABEL *tlabels; - char *d; - - d = osc_version_readdir(p); - if (d == NULL) - break; - - if (!shadow_copy_match_name(d, &snap_component)) { - DEBUG(10,("shadow_copy_get_shadow_copy_data: ignore " - "[%s]\n",d)); - continue; - } - - DEBUG(7,("shadow_copy_get_shadow_copy_data: not ignore " - "[%s]\n",d)); - - if (!labels) { - shadow_copy_data->num_volumes++; - continue; - } - - tlabels = (SHADOW_COPY_LABEL *)TALLOC_REALLOC( - shadow_copy_data->mem_ctx, - shadow_copy_data->labels, - (shadow_copy_data->num_volumes+1) * - sizeof(SHADOW_COPY_LABEL)); - - if (tlabels == NULL) { - DEBUG(0,("shadow_copy_get_shadow_copy_data: Out of " - "memory\n")); - osc_version_closedir(p); - return -1; - } - - snprintf(tlabels[shadow_copy_data->num_volumes++], - sizeof(*tlabels), "%s",d); - - shadow_copy_data->labels = tlabels; - } - - osc_version_closedir(p); - - return 0; -} - -#define SHADOW_NEXT(op, args, rtype) do { \ - char *cpath = NULL; \ - char *snap_component = NULL; \ - rtype ret; \ - if (shadow_copy_match_name(path, &snap_component)) \ - cpath = osc_canonicalize_path(path, snap_component); \ - ret = SMB_VFS_NEXT_ ## op args; \ - SAFE_FREE(cpath); \ - return ret; \ - } while (0) \ - -/* - * XXX: Convert osc_canonicalize_path to use talloc instead of malloc. - */ -#define SHADOW_NEXT_SMB_FNAME(op, args, rtype) do { \ - char *smb_base_name_tmp = NULL; \ - char *cpath = NULL; \ - char *snap_component = NULL; \ - rtype ret; \ - smb_base_name_tmp = smb_fname->base_name; \ - if (shadow_copy_match_name(smb_fname->base_name, \ - &snap_component)) { \ - cpath = osc_canonicalize_path(smb_fname->base_name, \ - snap_component); \ - smb_fname->base_name = cpath; \ - } \ - ret = SMB_VFS_NEXT_ ## op args; \ - smb_fname->base_name = smb_base_name_tmp; \ - SAFE_FREE(cpath); \ - return ret; \ - } while (0) \ - -static uint64_t -onefs_shadow_copy_disk_free(vfs_handle_struct *handle, const char *path, - bool small_query, uint64_t *bsize, uint64_t *dfree, - uint64_t *dsize) -{ - - SHADOW_NEXT(DISK_FREE, - (handle, cpath ?: path, small_query, bsize, dfree, dsize), - uint64_t); - -} - -static int -onefs_shadow_copy_statvfs(struct vfs_handle_struct *handle, const char *path, - struct vfs_statvfs_struct *statbuf) -{ - SHADOW_NEXT(STATVFS, - (handle, cpath ?: path, statbuf), - int); -} - -static DIR * -onefs_shadow_copy_opendir(vfs_handle_struct *handle, const char *path, - const char *mask, uint32_t attr) -{ - SHADOW_NEXT(OPENDIR, - (handle, cpath ?: path, mask, attr), - DIR *); -} - -static int -onefs_shadow_copy_mkdir(vfs_handle_struct *handle, const char *path, - mode_t mode) -{ - SHADOW_NEXT(MKDIR, - (handle, cpath ?: path, mode), - int); -} - -static int -onefs_shadow_copy_rmdir(vfs_handle_struct *handle, const char *path) -{ - SHADOW_NEXT(RMDIR, - (handle, cpath ?: path), - int); -} - -static int -onefs_shadow_copy_open(vfs_handle_struct *handle, - struct smb_filename *smb_fname, files_struct *fsp, - int flags, mode_t mode) -{ - SHADOW_NEXT_SMB_FNAME(OPEN, - (handle, smb_fname, fsp, flags, mode), - int); -} - -static NTSTATUS -onefs_shadow_copy_create_file(vfs_handle_struct *handle, - struct smb_request *req, - uint16_t root_dir_fid, - struct smb_filename *smb_fname, - uint32_t access_mask, - uint32_t share_access, - uint32_t create_disposition, - uint32_t create_options, - uint32_t file_attributes, - uint32_t oplock_request, - uint64_t allocation_size, - uint32_t private_flags, - struct security_descriptor *sd, - struct ea_list *ea_list, - files_struct **result, - int *pinfo) -{ - SHADOW_NEXT_SMB_FNAME(CREATE_FILE, - (handle, req, root_dir_fid, smb_fname, - access_mask, share_access, - create_disposition, create_options, - file_attributes, oplock_request, - allocation_size, private_flags, - sd, ea_list, result, pinfo), - NTSTATUS); -} - -/** - * XXX: macro-ize - */ -static int -onefs_shadow_copy_rename(vfs_handle_struct *handle, - const struct smb_filename *smb_fname_src, - const struct smb_filename *smb_fname_dst) -{ - char *old_cpath = NULL; - char *old_snap_component = NULL; - char *new_cpath = NULL; - char *new_snap_component = NULL; - struct smb_filename *smb_fname_src_tmp = NULL; - struct smb_filename *smb_fname_dst_tmp = NULL; - NTSTATUS status; - int ret = -1; - - status = copy_smb_filename(talloc_tos(), smb_fname_src, - &smb_fname_src_tmp); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - goto out; - } - status = copy_smb_filename(talloc_tos(), smb_fname_dst, - &smb_fname_dst_tmp); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - goto out; - } - - if (shadow_copy_match_name(smb_fname_src_tmp->base_name, - &old_snap_component)) { - old_cpath = osc_canonicalize_path(smb_fname_src_tmp->base_name, - old_snap_component); - smb_fname_src_tmp->base_name = old_cpath; - } - - if (shadow_copy_match_name(smb_fname_dst_tmp->base_name, - &new_snap_component)) { - new_cpath = osc_canonicalize_path(smb_fname_dst_tmp->base_name, - new_snap_component); - smb_fname_dst_tmp->base_name = new_cpath; - } - - ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src_tmp, - smb_fname_dst_tmp); - - out: - SAFE_FREE(old_cpath); - SAFE_FREE(new_cpath); - TALLOC_FREE(smb_fname_src_tmp); - TALLOC_FREE(smb_fname_dst_tmp); - - return ret; -} - -static int -onefs_shadow_copy_stat(vfs_handle_struct *handle, - struct smb_filename *smb_fname) -{ - SHADOW_NEXT_SMB_FNAME(STAT, - (handle, smb_fname), - int); -} - -static int -onefs_shadow_copy_lstat(vfs_handle_struct *handle, - struct smb_filename *smb_fname) -{ - SHADOW_NEXT_SMB_FNAME(LSTAT, - (handle, smb_fname), - int); -} - -static int -onefs_shadow_copy_unlink(vfs_handle_struct *handle, - const struct smb_filename *smb_fname_in) -{ - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - - status = copy_smb_filename(talloc_tos(), smb_fname_in, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return -1; - } - - SHADOW_NEXT_SMB_FNAME(UNLINK, - (handle, smb_fname), - int); -} - -static int -onefs_shadow_copy_chmod(vfs_handle_struct *handle, const char *path, - mode_t mode) -{ - SHADOW_NEXT(CHMOD, - (handle, cpath ?: path, mode), - int); -} - -static int -onefs_shadow_copy_chown(vfs_handle_struct *handle, const char *path, - uid_t uid, gid_t gid) -{ - SHADOW_NEXT(CHOWN, - (handle, cpath ?: path, uid, gid), - int); -} - -static int -onefs_shadow_copy_lchown(vfs_handle_struct *handle, const char *path, - uid_t uid, gid_t gid) -{ - SHADOW_NEXT(LCHOWN, - (handle, cpath ?: path, uid, gid), - int); -} - -static int -onefs_shadow_copy_chdir(vfs_handle_struct *handle, const char *path) -{ - SHADOW_NEXT(CHDIR, - (handle, cpath ?: path), - int); -} - -static int -onefs_shadow_copy_ntimes(vfs_handle_struct *handle, - const struct smb_filename *smb_fname_in, - struct smb_file_time *ft) -{ - struct smb_filename *smb_fname = NULL; - NTSTATUS status; - - status = copy_smb_filename(talloc_tos(), smb_fname_in, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - errno = map_errno_from_nt_status(status); - return -1; - } - - SHADOW_NEXT_SMB_FNAME(NTIMES, - (handle, smb_fname, ft), - int); - -} - -/** - * XXX: macro-ize - */ -static int -onefs_shadow_copy_symlink(vfs_handle_struct *handle, - const char *oldpath, const char *newpath) -{ - char *old_cpath = NULL; - char *old_snap_component = NULL; - char *new_cpath = NULL; - char *new_snap_component = NULL; - bool ret; - - if (shadow_copy_match_name(oldpath, &old_snap_component)) - old_cpath = osc_canonicalize_path(oldpath, old_snap_component); - - if (shadow_copy_match_name(newpath, &new_snap_component)) - new_cpath = osc_canonicalize_path(newpath, new_snap_component); - - ret = SMB_VFS_NEXT_SYMLINK(handle, old_cpath ?: oldpath, - new_cpath ?: newpath); - - SAFE_FREE(old_cpath); - SAFE_FREE(new_cpath); - - return ret; -} - -static int -onefs_shadow_copy_readlink(vfs_handle_struct *handle, const char *path, - char *buf, size_t bufsiz) -{ - SHADOW_NEXT(READLINK, - (handle, cpath ?: path, buf, bufsiz), - int); -} - -/** - * XXX: macro-ize - */ -static int -onefs_shadow_copy_link(vfs_handle_struct *handle, const char *oldpath, - const char *newpath) -{ - char *old_cpath = NULL; - char *old_snap_component = NULL; - char *new_cpath = NULL; - char *new_snap_component = NULL; - int ret; - - if (shadow_copy_match_name(oldpath, &old_snap_component)) - old_cpath = osc_canonicalize_path(oldpath, old_snap_component); - - if (shadow_copy_match_name(newpath, &new_snap_component)) - new_cpath = osc_canonicalize_path(newpath, new_snap_component); - - ret = SMB_VFS_NEXT_LINK(handle, old_cpath ?: oldpath, - new_cpath ?: newpath); - - SAFE_FREE(old_cpath); - SAFE_FREE(new_cpath); - - return ret; -} - -static int -onefs_shadow_copy_mknod(vfs_handle_struct *handle, const char *path, - mode_t mode, SMB_DEV_T dev) -{ - SHADOW_NEXT(MKNOD, - (handle, cpath ?: path, mode, dev), - int); -} - -static char * -onefs_shadow_copy_realpath(vfs_handle_struct *handle, const char *path) -{ - SHADOW_NEXT(REALPATH, - (handle, cpath ?: path), - char *); -} - -static int onefs_shadow_copy_chflags(struct vfs_handle_struct *handle, - const char *path, unsigned int flags) -{ - SHADOW_NEXT(CHFLAGS, - (handle, cpath ?: path, flags), - int); -} - -static NTSTATUS -onefs_shadow_copy_streaminfo(struct vfs_handle_struct *handle, - struct files_struct *fsp, - const char *path, - TALLOC_CTX *mem_ctx, - unsigned int *num_streams, - struct stream_struct **streams) -{ - SHADOW_NEXT(STREAMINFO, - (handle, fsp, cpath ?: path, mem_ctx, num_streams, - streams), - NTSTATUS); -} - -static int -onefs_shadow_copy_get_real_filename(struct vfs_handle_struct *handle, - const char *full_path, - const char *path, - TALLOC_CTX *mem_ctx, - char **found_name) -{ - SHADOW_NEXT(GET_REAL_FILENAME, - (handle, full_path, cpath ?: path, mem_ctx, found_name), - int); -} - -static NTSTATUS -onefs_shadow_copy_get_nt_acl(struct vfs_handle_struct *handle, - const char *path, uint32 security_info, - struct security_descriptor **ppdesc) -{ - SHADOW_NEXT(GET_NT_ACL, - (handle, cpath ?: path, security_info, ppdesc), - NTSTATUS); -} - -static int -onefs_shadow_copy_chmod_acl(vfs_handle_struct *handle, const char *path, - mode_t mode) -{ - SHADOW_NEXT(CHMOD_ACL, - (handle, cpath ?: path, mode), - int); -} - -static SMB_ACL_T -onefs_shadow_copy_sys_acl_get_file(vfs_handle_struct *handle, - const char *path, SMB_ACL_TYPE_T type) -{ - SHADOW_NEXT(SYS_ACL_GET_FILE, - (handle, cpath ?: path, type), - SMB_ACL_T); -} - -static int -onefs_shadow_copy_sys_acl_set_file(vfs_handle_struct *handle, const char *path, - SMB_ACL_TYPE_T type, SMB_ACL_T theacl) -{ - SHADOW_NEXT(SYS_ACL_SET_FILE, - (handle, cpath ?: path, type, theacl), - int); -} - -static int -onefs_shadow_copy_sys_acl_delete_def_file(vfs_handle_struct *handle, - const char *path) -{ - SHADOW_NEXT(SYS_ACL_DELETE_DEF_FILE, - (handle, cpath ?: path), - int); -} - -static ssize_t -onefs_shadow_copy_getxattr(vfs_handle_struct *handle, const char *path, - const char *name, void *value, size_t size) -{ - SHADOW_NEXT(GETXATTR, - (handle, cpath ?: path, name, value, size), - ssize_t); -} - -static ssize_t -onefs_shadow_copy_listxattr(vfs_handle_struct *handle, const char *path, - char *list, size_t size) -{ - SHADOW_NEXT(LISTXATTR, - (handle, cpath ?: path, list, size), - ssize_t); -} - -static int -onefs_shadow_copy_removexattr(vfs_handle_struct *handle, const char *path, - const char *name) -{ - SHADOW_NEXT(REMOVEXATTR, - (handle, cpath ?: path, name), - int); -} - -static int -onefs_shadow_copy_setxattr(vfs_handle_struct *handle, const char *path, - const char *name, const void *value, size_t size, - int flags) -{ - SHADOW_NEXT(SETXATTR, - (handle, cpath ?: path, name, value, size, flags), - int); -} - -static bool -onefs_shadow_copy_is_offline(struct vfs_handle_struct *handle, - const struct smb_fname *fname, - SMB_STRUCT_STAT *sbuf) -{ -#error Isilon, please convert "char *path" to "struct smb_fname *fname" - SHADOW_NEXT(IS_OFFLINE, - (handle, cpath ?: path, sbuf), - bool); -} - -static int -onefs_shadow_copy_set_offline(struct vfs_handle_struct *handle, - const struct smb_filename *fname) -{ -#error Isilon, please convert "char *path" to "struct smb_fname *fname" - SHADOW_NEXT(SET_OFFLINE, - (handle, cpath ?: path), - int); -} - -/* VFS operations structure */ - -static struct vfs_fn_pointers onefs_shadow_copy_fns = { - .disk_free_fn = onefs_shadow_copy_disk_free, - .get_shadow_copy_data_fn = onefs_shadow_copy_get_shadow_copy_data, - .statvfs_fn = onefs_shadow_copy_statvfs, - .opendir_fn = onefs_shadow_copy_opendir, - .mkdir_fn = onefs_shadow_copy_mkdir, - .rmdir_fn = onefs_shadow_copy_rmdir, - .open_fn = onefs_shadow_copy_open, - .create_file_fn = onefs_shadow_copy_create_file, - .rename_fn = onefs_shadow_copy_rename, - .stat_fn = onefs_shadow_copy_stat, - .stat_fn = onefs_shadow_copy_stat, - .lstat_fn = onefs_shadow_copy_lstat, - .unlink_fn = onefs_shadow_copy_unlink, - .chmod_fn = onefs_shadow_copy_chmod, - .chown_fn = onefs_shadow_copy_chown, - .lchown_fn = onefs_shadow_copy_lchown, - .chdir_fn = onefs_shadow_copy_chdir, - .ntimes_fn = onefs_shadow_copy_ntimes, - .symlink_fn = onefs_shadow_copy_symlink, - .readlink_fn = onefs_shadow_copy_readlink, - .link_fn = onefs_shadow_copy_link, - .mknod_fn = onefs_shadow_copy_mknod, - .realpath_fn = onefs_shadow_copy_realpath, - .chflags_fn = onefs_shadow_copy_chflags, - .streaminfo_fn = onefs_shadow_copy_streaminfo, - .get_real_filename_fn = onefs_shadow_copy_get_real_filename, - .get_nt_acl_fn = onefs_shadow_copy_get_nt_acl, - .chmod_acl_fn = onefs_shadow_copy_chmod_acl, - .sys_acl_get_file_fn = onefs_shadow_copy_sys_acl_get_file, - .sys_acl_set_file_fn = onefs_shadow_copy_sys_acl_set_file, - .sys_acl_delete_def_file_fn = onefs_shadow_copy_sys_acl_delete_def_file, - .getxattr_fn = onefs_shadow_copy_getxattr, - .listxattr_fn = onefs_shadow_copy_listxattr, - .removexattr_fn = onefs_shadow_copy_removexattr, - .setxattr_fn = onefs_shadow_copy_setxattr, - .lsetxattr_fn = onefs_shadow_copy_lsetxattr, - .is_offline_fn = onefs_shadow_copy_is_offline, - .set_offline_fn = onefs_shadow_copy_set_offline, -}; - -NTSTATUS vfs_shadow_copy_init(void) -{ - NTSTATUS ret; - - ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, - "onefs_shadow_copy", - &onefs_shadow_copy_fns); - - if (!NT_STATUS_IS_OK(ret)) - return ret; - - vfs_onefs_shadow_copy_debug_level = debug_add_class("onefs_shadow_copy"); - - if (vfs_onefs_shadow_copy_debug_level == -1) { - vfs_onefs_shadow_copy_debug_level = DBGC_VFS; - DEBUG(0, ("Couldn't register custom debugging class!\n")); - } else { - DEBUG(10, ("Debug class number of 'onefs_shadow_copy': %d\n", - vfs_onefs_shadow_copy_debug_level)); - } - - return ret; -} diff --git a/source3/modules/wscript_build b/source3/modules/wscript_build index 9607c34abe..3b257bcf66 100644 --- a/source3/modules/wscript_build +++ b/source3/modules/wscript_build @@ -43,10 +43,6 @@ VFS_SYNCOPS_SRC = 'vfs_syncops.c' VFS_ACL_XATTR_SRC = 'vfs_acl_xattr.c' VFS_ACL_TDB_SRC = 'vfs_acl_tdb.c' VFS_SMB_TRAFFIC_ANALYZER_SRC = 'vfs_smb_traffic_analyzer.c' -VFS_ONEFS_SRC = '''vfs_onefs.c onefs_acl.c onefs_system.c - onefs_open.c onefs_streams.c onefs_dir.c - onefs_cbrl.c onefs_notify.c onefs_config.c''' -VFS_ONEFS_SHADOW_COPY_SRC = 'vfs_onefs_shadow_copy.c onefs_shadow_copy.c' VFS_DIRSORT_SRC = 'vfs_dirsort.c' VFS_SCANNEDONLY_SRC = 'vfs_scannedonly.c' VFS_CROSSRENAME_SRC = 'vfs_crossrename.c' @@ -416,22 +412,6 @@ bld.SAMBA3_MODULE('vfs_smb_traffic_analyzer', internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_smb_traffic_analyzer'), enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_smb_traffic_analyzer')) -bld.SAMBA3_MODULE('vfs_onefs', - subsystem='vfs', - source=VFS_ONEFS_SRC, - deps='samba-util', - init_function='', - internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_onefs'), - enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_onefs')) - -bld.SAMBA3_MODULE('vfs_onefs_shadow_copy', - subsystem='vfs', - source=VFS_ONEFS_SHADOW_COPY_SRC, - deps='samba-util', - init_function='', - internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_onefs_shadow_copy'), - enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_onefs_shadow_copy')) - bld.SAMBA3_MODULE('vfs_dirsort', subsystem='vfs', source=VFS_DIRSORT_SRC, @@ -480,20 +460,12 @@ bld.SAMBA3_MODULE('vfs_dfs_samba4', internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_dfs_samba4'), enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_dfs_samba4')) -PERFCOUNT_ONEFS_SRC = 'perfcount_onefs.c' PERFCOUNT_TEST_SRC = 'perfcount_test.c' bld.SAMBA3_SUBSYSTEM('perfcount', source='', deps='smbd_base') -bld.SAMBA3_MODULE('perfcount_onefs', - subsystem='perfcount', - source=PERFCOUNT_ONEFS_SRC, - init_function='', - internal_module=bld.SAMBA3_IS_STATIC_MODULE('perfcount_onefs'), - enabled=bld.SAMBA3_IS_ENABLED_MODULE('perfcount_onefs')) - bld.SAMBA3_MODULE('perfcount_test', subsystem='perfcount', source=PERFCOUNT_TEST_SRC, |