📄 pvfs_open.c
字号:
NOTIFY_ACTION_REMOVED, FILE_NOTIFY_CHANGE_FILE_NAME, delete_path); } } talloc_free(lck); } return 0;}/* destroy a struct pvfs_file*/static int pvfs_fnum_destructor(struct pvfs_file *f){ DLIST_REMOVE(f->pvfs->files.list, f); pvfs_lock_close(f->pvfs, f); ntvfs_handle_remove_backend_data(f->ntvfs, f->pvfs->ntvfs); return 0;}/* form the lock context used for byte range locking. This is separate from the locking key used for opendb locking as it needs to take account of file streams (each stream is a separate byte range locking space)*/static NTSTATUS pvfs_brl_locking_handle(TALLOC_CTX *mem_ctx, struct pvfs_filename *name, struct ntvfs_handle *ntvfs, struct brl_handle **_h){ DATA_BLOB odb_key, key; NTSTATUS status; struct brl_handle *h; status = pvfs_locking_key(name, mem_ctx, &odb_key); NT_STATUS_NOT_OK_RETURN(status); if (name->stream_name == NULL) { key = odb_key; } else { key = data_blob_talloc(mem_ctx, NULL, odb_key.length + strlen(name->stream_name) + 1); NT_STATUS_HAVE_NO_MEMORY(key.data); memcpy(key.data, odb_key.data, odb_key.length); memcpy(key.data + odb_key.length, name->stream_name, strlen(name->stream_name) + 1); data_blob_free(&odb_key); } h = brl_create_handle(mem_ctx, ntvfs, &key); NT_STATUS_HAVE_NO_MEMORY(h); *_h = h; return NT_STATUS_OK;}/* create a new file*/static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, struct ntvfs_request *req, struct pvfs_filename *name, union smb_open *io){ struct pvfs_file *f; NTSTATUS status; struct ntvfs_handle *h; int flags, fd; struct odb_lock *lck; uint32_t create_options = io->generic.in.create_options; uint32_t share_access = io->generic.in.share_access; uint32_t access_mask = io->generic.in.access_mask; mode_t mode; uint32_t attrib; bool del_on_close; struct pvfs_filename *parent; uint32_t oplock_level = OPLOCK_NONE, oplock_granted; bool allow_level_II_oplock = false; if (io->ntcreatex.in.file_attr & ~FILE_ATTRIBUTE_ALL_MASK) { return NT_STATUS_INVALID_PARAMETER; } if (io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_ENCRYPTED) { return NT_STATUS_ACCESS_DENIED; } if ((io->ntcreatex.in.file_attr & FILE_ATTRIBUTE_READONLY) && (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE)) { return NT_STATUS_CANNOT_DELETE; } 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); } /* check that the parent isn't opened with delete on close set */ status = pvfs_resolve_parent(pvfs, req, name, &parent); if (NT_STATUS_IS_OK(status)) { DATA_BLOB locking_key; status = pvfs_locking_key(parent, req, &locking_key); NT_STATUS_NOT_OK_RETURN(status); status = odb_get_delete_on_close(pvfs->odb_context, &locking_key, &del_on_close); NT_STATUS_NOT_OK_RETURN(status); if (del_on_close) { return NT_STATUS_DELETE_PENDING; } } if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) { flags = O_RDWR; } else { flags = O_RDONLY; } status = ntvfs_handle_new(pvfs->ntvfs, req, &h); NT_STATUS_NOT_OK_RETURN(status); f = talloc(h, struct pvfs_file); NT_STATUS_HAVE_NO_MEMORY(f); f->handle = talloc(f, struct pvfs_file_handle); NT_STATUS_HAVE_NO_MEMORY(f->handle); attrib = io->ntcreatex.in.file_attr | FILE_ATTRIBUTE_ARCHIVE; mode = pvfs_fileperms(pvfs, attrib); /* create the file */ fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode); if (fd == -1) { return pvfs_map_errno(pvfs, errno); } pvfs_xattr_unlink_hook(pvfs, name->full_name); /* if this was a stream create then create the stream as well */ if (name->stream_name) { status = pvfs_stream_create(pvfs, name, fd); if (!NT_STATUS_IS_OK(status)) { close(fd); return status; } } /* re-resolve the open fd */ status = pvfs_resolve_name_fd(pvfs, fd, name); if (!NT_STATUS_IS_OK(status)) { close(fd); return status; } /* support initial alloc sizes */ name->dos.alloc_size = io->ntcreatex.in.alloc_size; name->dos.attrib = attrib; status = pvfs_dosattrib_save(pvfs, name, fd); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } status = pvfs_open_setup_eas_acl(pvfs, req, name, fd, f, io); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } /* form the lock context used for byte range locking and opendb locking */ status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } status = pvfs_brl_locking_handle(f, name, h, &f->brl_handle); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } /* grab a lock on the open file record */ 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! */ status = NT_STATUS_INTERNAL_DB_CORRUPTION; goto cleanup_delete; } if (create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) { del_on_close = true; } else { del_on_close = false; } if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) { oplock_level = OPLOCK_NONE; } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK) { oplock_level = OPLOCK_BATCH; } else if (io->ntcreatex.in.flags & NTCREATEX_FLAGS_REQUEST_OPLOCK) { oplock_level = OPLOCK_EXCLUSIVE; } if (req->client_caps & NTVFS_CLIENT_CAP_LEVEL_II_OPLOCKS) { allow_level_II_oplock = true; } 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); /* bad news, we must have hit a race - we don't delete the file here as the most likely scenario is that someone else created the file at the same time */ close(fd); 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->access_mask = access_mask; f->impersonation = io->generic.in.impersonation; f->notify_buffer = NULL; f->search = NULL; f->handle->pvfs = pvfs; f->handle->name = talloc_steal(f->handle, name); f->handle->fd = fd; 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->have_opendb_entry = true; f->handle->open_completed = false; status = odb_open_file(lck, f->handle, name->full_name, &f->handle->fd, allow_level_II_oplock, oplock_level, &oplock_granted); talloc_free(lck); if (!NT_STATUS_IS_OK(status)) { /* bad news, we must have hit a race - we don't delete the file here as the most likely scenario is that someone else created the file at the same time */ close(fd); return status; } DLIST_ADD(pvfs->files.list, f); /* setup a destructor to avoid file descriptor leaks on abnormal termination */ talloc_set_destructor(f, pvfs_fnum_destructor); talloc_set_destructor(f->handle, pvfs_handle_destructor); if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) { oplock_granted = OPLOCK_BATCH; } else if (oplock_granted != OPLOCK_NONE) { status = pvfs_setup_oplock(f, oplock_granted); if (!NT_STATUS_IS_OK(status)) { return status; } } io->generic.out.oplock_level = oplock_granted; io->generic.out.file.ntvfs = f->ntvfs; io->generic.out.create_action = NTCREATEX_ACTION_CREATED; 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 = 0; /* success - keep the file handle */ status = ntvfs_handle_set_backend_data(h, pvfs->ntvfs, f); if (!NT_STATUS_IS_OK(status)) { goto cleanup_delete; } f->handle->open_completed = true; notify_trigger(pvfs->notify_context, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_FILE_NAME, name->full_name); return NT_STATUS_OK;cleanup_delete: close(fd); unlink(name->full_name); return status;}/* state of a pending retry*/struct pvfs_odb_retry { struct ntvfs_module_context *ntvfs; struct ntvfs_request *req; DATA_BLOB odb_locking_key; void *io; void *private_data; void (*callback)(struct pvfs_odb_retry *r, struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, void *io, void *private_data, enum pvfs_wait_notice reason);};/* destroy a pending request */static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r){ struct pvfs_state *pvfs = r->ntvfs->private_data; if (r->odb_locking_key.data) { struct odb_lock *lck; lck = odb_lock(r->req, pvfs->odb_context, &r->odb_locking_key); if (lck != NULL) { odb_remove_pending(lck, r); } talloc_free(lck); } return 0;}static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason){ struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry); if (reason == PVFS_WAIT_EVENT) { /* * The pending odb entry is already removed. * We use a null locking key to indicate this * to the destructor. */ data_blob_free(&r->odb_locking_key); } r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);}/* setup for a retry of a request that was rejected by odb_can_open()*/NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, struct odb_lock *lck, struct timeval end_time, void *io, void *private_data, void (*callback)(struct pvfs_odb_retry *r, struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, void *io, void *private_data, enum pvfs_wait_notice reason)){ struct pvfs_state *pvfs = ntvfs->private_data; struct pvfs_odb_retry *r; struct pvfs_wait *wait_handle; NTSTATUS status; r = talloc(req, struct pvfs_odb_retry); NT_STATUS_HAVE_NO_MEMORY(r); r->ntvfs = ntvfs; r->req = req; r->io = io; r->private_data = private_data; r->callback = callback; r->odb_locking_key = odb_get_key(r, lck); if (r->odb_locking_key.data == NULL) { return NT_STATUS_NO_MEMORY; } /* setup a pending lock */ status = odb_open_file_pending(lck, r); if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) { /* * maybe only a unix application * has the file open */ data_blob_free(&r->odb_locking_key); } else if (!NT_STATUS_IS_OK(status)) { return status; } talloc_free(lck); talloc_set_destructor(r, pvfs_odb_retry_destructor); wait_handle = pvfs_wait_message(pvfs, req, MSG_PVFS_RETRY_OPEN, end_time, pvfs_odb_retry_callback, r); if (wait_handle == NULL) { return NT_STATUS_NO_MEMORY; } talloc_steal(r, wait_handle); return NT_STATUS_OK;}/* retry an open after a sharing violation*/static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r, struct ntvfs_module_context *ntvfs, struct ntvfs_request *req, void *_io, void *private_data, enum pvfs_wait_notice reason){ union smb_open *io = talloc_get_type(_io, union smb_open); struct timeval *final_timeout = NULL; NTSTATUS status; if (private_data) { final_timeout = talloc_get_type(private_data, struct timeval); } /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably just a bug in their server, but we better do the same */ if (reason == PVFS_WAIT_CANCEL) { return; } if (reason == PVFS_WAIT_TIMEOUT) { if (final_timeout && !timeval_expired(final_timeout)) { /* * we need to retry periodictly * after an EAGAIN as there's * no way the kernel tell us * an oplock is released. */ goto retry; } /* if it timed out, then give the failure immediately */ talloc_free(r); req->async_states->status = NT_STATUS_SHARING_VIOLATION; req->async_states->send_fn(req); return; }retry: talloc_free(r); /* try the open again, which could trigger another retry setup if it wants to, so we have to unmark the async flag so we will know if it does a second async reply */ req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC; status = pvfs_open(ntvfs, req, io); if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) { /* the 2nd try also replied async, so we don't send the reply yet */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -