📄 pvfs_open.c
字号:
/* Unix SMB/CIFS implementation. POSIX NTVFS backend - open and close Copyright (C) Andrew Tridgell 2004 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "vfs_posix.h"#include "system/dir.h"#include "system/time.h"#include "lib/util/dlinklist.h"#include "messaging/messaging.h"#include "librpc/gen_ndr/xattr.h"/* find open file handle given fnum*/struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs, struct ntvfs_request *req, struct ntvfs_handle *h){ void *p; struct pvfs_file *f; p = ntvfs_handle_get_backend_data(h, pvfs->ntvfs); if (!p) return NULL; f = talloc_get_type(p, struct pvfs_file); if (!f) return NULL; return f;}/* cleanup a open directory handle*/static int pvfs_dir_handle_destructor(struct pvfs_file_handle *h){ if (h->have_opendb_entry) { struct odb_lock *lck; NTSTATUS status; const char *delete_path = NULL; lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); if (lck == NULL) { DEBUG(0,("Unable to lock opendb for close\n")); return 0; } status = odb_close_file(lck, h, &delete_path); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", h->name->full_name, nt_errstr(status))); } if (h->name->stream_name == NULL && delete_path) { status = pvfs_xattr_unlink_hook(h->pvfs, delete_path); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n", delete_path, nt_errstr(status))); } if (rmdir(delete_path) != 0) { DEBUG(0,("pvfs_dir_handle_destructor: failed to rmdir '%s' - %s\n", delete_path, strerror(errno))); } } talloc_free(lck); } return 0;}/* cleanup a open directory fnum*/static int pvfs_dir_fnum_destructor(struct pvfs_file *f){ DLIST_REMOVE(f->pvfs->files.list, f); ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs); return 0;}/* setup any EAs and the ACL on newly created files/directories*/static NTSTATUS pvfs_open_setup_eas_acl(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, int fd, struct pvfs_file *f, union smb_open *io){ NTSTATUS status; /* setup any EAs that were asked for */ if (io->ntcreatex.in.ea_list) { status = pvfs_setfileinfo_ea_set(pvfs, name, fd, io->ntcreatex.in.ea_list->num_eas, io->ntcreatex.in.ea_list->eas); if (!NT_STATUS_IS_OK(status)) { return status; } } /* setup an initial sec_desc if requested */ if (io->ntcreatex.in.sec_desc) { union smb_setfileinfo set;/* * TODO: set the full ACL! * - vista denies the creation of the file with NT_STATUS_PRIVILEGE_NOT_HELD, * when a SACL is present on the sd, * but the user doesn't have SeSecurityPrivilege * - w2k3 allows it */ set.set_secdesc.in.file.ntvfs = f->ntvfs; set.set_secdesc.in.secinfo_flags = SECINFO_DACL; set.set_secdesc.in.sd = io->ntcreatex.in.sec_desc; status = pvfs_acl_set(pvfs, req, name, fd, SEC_STD_WRITE_DAC, &set); } else { /* otherwise setup an inherited acl from the parent */ status = pvfs_acl_inherit(pvfs, req, name, fd); } return status;}/* form the lock context used for opendb locking. Note that we must zero here to take account of possible padding on some architectures*/NTSTATUS pvfs_locking_key(struct pvfs_filename *name, TALLOC_CTX *mem_ctx, DATA_BLOB *key){ struct { dev_t device; ino_t inode; } lock_context; ZERO_STRUCT(lock_context); lock_context.device = name->st.st_dev; lock_context.inode = name->st.st_ino; *key = data_blob_talloc(mem_ctx, &lock_context, sizeof(lock_context)); if (key->data == NULL) { return NT_STATUS_NO_MEMORY; } return NT_STATUS_OK;}/* open a directory*/static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, union smb_open *io){ struct pvfs_file *f; struct ntvfs_handle *h; NTSTATUS status; uint32_t create_action; uint32_t access_mask = io->generic.in.access_mask; struct odb_lock *lck; bool del_on_close; uint32_t create_options; uint32_t share_access; bool forced; create_options = io->generic.in.create_options; share_access = io->generic.in.share_access; forced = (io->generic.in.create_options & NTCREATEX_OPTIONS_DIRECTORY)?true:false; if (name->stream_name) { if (forced) { return NT_STATUS_NOT_A_DIRECTORY; } else { return NT_STATUS_FILE_IS_A_DIRECTORY; } } /* if the client says it must be a directory, and it isn't, then fail */ if (name->exists && !(name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) { return NT_STATUS_NOT_A_DIRECTORY; } /* found with gentest */ if (io->ntcreatex.in.access_mask == SEC_FLAG_MAXIMUM_ALLOWED && (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DIRECTORY) && (io->ntcreatex.in.create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) { return NT_STATUS_INVALID_PARAMETER; } switch (io->generic.in.open_disposition) { case NTCREATEX_DISP_OPEN_IF: break; case NTCREATEX_DISP_OPEN: if (!name->exists) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } break; case NTCREATEX_DISP_CREATE: if (name->exists) { return NT_STATUS_OBJECT_NAME_COLLISION; } break; case NTCREATEX_DISP_OVERWRITE_IF: case NTCREATEX_DISP_OVERWRITE: case NTCREATEX_DISP_SUPERSEDE: default: return NT_STATUS_INVALID_PARAMETER; } status = ntvfs_handle_new(pvfs->ntvfs, req, &h); NT_STATUS_NOT_OK_RETURN(status); f = talloc(h, struct pvfs_file); if (f == NULL) { return NT_STATUS_NO_MEMORY; } f->handle = talloc(f, struct pvfs_file_handle); if (f->handle == NULL) { return NT_STATUS_NO_MEMORY; } if (name->exists) { /* check the security descriptor */ status = pvfs_access_check(pvfs, req, name, &access_mask); } else { status = pvfs_access_check_create(pvfs, req, name, &access_mask); } NT_STATUS_NOT_OK_RETURN(status); if (io->generic.in.query_maximal_access) { status = pvfs_access_maximal_allowed(pvfs, req, name, &io->generic.out.maximal_access); NT_STATUS_NOT_OK_RETURN(status); } f->ntvfs = h; f->pvfs = pvfs; f->pending_list = NULL; f->lock_count = 0; f->share_access = io->generic.in.share_access; f->impersonation = io->generic.in.impersonation; f->access_mask = access_mask; f->brl_handle = NULL; f->notify_buffer = NULL; f->search = NULL; f->handle->pvfs = pvfs; f->handle->name = talloc_steal(f->handle, name); f->handle->fd = -1; f->handle->odb_locking_key = data_blob(NULL, 0); f->handle->create_options = io->generic.in.create_options; f->handle->seek_offset = 0; f->handle->position = 0; f->handle->mode = 0; f->handle->oplock = NULL; f->handle->open_completed = false; if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) && pvfs_directory_empty(pvfs, f->handle->name)) { del_on_close = true; } else { del_on_close = false; } if (name->exists) { /* form the lock context used for opendb locking */ status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key); if (!NT_STATUS_IS_OK(status)) { return status; } /* get a lock on this file before the actual open */ lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key); if (lck == NULL) { DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n", name->full_name)); /* we were supposed to do a blocking lock, so something is badly wrong! */ return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* see if we are allowed to open at the same time as existing opens */ status = odb_can_open(lck, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, false); if (!NT_STATUS_IS_OK(status)) { talloc_free(lck); return status; } /* now really mark the file as open */ status = odb_open_file(lck, f->handle, name->full_name, NULL, false, OPLOCK_NONE, NULL); if (!NT_STATUS_IS_OK(status)) { talloc_free(lck); return status; } f->handle->have_opendb_entry = true; } DLIST_ADD(pvfs->files.list, f); /* setup destructors to avoid leaks on abnormal termination */ talloc_set_destructor(f->handle, pvfs_dir_handle_destructor); talloc_set_destructor(f, pvfs_dir_fnum_destructor); if (!name->exists) { uint32_t attrib = io->generic.in.file_attr | FILE_ATTRIBUTE_DIRECTORY; mode_t mode = pvfs_fileperms(pvfs, attrib); if (mkdir(name->full_name, mode) == -1) { return pvfs_map_errno(pvfs,errno); } pvfs_xattr_unlink_hook(pvfs, name->full_name); status = pvfs_resolve_name(pvfs, req, io->ntcreatex.in.fname, 0, &name); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } status = pvfs_open_setup_eas_acl(pvfs, req, name, -1, f, io); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } /* form the lock context used for opendb locking */ status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key); if (!NT_STATUS_IS_OK(status)) { return status; } lck = odb_lock(req, pvfs->odb_context, &f->handle->odb_locking_key); if (lck == NULL) { DEBUG(0,("pvfs_open: failed to lock file '%s' in opendb\n", name->full_name)); /* we were supposed to do a blocking lock, so something is badly wrong! */ return NT_STATUS_INTERNAL_DB_CORRUPTION; } status = odb_can_open(lck, name->stream_id, share_access, access_mask, del_on_close, io->generic.in.open_disposition, false); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } status = odb_open_file(lck, f->handle, name->full_name, NULL, false, OPLOCK_NONE, NULL); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } f->handle->have_opendb_entry = true; create_action = NTCREATEX_ACTION_CREATED; notify_trigger(pvfs->notify_context, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_DIR_NAME, name->full_name); } else { create_action = NTCREATEX_ACTION_EXISTED; } if (!name->exists) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } /* the open succeeded, keep this handle permanently */ status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } f->handle->open_completed = true; io->generic.out.oplock_level = OPLOCK_NONE; io->generic.out.file.ntvfs = h; io->generic.out.create_action = create_action; io->generic.out.create_time = name->dos.create_time; io->generic.out.access_time = name->dos.access_time; io->generic.out.write_time = name->dos.write_time; io->generic.out.change_time = name->dos.change_time; io->generic.out.attrib = name->dos.attrib; io->generic.out.alloc_size = name->dos.alloc_size; io->generic.out.size = name->st.st_size; io->generic.out.file_type = FILE_TYPE_DISK; io->generic.out.ipc_state = 0; io->generic.out.is_directory = 1; return NT_STATUS_OK;cleanup_delete: rmdir(name->full_name); return status;}/* destroy a struct pvfs_file_handle*/static int pvfs_handle_destructor(struct pvfs_file_handle *h){ if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) && h->name->stream_name) { NTSTATUS status; status = pvfs_stream_delete(h->pvfs, h->name, h->fd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Failed to delete stream '%s' on close of '%s'\n", h->name->stream_name, h->name->full_name)); } } if (h->fd != -1) { if (close(h->fd) != 0) { DEBUG(0,("pvfs_handle_destructor: close(%d) failed for %s - %s\n", h->fd, h->name->full_name, strerror(errno))); } h->fd = -1; } if (h->have_opendb_entry) { struct odb_lock *lck; NTSTATUS status; const char *delete_path = NULL; lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key); if (lck == NULL) { DEBUG(0,("Unable to lock opendb for close\n")); return 0; } status = odb_close_file(lck, h, &delete_path); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", h->name->full_name, nt_errstr(status))); } if (h->name->stream_name == NULL && h->open_completed && delete_path) { status = pvfs_xattr_unlink_hook(h->pvfs, delete_path); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Warning: xattr unlink hook failed for '%s' - %s\n", delete_path, nt_errstr(status))); } if (unlink(delete_path) != 0) { DEBUG(0,("pvfs_close: failed to delete '%s' - %s\n", delete_path, strerror(errno))); } else { notify_trigger(h->pvfs->notify_context,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -