From f38d7f20a865b1ff5f7b039dd284d91b2ba7ec26 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Mon, 20 Oct 2008 17:43:45 -0700 Subject: s3: Add SMB_VFS_CREATE_FILE to the vfs layer Modify all callers of create_file to go through SMB_VFS_CREATE_FILE --- source3/modules/vfs_default.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'source3/modules') diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index d972828ba9..bca06dfaf7 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -208,6 +208,31 @@ static int vfswrap_open(vfs_handle_struct *handle, const char *fname, return result; } +static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle, + struct smb_request *req, + uint16_t root_dir_fid, + const char *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, + SMB_STRUCT_STAT *psbuf) +{ + return create_file_default(handle->conn, req, root_dir_fid, fname, + access_mask, share_access, + create_disposition, create_options, + file_attributes, oplock_request, + allocation_size, sd, ea_list, result, pinfo, + psbuf); +} + static int vfswrap_close(vfs_handle_struct *handle, files_struct *fsp) { int result; @@ -1359,6 +1384,8 @@ static vfs_op_tuple vfs_default_ops[] = { {SMB_VFS_OP(vfswrap_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(vfswrap_create_file), SMB_VFS_OP_CREATE_FILE, + SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(vfswrap_close), SMB_VFS_OP_CLOSE, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(vfswrap_read), SMB_VFS_OP_READ, -- cgit From f995a7af2a06ccff29f23f1b099e0a84bc948f6e Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Wed, 19 Nov 2008 17:55:28 -0800 Subject: s3: Add new "is_dos_path" argument to SMB_VFS_CREATE_FILE Now unix paths can be differentiated from windows paths so the underlying create_file implementations can convert paths correctly. --- source3/modules/vfs_default.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index bca06dfaf7..fde899d1af 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -212,6 +212,7 @@ static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle, struct smb_request *req, uint16_t root_dir_fid, const char *fname, + bool is_dos_path, uint32_t access_mask, uint32_t share_access, uint32_t create_disposition, @@ -226,7 +227,7 @@ static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle, SMB_STRUCT_STAT *psbuf) { return create_file_default(handle->conn, req, root_dir_fid, fname, - access_mask, share_access, + is_dos_path, access_mask, share_access, create_disposition, create_options, file_attributes, oplock_request, allocation_size, sd, ea_list, result, pinfo, -- cgit From 61b4597e3c9016b3fdd540857abf3b72963ad4b2 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Sun, 23 Nov 2008 14:37:37 -0800 Subject: s3: Add SMB_VFS_CREATE_FILE to vfs_full_audit module --- source3/modules/vfs_full_audit.c | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'source3/modules') diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 6342c4a14e..fd97a4ccff 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -109,6 +109,23 @@ static int smb_full_audit_closedir(vfs_handle_struct *handle, SMB_STRUCT_DIR *dirp); static int smb_full_audit_open(vfs_handle_struct *handle, const char *fname, files_struct *fsp, int flags, mode_t mode); +static NTSTATUS smb_full_audit_create_file(vfs_handle_struct *handle, + struct smb_request *req, + uint16_t root_dir_fid, + const char *fname, + bool is_dos_path, + 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, + SMB_STRUCT_STAT *psbuf); static int smb_full_audit_close(vfs_handle_struct *handle, files_struct *fsp); static ssize_t smb_full_audit_read(vfs_handle_struct *handle, files_struct *fsp, void *data, size_t n); @@ -353,6 +370,8 @@ static vfs_op_tuple audit_op_tuples[] = { {SMB_VFS_OP(smb_full_audit_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_LOGGER}, + {SMB_VFS_OP(smb_full_audit_create_file),SMB_VFS_OP_CREATE_FILE, + SMB_VFS_LAYER_LOGGER}, {SMB_VFS_OP(smb_full_audit_close), SMB_VFS_OP_CLOSE, SMB_VFS_LAYER_LOGGER}, {SMB_VFS_OP(smb_full_audit_read), SMB_VFS_OP_READ, @@ -1087,6 +1106,51 @@ static int smb_full_audit_open(vfs_handle_struct *handle, return result; } +static NTSTATUS smb_full_audit_create_file(vfs_handle_struct *handle, + struct smb_request *req, + uint16_t root_dir_fid, + const char *fname, + bool is_dos_path, + 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_fsp, + int *pinfo, + SMB_STRUCT_STAT *psbuf) +{ + NTSTATUS result; + + result = SMB_VFS_NEXT_CREATE_FILE( + handle, /* handle */ + req, /* req */ + root_dir_fid, /* root_dir_fid */ + fname, /* fname */ + is_dos_path, /* is_dos_path */ + 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 */ + sd, /* sd */ + ea_list, /* ea_list */ + result_fsp, /* result */ + pinfo, /* pinfo */ + psbuf); /* psbuf */ + + do_log(SMB_VFS_OP_CREATE_FILE, (NT_STATUS_IS_OK(result)), handle, "0x%x|%s", + access_mask, fname); + + return result; +} + static int smb_full_audit_close(vfs_handle_struct *handle, files_struct *fsp) { int result; -- cgit From 58440122853b65048793efd90ee45916e25c08c1 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Mon, 1 Dec 2008 12:47:31 -0800 Subject: s3: Change SMB_VFS_CREATE_FILE to take a create_file_flags argument This replaces the is_dos_path bool with a more future-proof argument. The next step is to plumb INTERNAL_OPEN_ONLY through this flag instead of overridding the oplock_request. --- source3/modules/vfs_default.c | 4 ++-- source3/modules/vfs_full_audit.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index fde899d1af..6d8d8f8065 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -212,7 +212,7 @@ static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle, struct smb_request *req, uint16_t root_dir_fid, const char *fname, - bool is_dos_path, + uint32_t create_file_flags, uint32_t access_mask, uint32_t share_access, uint32_t create_disposition, @@ -227,7 +227,7 @@ static NTSTATUS vfswrap_create_file(vfs_handle_struct *handle, SMB_STRUCT_STAT *psbuf) { return create_file_default(handle->conn, req, root_dir_fid, fname, - is_dos_path, access_mask, share_access, + create_file_flags, access_mask, share_access, create_disposition, create_options, file_attributes, oplock_request, allocation_size, sd, ea_list, result, pinfo, diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index fd97a4ccff..7970bf2644 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -113,7 +113,7 @@ static NTSTATUS smb_full_audit_create_file(vfs_handle_struct *handle, struct smb_request *req, uint16_t root_dir_fid, const char *fname, - bool is_dos_path, + uint32_t create_file_flags, uint32_t access_mask, uint32_t share_access, uint32_t create_disposition, @@ -1110,7 +1110,7 @@ static NTSTATUS smb_full_audit_create_file(vfs_handle_struct *handle, struct smb_request *req, uint16_t root_dir_fid, const char *fname, - bool is_dos_path, + uint32_t create_file_flags, uint32_t access_mask, uint32_t share_access, uint32_t create_disposition, @@ -1131,7 +1131,7 @@ static NTSTATUS smb_full_audit_create_file(vfs_handle_struct *handle, req, /* req */ root_dir_fid, /* root_dir_fid */ fname, /* fname */ - is_dos_path, /* is_dos_path */ + create_file_flags, /* create_file_flags */ access_mask, /* access_mask */ share_access, /* share_access */ create_disposition, /* create_disposition*/ -- cgit From 09b4a9513cf0be52dcd43660ae384b8f7c398287 Mon Sep 17 00:00:00 2001 From: Henning Henkel Date: Thu, 4 Dec 2008 13:55:12 -0800 Subject: Fix bug #5929 - vfs_prealloc does not build with option --with-cluster-support and GPFS --- source3/modules/vfs_prealloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_prealloc.c b/source3/modules/vfs_prealloc.c index 2a06e3d81b..5a339dbf8d 100644 --- a/source3/modules/vfs_prealloc.c +++ b/source3/modules/vfs_prealloc.c @@ -56,9 +56,9 @@ static int module_debug; static int preallocate_space(int fd, SMB_OFF_T size) { + int err; #ifndef HAVE_GPFS lock_type fl = {0}; - int err; if (size <= 0) { return 0; -- cgit From 51e7f79b3b4ae0fa830ac176df5ba8229e14f32d Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Mon, 8 Dec 2008 16:42:45 -0800 Subject: s3: Add onefs_open.c with code copied verbatim from smbd/open.c This is an intermediate step that makes it much easier to see how the OneFS SMB_VFS_CREATE_FILE implementation diverges from stock samba. The goal is that more common code can be refactored into utility functions. --- source3/modules/onefs_open.c | 2028 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2028 insertions(+) create mode 100644 source3/modules/onefs_open.c (limited to 'source3/modules') diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c new file mode 100644 index 0000000000..f45cc471ce --- /dev/null +++ b/source3/modules/onefs_open.c @@ -0,0 +1,2028 @@ +/* + Unix SMB/CIFS implementation. + file opening and share modes + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Jeremy Allison 2001-2004 + Copyright (C) Volker Lendecke 2005 + + 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 "includes.h" + +extern const struct generic_mapping file_generic_mapping; +extern bool global_client_failed_oplock_break; + +struct deferred_open_record { + bool delayed_for_oplocks; + struct file_id id; +}; + +static NTSTATUS create_file_unixpath(connection_struct *conn, + struct smb_request *req, + const char *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, + SMB_STRUCT_STAT *psbuf); + +/**************************************************************************** + Open a file. +****************************************************************************/ + +static NTSTATUS open_file(files_struct *fsp, + connection_struct *conn, + struct smb_request *req, + const char *parent_dir, + const char *name, + const char *path, + SMB_STRUCT_STAT *psbuf, + int flags, + mode_t unx_mode, + uint32 access_mask, /* client requested access mask. */ + uint32 open_access_mask) /* what we're actually using in the open. */ +{ + NTSTATUS status = NT_STATUS_OK; + int accmode = (flags & O_ACCMODE); + int local_flags = flags; + bool file_existed = VALID_STAT(*psbuf); + + 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", path)); + 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." + * 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,("open_file: truncate requested on read-only open " + "for file %s\n", path)); + local_flags = (flags & ~O_ACCMODE)|O_RDWR; + } + + if ((open_access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || + (!file_existed && (local_flags & O_CREAT)) || + ((local_flags & O_TRUNC) == O_TRUNC) ) { + const char *wild; + + /* + * We can't actually truncate here as the file may be locked. + * open_file_ntcreate will take care of the truncate later. JRA. + */ + + local_flags &= ~O_TRUNC; + +#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(psbuf->st_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; + } else { + wild = path; + } + if ((local_flags & O_CREAT) && !file_existed && + ms_has_wild(wild)) { + return NT_STATUS_OBJECT_NAME_INVALID; + } + + /* Actually do the open */ + status = fd_open(conn, path, fsp, local_flags, unx_mode); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3,("Error opening file %s (%s) (local_flags=%d) " + "(flags=%d)\n", + path,nt_errstr(status),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, path, + 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, path); + } + + } else { + fsp->fh->fd = -1; /* What we used to call a stat open. */ + if (file_existed) { + status = check_open_rights(conn, + path, + access_mask); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("open_file: Access denied on " + "file %s\n", + path)); + return status; + } + } + } + + if (!file_existed) { + int ret; + + if (fsp->fh->fd == -1) { + ret = SMB_VFS_STAT(conn, path, psbuf); + } else { + ret = SMB_VFS_FSTAT(fsp, psbuf); + /* If we have an fd, this stat should succeed. */ + if (ret == -1) { + DEBUG(0,("Error doing fstat on open file %s " + "(%s)\n", path,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(psbuf->st_mode)) { + fd_close(fsp); + errno = EISDIR; + return NT_STATUS_FILE_IS_A_DIRECTORY; + } + + fsp->mode = psbuf->st_mode; + fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); + 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 = False; + fsp->modified = False; + fsp->sent_oplock_break = NO_BREAK_SENT; + fsp->is_directory = False; + if (conn->aio_write_behind_list && + is_in_path(path, conn->aio_write_behind_list, conn->case_sensitive)) { + fsp->aio_write_behind = True; + } + + string_set(&fsp->fsp_name, path); + fsp->wcp = NULL; /* Write cache pointer. */ + + DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n", + conn->server_info->unix_name, + fsp->fsp_name, + 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; inum_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=%d, exiting\n", 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 %u\n", + (unsigned int)request_time.tv_sec, + (unsigned int)request_time.tv_usec, + (unsigned int)req->mid)); + + if (!push_deferred_smb_message(req, request_time, timeout, + (char *)state, sizeof(*state))) { + exit_server("push_deferred_smb_message failed"); + } + add_deferred_open(lck, req->mid, request_time, state->id); + + /* + * Push the MID of this packet on the signing queue. + * We only do this once, the first time we push the packet + * onto the deferred open queue, as this has a side effect + * of incrementing the response sequence number. + */ + + srv_defer_sign_response(req->mid); +} + +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. */ + + timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 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.id = lck->id; + + if (!request_timed_out(request_time, timeout)) { + defer_open(lck, request_time, timeout, req, &state); + } +} + +/**************************************************************************** + Open a file with a share mode. Passed in an already created files_struct *. +****************************************************************************/ + +static NTSTATUS open_file_ntcreate(connection_struct *conn, + struct smb_request *req, + const char *fname, + SMB_STRUCT_STAT *psbuf, + uint32 access_mask, /* access bits (FILE_READ_DATA etc.) */ + uint32 share_access, /* share constants (FILE_SHARE_READ etc) */ + uint32 create_disposition, /* FILE_OPEN_IF etc. */ + uint32 create_options, /* options such as delete on close. */ + uint32 new_dos_attributes, /* attributes used for new file. */ + int oplock_request, /* internal Samba oplock codes. */ + /* Information (FILE_EXISTS etc.) */ + int *pinfo, + files_struct *fsp) +{ + int flags=0; + int flags2=0; + bool file_existed = VALID_STAT(*psbuf); + bool def_acl = False; + bool posix_open = False; + bool new_file_created = False; + struct file_id id; + NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED; + mode_t new_unx_mode = (mode_t)0; + mode_t unx_mode = (mode_t)0; + int info; + uint32 existing_dos_attributes = 0; + struct pending_message_list *pml = NULL; + 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; + const char *newname; + + 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, ("open_file_ntcreate: printer open fname=%s\n", fname)); + + return print_fsp_open(req, conn, fname, req->vuid, fsp); + } + + if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir, + &newname)) { + 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 aARCH to this as this mode is only used if the file is + * created new. */ + unx_mode = unix_mode(conn, new_dos_attributes | aARCH, fname, + parent_dir); + } + + DEBUG(10, ("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=%d\n", + fname, new_dos_attributes, access_mask, share_access, + create_disposition, create_options, unx_mode, + oplock_request)); + + 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 != NULL) + && ((pml = get_open_deferred_message(req->mid)) != NULL)) { + struct deferred_open_record *state = + (struct deferred_open_record *)pml->private_data.data; + + /* Remember the absolute time of the original + request with this mid. We'll use it later to + see if this has timed out. */ + + request_time = pml->request_time; + + /* Remove the deferred open entry under lock. */ + lck = get_share_mode_lock(talloc_tos(), state->id, NULL, NULL, + NULL); + if (lck == NULL) { + DEBUG(0, ("could not get share mode lock\n")); + } else { + del_deferred_open_entry(lck, req->mid); + TALLOC_FREE(lck); + } + + /* Ensure we don't reprocess this message. */ + remove_deferred_open_smb_message(req->mid); + } + + status = check_name(conn, fname); + 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, fname, psbuf); + } + } + + /* ignore any oplock requests if oplocks are disabled */ + if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break || + IS_VETO_OPLOCK_PATH(conn, fname)) { + /* 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(fname,".+,;=[].")) { + /* OS/2 Workplace shell fix may be main code stream in a later + * release. */ + DEBUG(5,("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: + /* If file exists replace/overwrite. If file doesn't + * exist create. */ + flags2 |= (O_CREAT | O_TRUNC); + break; + + case FILE_OVERWRITE_IF: + /* If file exists replace/overwrite. If file doesn't + * exist create. */ + flags2 |= (O_CREAT | O_TRUNC); + break; + + case FILE_OPEN: + /* If file exists open. If file doesn't exist error. */ + if (!file_existed) { + DEBUG(5,("open_file_ntcreate: FILE_OPEN " + "requested for file %s and file " + "doesn't exist.\n", 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,("open_file_ntcreate: FILE_OVERWRITE " + "requested for file %s and file " + "doesn't exist.\n", fname )); + errno = ENOENT; + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + flags2 |= O_TRUNC; + break; + + case FILE_CREATE: + /* If file exists error. If file doesn't exist + * create. */ + if (file_existed) { + DEBUG(5,("open_file_ntcreate: FILE_CREATE " + "requested for file %s and file " + "already exists.\n", fname )); + if (S_ISDIR(psbuf->st_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; + } + + /* We only care about matching 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, fname, + existing_dos_attributes, + new_dos_attributes, psbuf->st_mode, + unx_mode, &new_unx_mode)) { + DEBUG(5,("open_file_ntcreate: attributes missmatch " + "for file %s (%x %x) (0%o, 0%o)\n", + fname, existing_dos_attributes, + new_dos_attributes, + (unsigned int)psbuf->st_mode, + (unsigned int)unx_mode )); + errno = EACCES; + return NT_STATUS_ACCESS_DENIED; + } + } + + status = calculate_access_mask(conn, fname, file_existed, + access_mask, + &access_mask); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("open_file_ntcreate: calculate_access_mask " + "on file %s returned %s\n", + fname, + nt_errstr(status))); + return status; + } + + open_access_mask = access_mask; + + if ((flags2 & O_TRUNC) || (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) { + open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */ + } + + DEBUG(10, ("open_file_ntcreate: fname=%s, after mapping " + "access_mask=0x%x\n", fname, 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. */ + if ((create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS) || + 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); + } + + /* + * 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,("open_file_ntcreate: write access requested for " + "file %s on read only %s\n", + fname, !CAN_WRITE(conn) ? "share" : "file" )); + errno = EACCES; + return NT_STATUS_ACCESS_DENIED; + } + + fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); + fsp->share_access = share_access; + fsp->fh->private_options = create_options; + 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 = get_mtimespec(psbuf); + id = vfs_file_id_from_sbuf(conn, psbuf); + + lck = get_share_mode_lock(talloc_tos(), id, + conn->connectpath, + fname, &old_write_time); + + if (lck == NULL) { + DEBUG(0, ("Could not get share mode lock\n")); + return NT_STATUS_SHARING_VIOLATION; + } + + /* First pass - send break only on batch oplocks. */ + if ((req != NULL) + && delay_for_oplocks(lck, fsp, req->mid, 1, + oplock_request)) { + schedule_defer_open(lck, request_time, req); + TALLOC_FREE(lck); + return NT_STATUS_SHARING_VIOLATION; + } + + /* Use the client requested access mask here, not the one we + * open with. */ + status = open_mode_check(conn, fname, lck, + access_mask, share_access, + create_options, &file_existed); + + if (NT_STATUS_IS_OK(status)) { + /* We might be going to allow this open. Check oplock + * status again. */ + /* Second pass - send break for both batch or + * exclusive oplocks. */ + if ((req != NULL) + && delay_for_oplocks(lck, fsp, req->mid, 2, + oplock_request)) { + schedule_defer_open(lck, request_time, req); + TALLOC_FREE(lck); + return NT_STATUS_SHARING_VIOLATION; + } + } + + if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) { + /* DELETE_PENDING is not deferred for a second */ + TALLOC_FREE(lck); + return status; + } + + if (!NT_STATUS_IS_OK(status)) { + uint32 can_access_mask; + bool can_access = True; + + SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)); + + /* Check if this can be done with the deny_dos and fcb + * calls. */ + if (create_options & + (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS| + NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) { + if (req == NULL) { + DEBUG(0, ("DOS open without an SMB " + "request!\n")); + TALLOC_FREE(lck); + return NT_STATUS_INTERNAL_ERROR; + } + + /* Use the client requested access mask here, + * not the one we open with. */ + status = fcb_or_dos_open(req, + conn, + fsp, + fname, + id, + req->smbpid, + req->vuid, + access_mask, + share_access, + create_options); + + if (NT_STATUS_IS_OK(status)) { + TALLOC_FREE(lck); + if (pinfo) { + *pinfo = FILE_WAS_OPENED; + } + return NT_STATUS_OK; + } + } + + /* + * 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)) || + !can_access_file_data(conn,fname,psbuf,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; + + if ((req != NULL) + && !request_timed_out(request_time, + timeout)) { + defer_open(lck, request_time, timeout, + req, &state); + } + } + + TALLOC_FREE(lck); + 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; + } + return status; + } + + /* + * We exit this block with the share entry *locked*..... + */ + } + + SMB_ASSERT(!file_existed || (lck != NULL)); + + /* + * Ensure we pay attention to default ACLs on directories if required. + */ + + if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) && + (def_acl = directory_has_default_acl(conn, parent_dir))) { + unx_mode = 0777; + } + + DEBUG(4,("calling 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)); + + /* + * open_file strips any O_TRUNC flags itself. + */ + + fsp_open = open_file(fsp, conn, req, parent_dir, newname, fname, psbuf, + flags|flags2, unx_mode, access_mask, + open_access_mask); + + if (!NT_STATUS_IS_OK(fsp_open)) { + if (lck != NULL) { + TALLOC_FREE(lck); + } + return fsp_open; + } + + if (!file_existed) { + struct timespec old_write_time = get_mtimespec(psbuf); + /* + * 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->dev and fsp->inode are valid and should replace the + * dev=0,inode=0 from a non existent file. Spotted by + * Nadav Danieli . JRA. + */ + + id = fsp->file_id; + + lck = get_share_mode_lock(talloc_tos(), id, + conn->connectpath, + fname, &old_write_time); + + if (lck == NULL) { + DEBUG(0, ("open_file_ntcreate: Could not get share " + "mode lock for %s\n", fname)); + fd_close(fsp); + return NT_STATUS_SHARING_VIOLATION; + } + + /* First pass - send break only on batch oplocks. */ + if ((req != NULL) + && delay_for_oplocks(lck, fsp, req->mid, 1, + oplock_request)) { + schedule_defer_open(lck, request_time, req); + TALLOC_FREE(lck); + fd_close(fsp); + return NT_STATUS_SHARING_VIOLATION; + } + + status = open_mode_check(conn, fname, lck, + access_mask, share_access, + create_options, &file_existed); + + if (NT_STATUS_IS_OK(status)) { + /* We might be going to allow this open. Check oplock + * status again. */ + /* Second pass - send break for both batch or + * exclusive oplocks. */ + if ((req != NULL) + && delay_for_oplocks(lck, fsp, req->mid, 2, + oplock_request)) { + schedule_defer_open(lck, request_time, req); + TALLOC_FREE(lck); + fd_close(fsp); + return NT_STATUS_SHARING_VIOLATION; + } + } + + 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); + + /* 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); + 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. + */ + + /* + * If requested, truncate the file. + */ + + if (flags2&O_TRUNC) { + /* + * We are modifing the file after open - update the stat + * struct.. + */ + if ((SMB_VFS_FTRUNCATE(fsp, 0) == -1) || + (SMB_VFS_FSTAT(fsp, psbuf)==-1)) { + status = map_nt_error_from_unix(errno); + TALLOC_FREE(lck); + fd_close(fsp); + return status; + } + } + + /* Record the options we were opened with. */ + fsp->share_access = share_access; + fsp->fh->private_options = create_options; + /* + * 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 (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || info == FILE_WAS_SUPERSEDED) { + new_file_created = True; + } + + set_share_mode(lck, fsp, conn->server_info->utok.uid, 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, True, 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; + } + + if (new_file_created) { + /* Files should be initially set as archive */ + if (lp_map_archive(SNUM(conn)) || + lp_store_dos_attributes(SNUM(conn))) { + if (!posix_open) { + SMB_STRUCT_STAT tmp_sbuf; + SET_STAT_INVALID(tmp_sbuf); + if (file_set_dosmode( + conn, fname, + new_dos_attributes | aARCH, + &tmp_sbuf, parent_dir, + true) == 0) { + unx_mode = tmp_sbuf.st_mode; + } + } + } + } + + /* + * Take care of inherited ACLs on created files - if default ACL not + * selected. + */ + + if (!posix_open && !file_existed && !def_acl) { + + 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, ("open_file_ntcreate: reset " + "attributes of file %s to 0%o\n", + 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, ("open_file_ntcreate: failed to reset " + "attributes of file %s to 0%o\n", + 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 open_directory(connection_struct *conn, + struct smb_request *req, + const char *fname, + SMB_STRUCT_STAT *psbuf, + uint32 access_mask, + uint32 share_access, + uint32 create_disposition, + uint32 create_options, + uint32 file_attributes, + int *pinfo, + files_struct **result) +{ + files_struct *fsp = NULL; + bool dir_existed = VALID_STAT(*psbuf) ? True : False; + struct share_mode_lock *lck = NULL; + NTSTATUS status; + struct timespec mtimespec; + int info = 0; + + DEBUG(5,("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", + fname, + (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_name(fname)) { + DEBUG(2, ("open_directory: %s is a stream name!\n", fname)); + return NT_STATUS_NOT_A_DIRECTORY; + } + + status = calculate_access_mask(conn, fname, dir_existed, + access_mask, + &access_mask); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("open_directory: calculate_access_mask " + "on file %s returned %s\n", + fname, + nt_errstr(status))); + return status; + } + + switch( create_disposition ) { + case FILE_OPEN: + + info = FILE_WAS_OPENED; + + /* + * We want to follow symlinks here. + */ + + if (SMB_VFS_STAT(conn, fname, psbuf) != 0) { + return map_nt_error_from_unix(errno); + } + + break; + + case FILE_CREATE: + + /* If directory exists error. If directory doesn't + * exist create. */ + + status = mkdir_internal(conn, + fname, + file_attributes, + psbuf); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2, ("open_directory: unable to create " + "%s. Error was %s\n", fname, + nt_errstr(status))); + return status; + } + + info = FILE_WAS_CREATED; + break; + + case FILE_OPEN_IF: + /* + * If directory exists open. If directory doesn't + * exist create. + */ + + status = mkdir_internal(conn, + fname, + file_attributes, + psbuf); + + if (NT_STATUS_IS_OK(status)) { + info = FILE_WAS_CREATED; + } + + if (NT_STATUS_EQUAL(status, + NT_STATUS_OBJECT_NAME_COLLISION)) { + info = FILE_WAS_OPENED; + status = NT_STATUS_OK; + } + + break; + + case FILE_SUPERSEDE: + case FILE_OVERWRITE: + case FILE_OVERWRITE_IF: + default: + DEBUG(5,("open_directory: invalid create_disposition " + "0x%x for directory %s\n", + (unsigned int)create_disposition, fname)); + return NT_STATUS_INVALID_PARAMETER; + } + + if(!S_ISDIR(psbuf->st_mode)) { + DEBUG(5,("open_directory: %s is not a directory !\n", + fname )); + return NT_STATUS_NOT_A_DIRECTORY; + } + + if (info == FILE_WAS_OPENED) { + status = check_open_rights(conn, + fname, + access_mask); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("open_directory: check_open_rights on " + "file %s failed with %s\n", + fname, + nt_errstr(status))); + return status; + } + } + + status = file_new(req, conn, &fsp); + if(!NT_STATUS_IS_OK(status)) { + return status; + } + + /* + * Setup the files_struct for it. + */ + + fsp->mode = psbuf->st_mode; + fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); + 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 = create_options; + /* + * According to Samba4, SEC_FILE_READ_ATTRIBUTE is always granted, + */ + fsp->access_mask = access_mask | FILE_READ_ATTRIBUTES; + fsp->print_file = False; + fsp->modified = False; + fsp->oplock_type = NO_OPLOCK; + fsp->sent_oplock_break = NO_BREAK_SENT; + fsp->is_directory = True; + fsp->posix_open = (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ? True : False; + + string_set(&fsp->fsp_name,fname); + + mtimespec = get_mtimespec(psbuf); + + lck = get_share_mode_lock(talloc_tos(), fsp->file_id, + conn->connectpath, + fname, &mtimespec); + + if (lck == NULL) { + DEBUG(0, ("open_directory: Could not get share mode lock for %s\n", fname)); + file_free(req, fsp); + return NT_STATUS_SHARING_VIOLATION; + } + + status = open_mode_check(conn, fname, lck, + access_mask, share_access, + create_options, &dir_existed); + + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(lck); + file_free(req, fsp); + return status; + } + + set_share_mode(lck, fsp, conn->server_info->utok.uid, 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, True, 0); + if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) { + TALLOC_FREE(lck); + 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; +} + +/* + * If a main file is opened for delete, all streams need to be checked for + * !FILE_SHARE_DELETE. Do this by opening with DELETE_ACCESS. + * If that works, delete them all by setting the delete on close and close. + */ + +static NTSTATUS open_streams_for_delete(connection_struct *conn, + const char *fname) +{ + struct stream_struct *stream_info; + files_struct **streams; + int i; + unsigned int num_streams; + TALLOC_CTX *frame = talloc_stackframe(); + NTSTATUS status; + + status = SMB_VFS_STREAMINFO(conn, NULL, fname, talloc_tos(), + &num_streams, &stream_info); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED) + || NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + DEBUG(10, ("no streams around\n")); + TALLOC_FREE(frame); + return NT_STATUS_OK; + } + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("SMB_VFS_STREAMINFO failed: %s\n", + nt_errstr(status))); + goto fail; + } + + DEBUG(10, ("open_streams_for_delete found %d streams\n", + num_streams)); + + if (num_streams == 0) { + TALLOC_FREE(frame); + return NT_STATUS_OK; + } + + streams = TALLOC_ARRAY(talloc_tos(), files_struct *, num_streams); + if (streams == NULL) { + DEBUG(0, ("talloc failed\n")); + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + for (i=0; i= 0; i--) { + if (streams[i] == NULL) { + continue; + } + + DEBUG(10, ("Closing stream # %d, %s\n", i, + streams[i]->fsp_name)); + close_file(NULL, streams[i], NORMAL_CLOSE); + } + + fail: + TALLOC_FREE(frame); + return status; +} + +/* + * Wrapper around open_file_ntcreate and open_directory + */ + +static NTSTATUS create_file_unixpath(connection_struct *conn, + struct smb_request *req, + const char *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, + SMB_STRUCT_STAT *psbuf) +{ + SMB_STRUCT_STAT sbuf; + int info = FILE_WAS_OPENED; + files_struct *base_fsp = NULL; + files_struct *fsp = NULL; + NTSTATUS status; + + DEBUG(10,("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 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, + ea_list, sd, 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) { + oplock_request |= INTERNAL_OPEN_ONLY; + } + + if (psbuf != NULL) { + sbuf = *psbuf; + } + else { + if (SMB_VFS_STAT(conn, fname, &sbuf) == -1) { + SET_STAT_INVALID(sbuf); + } + } + + if ((conn->fs_capabilities & FILE_NAMED_STREAMS) + && (access_mask & DELETE_ACCESS) + && !is_ntfs_stream_name(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, fname); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + } + + /* This is the correct thing to do (check every time) but can_delete + * is expensive (it may have to read the parent directory + * permissions). So for now we're not doing it unless we have a strong + * hint the client is really going to delete this file. If the client + * is forcing FILE_CREATE let the filesystem take care of the + * permissions. */ + + /* Setting FILE_SHARE_DELETE is the hint. */ + + if (lp_acl_check_permissions(SNUM(conn)) + && (create_disposition != FILE_CREATE) + && (share_access & FILE_SHARE_DELETE) + && (access_mask & DELETE_ACCESS) + && (!can_delete_file_in_directory(conn, fname))) { + status = NT_STATUS_ACCESS_DENIED; + goto fail; + } + +#if 0 + /* We need to support SeSecurityPrivilege for this. */ + if ((access_mask & SEC_RIGHT_SYSTEM_SECURITY) && + !user_has_privileges(current_user.nt_user_token, + &se_security)) { + status = NT_STATUS_PRIVILEGE_NOT_HELD; + goto fail; + } +#endif + + if ((conn->fs_capabilities & FILE_NAMED_STREAMS) + && is_ntfs_stream_name(fname) + && (!(create_options & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) { + char *base; + uint32 base_create_disposition; + + if (create_options & FILE_DIRECTORY_FILE) { + status = NT_STATUS_NOT_A_DIRECTORY; + goto fail; + } + + status = split_ntfs_stream_name(talloc_tos(), fname, + &base, NULL); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("create_file_unixpath: " + "split_ntfs_stream_name failed: %s\n", + nt_errstr(status))); + goto fail; + } + + SMB_ASSERT(!is_ntfs_stream_name(base)); /* paranoia.. */ + + switch (create_disposition) { + case FILE_OPEN: + base_create_disposition = FILE_OPEN; + break; + default: + base_create_disposition = FILE_OPEN_IF; + break; + } + + status = create_file_unixpath(conn, NULL, base, 0, + FILE_SHARE_READ + | FILE_SHARE_WRITE + | FILE_SHARE_DELETE, + base_create_disposition, + 0, 0, 0, 0, NULL, NULL, + &base_fsp, NULL, NULL); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("create_file_unixpath for base %s failed: " + "%s\n", base, nt_errstr(status))); + goto fail; + } + /* we don't need to low level fd */ + fd_close(base_fsp); + } + + /* + * 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. + */ + + oplock_request = 0; + status = open_directory( + conn, req, fname, &sbuf, access_mask, share_access, + create_disposition, create_options, file_attributes, + &info, &fsp); + } 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 = open_file_ntcreate(conn, + req, + fname, + &sbuf, + access_mask, + share_access, + create_disposition, + create_options, + file_attributes, + oplock_request, + &info, + fsp); + + 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; + } + + oplock_request = 0; + status = open_directory( + conn, req, fname, &sbuf, access_mask, + share_access, create_disposition, + create_options, file_attributes, + &info, &fsp); + } + } + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + fsp->base_fsp = base_fsp; + + /* + * According to the MS documentation, the only time the security + * descriptor is applied to the opened file is iff we *created* the + * file; an existing file stays the same. + * + * Also, it seems (from observation) that you can open the file with + * any access mask but you can still write the sd. We need to override + * the granted access before we call set_sd + * Patch for bug #2242 from Tom Lackemann . + */ + + if ((sd != NULL) && (info == FILE_WAS_CREATED) + && lp_nt_acl_support(SNUM(conn))) { + + uint32_t sec_info_sent; + uint32_t saved_access_mask = fsp->access_mask; + + sec_info_sent = get_sec_info(sd); + + fsp->access_mask = FILE_GENERIC_ALL; + + /* Convert all the generic bits. */ + security_acl_map_generic(sd->dacl, &file_generic_mapping); + security_acl_map_generic(sd->sacl, &file_generic_mapping); + + if (sec_info_sent & (OWNER_SECURITY_INFORMATION| + GROUP_SECURITY_INFORMATION| + DACL_SECURITY_INFORMATION| + SACL_SECURITY_INFORMATION)) { + status = SMB_VFS_FSET_NT_ACL(fsp, sec_info_sent, sd); + } + + fsp->access_mask = saved_access_mask; + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + } + + if ((ea_list != NULL) && (info == FILE_WAS_CREATED)) { + status = set_ea(conn, fsp, fname, ea_list); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + } + + if (!fsp->is_directory && S_ISDIR(sbuf.st_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 > sbuf.st_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)sbuf.st_size); + } + } + + DEBUG(10, ("create_file_unixpath: info=%d\n", info)); + + *result = fsp; + if (pinfo != NULL) { + *pinfo = info; + } + if (psbuf != NULL) { + if ((fsp->fh == NULL) || (fsp->fh->fd == -1)) { + *psbuf = sbuf; + } + else { + SMB_VFS_FSTAT(fsp, psbuf); + } + } + return NT_STATUS_OK; + + fail: + DEBUG(10, ("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; +} +NTSTATUS create_file_default(connection_struct *conn, + struct smb_request *req, + uint16_t root_dir_fid, + const char *fname, + uint32_t create_file_flags, + 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, + SMB_STRUCT_STAT *psbuf) +{ + struct case_semantics_state *case_state = NULL; + SMB_STRUCT_STAT sbuf; + int info = FILE_WAS_OPENED; + files_struct *fsp = NULL; + NTSTATUS status; + + DEBUG(10,("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 " + "root_dir_fid = 0x%x, ea_list = 0x%p, sd = 0x%p, " + "create_file_flags = 0x%x, 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)root_dir_fid, + ea_list, sd, create_file_flags, fname)); + + /* + * Calculate the filename from the root_dir_if if necessary. + */ + + if (root_dir_fid != 0) { + char *new_fname; + + status = get_relative_fid_filename(conn, req, root_dir_fid, + fname, &new_fname); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + fname = new_fname; + } + + /* + * Check to see if this is a mac fork of some kind. + */ + + if (is_ntfs_stream_name(fname)) { + enum FAKE_FILE_TYPE fake_file_type; + + fake_file_type = is_fake_file(fname); + + if (fake_file_type != FAKE_FILE_TYPE_NONE) { + + /* + * Here we go! support for changing the disk quotas + * --metze + * + * We need to fake up to open this MAGIC QUOTA file + * and return a valid FID. + * + * w2k close this file directly after openening xp + * also tries a QUERY_FILE_INFO on the file and then + * close it + */ + status = open_fake_file(req, conn, req->vuid, + fake_file_type, fname, + access_mask, &fsp); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + ZERO_STRUCT(sbuf); + goto done; + } + + if (!(conn->fs_capabilities & FILE_NAMED_STREAMS)) { + status = NT_STATUS_OBJECT_PATH_NOT_FOUND; + goto fail; + } + } + + if ((req != NULL) && (req->flags2 & FLAGS2_DFS_PATHNAMES)) { + char *resolved_fname; + + status = resolve_dfspath(talloc_tos(), conn, true, fname, + &resolved_fname); + + if (!NT_STATUS_IS_OK(status)) { + /* + * For PATH_NOT_COVERED we had + * reply_botherror(req, NT_STATUS_PATH_NOT_COVERED, + * ERRSRV, ERRbadpath); + * Need to fix in callers + */ + goto fail; + } + fname = resolved_fname; + } + + /* + * Check if POSIX semantics are wanted. + */ + + if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { + case_state = set_posix_case_semantics(talloc_tos(), conn); + } + + if (create_file_flags & CFF_DOS_PATH) { + char *converted_fname; + + SET_STAT_INVALID(sbuf); + + status = unix_convert(talloc_tos(), conn, fname, False, + &converted_fname, NULL, &sbuf); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + fname = converted_fname; + } else { + if (psbuf != NULL) { + sbuf = *psbuf; + } else { + if (SMB_VFS_STAT(conn, fname, &sbuf) == -1) { + SET_STAT_INVALID(sbuf); + } + } + + } + + TALLOC_FREE(case_state); + + /* All file access must go through check_name() */ + + status = check_name(conn, fname); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = create_file_unixpath( + conn, req, fname, access_mask, share_access, + create_disposition, create_options, file_attributes, + oplock_request, allocation_size, sd, ea_list, + &fsp, &info, &sbuf); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + done: + DEBUG(10, ("create_file: info=%d\n", info)); + + *result = fsp; + if (pinfo != NULL) { + *pinfo = info; + } + if (psbuf != NULL) { + *psbuf = sbuf; + } + return NT_STATUS_OK; + + fail: + DEBUG(10, ("create_file: %s\n", nt_errstr(status))); + + if (fsp != NULL) { + close_file(req, fsp, ERROR_CLOSE); + fsp = NULL; + } + return status; +} -- cgit From e0711ffa526e22e3ffe483319ce5d7725d578647 Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Mon, 8 Dec 2008 16:57:58 -0800 Subject: s3: Add the OneFS SMB_VFS_CREATE_FILE implementation This is the first pass at extending the onefs vfs module to support the CIFS-specific enhancements available on OneFS. Most of this patch is massaging the sama open path to 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 This patch does not implement the samba side of the streams support or oplocks support. Tests that expect oplocks to be granted or streams to be supported will fail. This will be remedied in upcoming patches. --- source3/modules/onefs.h | 68 +- source3/modules/onefs_acl.c | 119 ++-- source3/modules/onefs_open.c | 1442 ++++++++++++++++++++++------------------ source3/modules/onefs_system.c | 214 ++++++ source3/modules/vfs_onefs.c | 27 +- 5 files changed, 1160 insertions(+), 710 deletions(-) create mode 100644 source3/modules/onefs_system.c (limited to 'source3/modules') diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h index 965f39509a..8d0f45abdb 100644 --- a/source3/modules/onefs.h +++ b/source3/modules/onefs.h @@ -21,6 +21,10 @@ #ifndef _ONEFS_H #define _ONEFS_H +#include "includes.h" + +#include + /* OneFS Module smb.conf parameters and defaults */ /** @@ -34,13 +38,6 @@ enum onefs_acl_wire_format ACL_FORMAT_ALWAYS /**< Always canonicalize */ }; -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} -}; - #define PARM_ONEFS_TYPE "onefs" #define PARM_ACL_WIRE_FORMAT "acl wire format" #define PARM_ACL_WIRE_FORMAT_DEFAULT ACL_FORMAT_WINDOWS_SD @@ -49,4 +46,61 @@ const struct enum_list enum_onefs_acl_wire_format[] = { #define PARM_CREATOR_OWNER_GETS_FULL_CONTROL "creator owner gets full control" #define PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT true +/* + * vfs interface handlers + */ +NTSTATUS onefs_create_file(vfs_handle_struct *handle, + struct smb_request *req, + uint16_t root_dir_fid, + const char *fname, + uint32_t create_file_flags, + 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, + SMB_STRUCT_STAT *psbuf); + +NTSTATUS onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, + uint32 security_info, SEC_DESC **ppdesc); + +NTSTATUS onefs_get_nt_acl(vfs_handle_struct *handle, const char* name, + uint32 security_info, SEC_DESC **ppdesc); + +NTSTATUS onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, + uint32 security_info_sent, SEC_DESC *psd); + + +/* + * Utility functions + */ +NTSTATUS onefs_setup_sd(uint32 security_info_sent, SEC_DESC *psd, + struct ifs_security_descriptor *sd); + +/* + * 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); + + + #endif /* _ONEFS_H */ diff --git a/source3/modules/onefs_acl.c b/source3/modules/onefs_acl.c index 3a692c95ab..5351118a87 100644 --- a/source3/modules/onefs_acl.c +++ b/source3/modules/onefs_acl.c @@ -19,20 +19,23 @@ * along with this program; if not, see . */ -#include "includes.h" +#include "onefs.h" -#include #include -#include #include -#include "onefs.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(DOM_SID *sid, struct ifs_identity *id, bool is_group) +onefs_sid_to_identity(const DOM_SID *sid, struct ifs_identity *id, bool is_group) { enum ifs_identity_type type = IFS_ID_TYPE_LAST+1; uid_t uid = 0; @@ -514,15 +517,22 @@ onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, if (security_info & SACL_SECURITY_INFORMATION) desired_access |= IFS_RTS_SACL_ACCESS; - if ((fsp->fh->fd = ifs_createfile(-1, - fsp->fsp_name, - desired_access, - 0, 0, - OPLOCK_NONE, - 0, NULL, 0, - NULL, 0, NULL)) == -1) { - DEBUG(0, ("Error opening file %s. errno=%d\n", - fsp->fsp_name, errno)); + if ((fsp->fh->fd = onefs_sys_create_file(handle->conn, + -1, + fsp->fsp_name, + desired_access, + desired_access, + 0, + 0, + 0, + 0, + INTERNAL_OPEN_ONLY, + 0, + NULL, + 0, + NULL)) == -1) { + DEBUG(0, ("Error opening file %s. errno=%d (%s)\n", + fsp->fsp_name, errno, strerror(errno))); status = map_nt_error_from_unix(errno); goto out; } @@ -679,22 +689,18 @@ onefs_get_nt_acl(vfs_handle_struct *handle, const char* name, } /** - * Isilon-specific function for setting an NTFS ACL on an open file. + * Isilon-specific function for setting up an ifs_security_descriptor, given a + * samba SEC_DESC. * - * @return NT_STATUS_UNSUCCESSFUL for userspace errors, NTSTATUS based off - * errno on syscall errors + * @param[out] sd ifs_security_descriptor to fill in + * + * @return NTSTATUS_OK if successful */ -NTSTATUS -onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - uint32 security_info_sent, SEC_DESC *psd) +NTSTATUS onefs_setup_sd(uint32 security_info_sent, SEC_DESC *psd, + struct ifs_security_descriptor *sd) { - struct ifs_security_descriptor sd = {}; struct ifs_security_acl dacl, sacl, *daclp, *saclp; struct ifs_identity owner, group, *ownerp, *groupp; - int fd; - bool fopened = false; - - DEBUG(5,("Setting SD on file %s.\n", fsp->fsp_name )); ownerp = NULL; groupp = NULL; @@ -759,10 +765,37 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, /* 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)) + if (aclu_initialize_sd(sd, psd->type, ownerp, groupp, + (daclp ? &daclp : NULL), (saclp ? &saclp : NULL), false)) return NT_STATUS_UNSUCCESSFUL; + 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 security_info_sent, SEC_DESC *psd) +{ + struct ifs_security_descriptor sd = {}; + int fd; + bool fopened = false; + NTSTATUS status; + + DEBUG(5,("Setting SD on file %s.\n", fsp->fsp_name )); + + status = onefs_setup_sd(security_info_sent, psd, &sd); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("SD initialization failure: %s", nt_errstr(status))); + return status; + } + fd = fsp->fh->fd; if (fd == -1) { enum ifs_ace_rights desired_access = 0; @@ -775,16 +808,24 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, if (security_info_sent & SACL_SECURITY_INFORMATION) desired_access |= IFS_RTS_SACL_ACCESS; - if ((fd = ifs_createfile(-1, - fsp->fsp_name, - desired_access, - 0, 0, - OPLOCK_NONE, - 0, NULL, 0, - NULL, 0, NULL)) == -1) { - DEBUG(0, ("Error opening file %s. errno=%d\n", - fsp->fsp_name, errno)); - return map_nt_error_from_unix(errno); + if ((fd = onefs_sys_create_file(handle->conn, + -1, + fsp->fsp_name, + desired_access, + desired_access, + 0, + 0, + 0, + 0, + INTERNAL_OPEN_ONLY, + 0, + NULL, + 0, + NULL)) == -1) { + DEBUG(0, ("Error opening file %s. errno=%d (%s)\n", + fsp->fsp_name, errno, strerror(errno))); + status = map_nt_error_from_unix(errno); + goto out; } fopened = true; } @@ -792,10 +833,12 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, errno = 0; if (ifs_set_security_descriptor(fd, security_info_sent, &sd)) { DEBUG(0, ("Error setting security descriptor = %d\n", errno)); + status = map_nt_error_from_unix(errno); goto out; } DEBUG(5, ("Security descriptor set correctly!\n")); + status = NT_STATUS_OK; /* FALLTHROUGH */ out: @@ -803,5 +846,5 @@ out: close(fd); aclu_free_sd(&sd, false); - return errno ? map_nt_error_from_unix(errno) : NT_STATUS_OK; + return status; } diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c index f45cc471ce..bda5e7e91a 100644 --- a/source3/modules/onefs_open.c +++ b/source3/modules/onefs_open.c @@ -1,71 +1,93 @@ /* - Unix SMB/CIFS implementation. - file opening and share modes - Copyright (C) Andrew Tridgell 1992-1998 - Copyright (C) Jeremy Allison 2001-2004 - Copyright (C) Volker Lendecke 2005 - - 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 . -*/ + * Unix SMB/CIFS implementation. + * + * This file began with some code from source3/smbd/open.c and modified it to + * 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 . + */ -#include "includes.h" +#include "onefs.h" extern const struct generic_mapping file_generic_mapping; extern bool global_client_failed_oplock_break; struct deferred_open_record { bool delayed_for_oplocks; + bool failed; /* added for onefs_oplocks */ struct file_id id; }; -static NTSTATUS create_file_unixpath(connection_struct *conn, - struct smb_request *req, - const char *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, - SMB_STRUCT_STAT *psbuf); +static NTSTATUS onefs_create_file_unixpath(connection_struct *conn, + struct smb_request *req, + const char *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, + SMB_STRUCT_STAT *psbuf); /**************************************************************************** Open a file. ****************************************************************************/ -static NTSTATUS open_file(files_struct *fsp, - connection_struct *conn, - struct smb_request *req, - const char *parent_dir, - const char *name, - const char *path, - SMB_STRUCT_STAT *psbuf, - int flags, - mode_t unx_mode, - uint32 access_mask, /* client requested access mask. */ - uint32 open_access_mask) /* what we're actually using in the open. */ +static NTSTATUS onefs_open_file(files_struct *fsp, + connection_struct *conn, + struct smb_request *req, + const char *parent_dir, + const char *name, + const char *path, + SMB_STRUCT_STAT *psbuf, + 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) { NTSTATUS status = NT_STATUS_OK; int accmode = (flags & O_ACCMODE); int local_flags = flags; bool file_existed = VALID_STAT(*psbuf); + const char *wild; fsp->fh->fd = -1; errno = EPERM; @@ -110,90 +132,118 @@ static NTSTATUS open_file(files_struct *fsp, */ if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) { - DEBUG(10,("open_file: truncate requested on read-only open " - "for file %s\n", path)); + DEBUG(10,("onefs_open_file: truncate requested on read-only " + "open for file %s\n", path)); local_flags = (flags & ~O_ACCMODE)|O_RDWR; } - if ((open_access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) || - (!file_existed && (local_flags & O_CREAT)) || - ((local_flags & O_TRUNC) == O_TRUNC) ) { - const char *wild; +#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(psbuf->st_mode)) { + local_flags |= O_NONBLOCK; + } +#endif + /* Don't create files with Microsoft wildcard characters. */ + if (fsp->base_fsp) { /* - * We can't actually truncate here as the file may be locked. - * open_file_ntcreate will take care of the truncate later. JRA. + * wildcard characters are allowed in stream names + * only test the basefilename */ - - local_flags &= ~O_TRUNC; - -#if defined(O_NONBLOCK) && defined(S_ISFIFO) + wild = fsp->base_fsp->fsp_name; + } else { + wild = path; + } + if ((local_flags & O_CREAT) && !file_existed && + ms_has_wild(wild)) { /* - * 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. + * 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", + path)); + return NT_STATUS_OBJECT_NAME_INVALID; + } - if (file_existed && S_ISFIFO(psbuf->st_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; - } else { - wild = path; - } - if ((local_flags & O_CREAT) && !file_existed && - ms_has_wild(wild)) { - return NT_STATUS_OBJECT_NAME_INVALID; - } + /* Actually do the open */ - /* Actually do the open */ - status = fd_open(conn, path, fsp, local_flags, unx_mode); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3,("Error opening file %s (%s) (local_flags=%d) " - "(flags=%d)\n", - path,nt_errstr(status),local_flags,flags)); - return status; - } +#ifdef O_NOFOLLOW + /* + * Never follow symlinks on a POSIX client. The + * client should be doing this. + */ - if ((local_flags & O_CREAT) && !file_existed) { + if (fsp->posix_open || !lp_symlinks(SNUM(conn))) { + flags |= O_NOFOLLOW; + } +#endif + /* Don't request an oplock if oplocks are turned off for the + * share. */ + if (!lp_oplocks(SNUM(conn))) + oplock_request = 0; - /* Inherit the ACL if required */ - if (lp_inherit_perms(SNUM(conn))) { - inherit_access_posix_acl(conn, parent_dir, path, - unx_mode); + fsp->fh->fd = onefs_sys_create_file(conn, + -1, + path, + access_mask, + open_access_mask, + share_access, + create_options, + flags, + unx_mode, + oplock_request, + id, + sd, + new_dos_attributes, + granted_oplock); + + 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); } + } - /* Change the owner if required. */ - if (lp_inherit_owner(SNUM(conn))) { - change_file_owner_to_parent(conn, parent_dir, - fsp); - } + status = map_nt_error_from_unix(errno); + DEBUG(3,("Error opening file %s (%s) (local_flags=%d) " + "(flags=%d)\n", + path,nt_errstr(status),local_flags,flags)); + return status; + } + + if ((local_flags & O_CREAT) && !file_existed) { - notify_fname(conn, NOTIFY_ACTION_ADDED, - FILE_NOTIFY_CHANGE_FILE_NAME, path); + /* Inherit the ACL if required */ + if (lp_inherit_perms(SNUM(conn))) { + inherit_access_posix_acl(conn, parent_dir, path, + unx_mode); } - } else { - fsp->fh->fd = -1; /* What we used to call a stat open. */ - if (file_existed) { - status = check_open_rights(conn, - path, - access_mask); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("open_file: Access denied on " - "file %s\n", - path)); - return status; - } + /* 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, path); } if (!file_existed) { @@ -346,6 +396,7 @@ static void schedule_defer_open(struct share_mode_lock *lck, 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)) { @@ -354,22 +405,21 @@ static void schedule_defer_open(struct share_mode_lock *lck, } /**************************************************************************** - Open a file with a share mode. Passed in an already created files_struct *. + Open a file with a share mode. Passed in an already created files_struct. ****************************************************************************/ - -static NTSTATUS open_file_ntcreate(connection_struct *conn, - struct smb_request *req, - const char *fname, - SMB_STRUCT_STAT *psbuf, - uint32 access_mask, /* access bits (FILE_READ_DATA etc.) */ - uint32 share_access, /* share constants (FILE_SHARE_READ etc) */ - uint32 create_disposition, /* FILE_OPEN_IF etc. */ - uint32 create_options, /* options such as delete on close. */ - uint32 new_dos_attributes, /* attributes used for new file. */ - int oplock_request, /* internal Samba oplock codes. */ - /* Information (FILE_EXISTS etc.) */ - int *pinfo, - files_struct *fsp) +NTSTATUS onefs_open_file_ntcreate(connection_struct *conn, + struct smb_request *req, + const char *fname, + uint32 access_mask, + uint32 share_access, + uint32 create_disposition, + uint32 create_options, + uint32 new_dos_attributes, + int oplock_request, + struct security_descriptor *sd, + files_struct *fsp, + int *pinfo, + SMB_STRUCT_STAT *psbuf) { int flags=0; int flags2=0; @@ -378,7 +428,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, bool posix_open = False; bool new_file_created = False; struct file_id id; - NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED; mode_t new_unx_mode = (mode_t)0; mode_t unx_mode = (mode_t)0; int info; @@ -391,6 +440,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, int ret_flock; char *parent_dir; const char *newname; + int granted_oplock; + uint64 oplock_waiter; + uint32 createfile_attributes = 0; ZERO_STRUCT(id); @@ -404,7 +456,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, *pinfo = FILE_WAS_CREATED; } - DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname)); + DEBUG(10, ("onefs_open_file_ntcreate: printer open fname=%s\n", + fname)); return print_fsp_open(req, conn, fname, req->vuid, fsp); } @@ -425,13 +478,13 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, parent_dir); } - DEBUG(10, ("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=%d\n", - fname, new_dos_attributes, access_mask, share_access, - create_disposition, create_options, unx_mode, - oplock_request)); + 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", + fname, new_dos_attributes, access_mask, share_access, + create_disposition, create_options, unx_mode, + oplock_request)); if ((req == NULL) && ((oplock_request & INTERNAL_OPEN_ONLY) == 0)) { DEBUG(0, ("No smb request but not an internal only open!\n")); @@ -465,6 +518,17 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, /* Ensure we don't reprocess this message. */ remove_deferred_open_smb_message(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, fname); @@ -479,7 +543,13 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } } - /* ignore any oplock requests if oplocks are disabled */ + /* Setup dos_attributes to be set by ifs_createfile */ + if (lp_store_dos_attributes(SNUM(conn))) { + createfile_attributes = (new_dos_attributes | aARCH) & + ~(FILE_ATTRIBUTE_NONINDEXED | FILE_ATTRIBUTE_COMPRESSED); + } + + /* Ignore oplock requests if oplocks are disabled. */ if (!lp_oplocks(SNUM(conn)) || global_client_failed_oplock_break || IS_VETO_OPLOCK_PATH(conn, fname)) { /* Mask off everything except the private Samba bits. */ @@ -490,8 +560,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (!lp_posix_pathnames() && strstr(fname,".+,;=[].")) { /* OS/2 Workplace shell fix may be main code stream in a later * release. */ - DEBUG(5,("open_file_ntcreate: OS/2 long filenames are not " - "supported.\n")); + 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; } @@ -508,6 +578,14 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, case FILE_SUPERSEDE: /* If file exists replace/overwrite. If file doesn't * exist create. */ + /** + * @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); break; @@ -520,7 +598,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, case FILE_OPEN: /* If file exists open. If file doesn't exist error. */ if (!file_existed) { - DEBUG(5,("open_file_ntcreate: FILE_OPEN " + DEBUG(5,("onefs_open_file_ntcreate: FILE_OPEN " "requested for file %s and file " "doesn't exist.\n", fname )); errno = ENOENT; @@ -532,9 +610,10 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, /* If file exists overwrite. If file doesn't exist * error. */ if (!file_existed) { - DEBUG(5,("open_file_ntcreate: FILE_OVERWRITE " - "requested for file %s and file " - "doesn't exist.\n", fname )); + DEBUG(5, ("onefs_open_file_ntcreate: " + "FILE_OVERWRITE requested for file " + "%s and file doesn't exist.\n", + fname)); errno = ENOENT; return NT_STATUS_OBJECT_NAME_NOT_FOUND; } @@ -545,9 +624,10 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, /* If file exists error. If file doesn't exist * create. */ if (file_existed) { - DEBUG(5,("open_file_ntcreate: FILE_CREATE " - "requested for file %s and file " - "already exists.\n", fname )); + DEBUG(5, ("onefs_open_file_ntcreate: " + "FILE_CREATE requested for file %s " + "and file already exists.\n", + fname)); if (S_ISDIR(psbuf->st_mode)) { errno = EISDIR; } else { @@ -568,45 +648,47 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } - /* We only care about matching attributes on file exists and - * overwrite. */ - - if (!posix_open && file_existed && ((create_disposition == FILE_OVERWRITE) || - (create_disposition == FILE_OVERWRITE_IF))) { + /* 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, fname, existing_dos_attributes, new_dos_attributes, psbuf->st_mode, unx_mode, &new_unx_mode)) { - DEBUG(5,("open_file_ntcreate: attributes missmatch " - "for file %s (%x %x) (0%o, 0%o)\n", - fname, existing_dos_attributes, - new_dos_attributes, - (unsigned int)psbuf->st_mode, - (unsigned int)unx_mode )); + DEBUG(5, ("onefs_open_file_ntcreate: attributes " + "missmatch for file %s (%x %x) (0%o, 0%o)\n", + fname, existing_dos_attributes, + new_dos_attributes, + (unsigned int)psbuf->st_mode, + (unsigned int)unx_mode )); errno = EACCES; return NT_STATUS_ACCESS_DENIED; } } - status = calculate_access_mask(conn, fname, file_existed, - access_mask, - &access_mask); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("open_file_ntcreate: calculate_access_mask " - "on file %s returned %s\n", - fname, - nt_errstr(status))); - return status; + /* + * 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; } - open_access_mask = access_mask; + /* 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)) { - open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */ + /* This will cause oplock breaks. */ + open_access_mask |= FILE_WRITE_DATA; } - DEBUG(10, ("open_file_ntcreate: fname=%s, after mapping " - "access_mask=0x%x\n", fname, access_mask )); + DEBUG(10, ("onefs_open_file_ntcreate: fname=%s, after mapping " + "open_access_mask=%#x, access_mask=0x%x\n", + fname, open_access_mask, access_mask)); /* * Note that we ignore the append flag as append does not @@ -614,12 +696,31 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, */ 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. */ - if ((create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS) || - access_mask & (FILE_READ_ATTRIBUTES|FILE_READ_DATA|FILE_READ_EA|FILE_EXECUTE)) { + (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; @@ -628,12 +729,10 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, flags = O_RDONLY; } - /* - * Currently we only look at FILE_WRITE_THROUGH for create options. - */ - + /* 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))) { + if ((create_options & FILE_WRITE_THROUGH) && + lp_strict_sync(SNUM(conn))) { flags2 |= O_SYNC; } #endif /* O_SYNC */ @@ -649,21 +748,36 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, * older versions of Samba we just AND them out. */ flags2 &= ~(O_CREAT|O_TRUNC); - } - /* - * Ensure we can't write on a read-only share or file. - */ + /** + * XXX: TODO + * Apparently this is necessary because we ship with + * lp_acl_check_permissions = no. It is set to no because our + * ifs_createfile does the access check correctly. This check + * was added in the last merge, and the question is why is it + * necessary? Check out Bug 25547 and Bug 14596. The key is + * to figure out what case this is covering, and do some + * testing to see if it's actually necessary. If it is, maybe + * it should go upstream in open.c. + */ + if (!lp_acl_check_permissions(SNUM(conn)) && + (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,("open_file_ntcreate: write access requested for " - "file %s on read only %s\n", - fname, !CAN_WRITE(conn) ? "share" : "file" )); + DEBUG(5, ("onefs_open_file_ntcreate: write access requested " + "for file %s on read only %s\n", + fname, !CAN_WRITE(conn) ? "share" : "file" )); errno = EACCES; return NT_STATUS_ACCESS_DENIED; } + DEBUG(10, ("fsp = %p\n", fsp)); + fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); fsp->share_access = share_access; fsp->fh->private_options = create_options; @@ -692,57 +806,124 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, return NT_STATUS_SHARING_VIOLATION; } - /* First pass - send break only on batch oplocks. */ - if ((req != NULL) - && delay_for_oplocks(lck, fsp, req->mid, 1, - oplock_request)) { - schedule_defer_open(lck, request_time, req); + if (lck->delete_on_close) { + /* DELETE_PENDING is not deferred for a second */ TALLOC_FREE(lck); - return NT_STATUS_SHARING_VIOLATION; + return NT_STATUS_DELETE_PENDING; } + } - /* Use the client requested access mask here, not the one we - * open with. */ - status = open_mode_check(conn, fname, lck, - access_mask, share_access, - create_options, &file_existed); + SMB_ASSERT(!file_existed || (lck != NULL)); - if (NT_STATUS_IS_OK(status)) { - /* We might be going to allow this open. Check oplock - * status again. */ - /* Second pass - send break for both batch or - * exclusive oplocks. */ - if ((req != NULL) - && delay_for_oplocks(lck, fsp, req->mid, 2, - oplock_request)) { - schedule_defer_open(lck, request_time, req); - TALLOC_FREE(lck); - return NT_STATUS_SHARING_VIOLATION; - } - } + /* + * 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; + } - if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) { - /* DELETE_PENDING is not deferred for a second */ - TALLOC_FREE(lck); - return status; + 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)); + + oplock_waiter = 1; //ifs_oplock_wait_record(mid); + + if (oplock_waiter == 0) { + return NT_STATUS_NO_MEMORY; + } + + /* Do the open. */ + status = onefs_open_file(fsp, + conn, + req, + parent_dir, + newname, + fname, + psbuf, + flags|flags2, + unx_mode, + access_mask, + open_access_mask, + fsp->oplock_type, + oplock_waiter, + share_access, + create_options, + createfile_attributes, + sd, + &granted_oplock); + + if (!NT_STATUS_IS_OK(status)) { + + /* OneFS Oplock Handling */ + if (errno == EINPROGRESS) { + + if (lck == NULL) { + + struct deferred_open_record state; + struct timespec old_write_time; + + old_write_time = get_mtimespec(psbuf); + + DEBUG(3, ("Someone created file %s with an " + "oplock after we looked: Retrying\n", + 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, psbuf); + if (!(lck = get_share_mode_lock(talloc_tos(), + id, conn->connectpath, fname, + &old_write_time))) { + /* + * Emergency exit + */ + DEBUG(0, ("onefs_open_file_ntcreate: " + "Could not get share mode " + "lock for %s\n", fname)); + status = NT_STATUS_SHARING_VIOLATION; + goto cleanup_destroy; + } + + state.delayed_for_oplocks = False; + state.id = id; + + if (req != NULL) { + defer_open(lck, request_time, + timeval_zero(), req, &state); + } + goto cleanup_destroy; + } + /* Waiting for an oplock */ + SMB_ASSERT(req); + schedule_defer_open(lck, request_time, req); + goto cleanup; } - if (!NT_STATUS_IS_OK(status)) { + /* Check for a sharing violation */ + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { uint32 can_access_mask; bool can_access = True; - SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)); - /* Check if this can be done with the deny_dos and fcb * calls. */ + + /* Try to find dup fsp if possible. */ if (create_options & (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS| NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) { + if (req == NULL) { DEBUG(0, ("DOS open without an SMB " "request!\n")); - TALLOC_FREE(lck); - return NT_STATUS_INTERNAL_ERROR; + status = NT_STATUS_INTERNAL_ERROR; + goto cleanup_destroy; } /* Use the client requested access mask here, @@ -763,7 +944,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (pinfo) { *pinfo = FILE_WAS_OPENED; } - return NT_STATUS_OK; + status = NT_STATUS_OK; + goto cleanup; } } @@ -794,7 +976,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, * 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; @@ -804,26 +985,30 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, /* 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. */ + "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. */ + /* 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; if ((req != NULL) && !request_timed_out(request_time, @@ -833,7 +1018,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } } - TALLOC_FREE(lck); if (can_access) { /* * We have detected a sharing violation here @@ -843,45 +1027,25 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } else { status = NT_STATUS_ACCESS_DENIED; } - return status; + + goto cleanup_destroy; } /* - * We exit this block with the share entry *locked*..... + * Normal error, for example EACCES */ + cleanup_destroy: + //destroy_ifs_callback_record(oplock_waiter); + cleanup: + TALLOC_FREE(lck); + return status; } - SMB_ASSERT(!file_existed || (lck != NULL)); - - /* - * Ensure we pay attention to default ACLs on directories if required. - */ - - if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) && - (def_acl = directory_has_default_acl(conn, parent_dir))) { - unx_mode = 0777; - } - - DEBUG(4,("calling 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)); - - /* - * open_file strips any O_TRUNC flags itself. - */ - - fsp_open = open_file(fsp, conn, req, parent_dir, newname, fname, psbuf, - flags|flags2, unx_mode, access_mask, - open_access_mask); + fsp->oplock_type = granted_oplock; - if (!NT_STATUS_IS_OK(fsp_open)) { - if (lck != NULL) { - TALLOC_FREE(lck); - } - return fsp_open; - } + /* XXX uncomment for oplocks */ + //ifs_set_oplock_callback(oplock_waiter, fsp); + //fsp->oplock_callback_id = oplock_waiter; if (!file_existed) { struct timespec old_write_time = get_mtimespec(psbuf); @@ -907,39 +1071,14 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, fname, &old_write_time); if (lck == NULL) { - DEBUG(0, ("open_file_ntcreate: Could not get share " - "mode lock for %s\n", fname)); + DEBUG(0, ("onefs_open_file_ntcreate: Could not get " + "share mode lock for %s\n", fname)); fd_close(fsp); return NT_STATUS_SHARING_VIOLATION; } - /* First pass - send break only on batch oplocks. */ - if ((req != NULL) - && delay_for_oplocks(lck, fsp, req->mid, 1, - oplock_request)) { - schedule_defer_open(lck, request_time, req); - TALLOC_FREE(lck); - fd_close(fsp); - return NT_STATUS_SHARING_VIOLATION; - } - - status = open_mode_check(conn, fname, lck, - access_mask, share_access, - create_options, &file_existed); - - if (NT_STATUS_IS_OK(status)) { - /* We might be going to allow this open. Check oplock - * status again. */ - /* Second pass - send break for both batch or - * exclusive oplocks. */ - if ((req != NULL) - && delay_for_oplocks(lck, fsp, req->mid, 2, - oplock_request)) { - schedule_defer_open(lck, request_time, req); - TALLOC_FREE(lck); - fd_close(fsp); - return NT_STATUS_SHARING_VIOLATION; - } + if (lck->delete_on_close) { + status = NT_STATUS_DELETE_PENDING; } if (!NT_STATUS_IS_OK(status)) { @@ -987,7 +1126,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, TALLOC_FREE(lck); fd_close(fsp); - return NT_STATUS_SHARING_VIOLATION; } } @@ -998,24 +1136,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, * deny mode is compatible with all current opens. */ - /* - * If requested, truncate the file. - */ - - if (flags2&O_TRUNC) { - /* - * We are modifing the file after open - update the stat - * struct.. - */ - if ((SMB_VFS_FTRUNCATE(fsp, 0) == -1) || - (SMB_VFS_FSTAT(fsp, psbuf)==-1)) { - status = map_nt_error_from_unix(errno); - TALLOC_FREE(lck); - fd_close(fsp); - return status; - } - } - /* Record the options we were opened with. */ fsp->share_access = share_access; fsp->fh->private_options = create_options; @@ -1056,16 +1176,16 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, } } - if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || info == FILE_WAS_SUPERSEDED) { + if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || + info == FILE_WAS_SUPERSEDED) { new_file_created = True; } set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, - fsp->oplock_type); + fsp->oplock_type, true); /* Handle strange delete on close create semantics. */ if (create_options & FILE_DELETE_ON_CLOSE) { - status = can_set_delete_on_close(fsp, True, new_dos_attributes); if (!NT_STATUS_IS_OK(status)) { @@ -1080,30 +1200,13 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, fsp->initial_delete_on_close = True; } - if (new_file_created) { - /* Files should be initially set as archive */ - if (lp_map_archive(SNUM(conn)) || - lp_store_dos_attributes(SNUM(conn))) { - if (!posix_open) { - SMB_STRUCT_STAT tmp_sbuf; - SET_STAT_INVALID(tmp_sbuf); - if (file_set_dosmode( - conn, fname, - new_dos_attributes | aARCH, - &tmp_sbuf, parent_dir, - true) == 0) { - unx_mode = tmp_sbuf.st_mode; - } - } - } - } - /* * 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) { + if (!posix_open && !file_existed && !def_acl && !(VALID_STAT(*psbuf) + && (psbuf->st_flags & SF_HASNTFSACL))) { int saved_errno = errno; /* We might get ENOSYS in the next * call.. */ @@ -1127,7 +1230,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if (ret == -1 && errno == ENOSYS) { errno = saved_errno; /* Ignore ENOSYS */ } else { - DEBUG(5, ("open_file_ntcreate: reset " + DEBUG(5, ("onefs_open_file_ntcreate: reset " "attributes of file %s to 0%o\n", fname, (unsigned int)new_unx_mode)); ret = 0; /* Don't do the fchmod below. */ @@ -1136,7 +1239,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, if ((ret == -1) && (SMB_VFS_FCHMOD(fsp, new_unx_mode) == -1)) - DEBUG(5, ("open_file_ntcreate: failed to reset " + DEBUG(5, ("onefs_open_file_ntcreate: failed to reset " "attributes of file %s to 0%o\n", fname, (unsigned int)new_unx_mode)); } @@ -1151,153 +1254,225 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, return NT_STATUS_OK; } + /**************************************************************************** Open a directory from an NT SMB call. ****************************************************************************/ - -static NTSTATUS open_directory(connection_struct *conn, - struct smb_request *req, - const char *fname, - SMB_STRUCT_STAT *psbuf, - uint32 access_mask, - uint32 share_access, - uint32 create_disposition, - uint32 create_options, - uint32 file_attributes, - int *pinfo, - files_struct **result) +static NTSTATUS onefs_open_directory(connection_struct *conn, + struct smb_request *req, + const char *fname, + uint32 access_mask, + uint32 share_access, + uint32 create_disposition, + uint32 create_options, + uint32 file_attributes, + struct security_descriptor *sd, + files_struct **result, + int *pinfo, + SMB_STRUCT_STAT *psbuf) { files_struct *fsp = NULL; - bool dir_existed = VALID_STAT(*psbuf) ? True : False; struct share_mode_lock *lck = NULL; NTSTATUS status; struct timespec mtimespec; int info = 0; - - DEBUG(5,("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", - fname, - (unsigned int)access_mask, - (unsigned int)share_access, - (unsigned int)create_options, - (unsigned int)create_disposition, - (unsigned int)file_attributes)); + char *parent_dir; + const char *dirname; + 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", + fname, (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_name(fname)) { - DEBUG(2, ("open_directory: %s is a stream name!\n", fname)); + (conn->fs_capabilities & FILE_NAMED_STREAMS) && + is_ntfs_stream_name(fname)) { + DEBUG(2, ("onefs_open_directory: %s is a stream name!\n", fname)); return NT_STATUS_NOT_A_DIRECTORY; } - status = calculate_access_mask(conn, fname, dir_existed, - access_mask, - &access_mask); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("open_directory: calculate_access_mask " - "on file %s returned %s\n", - fname, - nt_errstr(status))); - return status; - } - - switch( create_disposition ) { + switch (create_disposition) { case FILE_OPEN: - + /* If directory exists open. If directory doesn't + * exist error. */ + create_flags = 0; info = FILE_WAS_OPENED; - - /* - * We want to follow symlinks here. - */ - - if (SMB_VFS_STAT(conn, fname, psbuf) != 0) { - return map_nt_error_from_unix(errno); - } - break; - case FILE_CREATE: - /* If directory exists error. If directory doesn't * exist create. */ - - status = mkdir_internal(conn, - fname, - file_attributes, - psbuf); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(2, ("open_directory: unable to create " - "%s. Error was %s\n", fname, - nt_errstr(status))); - return status; - } - + 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. - */ - - status = mkdir_internal(conn, - fname, - file_attributes, - psbuf); - - if (NT_STATUS_IS_OK(status)) { - info = FILE_WAS_CREATED; - } - - if (NT_STATUS_EQUAL(status, - NT_STATUS_OBJECT_NAME_COLLISION)) { - info = FILE_WAS_OPENED; - status = NT_STATUS_OK; - } + /* 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,("open_directory: invalid create_disposition " - "0x%x for directory %s\n", - (unsigned int)create_disposition, fname)); + DEBUG(5, ("onefs_open_directory: invalid " + "create_disposition 0x%x for directory %s\n", + (unsigned int)create_disposition, fname)); return NT_STATUS_INVALID_PARAMETER; } - if(!S_ISDIR(psbuf->st_mode)) { - DEBUG(5,("open_directory: %s is not a directory !\n", - fname )); - return NT_STATUS_NOT_A_DIRECTORY; + /* + * 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; } - if (info == FILE_WAS_OPENED) { - status = check_open_rights(conn, - fname, - access_mask); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("open_directory: check_open_rights on " - "file %s failed with %s\n", - fname, - nt_errstr(status))); - return status; - } + /* Get parent dirname */ + if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir, + &dirname)) { + 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, aDIR, fname, 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; } /* - * Setup the files_struct for it. + * 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, + fname, + 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", fname, 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", fname )); + 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", fname )); + 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, fname, psbuf) == -1) { + DEBUG(2, ("Could not stat directory '%s' just " + "created: %s\n",fname, strerror(errno))); + return map_nt_error_from_unix(errno); + } + + if (!S_ISDIR(psbuf->st_mode)) { + DEBUG(0, ("Directory just '%s' created is not a " + "directory\n", fname)); + 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 & ~psbuf->st_mode)) { + SMB_VFS_CHMOD(conn, fname, (psbuf->st_mode | + (mode & ~psbuf->st_mode))); + } + } + + /* Change the owner if required. */ + if (lp_inherit_owner(SNUM(conn))) { + change_dir_owner_to_parent(conn, parent_dir, fname, + psbuf); + } + + notify_fname(conn, NOTIFY_ACTION_ADDED, + FILE_NOTIFY_CHANGE_DIR_NAME, fname); + } + + /* Stat the fd for Samba bookkeeping. */ + if(SMB_VFS_FSTAT(fsp, psbuf) != 0) { + fd_close(fsp); + file_free(req, fsp); + return map_nt_error_from_unix(errno); + } + /* Setup the files_struct for it. */ fsp->mode = psbuf->st_mode; fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf); fsp->vuid = req ? req->vuid : UID_FIELD_INVALID; @@ -1317,40 +1492,48 @@ static NTSTATUS open_directory(connection_struct *conn, fsp->oplock_type = NO_OPLOCK; fsp->sent_oplock_break = NO_BREAK_SENT; fsp->is_directory = True; - fsp->posix_open = (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ? True : False; + fsp->posix_open = posix_open; string_set(&fsp->fsp_name,fname); mtimespec = get_mtimespec(psbuf); + /* + * 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, fname, &mtimespec); if (lck == NULL) { - DEBUG(0, ("open_directory: Could not get share mode lock for %s\n", fname)); + DEBUG(0, ("onefs_open_directory: Could not get share mode " + "lock for %s\n", fname)); + fd_close(fsp); file_free(req, fsp); return NT_STATUS_SHARING_VIOLATION; } - status = open_mode_check(conn, fname, lck, - access_mask, share_access, - create_options, &dir_existed); - - if (!NT_STATUS_IS_OK(status)) { + if (lck->delete_on_close) { TALLOC_FREE(lck); + fd_close(fsp); file_free(req, fsp); - return status; + return NT_STATUS_DELETE_PENDING; } - set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, NO_OPLOCK); + set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, NO_OPLOCK, + true); - /* For directories the delete on close bit at open time seems - always to be honored on close... See test 19 in Samba4 BASE-DELETE. */ + /* + * 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, True, 0); - if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) { + 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; } @@ -1436,7 +1619,7 @@ static NTSTATUS open_streams_for_delete(connection_struct *conn, goto fail; } - status = create_file_unixpath + status = onefs_create_file_unixpath (conn, /* conn */ NULL, /* req */ streamname, /* fname */ @@ -1483,25 +1666,23 @@ static NTSTATUS open_streams_for_delete(connection_struct *conn, } /* - * Wrapper around open_file_ntcreate and open_directory + * Wrapper around onefs_open_file_ntcreate and onefs_open_directory. */ - -static NTSTATUS create_file_unixpath(connection_struct *conn, - struct smb_request *req, - const char *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, - SMB_STRUCT_STAT *psbuf) +static NTSTATUS onefs_create_file_unixpath(connection_struct *conn, + struct smb_request *req, + const char *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, + SMB_STRUCT_STAT *psbuf) { SMB_STRUCT_STAT sbuf; int info = FILE_WAS_OPENED; @@ -1509,7 +1690,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, files_struct *fsp = NULL; NTSTATUS status; - DEBUG(10,("create_file_unixpath: access_mask = 0x%x " + 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 ea_list = 0x%p, sd = 0x%p, " @@ -1559,34 +1740,6 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, } } - /* This is the correct thing to do (check every time) but can_delete - * is expensive (it may have to read the parent directory - * permissions). So for now we're not doing it unless we have a strong - * hint the client is really going to delete this file. If the client - * is forcing FILE_CREATE let the filesystem take care of the - * permissions. */ - - /* Setting FILE_SHARE_DELETE is the hint. */ - - if (lp_acl_check_permissions(SNUM(conn)) - && (create_disposition != FILE_CREATE) - && (share_access & FILE_SHARE_DELETE) - && (access_mask & DELETE_ACCESS) - && (!can_delete_file_in_directory(conn, fname))) { - status = NT_STATUS_ACCESS_DENIED; - goto fail; - } - -#if 0 - /* We need to support SeSecurityPrivilege for this. */ - if ((access_mask & SEC_RIGHT_SYSTEM_SECURITY) && - !user_has_privileges(current_user.nt_user_token, - &se_security)) { - status = NT_STATUS_PRIVILEGE_NOT_HELD; - goto fail; - } -#endif - if ((conn->fs_capabilities & FILE_NAMED_STREAMS) && is_ntfs_stream_name(fname) && (!(create_options & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) { @@ -1601,9 +1754,9 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, status = split_ntfs_stream_name(talloc_tos(), fname, &base, NULL); if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("create_file_unixpath: " - "split_ntfs_stream_name failed: %s\n", - nt_errstr(status))); + DEBUG(10, ("onefs_create_file_unixpath: " + "split_ntfs_stream_name failed: %s\n", + nt_errstr(status))); goto fail; } @@ -1618,22 +1771,43 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, break; } - status = create_file_unixpath(conn, NULL, base, 0, - FILE_SHARE_READ - | FILE_SHARE_WRITE - | FILE_SHARE_DELETE, - base_create_disposition, - 0, 0, 0, 0, NULL, NULL, - &base_fsp, NULL, NULL); + status = onefs_create_file_unixpath( + conn, /* conn */ + NULL, /* req */ + base, /* fname */ + 0, /* access_mask */ + (FILE_SHARE_READ | + FILE_SHARE_WRITE | + FILE_SHARE_DELETE), /* share_access */ + base_create_disposition, /* create_disposition*/ + 0, /* create_options */ + 0, /* file_attributes */ + NO_OPLOCK, /* oplock_request */ + 0, /* allocation_size */ + NULL, /* sd */ + NULL, /* ea_list */ + &base_fsp, /* result */ + NULL, /* pinfo */ + NULL); /* psbuf */ + if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("create_file_unixpath for base %s failed: " - "%s\n", base, nt_errstr(status))); + DEBUG(10, ("onefs_create_file_unixpath for base %s " + "failed: %s\n", base, nt_errstr(status))); goto fail; } - /* we don't need to low level fd */ + /* + * we don't need to low level fd: This might conflict with + * OneFS streams. + */ fd_close(base_fsp); } + /* Covert generic bits in the security descriptor. */ + 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. */ @@ -1658,11 +1832,19 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, * CreateDirectory() call. */ - oplock_request = 0; - status = open_directory( - conn, req, fname, &sbuf, access_mask, share_access, - create_disposition, create_options, file_attributes, - &info, &fsp); + status = onefs_open_directory( + conn, /* conn */ + req, /* req */ + 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 */ + &sbuf); /* psbuf */ } else { /* @@ -1682,18 +1864,20 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, fsp->base_fsp = base_fsp; } - status = open_file_ntcreate(conn, - req, - fname, - &sbuf, - access_mask, - share_access, - create_disposition, - create_options, - file_attributes, - oplock_request, - &info, - fsp); + status = onefs_open_file_ntcreate( + conn, /* conn */ + req, /* req */ + 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 */ + &sbuf); /* psbuf */ if(!NT_STATUS_IS_OK(status)) { file_free(req, fsp); @@ -1719,12 +1903,21 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, goto fail; } - oplock_request = 0; - status = open_directory( - conn, req, fname, &sbuf, access_mask, - share_access, create_disposition, - create_options, file_attributes, - &info, &fsp); + create_options |= FILE_DIRECTORY_FILE; + + status = onefs_open_directory( + conn, /* conn */ + req, /* req */ + 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 */ + &sbuf); /* psbuf */ } } @@ -1734,44 +1927,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, fsp->base_fsp = base_fsp; - /* - * According to the MS documentation, the only time the security - * descriptor is applied to the opened file is iff we *created* the - * file; an existing file stays the same. - * - * Also, it seems (from observation) that you can open the file with - * any access mask but you can still write the sd. We need to override - * the granted access before we call set_sd - * Patch for bug #2242 from Tom Lackemann . - */ - - if ((sd != NULL) && (info == FILE_WAS_CREATED) - && lp_nt_acl_support(SNUM(conn))) { - - uint32_t sec_info_sent; - uint32_t saved_access_mask = fsp->access_mask; - - sec_info_sent = get_sec_info(sd); - - fsp->access_mask = FILE_GENERIC_ALL; - - /* Convert all the generic bits. */ - security_acl_map_generic(sd->dacl, &file_generic_mapping); - security_acl_map_generic(sd->sacl, &file_generic_mapping); - - if (sec_info_sent & (OWNER_SECURITY_INFORMATION| - GROUP_SECURITY_INFORMATION| - DACL_SECURITY_INFORMATION| - SACL_SECURITY_INFORMATION)) { - status = SMB_VFS_FSET_NT_ACL(fsp, sec_info_sent, sd); - } - - fsp->access_mask = saved_access_mask; - - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - } + SMB_ASSERT(fsp); if ((ea_list != NULL) && (info == FILE_WAS_CREATED)) { status = set_ea(conn, fsp, fname, ea_list); @@ -1807,7 +1963,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, } } - DEBUG(10, ("create_file_unixpath: info=%d\n", info)); + DEBUG(10, ("onefs_create_file_unixpath: info=%d\n", info)); *result = fsp; if (pinfo != NULL) { @@ -1824,7 +1980,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, return NT_STATUS_OK; fail: - DEBUG(10, ("create_file_unixpath: %s\n", nt_errstr(status))); + DEBUG(10, ("onefs_create_file_unixpath: %s\n", nt_errstr(status))); if (fsp != NULL) { if (base_fsp && fsp->base_fsp == base_fsp) { @@ -1843,32 +1999,36 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, } return status; } -NTSTATUS create_file_default(connection_struct *conn, - struct smb_request *req, - uint16_t root_dir_fid, - const char *fname, - uint32_t create_file_flags, - 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, - SMB_STRUCT_STAT *psbuf) + +/** + * SMB_VFS_CREATE_FILE interface to onefs. + */ +NTSTATUS onefs_create_file(vfs_handle_struct *handle, + struct smb_request *req, + uint16_t root_dir_fid, + const char *fname, + uint32_t create_file_flags, + 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, + SMB_STRUCT_STAT *psbuf) { + connection_struct *conn = handle->conn; struct case_semantics_state *case_state = NULL; SMB_STRUCT_STAT sbuf; int info = FILE_WAS_OPENED; files_struct *fsp = NULL; NTSTATUS status; - DEBUG(10,("create_file: access_mask = 0x%x " + 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 " @@ -1883,10 +2043,7 @@ NTSTATUS create_file_default(connection_struct *conn, (unsigned int)root_dir_fid, ea_list, sd, create_file_flags, fname)); - /* - * Calculate the filename from the root_dir_if if necessary. - */ - + /* Get the file name if root_dir_fid was specified. */ if (root_dir_fid != 0) { char *new_fname; @@ -1899,45 +2056,7 @@ NTSTATUS create_file_default(connection_struct *conn, fname = new_fname; } - /* - * Check to see if this is a mac fork of some kind. - */ - - if (is_ntfs_stream_name(fname)) { - enum FAKE_FILE_TYPE fake_file_type; - - fake_file_type = is_fake_file(fname); - - if (fake_file_type != FAKE_FILE_TYPE_NONE) { - - /* - * Here we go! support for changing the disk quotas - * --metze - * - * We need to fake up to open this MAGIC QUOTA file - * and return a valid FID. - * - * w2k close this file directly after openening xp - * also tries a QUERY_FILE_INFO on the file and then - * close it - */ - status = open_fake_file(req, conn, req->vuid, - fake_file_type, fname, - access_mask, &fsp); - if (!NT_STATUS_IS_OK(status)) { - goto fail; - } - - ZERO_STRUCT(sbuf); - goto done; - } - - if (!(conn->fs_capabilities & FILE_NAMED_STREAMS)) { - status = NT_STATUS_OBJECT_PATH_NOT_FOUND; - goto fail; - } - } - + /* Resolve the file name if this was a DFS pathname. */ if ((req != NULL) && (req->flags2 & FLAGS2_DFS_PATHNAMES)) { char *resolved_fname; @@ -1956,14 +2075,12 @@ NTSTATUS create_file_default(connection_struct *conn, fname = resolved_fname; } - /* - * Check if POSIX semantics are wanted. - */ - + /* Check if POSIX semantics are wanted. */ if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) { case_state = set_posix_case_semantics(talloc_tos(), conn); } + /* Convert dos path to unix path if it hasn't already been done. */ if (create_file_flags & CFF_DOS_PATH) { char *converted_fname; @@ -1989,24 +2106,33 @@ NTSTATUS create_file_default(connection_struct *conn, TALLOC_FREE(case_state); /* All file access must go through check_name() */ - status = check_name(conn, fname); if (!NT_STATUS_IS_OK(status)) { goto fail; } - status = create_file_unixpath( - conn, req, fname, access_mask, share_access, - create_disposition, create_options, file_attributes, - oplock_request, allocation_size, sd, ea_list, - &fsp, &info, &sbuf); + status = onefs_create_file_unixpath( + conn, /* conn */ + req, /* req */ + 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 */ + sd, /* sd */ + ea_list, /* ea_list */ + &fsp, /* result */ + &info, /* pinfo */ + &sbuf); /* psbuf */ if (!NT_STATUS_IS_OK(status)) { goto fail; } - done: - DEBUG(10, ("create_file: info=%d\n", info)); + DEBUG(10, ("onefs_create_file: info=%d\n", info)); *result = fsp; if (pinfo != NULL) { @@ -2018,7 +2144,7 @@ NTSTATUS create_file_default(connection_struct *conn, return NT_STATUS_OK; fail: - DEBUG(10, ("create_file: %s\n", nt_errstr(status))); + DEBUG(10, ("onefs_create_file: %s\n", nt_errstr(status))); if (fsp != NULL) { close_file(req, fsp, ERROR_CLOSE); diff --git a/source3/modules/onefs_system.c b/source3/modules/onefs_system.c new file mode 100644 index 0000000000..485e7f56ac --- /dev/null +++ b/source3/modules/onefs_system.c @@ -0,0 +1,214 @@ +/* + * 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; +} diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c index 193a986cf6..b51858fbae 100644 --- a/source3/modules/vfs_onefs.c +++ b/source3/modules/vfs_onefs.c @@ -1,4 +1,5 @@ /* + * Unix SMB/CIFS implementation. * Support for OneFS * * Copyright (C) Tim Prouty, 2008 @@ -18,20 +19,32 @@ */ #include "includes.h" +#include "onefs.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS -NTSTATUS onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - uint32 security_info, SEC_DESC **ppdesc); - -NTSTATUS onefs_get_nt_acl(vfs_handle_struct *handle, const char* name, - uint32 security_info, SEC_DESC **ppdesc); +static int onefs_mkdir(vfs_handle_struct *handle, const char *path, + mode_t mode) +{ + DEBUG(0, ("SMB_VFS_MKDIR should never be called in vfs_onefs")); + return SMB_VFS_NEXT_MKDIR(handle, path, mode); +} -NTSTATUS onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, - uint32 security_info_sent, SEC_DESC *psd); +static int onefs_open(vfs_handle_struct *handle, const char *fname, + files_struct *fsp, int flags, mode_t mode) +{ + DEBUG(0, ("SMB_VFS_OPEN should never be called in vfs_onefs")); + return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode); +} static vfs_op_tuple onefs_ops[] = { + {SMB_VFS_OP(onefs_mkdir), SMB_VFS_OP_MKDIR, + SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(onefs_open), SMB_VFS_OP_OPEN, + SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(onefs_create_file), SMB_VFS_OP_CREATE_FILE, + SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(onefs_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, -- cgit From 7b9f6dda131f471ae61c12e7eb06d67b8f02b1cf Mon Sep 17 00:00:00 2001 From: Tim Prouty Date: Sat, 6 Dec 2008 16:08:35 -0800 Subject: s3: [3/3]: Fix a delete on close divergence from windows and the associated torture test This third patch cleans up by removing all of the code that is made obsolete by the first patch. It should cause no functional changes. --- source3/modules/onefs_open.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/onefs_open.c b/source3/modules/onefs_open.c index bda5e7e91a..d0310d0174 100644 --- a/source3/modules/onefs_open.c +++ b/source3/modules/onefs_open.c @@ -1182,7 +1182,7 @@ NTSTATUS onefs_open_file_ntcreate(connection_struct *conn, } set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, - fsp->oplock_type, true); + fsp->oplock_type); /* Handle strange delete on close create semantics. */ if (create_options & FILE_DELETE_ON_CLOSE) { @@ -1521,8 +1521,7 @@ static NTSTATUS onefs_open_directory(connection_struct *conn, return NT_STATUS_DELETE_PENDING; } - set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, NO_OPLOCK, - true); + set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, NO_OPLOCK); /* * For directories the delete on close bit at open time seems -- cgit From 21b9dec990b08a104600bf8e408e64e805a02835 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 10 Dec 2008 03:17:19 +0100 Subject: Pass the get_real_filename operation through the VFS This is done to help file systems that can tell us about the real upper/lower case combination given a case-insensitive file name. The sample I will soon push is the gpfs module (recent gpfs has a get_real_filename function), others might have a similar function to help alleviate the 1million files in a single directory problem. Jeremy, please comment! Thanks, Volker --- source3/modules/vfs_default.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'source3/modules') diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 6d8d8f8065..8fa8f6ae06 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -1038,6 +1038,16 @@ static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle, return NT_STATUS_OK; } +static int vfswrap_get_real_filename(struct vfs_handle_struct *handle, + const char *path, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + return get_real_filename(handle->conn, path, name, mem_ctx, + found_name); +} + static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc) @@ -1459,6 +1469,8 @@ static vfs_op_tuple vfs_default_ops[] = { SMB_VFS_LAYER_OPAQUE}, {SMB_VFS_OP(vfswrap_streaminfo), SMB_VFS_OP_STREAMINFO, SMB_VFS_LAYER_OPAQUE}, + {SMB_VFS_OP(vfswrap_get_real_filename), SMB_VFS_OP_GET_REAL_FILENAME, + SMB_VFS_LAYER_OPAQUE}, /* NT ACL operations. */ -- cgit From a0efc4cffbd84898c454d27eaf946d073dfdad0f Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 10 Dec 2008 18:10:03 +0100 Subject: Fix some merge omissions for GPFS --- source3/modules/gpfs.c | 10 +++++----- source3/modules/vfs_gpfs.c | 13 +++++++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c index 4e76b97ccf..c4b2518e02 100644 --- a/source3/modules/gpfs.c +++ b/source3/modules/gpfs.c @@ -43,7 +43,7 @@ bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask, if (!gpfs_share_modes) { return True; } - + if (gpfs_set_share_fn == NULL) { return False; } @@ -104,7 +104,7 @@ int set_gpfs_lease(int fd, int leasetype) if (leasetype == F_WRLCK) { gpfs_type = GPFS_LEASE_WRITE; } - + /* we unconditionally set CAP_LEASE, rather than looking for -1/EACCES as there is a bug in some versions of libgpfs_gpl.so which results in a leaked fd on /dev/ss0 @@ -143,7 +143,7 @@ static bool init_gpfs_function_lib(void *plibhandle_pointer, void **fn_pointer = (void **)pfn_pointer; if (*libhandle_pointer == NULL) { - *libhandle_pointer = dlopen(libname, RTLD_LAZY); + *libhandle_pointer = sys_dlopen(libname, RTLD_LAZY); did_open_here = true; } if (*libhandle_pointer == NULL) { @@ -151,12 +151,12 @@ static bool init_gpfs_function_lib(void *plibhandle_pointer, return false; } - *fn_pointer = dlsym(*libhandle_pointer, fn_name); + *fn_pointer = sys_dlsym(*libhandle_pointer, fn_name); if (*fn_pointer == NULL) { DEBUG(10, ("Did not find symbol %s in lib %s\n", fn_name, libname)); if (did_open_here) { - dlclose(*libhandle_pointer); + sys_dlclose(*libhandle_pointer); *libhandle_pointer = NULL; } return false; diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index fa0b4e97a5..a9e7a84249 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -365,7 +365,7 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) return True; } -static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd) +static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) { struct gpfs_acl *acl; NTSTATUS result = NT_STATUS_ACCESS_DENIED; @@ -386,7 +386,12 @@ static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_i return result; } -static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd) +static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) +{ + return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd); +} + +static NTSTATUS gpfsacl_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, char *name, uint32 security_info_sent, SEC_DESC *psd) { return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd); } @@ -834,6 +839,10 @@ static vfs_op_tuple gpfs_op_tuples[] = { SMB_VFS_OP_FSET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, + { SMB_VFS_OP(gpfsacl_set_nt_acl), + SMB_VFS_OP_SET_NT_ACL, + SMB_VFS_LAYER_TRANSPARENT }, + { SMB_VFS_OP(gpfsacl_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT }, -- cgit From a4b52118d44906882677ed1234428d8025134036 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 10 Dec 2008 03:22:04 +0100 Subject: Fix nonempty blank lines in vfs_gpfs.c --- source3/modules/vfs_gpfs.c | 105 +++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 55 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index a9e7a84249..5cadce9e1d 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -1,26 +1,24 @@ /* Unix SMB/CIFS implementation. Wrap gpfs calls in vfs functions. - + Copyright (C) Christian Ambach 2006 - + Major code contributions by Chetan Shringarpure and Gomati Mohanan - + 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 "includes.h" @@ -55,14 +53,14 @@ static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, int leasetype) { int ret; - + START_PROFILE(syscall_linux_setlease); - + if ( linux_set_lease_sighandler(fsp->fh->fd) == -1) return -1; ret = set_gpfs_lease(fsp->fh->fd,leasetype); - + if ( ret < 0 ) { /* This must have come from GPFS not being available */ /* or some other error, hence call the default */ @@ -301,13 +299,13 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) gace->aceType = aceprop->aceType; gace->aceFlags = aceprop->aceFlags; gace->aceMask = aceprop->aceMask; - + /* * GPFS can't distinguish between WRITE and APPEND on * files, so one being set without the other is an * error. Sorry for the many ()'s :-) */ - + if (!fsp->is_directory && ((((gace->aceMask & ACE4_MASK_WRITE) == 0) @@ -323,9 +321,9 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) fsp->fsp_name)); gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND; } - + gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0; - + if (aceprop->flags&SMB_ACE4_ID_SPECIAL) { switch(aceprop->who.special_id) @@ -483,7 +481,7 @@ static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type) errno = EINVAL; goto done; } - + DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n", pacl->acl_len, pacl->acl_level, pacl->acl_version, pacl->acl_nace)); @@ -502,7 +500,6 @@ static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type) } SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle, - const char *path_p, SMB_ACL_TYPE_T type) { @@ -562,7 +559,7 @@ static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl, for (i=0; icount; i++) { const struct smb_acl_entry *ace = &pacl->acl[i]; struct gpfs_ace_v1 *g_ace = &result->ace_v1[i]; - + DEBUG(10, ("Converting type %d perm %x\n", (int)ace->a_type, (int)ace->a_perm)); @@ -617,7 +614,6 @@ static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl, } int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle, - const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T theacl) @@ -644,7 +640,6 @@ int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle, } int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle, - const char *path) { errno = ENOTSUP; @@ -666,11 +661,11 @@ static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx) uint32_t posix_mask = 0x01; uint32_t posix_bit; uint32_t nfs4_bits; - + for(i=0; i<3; i++) { nfs4_bits = posix_nfs4map[i]; posix_bit = rwx & posix_mask; - + if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) { if (posix_bit) aceMask |= nfs4_bits; @@ -683,10 +678,10 @@ static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx) else aceMask &= ~nfs4_bits; } /* other ace types are unexpected */ - + posix_mask <<= 1; } - + return aceMask; } @@ -698,30 +693,30 @@ static int gpfsacl_emu_chmod(const char *path, mode_t mode) int i; files_struct fake_fsp; /* TODO: rationalize parametrization */ SMB4ACE_T *smbace; - + DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode)); - + result = gpfs_get_nfs4_acl(path, &pacl); if (result) return result; - + if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) { DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path)); } - + for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) { SMB_ACE4PROP_T *ace = smb_get_ace4(smbace); uint32_t specid = ace->who.special_id; - + if (ace->flags&SMB_ACE4_ID_SPECIAL && ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE && specid <= SMB_ACE4_WHO_EVERYONE) { - + uint32_t newMask; - + if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) haveAllowEntry[specid] = True; - + /* mode >> 6 for @owner, mode >> 3 for @group, * mode >> 0 for @everyone */ newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask, @@ -740,35 +735,35 @@ static int gpfsacl_emu_chmod(const char *path, mode_t mode) */ for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) { SMB_ACE4PROP_T ace; - + if (haveAllowEntry[i]==True) continue; - + ZERO_STRUCT(ace); ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE; ace.flags |= SMB_ACE4_ID_SPECIAL; ace.who.special_id = i; - + if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */ ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; - + ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask, mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3)); - + /* don't add unnecessary aces */ if (!ace.aceMask) continue; - + /* we add it to the END - as windows expects allow aces */ smb_add_ace4(pacl, &ace); DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n", path, mode, i, ace.aceMask)); } - + /* don't add complementary DENY ACEs here */ ZERO_STRUCT(fake_fsp); fake_fsp.fsp_name = (char *)path; /* no file_new is needed here */ - + /* put the acl */ if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False) return -1; @@ -779,11 +774,11 @@ static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mo { SMB_STRUCT_STAT st; int rc; - + if (SMB_VFS_NEXT_STAT(handle, path, &st) != 0) { return -1; } - + /* avoid chmod() if possible, to preserve acls */ if ((st.st_mode & ~S_IFMT) == mode) { return 0; @@ -799,7 +794,7 @@ static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t { SMB_STRUCT_STAT st; int rc; - + if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) { return -1; } @@ -818,27 +813,27 @@ static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t /* VFS operations structure */ static vfs_op_tuple gpfs_op_tuples[] = { - + { SMB_VFS_OP(vfs_gpfs_kernel_flock), SMB_VFS_OP_KERNEL_FLOCK, SMB_VFS_LAYER_OPAQUE }, - + { SMB_VFS_OP(vfs_gpfs_setlease), SMB_VFS_OP_LINUX_SETLEASE, SMB_VFS_LAYER_OPAQUE }, - + { SMB_VFS_OP(gpfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_set_nt_acl), SMB_VFS_OP_SET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, @@ -846,27 +841,27 @@ static vfs_op_tuple gpfs_op_tuples[] = { { SMB_VFS_OP(gpfsacl_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_set_fd), SMB_VFS_OP_SYS_ACL_SET_FD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_delete_def_file), SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(vfs_gpfs_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(vfs_gpfs_fchmod), SMB_VFS_OP_FCHMOD, SMB_VFS_LAYER_TRANSPARENT }, @@ -880,7 +875,7 @@ NTSTATUS vfs_gpfs_init(void); NTSTATUS vfs_gpfs_init(void) { init_gpfs(); - + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs", gpfs_op_tuples); } -- cgit From b37684ffcec4ba0beada55d37bcaf4f5e79bcd58 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 10 Dec 2008 12:32:24 +0100 Subject: Make use of smbd_gpfs_get_realfilename_path in unix_convert --- source3/modules/gpfs.c | 25 +++++++++++++++++++ source3/modules/vfs_gpfs.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) (limited to 'source3/modules') diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c index c4b2518e02..92aecb9fb6 100644 --- a/source3/modules/gpfs.c +++ b/source3/modules/gpfs.c @@ -31,6 +31,8 @@ static int (*gpfs_set_share_fn)(int fd, unsigned int allow, unsigned int deny); static int (*gpfs_set_lease_fn)(int fd, unsigned int leaseType); static int (*gpfs_getacl_fn)(char *pathname, int flags, void *acl); static int (*gpfs_putacl_fn)(char *pathname, int flags, void *acl); +static int (*gpfs_get_realfilename_path_fn)(char *pathname, char *filenamep, + int *buflen); bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask, @@ -134,6 +136,17 @@ int smbd_gpfs_putacl(char *pathname, int flags, void *acl) return gpfs_putacl_fn(pathname, flags, acl); } +int smbd_gpfs_get_realfilename_path(char *pathname, char *filenamep, + int *buflen) +{ + if (gpfs_get_realfilename_path_fn == NULL) { + errno = ENOSYS; + return -1; + } + + return gpfs_get_realfilename_path_fn(pathname, filenamep, buflen); +} + static bool init_gpfs_function_lib(void *plibhandle_pointer, const char *libname, void *pfn_pointer, const char *fn_name) @@ -142,6 +155,9 @@ static bool init_gpfs_function_lib(void *plibhandle_pointer, void **libhandle_pointer = (void **)plibhandle_pointer; void **fn_pointer = (void **)pfn_pointer; + DEBUG(10, ("trying to load name %s from %s\n", + fn_name, libname)); + if (*libhandle_pointer == NULL) { *libhandle_pointer = sys_dlopen(libname, RTLD_LAZY); did_open_here = true; @@ -187,6 +203,8 @@ void init_gpfs(void) init_gpfs_function(&gpfs_set_lease_fn, "gpfs_set_lease"); init_gpfs_function(&gpfs_getacl_fn, "gpfs_getacl"); init_gpfs_function(&gpfs_putacl_fn, "gpfs_putacl"); + init_gpfs_function(&gpfs_get_realfilename_path_fn, + "gpfs_get_realfilename_path"); gpfs_share_modes = lp_parm_bool(-1, "gpfs", "sharemodes", True); gpfs_leases = lp_parm_bool(-1, "gpfs", "leases", True); @@ -226,6 +244,13 @@ int smbd_gpfs_putacl(char *pathname, int flags, void *acl) return -1; } +int smbd_gpfs_get_realfilename_path(char *pathname, char *fileamep, + int *buflen) +{ + errno = ENOSYS; + return -1; +} + void init_gpfs(void) { return; diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 5cadce9e1d..780bd9b8a5 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -72,7 +72,64 @@ static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, return ret; } +static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle, + const char *path, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + int result; + char *full_path; + char real_pathname[PATH_MAX+1]; + int buflen; + + full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name); + if (full_path == NULL) { + errno = ENOMEM; + return -1; + } + + buflen = sizeof(real_pathname) - 1; + + result = smbd_gpfs_get_realfilename_path(full_path, real_pathname, + &buflen); + + TALLOC_FREE(full_path); + + if (result == -1) { + DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n", + strerror(errno))); + return -1; + } + + /* + * GPFS does not necessarily null-terminate the returned path + * but instead returns the buffer length in buflen. + */ + if (buflen < sizeof(real_pathname)) { + real_pathname[buflen] = '\0'; + } else { + real_pathname[sizeof(real_pathname)-1] = '\0'; + } + + DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n", + path, name, real_pathname)); + + name = strrchr_m(real_pathname, '/'); + if (name == NULL) { + errno = ENOENT; + return -1; + } + + *found_name = talloc_strdup(mem_ctx, name+1); + if (*found_name == NULL) { + errno = ENOMEM; + return -1; + } + + return 0; +} static void gpfs_dumpacl(int level, struct gpfs_acl *gacl) { @@ -822,6 +879,10 @@ static vfs_op_tuple gpfs_op_tuples[] = { SMB_VFS_OP_LINUX_SETLEASE, SMB_VFS_LAYER_OPAQUE }, + { SMB_VFS_OP(vfs_gpfs_get_real_filename), + SMB_VFS_OP_GET_REAL_FILENAME, + SMB_VFS_LAYER_OPAQUE }, + { SMB_VFS_OP(gpfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, -- cgit From c044b09572631cbdd686e5dbbdfbcc731145533a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 10 Dec 2008 16:58:40 +0100 Subject: Fix the build Crap, too many trees and no instant, infinitely fast rebuild --- source3/modules/vfs_gpfs.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 780bd9b8a5..fae08dd252 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -446,11 +446,6 @@ static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd); } -static NTSTATUS gpfsacl_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, char *name, uint32 security_info_sent, SEC_DESC *psd) -{ - return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd); -} - static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl) { SMB_ACL_T result; @@ -895,10 +890,6 @@ static vfs_op_tuple gpfs_op_tuples[] = { SMB_VFS_OP_FSET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - { SMB_VFS_OP(gpfsacl_set_nt_acl), - SMB_VFS_OP_SET_NT_ACL, - SMB_VFS_LAYER_TRANSPARENT }, - { SMB_VFS_OP(gpfsacl_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT }, -- cgit From 7ad9676864a70366c3165c6f35e5c8665bc6468d Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 10 Dec 2008 23:13:34 +0100 Subject: Revert "Fix the build" This reverts commit c044b09572631cbdd686e5dbbdfbcc731145533a. --- source3/modules/vfs_gpfs.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'source3/modules') diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index fae08dd252..780bd9b8a5 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -446,6 +446,11 @@ static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd); } +static NTSTATUS gpfsacl_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, char *name, uint32 security_info_sent, SEC_DESC *psd) +{ + return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd); +} + static SMB_ACL_T gpfs2smb_acl(const struct gpfs_acl *pacl) { SMB_ACL_T result; @@ -890,6 +895,10 @@ static vfs_op_tuple gpfs_op_tuples[] = { SMB_VFS_OP_FSET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, + { SMB_VFS_OP(gpfsacl_set_nt_acl), + SMB_VFS_OP_SET_NT_ACL, + SMB_VFS_LAYER_TRANSPARENT }, + { SMB_VFS_OP(gpfsacl_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT }, -- cgit From 1896ccb24732fc9a3407224209d741640dd602d3 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 10 Dec 2008 23:14:01 +0100 Subject: Revert "Make use of smbd_gpfs_get_realfilename_path in unix_convert" This reverts commit b37684ffcec4ba0beada55d37bcaf4f5e79bcd58. --- source3/modules/gpfs.c | 25 ------------------- source3/modules/vfs_gpfs.c | 61 ---------------------------------------------- 2 files changed, 86 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c index 92aecb9fb6..c4b2518e02 100644 --- a/source3/modules/gpfs.c +++ b/source3/modules/gpfs.c @@ -31,8 +31,6 @@ static int (*gpfs_set_share_fn)(int fd, unsigned int allow, unsigned int deny); static int (*gpfs_set_lease_fn)(int fd, unsigned int leaseType); static int (*gpfs_getacl_fn)(char *pathname, int flags, void *acl); static int (*gpfs_putacl_fn)(char *pathname, int flags, void *acl); -static int (*gpfs_get_realfilename_path_fn)(char *pathname, char *filenamep, - int *buflen); bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask, @@ -136,17 +134,6 @@ int smbd_gpfs_putacl(char *pathname, int flags, void *acl) return gpfs_putacl_fn(pathname, flags, acl); } -int smbd_gpfs_get_realfilename_path(char *pathname, char *filenamep, - int *buflen) -{ - if (gpfs_get_realfilename_path_fn == NULL) { - errno = ENOSYS; - return -1; - } - - return gpfs_get_realfilename_path_fn(pathname, filenamep, buflen); -} - static bool init_gpfs_function_lib(void *plibhandle_pointer, const char *libname, void *pfn_pointer, const char *fn_name) @@ -155,9 +142,6 @@ static bool init_gpfs_function_lib(void *plibhandle_pointer, void **libhandle_pointer = (void **)plibhandle_pointer; void **fn_pointer = (void **)pfn_pointer; - DEBUG(10, ("trying to load name %s from %s\n", - fn_name, libname)); - if (*libhandle_pointer == NULL) { *libhandle_pointer = sys_dlopen(libname, RTLD_LAZY); did_open_here = true; @@ -203,8 +187,6 @@ void init_gpfs(void) init_gpfs_function(&gpfs_set_lease_fn, "gpfs_set_lease"); init_gpfs_function(&gpfs_getacl_fn, "gpfs_getacl"); init_gpfs_function(&gpfs_putacl_fn, "gpfs_putacl"); - init_gpfs_function(&gpfs_get_realfilename_path_fn, - "gpfs_get_realfilename_path"); gpfs_share_modes = lp_parm_bool(-1, "gpfs", "sharemodes", True); gpfs_leases = lp_parm_bool(-1, "gpfs", "leases", True); @@ -244,13 +226,6 @@ int smbd_gpfs_putacl(char *pathname, int flags, void *acl) return -1; } -int smbd_gpfs_get_realfilename_path(char *pathname, char *fileamep, - int *buflen) -{ - errno = ENOSYS; - return -1; -} - void init_gpfs(void) { return; diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 780bd9b8a5..5cadce9e1d 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -72,64 +72,7 @@ static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, return ret; } -static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle, - const char *path, - const char *name, - TALLOC_CTX *mem_ctx, - char **found_name) -{ - int result; - char *full_path; - char real_pathname[PATH_MAX+1]; - int buflen; - - full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name); - if (full_path == NULL) { - errno = ENOMEM; - return -1; - } - - buflen = sizeof(real_pathname) - 1; - - result = smbd_gpfs_get_realfilename_path(full_path, real_pathname, - &buflen); - - TALLOC_FREE(full_path); - - if (result == -1) { - DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n", - strerror(errno))); - return -1; - } - - /* - * GPFS does not necessarily null-terminate the returned path - * but instead returns the buffer length in buflen. - */ - if (buflen < sizeof(real_pathname)) { - real_pathname[buflen] = '\0'; - } else { - real_pathname[sizeof(real_pathname)-1] = '\0'; - } - - DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n", - path, name, real_pathname)); - - name = strrchr_m(real_pathname, '/'); - if (name == NULL) { - errno = ENOENT; - return -1; - } - - *found_name = talloc_strdup(mem_ctx, name+1); - if (*found_name == NULL) { - errno = ENOMEM; - return -1; - } - - return 0; -} static void gpfs_dumpacl(int level, struct gpfs_acl *gacl) { @@ -879,10 +822,6 @@ static vfs_op_tuple gpfs_op_tuples[] = { SMB_VFS_OP_LINUX_SETLEASE, SMB_VFS_LAYER_OPAQUE }, - { SMB_VFS_OP(vfs_gpfs_get_real_filename), - SMB_VFS_OP_GET_REAL_FILENAME, - SMB_VFS_LAYER_OPAQUE }, - { SMB_VFS_OP(gpfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, -- cgit From 8d641826595e3be8864097d4aea7a76879c173d6 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 10 Dec 2008 23:14:16 +0100 Subject: Revert "Fix nonempty blank lines in vfs_gpfs.c" This reverts commit a4b52118d44906882677ed1234428d8025134036. --- source3/modules/vfs_gpfs.c | 105 ++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 50 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 5cadce9e1d..a9e7a84249 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -1,24 +1,26 @@ /* Unix SMB/CIFS implementation. Wrap gpfs calls in vfs functions. - + Copyright (C) Christian Ambach 2006 - + Major code contributions by Chetan Shringarpure and Gomati Mohanan - + 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 "includes.h" @@ -53,14 +55,14 @@ static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, int leasetype) { int ret; - + START_PROFILE(syscall_linux_setlease); - + if ( linux_set_lease_sighandler(fsp->fh->fd) == -1) return -1; ret = set_gpfs_lease(fsp->fh->fd,leasetype); - + if ( ret < 0 ) { /* This must have come from GPFS not being available */ /* or some other error, hence call the default */ @@ -299,13 +301,13 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) gace->aceType = aceprop->aceType; gace->aceFlags = aceprop->aceFlags; gace->aceMask = aceprop->aceMask; - + /* * GPFS can't distinguish between WRITE and APPEND on * files, so one being set without the other is an * error. Sorry for the many ()'s :-) */ - + if (!fsp->is_directory && ((((gace->aceMask & ACE4_MASK_WRITE) == 0) @@ -321,9 +323,9 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) fsp->fsp_name)); gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND; } - + gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0; - + if (aceprop->flags&SMB_ACE4_ID_SPECIAL) { switch(aceprop->who.special_id) @@ -481,7 +483,7 @@ static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type) errno = EINVAL; goto done; } - + DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n", pacl->acl_len, pacl->acl_level, pacl->acl_version, pacl->acl_nace)); @@ -500,6 +502,7 @@ static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type) } SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle, + const char *path_p, SMB_ACL_TYPE_T type) { @@ -559,7 +562,7 @@ static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl, for (i=0; icount; i++) { const struct smb_acl_entry *ace = &pacl->acl[i]; struct gpfs_ace_v1 *g_ace = &result->ace_v1[i]; - + DEBUG(10, ("Converting type %d perm %x\n", (int)ace->a_type, (int)ace->a_perm)); @@ -614,6 +617,7 @@ static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl, } int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle, + const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T theacl) @@ -640,6 +644,7 @@ int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle, } int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle, + const char *path) { errno = ENOTSUP; @@ -661,11 +666,11 @@ static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx) uint32_t posix_mask = 0x01; uint32_t posix_bit; uint32_t nfs4_bits; - + for(i=0; i<3; i++) { nfs4_bits = posix_nfs4map[i]; posix_bit = rwx & posix_mask; - + if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) { if (posix_bit) aceMask |= nfs4_bits; @@ -678,10 +683,10 @@ static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx) else aceMask &= ~nfs4_bits; } /* other ace types are unexpected */ - + posix_mask <<= 1; } - + return aceMask; } @@ -693,30 +698,30 @@ static int gpfsacl_emu_chmod(const char *path, mode_t mode) int i; files_struct fake_fsp; /* TODO: rationalize parametrization */ SMB4ACE_T *smbace; - + DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode)); - + result = gpfs_get_nfs4_acl(path, &pacl); if (result) return result; - + if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) { DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path)); } - + for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) { SMB_ACE4PROP_T *ace = smb_get_ace4(smbace); uint32_t specid = ace->who.special_id; - + if (ace->flags&SMB_ACE4_ID_SPECIAL && ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE && specid <= SMB_ACE4_WHO_EVERYONE) { - + uint32_t newMask; - + if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) haveAllowEntry[specid] = True; - + /* mode >> 6 for @owner, mode >> 3 for @group, * mode >> 0 for @everyone */ newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask, @@ -735,35 +740,35 @@ static int gpfsacl_emu_chmod(const char *path, mode_t mode) */ for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) { SMB_ACE4PROP_T ace; - + if (haveAllowEntry[i]==True) continue; - + ZERO_STRUCT(ace); ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE; ace.flags |= SMB_ACE4_ID_SPECIAL; ace.who.special_id = i; - + if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */ ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; - + ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask, mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3)); - + /* don't add unnecessary aces */ if (!ace.aceMask) continue; - + /* we add it to the END - as windows expects allow aces */ smb_add_ace4(pacl, &ace); DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n", path, mode, i, ace.aceMask)); } - + /* don't add complementary DENY ACEs here */ ZERO_STRUCT(fake_fsp); fake_fsp.fsp_name = (char *)path; /* no file_new is needed here */ - + /* put the acl */ if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False) return -1; @@ -774,11 +779,11 @@ static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mo { SMB_STRUCT_STAT st; int rc; - + if (SMB_VFS_NEXT_STAT(handle, path, &st) != 0) { return -1; } - + /* avoid chmod() if possible, to preserve acls */ if ((st.st_mode & ~S_IFMT) == mode) { return 0; @@ -794,7 +799,7 @@ static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t { SMB_STRUCT_STAT st; int rc; - + if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) { return -1; } @@ -813,27 +818,27 @@ static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t /* VFS operations structure */ static vfs_op_tuple gpfs_op_tuples[] = { - + { SMB_VFS_OP(vfs_gpfs_kernel_flock), SMB_VFS_OP_KERNEL_FLOCK, SMB_VFS_LAYER_OPAQUE }, - + { SMB_VFS_OP(vfs_gpfs_setlease), SMB_VFS_OP_LINUX_SETLEASE, SMB_VFS_LAYER_OPAQUE }, - + { SMB_VFS_OP(gpfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_set_nt_acl), SMB_VFS_OP_SET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, @@ -841,27 +846,27 @@ static vfs_op_tuple gpfs_op_tuples[] = { { SMB_VFS_OP(gpfsacl_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_set_fd), SMB_VFS_OP_SYS_ACL_SET_FD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_delete_def_file), SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(vfs_gpfs_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(vfs_gpfs_fchmod), SMB_VFS_OP_FCHMOD, SMB_VFS_LAYER_TRANSPARENT }, @@ -875,7 +880,7 @@ NTSTATUS vfs_gpfs_init(void); NTSTATUS vfs_gpfs_init(void) { init_gpfs(); - + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs", gpfs_op_tuples); } -- cgit From 7c2bdead9e3e4436e427668a16df367e14885cbc Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 10 Dec 2008 23:14:46 +0100 Subject: Revert "Fix some merge omissions for GPFS" This reverts commit a0efc4cffbd84898c454d27eaf946d073dfdad0f. This one should have been done with careful cherry-picks, sorry. Volker --- source3/modules/gpfs.c | 10 +++++----- source3/modules/vfs_gpfs.c | 13 ++----------- 2 files changed, 7 insertions(+), 16 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c index c4b2518e02..4e76b97ccf 100644 --- a/source3/modules/gpfs.c +++ b/source3/modules/gpfs.c @@ -43,7 +43,7 @@ bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask, if (!gpfs_share_modes) { return True; } - + if (gpfs_set_share_fn == NULL) { return False; } @@ -104,7 +104,7 @@ int set_gpfs_lease(int fd, int leasetype) if (leasetype == F_WRLCK) { gpfs_type = GPFS_LEASE_WRITE; } - + /* we unconditionally set CAP_LEASE, rather than looking for -1/EACCES as there is a bug in some versions of libgpfs_gpl.so which results in a leaked fd on /dev/ss0 @@ -143,7 +143,7 @@ static bool init_gpfs_function_lib(void *plibhandle_pointer, void **fn_pointer = (void **)pfn_pointer; if (*libhandle_pointer == NULL) { - *libhandle_pointer = sys_dlopen(libname, RTLD_LAZY); + *libhandle_pointer = dlopen(libname, RTLD_LAZY); did_open_here = true; } if (*libhandle_pointer == NULL) { @@ -151,12 +151,12 @@ static bool init_gpfs_function_lib(void *plibhandle_pointer, return false; } - *fn_pointer = sys_dlsym(*libhandle_pointer, fn_name); + *fn_pointer = dlsym(*libhandle_pointer, fn_name); if (*fn_pointer == NULL) { DEBUG(10, ("Did not find symbol %s in lib %s\n", fn_name, libname)); if (did_open_here) { - sys_dlclose(*libhandle_pointer); + dlclose(*libhandle_pointer); *libhandle_pointer = NULL; } return false; diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index a9e7a84249..fa0b4e97a5 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -365,7 +365,7 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) return True; } -static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) +static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd) { struct gpfs_acl *acl; NTSTATUS result = NT_STATUS_ACCESS_DENIED; @@ -386,12 +386,7 @@ static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_i return result; } -static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd) -{ - return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd); -} - -static NTSTATUS gpfsacl_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp, char *name, uint32 security_info_sent, SEC_DESC *psd) +static NTSTATUS gpfsacl_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp, uint32 security_info_sent, const SEC_DESC *psd) { return gpfsacl_set_nt_acl_internal(fsp, security_info_sent, psd); } @@ -839,10 +834,6 @@ static vfs_op_tuple gpfs_op_tuples[] = { SMB_VFS_OP_FSET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - { SMB_VFS_OP(gpfsacl_set_nt_acl), - SMB_VFS_OP_SET_NT_ACL, - SMB_VFS_LAYER_TRANSPARENT }, - { SMB_VFS_OP(gpfsacl_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT }, -- cgit From 8e0cce5b38c4d12ff490eadecb028155b6eb5dce Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 1 Oct 2008 12:26:55 +0200 Subject: s3:modules/gpfs: Fix nonempty blank lines --- source3/modules/gpfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c index 4e76b97ccf..7caa810c49 100644 --- a/source3/modules/gpfs.c +++ b/source3/modules/gpfs.c @@ -43,7 +43,7 @@ bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask, if (!gpfs_share_modes) { return True; } - + if (gpfs_set_share_fn == NULL) { return False; } @@ -104,7 +104,7 @@ int set_gpfs_lease(int fd, int leasetype) if (leasetype == F_WRLCK) { gpfs_type = GPFS_LEASE_WRITE; } - + /* we unconditionally set CAP_LEASE, rather than looking for -1/EACCES as there is a bug in some versions of libgpfs_gpl.so which results in a leaked fd on /dev/ss0 -- cgit From de8bb1725540d7fd12fe76b6b0da719309b41d69 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 10 Dec 2008 03:22:04 +0100 Subject: Fix nonempty blank lines in vfs_gpfs.c Signed-off-by: Michael Adam --- source3/modules/vfs_gpfs.c | 105 +++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 55 deletions(-) (limited to 'source3/modules') diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index fa0b4e97a5..187c13b009 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -1,26 +1,24 @@ /* Unix SMB/CIFS implementation. Wrap gpfs calls in vfs functions. - + Copyright (C) Christian Ambach 2006 - + Major code contributions by Chetan Shringarpure and Gomati Mohanan - + 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 "includes.h" @@ -55,14 +53,14 @@ static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, int leasetype) { int ret; - + START_PROFILE(syscall_linux_setlease); - + if ( linux_set_lease_sighandler(fsp->fh->fd) == -1) return -1; ret = set_gpfs_lease(fsp->fh->fd,leasetype); - + if ( ret < 0 ) { /* This must have come from GPFS not being available */ /* or some other error, hence call the default */ @@ -301,13 +299,13 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) gace->aceType = aceprop->aceType; gace->aceFlags = aceprop->aceFlags; gace->aceMask = aceprop->aceMask; - + /* * GPFS can't distinguish between WRITE and APPEND on * files, so one being set without the other is an * error. Sorry for the many ()'s :-) */ - + if (!fsp->is_directory && ((((gace->aceMask & ACE4_MASK_WRITE) == 0) @@ -323,9 +321,9 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) fsp->fsp_name)); gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND; } - + gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0; - + if (aceprop->flags&SMB_ACE4_ID_SPECIAL) { switch(aceprop->who.special_id) @@ -478,7 +476,7 @@ static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type) errno = EINVAL; goto done; } - + DEBUG(10, ("len: %d, level: %d, version: %d, nace: %d\n", pacl->acl_len, pacl->acl_level, pacl->acl_version, pacl->acl_nace)); @@ -497,7 +495,6 @@ static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type) } SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle, - const char *path_p, SMB_ACL_TYPE_T type) { @@ -557,7 +554,7 @@ static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl, for (i=0; icount; i++) { const struct smb_acl_entry *ace = &pacl->acl[i]; struct gpfs_ace_v1 *g_ace = &result->ace_v1[i]; - + DEBUG(10, ("Converting type %d perm %x\n", (int)ace->a_type, (int)ace->a_perm)); @@ -612,7 +609,6 @@ static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl, } int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle, - const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T theacl) @@ -639,7 +635,6 @@ int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle, } int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle, - const char *path) { errno = ENOTSUP; @@ -661,11 +656,11 @@ static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx) uint32_t posix_mask = 0x01; uint32_t posix_bit; uint32_t nfs4_bits; - + for(i=0; i<3; i++) { nfs4_bits = posix_nfs4map[i]; posix_bit = rwx & posix_mask; - + if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) { if (posix_bit) aceMask |= nfs4_bits; @@ -678,10 +673,10 @@ static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx) else aceMask &= ~nfs4_bits; } /* other ace types are unexpected */ - + posix_mask <<= 1; } - + return aceMask; } @@ -693,30 +688,30 @@ static int gpfsacl_emu_chmod(const char *path, mode_t mode) int i; files_struct fake_fsp; /* TODO: rationalize parametrization */ SMB4ACE_T *smbace; - + DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode)); - + result = gpfs_get_nfs4_acl(path, &pacl); if (result) return result; - + if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) { DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path)); } - + for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) { SMB_ACE4PROP_T *ace = smb_get_ace4(smbace); uint32_t specid = ace->who.special_id; - + if (ace->flags&SMB_ACE4_ID_SPECIAL && ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE && specid <= SMB_ACE4_WHO_EVERYONE) { - + uint32_t newMask; - + if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) haveAllowEntry[specid] = True; - + /* mode >> 6 for @owner, mode >> 3 for @group, * mode >> 0 for @everyone */ newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask, @@ -735,35 +730,35 @@ static int gpfsacl_emu_chmod(const char *path, mode_t mode) */ for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) { SMB_ACE4PROP_T ace; - + if (haveAllowEntry[i]==True) continue; - + ZERO_STRUCT(ace); ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE; ace.flags |= SMB_ACE4_ID_SPECIAL; ace.who.special_id = i; - + if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */ ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP; - + ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask, mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3)); - + /* don't add unnecessary aces */ if (!ace.aceMask) continue; - + /* we add it to the END - as windows expects allow aces */ smb_add_ace4(pacl, &ace); DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n", path, mode, i, ace.aceMask)); } - + /* don't add complementary DENY ACEs here */ ZERO_STRUCT(fake_fsp); fake_fsp.fsp_name = (char *)path; /* no file_new is needed here */ - + /* put the acl */ if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False) return -1; @@ -774,11 +769,11 @@ static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mo { SMB_STRUCT_STAT st; int rc; - + if (SMB_VFS_NEXT_STAT(handle, path, &st) != 0) { return -1; } - + /* avoid chmod() if possible, to preserve acls */ if ((st.st_mode & ~S_IFMT) == mode) { return 0; @@ -794,7 +789,7 @@ static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t { SMB_STRUCT_STAT st; int rc; - + if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) { return -1; } @@ -813,51 +808,51 @@ static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t /* VFS operations structure */ static vfs_op_tuple gpfs_op_tuples[] = { - + { SMB_VFS_OP(vfs_gpfs_kernel_flock), SMB_VFS_OP_KERNEL_FLOCK, SMB_VFS_LAYER_OPAQUE }, - + { SMB_VFS_OP(vfs_gpfs_setlease), SMB_VFS_OP_LINUX_SETLEASE, SMB_VFS_LAYER_OPAQUE }, - + { SMB_VFS_OP(gpfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_set_fd), SMB_VFS_OP_SYS_ACL_SET_FD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(gpfsacl_sys_acl_delete_def_file), SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(vfs_gpfs_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT }, - + { SMB_VFS_OP(vfs_gpfs_fchmod), SMB_VFS_OP_FCHMOD, SMB_VFS_LAYER_TRANSPARENT }, @@ -871,7 +866,7 @@ NTSTATUS vfs_gpfs_init(void); NTSTATUS vfs_gpfs_init(void) { init_gpfs(); - + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "gpfs", gpfs_op_tuples); } -- cgit From 110bb2244931d0979461e75e5ff83b2ba21e2fc4 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Wed, 10 Dec 2008 12:32:24 +0100 Subject: Make use of smbd_gpfs_get_realfilename_path in unix_convert (cherry picked from commit b37684ffcec4ba0beada55d37bcaf4f5e79bcd58) Signed-off-by: Michael Adam --- source3/modules/gpfs.c | 25 +++++++++++++++++++ source3/modules/vfs_gpfs.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) (limited to 'source3/modules') diff --git a/source3/modules/gpfs.c b/source3/modules/gpfs.c index 7caa810c49..16599005b9 100644 --- a/source3/modules/gpfs.c +++ b/source3/modules/gpfs.c @@ -31,6 +31,8 @@ static int (*gpfs_set_share_fn)(int fd, unsigned int allow, unsigned int deny); static int (*gpfs_set_lease_fn)(int fd, unsigned int leaseType); static int (*gpfs_getacl_fn)(char *pathname, int flags, void *acl); static int (*gpfs_putacl_fn)(char *pathname, int flags, void *acl); +static int (*gpfs_get_realfilename_path_fn)(char *pathname, char *filenamep, + int *buflen); bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask, @@ -134,6 +136,17 @@ int smbd_gpfs_putacl(char *pathname, int flags, void *acl) return gpfs_putacl_fn(pathname, flags, acl); } +int smbd_gpfs_get_realfilename_path(char *pathname, char *filenamep, + int *buflen) +{ + if (gpfs_get_realfilename_path_fn == NULL) { + errno = ENOSYS; + return -1; + } + + return gpfs_get_realfilename_path_fn(pathname, filenamep, buflen); +} + static bool init_gpfs_function_lib(void *plibhandle_pointer, const char *libname, void *pfn_pointer, const char *fn_name) @@ -142,6 +155,9 @@ static bool init_gpfs_function_lib(void *plibhandle_pointer, void **libhandle_pointer = (void **)plibhandle_pointer; void **fn_pointer = (void **)pfn_pointer; + DEBUG(10, ("trying to load name %s from %s\n", + fn_name, libname)); + if (*libhandle_pointer == NULL) { *libhandle_pointer = dlopen(libname, RTLD_LAZY); did_open_here = true; @@ -187,6 +203,8 @@ void init_gpfs(void) init_gpfs_function(&gpfs_set_lease_fn, "gpfs_set_lease"); init_gpfs_function(&gpfs_getacl_fn, "gpfs_getacl"); init_gpfs_function(&gpfs_putacl_fn, "gpfs_putacl"); + init_gpfs_function(&gpfs_get_realfilename_path_fn, + "gpfs_get_realfilename_path"); gpfs_share_modes = lp_parm_bool(-1, "gpfs", "sharemodes", True); gpfs_leases = lp_parm_bool(-1, "gpfs", "leases", True); @@ -226,6 +244,13 @@ int smbd_gpfs_putacl(char *pathname, int flags, void *acl) return -1; } +int smbd_gpfs_get_realfilename_path(char *pathname, char *fileamep, + int *buflen) +{ + errno = ENOSYS; + return -1; +} + void init_gpfs(void) { return; diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 187c13b009..1d7cdba014 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -72,7 +72,64 @@ static int vfs_gpfs_setlease(vfs_handle_struct *handle, files_struct *fsp, return ret; } +static int vfs_gpfs_get_real_filename(struct vfs_handle_struct *handle, + const char *path, + const char *name, + TALLOC_CTX *mem_ctx, + char **found_name) +{ + int result; + char *full_path; + char real_pathname[PATH_MAX+1]; + int buflen; + + full_path = talloc_asprintf(talloc_tos(), "%s/%s", path, name); + if (full_path == NULL) { + errno = ENOMEM; + return -1; + } + + buflen = sizeof(real_pathname) - 1; + + result = smbd_gpfs_get_realfilename_path(full_path, real_pathname, + &buflen); + + TALLOC_FREE(full_path); + + if (result == -1) { + DEBUG(10, ("smbd_gpfs_get_realfilename_path returned %s\n", + strerror(errno))); + return -1; + } + + /* + * GPFS does not necessarily null-terminate the returned path + * but instead returns the buffer length in buflen. + */ + if (buflen < sizeof(real_pathname)) { + real_pathname[buflen] = '\0'; + } else { + real_pathname[sizeof(real_pathname)-1] = '\0'; + } + + DEBUG(10, ("smbd_gpfs_get_realfilename_path: %s/%s -> %s\n", + path, name, real_pathname)); + + name = strrchr_m(real_pathname, '/'); + if (name == NULL) { + errno = ENOENT; + return -1; + } + + *found_name = talloc_strdup(mem_ctx, name+1); + if (*found_name == NULL) { + errno = ENOMEM; + return -1; + } + + return 0; +} static void gpfs_dumpacl(int level, struct gpfs_acl *gacl) { @@ -817,6 +874,10 @@ static vfs_op_tuple gpfs_op_tuples[] = { SMB_VFS_OP_LINUX_SETLEASE, SMB_VFS_LAYER_OPAQUE }, + { SMB_VFS_OP(vfs_gpfs_get_real_filename), + SMB_VFS_OP_GET_REAL_FILENAME, + SMB_VFS_LAYER_OPAQUE }, + { SMB_VFS_OP(gpfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT }, -- cgit