/* * 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 . */ #include "onefs.h" #include #include /* * 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)); } /* * Return string value of onefs oplock types. */ static const char *onefs_oplock_str(enum oplock_type onefs_oplock_type) { switch (onefs_oplock_type) { case OPLOCK_NONE: return "OPLOCK_NONE"; case OPLOCK_EXCLUSIVE: return "OPLOCK_EXCLUSIVE"; case OPLOCK_BATCH: return "OPLOCK_BATCH"; case OPLOCK_SHARED: return "OPLOCK_SHARED"; default: break; } return "UNKNOWN"; } /* * Convert from onefs to samba oplock. */ static int onefs_to_samba_oplock(enum oplock_type onefs_oplock) { switch (onefs_oplock) { case OPLOCK_NONE: return NO_OPLOCK; case OPLOCK_EXCLUSIVE: return EXCLUSIVE_OPLOCK; case OPLOCK_BATCH: return BATCH_OPLOCK; case OPLOCK_SHARED: return LEVEL_II_OPLOCK; default: DEBUG(0, ("unknown oplock type %d found\n", onefs_oplock)); break; } return NO_OPLOCK; } /* * Convert from samba to onefs oplock. */ static enum oplock_type samba_to_onefs_oplock(int samba_oplock_type) { if (BATCH_OPLOCK_TYPE(samba_oplock_type)) return OPLOCK_BATCH; if (EXCLUSIVE_OPLOCK_TYPE(samba_oplock_type)) return OPLOCK_EXCLUSIVE; if (LEVEL_II_OPLOCK_TYPE(samba_oplock_type)) return OPLOCK_SHARED; return OPLOCK_NONE; } /** * 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; int secinfo = 0; int ret_fd = -1; uint32_t onefs_dos_attributes; /* Setup security descriptor and get secinfo. */ if (sd != NULL) { NTSTATUS status; secinfo = (get_sec_info(sd) & IFS_SEC_INFO_KNOWN_MASK); status = onefs_setup_sd(secinfo, sd, &ifs_sd); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("SD initialization failure: %s", nt_errstr(status))); errno = EINVAL; goto out; } pifs_sd = &ifs_sd; } onefs_oplock = samba_to_onefs_oplock(oplock_request); /* Temporary until oplock work is added to vfs_onefs */ onefs_oplock = OPLOCK_NONE; /* Convert samba dos flags to UF_DOS_* attributes. */ onefs_dos_attributes = dos_attributes_to_stat_dos_flags(dos_flags); DEBUG(10,("onefs_sys_create_file: base_fd = %d, " "open_access_mask = 0x%x, flags = 0x%x, mode = 0x%x, " "desired_oplock = %s, id = 0x%x, secinfo = 0x%x, sd = %p, " "dos_attributes = 0x%x, path = %s\n", base_fd, (unsigned int)open_access_mask, (unsigned int)flags, (unsigned int)mode, onefs_oplock_str(onefs_oplock), (unsigned int)id, (unsigned int)secinfo, sd, (unsigned int)onefs_dos_attributes, path)); /* Initialize smlock struct for files/dirs but not internal opens */ if (!(oplock_request & INTERNAL_OPEN_ONLY)) { smlock_init(conn, &sml, is_executable(path), access_mask, share_access, create_options); psml = &sml; } smlock_dump(10, psml); ret_fd = ifs_createfile(base_fd, path, (enum ifs_ace_rights)open_access_mask, flags & ~O_ACCMODE, mode, onefs_oplock, id, psml, secinfo, pifs_sd, onefs_dos_attributes, &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_to_samba_oplock(onefs_granted_oplock); } out: aclu_free_sd(pifs_sd, false); return ret_fd; }