diff options
Diffstat (limited to 'source4/ntvfs/posix')
-rw-r--r-- | source4/ntvfs/posix/config.mk | 4 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_lock.c | 151 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_open.c | 19 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_read.c | 9 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_write.c | 17 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.c | 28 | ||||
-rw-r--r-- | source4/ntvfs/posix/vfs_posix.h | 21 |
7 files changed, 227 insertions, 22 deletions
diff --git a/source4/ntvfs/posix/config.mk b/source4/ntvfs/posix/config.mk index 019288faaa..8ca5ad7b0b 100644 --- a/source4/ntvfs/posix/config.mk +++ b/source4/ntvfs/posix/config.mk @@ -19,6 +19,8 @@ ADD_OBJ_FILES = \ ntvfs/posix/pvfs_setfileinfo.o \ ntvfs/posix/pvfs_rename.o \ ntvfs/posix/pvfs_resolve.o \ - ntvfs/posix/pvfs_shortname.o + ntvfs/posix/pvfs_shortname.o \ + ntvfs/posix/pvfs_lock.o \ + ntvfs/common/brlock.o # End MODULE ntvfs_posix ################################################ diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c new file mode 100644 index 0000000000..d7aca9df8b --- /dev/null +++ b/source4/ntvfs/posix/pvfs_lock.c @@ -0,0 +1,151 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - locking + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "include/includes.h" +#include "vfs_posix.h" + + +/* + check if we can perform IO on a range that might be locked +*/ +NTSTATUS pvfs_check_lock(struct pvfs_state *pvfs, + struct pvfs_file *f, + uint16_t smbpid, + uint64_t offset, uint64_t count, + enum brl_type rw) +{ + if (!(pvfs->flags & PVFS_FLAG_STRICT_LOCKING)) { + return NT_STATUS_OK; + } + + return brl_locktest(pvfs->brl_context, + &f->locking_key, + f->fnum, + smbpid, + offset, count, rw); +} + +/* + lock or unlock a byte range +*/ +NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, union smb_lock *lck) +{ + struct pvfs_state *pvfs = ntvfs->private_data; + struct pvfs_file *f; + struct smb_lock_entry *locks; + int i; + enum brl_type rw; + + f = pvfs_find_fd(pvfs, req, lck->generic.in.fnum); + if (!f) { + return NT_STATUS_INVALID_HANDLE; + } + + switch (lck->generic.level) { + case RAW_LOCK_LOCK: + return brl_lock(pvfs->brl_context, + &f->locking_key, + req->smbpid, + f->fnum, + lck->lock.in.offset, + lck->lock.in.count, + WRITE_LOCK); + + case RAW_LOCK_UNLOCK: + return brl_unlock(pvfs->brl_context, + &f->locking_key, + req->smbpid, + f->fnum, + lck->lock.in.offset, + lck->lock.in.count); + + case RAW_LOCK_GENERIC: + return NT_STATUS_INVALID_LEVEL; + + case RAW_LOCK_LOCKX: + /* fall through to the most complex case */ + break; + } + + /* now the lockingX case, most common and also most complex */ + + if (lck->lockx.in.mode & LOCKING_ANDX_SHARED_LOCK) { + rw = READ_LOCK; + } else { + rw = WRITE_LOCK; + } + + if (lck->lockx.in.mode & + (LOCKING_ANDX_OPLOCK_RELEASE | + LOCKING_ANDX_CHANGE_LOCKTYPE | + LOCKING_ANDX_CANCEL_LOCK)) { + /* todo: need to add support for these */ + return NT_STATUS_NOT_IMPLEMENTED; + } + + + /* the unlocks happen first */ + locks = lck->lockx.in.locks; + + for (i=0;i<lck->lockx.in.ulock_cnt;i++) { + NTSTATUS status; + status = brl_unlock(pvfs->brl_context, + &f->locking_key, + locks[i].pid, + f->fnum, + locks[i].offset, + locks[i].count); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + locks += i; + + for (i=0;i<lck->lockx.in.lock_cnt;i++) { + NTSTATUS status; + + status = brl_lock(pvfs->brl_context, + &f->locking_key, + locks[i].pid, + f->fnum, + locks[i].offset, + locks[i].count, + rw); + if (!NT_STATUS_IS_OK(status)) { + /* undo the locks we just did */ + for (i=i-1;i>=0;i--) { + brl_unlock(pvfs->brl_context, + &f->locking_key, + locks[i].pid, + f->fnum, + locks[i].offset, + locks[i].count); + } + return status; + } + } + + return NT_STATUS_OK; +} + diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 29e57e5a08..51526461e0 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -51,6 +51,9 @@ struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs, static int pvfs_fd_destructor(void *p) { struct pvfs_file *f = p; + + brl_close(f->pvfs->brl_context, &f->locking_key, f->fnum); + if (f->fd != -1) { close(f->fd); f->fd = -1; @@ -71,6 +74,10 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, struct pvfs_filename *name; struct pvfs_file *f; NTSTATUS status; + struct { + dev_t device; + ino_t inode; + } lock_context; if (io->generic.level != RAW_OPEN_GENERIC) { return ntvfs_map_open(req, io, ntvfs); @@ -161,6 +168,13 @@ do_open: f->name = talloc_steal(f, name); f->session = req->session; f->smbpid = req->smbpid; + f->pvfs = pvfs; + + /* we must zero here to take account of padding */ + ZERO_STRUCT(lock_context); + lock_context.device = name->st.st_dev; + lock_context.inode = name->st.st_ino; + f->locking_key = data_blob_talloc(f, &lock_context, sizeof(lock_context)); /* setup a destructor to avoid file descriptor leaks on abnormal termination */ @@ -204,6 +218,11 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } + status = brl_close(pvfs->brl_context, &f->locking_key, f->fnum); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (close(f->fd) != 0) { status = pvfs_map_errno(pvfs, errno); } else { diff --git a/source4/ntvfs/posix/pvfs_read.c b/source4/ntvfs/posix/pvfs_read.c index e0c7e0b1f2..24142a81ee 100644 --- a/source4/ntvfs/posix/pvfs_read.c +++ b/source4/ntvfs/posix/pvfs_read.c @@ -32,6 +32,7 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs, struct pvfs_state *pvfs = ntvfs->private_data; ssize_t ret; struct pvfs_file *f; + NTSTATUS status; if (rd->generic.level != RAW_READ_READX) { return NT_STATUS_NOT_SUPPORTED; @@ -43,6 +44,14 @@ NTSTATUS pvfs_read(struct ntvfs_module_context *ntvfs, return NT_STATUS_INVALID_HANDLE; } + status = pvfs_check_lock(pvfs, f, req->smbpid, + rd->readx.in.offset, + rd->readx.in.maxcnt, + READ_LOCK); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + ret = pread(f->fd, rd->readx.out.data, rd->readx.in.maxcnt, diff --git a/source4/ntvfs/posix/pvfs_write.c b/source4/ntvfs/posix/pvfs_write.c index a49f4fe947..80a3dae3a7 100644 --- a/source4/ntvfs/posix/pvfs_write.c +++ b/source4/ntvfs/posix/pvfs_write.c @@ -33,6 +33,7 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs, struct pvfs_state *pvfs = ntvfs->private_data; ssize_t ret; struct pvfs_file *f; + NTSTATUS status; switch (wr->generic.level) { case RAW_WRITE_WRITEX: @@ -40,6 +41,14 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs, if (!f) { return NT_STATUS_INVALID_HANDLE; } + status = pvfs_check_lock(pvfs, f, req->smbpid, + wr->writex.in.offset, + wr->writex.in.count, + WRITE_LOCK); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + ret = pwrite(f->fd, wr->writex.in.data, wr->writex.in.count, @@ -62,6 +71,14 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs, /* a truncate! */ ret = ftruncate(f->fd, wr->write.in.offset); } else { + status = pvfs_check_lock(pvfs, f, req->smbpid, + wr->write.in.offset, + wr->write.in.count, + WRITE_LOCK); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + ret = pwrite(f->fd, wr->write.in.data, wr->write.in.count, diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index a17b90e369..5e7a605c9f 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -35,11 +35,12 @@ static void pvfs_setup_options(struct pvfs_state *pvfs) { int snum = pvfs->tcon->service; - if (lp_map_hidden(snum)) pvfs->flags |= PVFS_FLAG_MAP_HIDDEN; - if (lp_map_archive(snum)) pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE; - if (lp_map_system(snum)) pvfs->flags |= PVFS_FLAG_MAP_SYSTEM; - if (lp_readonly(snum)) pvfs->flags |= PVFS_FLAG_READONLY; - if (lp_strict_sync(snum)) pvfs->flags |= PVFS_FLAG_STRICT_SYNC; + if (lp_map_hidden(snum)) pvfs->flags |= PVFS_FLAG_MAP_HIDDEN; + if (lp_map_archive(snum)) pvfs->flags |= PVFS_FLAG_MAP_ARCHIVE; + if (lp_map_system(snum)) pvfs->flags |= PVFS_FLAG_MAP_SYSTEM; + if (lp_readonly(snum)) pvfs->flags |= PVFS_FLAG_READONLY; + if (lp_strict_sync(snum)) pvfs->flags |= PVFS_FLAG_STRICT_SYNC; + if (lp_strict_locking(snum)) pvfs->flags |= PVFS_FLAG_STRICT_LOCKING; pvfs->share_name = talloc_strdup(pvfs, lp_servicename(snum)); } @@ -86,6 +87,13 @@ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs, ntvfs->private_data = pvfs; + pvfs->brl_context = brl_init(pvfs, + pvfs->tcon->smb_conn->connection->server_id, + pvfs->tcon->service); + if (pvfs->brl_context == NULL) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + status = pvfs_mangle_init(pvfs); if (!NT_STATUS_IS_OK(status)) { return status; @@ -162,16 +170,6 @@ static NTSTATUS pvfs_seek(struct ntvfs_module_context *ntvfs, } /* - lock a byte range -*/ -static NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs, - struct smbsrv_request *req, union smb_lock *lck) -{ - DEBUG(0,("pvfs_lock not implemented\n")); - return NT_STATUS_NOT_IMPLEMENTED; -} - -/* set info on a pathname */ static NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs, diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h index 6819d01529..e83f0479a9 100644 --- a/source4/ntvfs/posix/vfs_posix.h +++ b/source4/ntvfs/posix/vfs_posix.h @@ -51,6 +51,8 @@ struct pvfs_state { struct pvfs_file *open_files; struct pvfs_mangle_context *mangle_ctx; + + void *brl_context; }; @@ -115,6 +117,12 @@ struct pvfs_file { /* we need to remember the client pid that opened the file so SMBexit works */ uint16_t smbpid; + + /* a unique file key to be used for file locking */ + DATA_BLOB locking_key; + + /* we need this hook back to our parent for lock destruction */ + struct pvfs_state *pvfs; }; struct pvfs_mangle_context { @@ -147,11 +155,12 @@ struct pvfs_mangle_context { #define PVFS_RESOLVE_STREAMS (1<<1) /* flags in pvfs->flags */ -#define PVFS_FLAG_CI_FILESYSTEM (1<<0) /* the filesystem is case insensitive */ -#define PVFS_FLAG_MAP_ARCHIVE (1<<1) -#define PVFS_FLAG_MAP_SYSTEM (1<<2) -#define PVFS_FLAG_MAP_HIDDEN (1<<3) -#define PVFS_FLAG_READONLY (1<<4) -#define PVFS_FLAG_STRICT_SYNC (1<<5) +#define PVFS_FLAG_CI_FILESYSTEM (1<<0) /* the filesystem is case insensitive */ +#define PVFS_FLAG_MAP_ARCHIVE (1<<1) +#define PVFS_FLAG_MAP_SYSTEM (1<<2) +#define PVFS_FLAG_MAP_HIDDEN (1<<3) +#define PVFS_FLAG_READONLY (1<<4) +#define PVFS_FLAG_STRICT_SYNC (1<<5) +#define PVFS_FLAG_STRICT_LOCKING (1<<6) #endif /* _VFS_POSIX_H_ */ |