#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_LOCKING
static TDB_CONTEXT *posix_pending_close_tdb;
static int map_posix_lock_type( files_struct *fsp, enum brl_type lock_type)
{
if((lock_type == WRITE_LOCK) && !fsp->can_write) {
DEBUG(10,("map_posix_lock_type: Downgrading write lock to read due to read-only file.\n"));
return F_RDLCK;
}
return (lock_type == READ_LOCK) ? F_RDLCK : F_WRLCK;
}
static const char *posix_lock_type_name(int lock_type)
{
return (lock_type == F_RDLCK) ? "READ" : "WRITE";
}
static BOOL posix_lock_in_range(SMB_OFF_T *offset_out, SMB_OFF_T *count_out,
SMB_BIG_UINT u_offset, SMB_BIG_UINT u_count)
{
SMB_OFF_T offset = (SMB_OFF_T)u_offset;
SMB_OFF_T count = (SMB_OFF_T)u_count;
#if defined(MAX_POSITIVE_LOCK_OFFSET)
SMB_OFF_T max_positive_lock_offset = (MAX_POSITIVE_LOCK_OFFSET);
#elif defined(LARGE_SMB_OFF_T) && !defined(HAVE_BROKEN_FCNTL64_LOCKS)
SMB_OFF_T mask2 = ((SMB_OFF_T)0x4) << (SMB_OFF_T_BITS-4);
SMB_OFF_T mask = (mask2<<1);
SMB_OFF_T max_positive_lock_offset = ~mask;
#else
SMB_OFF_T max_positive_lock_offset = 0x7FFFFFFF;
#endif
if (count == (SMB_OFF_T)0) {
DEBUG(10,("posix_lock_in_range: count = 0, ignoring.\n"));
return False;
}
if (u_offset & ~((SMB_BIG_UINT)max_positive_lock_offset)) {
DEBUG(10,("posix_lock_in_range: (offset = %.0f) offset > %.0f and we cannot handle this. Ignoring lock.\n",
(double)u_offset, (double)((SMB_BIG_UINT)max_positive_lock_offset) ));
return False;
}
if (u_count & ~((SMB_BIG_UINT)max_positive_lock_offset)) {
count = max_positive_lock_offset;
}
if (offset + count < 0 || offset + count > max_positive_lock_offset) {
count = max_positive_lock_offset - offset;
}
if (count == 0) {
DEBUG(10,("posix_lock_in_range: Count = 0. Ignoring lock u_offset = %.0f, u_count = %.0f\n",
(double)u_offset, (double)u_count ));
return False;
}
DEBUG(10,("posix_lock_in_range: offset_out = %.0f, count_out = %.0f\n",
(double)offset, (double)count ));
*offset_out = offset;
*count_out = count;
return True;
}
static BOOL posix_fcntl_lock(files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type)
{
BOOL ret;
DEBUG(8,("posix_fcntl_lock %d %d %.0f %.0f %d\n",fsp->fh->fd,op,(double)offset,(double)count,type));
ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type);
if (ret == False && errno == ENOTSUP) {
return False;
}
if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) {
DEBUG(0,("posix_fcntl_lock: WARNING: lock request at offset %.0f, length %.0f returned\n",
(double)offset,(double)count));
DEBUGADD(0,("an %s error. This can happen when using 64 bit lock offsets\n", strerror(errno)));
DEBUGADD(0,("on 32 bit NFS mounted file systems.\n"));
if (offset & ~((SMB_OFF_T)0x7fffffff)) {
DEBUG(0,("Offset greater than 31 bits. Returning success.\n"));
return True;
}
if (count & ~((SMB_OFF_T)0x7fffffff)) {
DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n"));
errno = 0;
count &= 0x7fffffff;
ret = SMB_VFS_LOCK(fsp,fsp->fh->fd,op,offset,count,type);
}
}
DEBUG(8,("posix_fcntl_lock: Lock call %s\n", ret ? "successful" : "failed"));
return ret;
}
static BOOL posix_fcntl_getlock(files_struct *fsp, SMB_OFF_T *poffset, SMB_OFF_T *pcount, int *ptype)
{
pid_t pid;
BOOL ret;
DEBUG(8,("posix_fcntl_getlock %d %.0f %.0f %d\n",
fsp->fh->fd,(double)*poffset,(double)*pcount,*ptype));
ret = SMB_VFS_GETLOCK(fsp,fsp->fh->fd,poffset,pcount,ptype,&pid);
if (ret == False && errno == ENOTSUP) {
return False;
}
if (!ret && ((errno == EFBIG) || (errno == ENOLCK) || (errno == EINVAL))) {
DEBUG(0,("posix_fcntl_getlock: WARNING: lock request at offset %.0f, length %.0f returned\n",
(double)*poffset,(double)*pcount));
DEBUGADD(0,("an %s error. This can happen when using 64 bit lock offsets\n", strerror(errno)));
DEBUGADD(0,("on 32 bit NFS mounted file systems.\n"));
if (*poffset & ~((SMB_OFF_T)0x7fffffff)) {
DEBUG(0,("Offset greater than 31 bits. Returning success.\n"));
return True;
}
if (*pcount & ~((SMB_OFF_T)0x7fffffff)) {
DEBUG(0,("Count greater than 31 bits - retrying with 31 bit truncated length.\n"));
errno = 0;
*pcount &= 0x7fffffff;
ret = SMB_VFS_GETLOCK(fsp,fsp->fh->fd,poffset,pcount,ptype,&pid);
}
}
DEBUG(8,("posix_fcntl_getlock: Lock query call %s\n", ret ? "successful" : "failed"));
return ret;
}
BOOL is_posix_locked(files_struct *fsp,
SMB_BIG_UINT *pu_offset,
SMB_BIG_UINT *pu_count,
enum brl_type *plock_type,
enum brl_flavour lock_flav)
{
SMB_OFF_T offset;
SMB_OFF_T count;
int posix_lock_type = map_posix_lock_type(fsp,*plock_type);
DEBUG(10,("is_posix_locked: File %s, offset = %.0f, count = %.0f, type = %s\n",
fsp->fsp_name, (double)*pu_offset, (double)*pu_count, posix_lock_type_name(*plock_type) ));
if(!posix_lock_in_range(&offset, &count, *pu_offset, *pu_count)) {
return False;
}
if (!posix_fcntl_getlock(fsp,&offset,&count,&posix_lock_type)) {
return False;
}
if (posix_lock_type == F_UNLCK) {
return False;
}
if (lock_flav == POSIX_LOCK) {
*pu_offset = (SMB_BIG_UINT)offset;
*pu_count = (SMB_BIG_UINT)count;
*plock_type = (posix_lock_type == F_RDLCK) ? READ_LOCK : WRITE_LOCK;
}
return True;
}
struct lock_ref_count_key {
SMB_DEV_T device;
SMB_INO_T inode;
char r;
};
struct fd_key {
SMB_DEV_T device;
SMB_INO_T inode;
};
static TDB_DATA fd_array_key(SMB_DEV_T dev, SMB_INO_T inode)
{
static struct fd_key key;
TDB_DATA kbuf;
memset(&key, '\0', sizeof(key));
key.device = dev;
key.inode = inode;
kbuf.dptr = (char *)&key;
kbuf.dsize = sizeof(key);
return kbuf;
}
static TDB_DATA locking_ref_count_key(SMB_DEV_T dev, SMB_INO_T inode)
{
static struct lock_ref_count_key key;
TDB_DATA kbuf;
memset(&key, '\0', sizeof(key));
key.device = dev;
key.inode = inode;
key.r = 'r';
kbuf.dptr = (char *)&key;
kbuf.dsize = sizeof(key);
return kbuf;
}
static TDB_DATA fd_array_key_fsp(files_struct *fsp)
{
return fd_array_key(fsp->dev, fsp->inode);
}
static TDB_DATA locking_ref_count_key_fsp(files_struct *fsp)
{
return locking_ref_count_key(fsp->dev, fsp->inode);
}
BOOL posix_locking_init(int read_only)
{
if (posix_pending_close_tdb) {
return True;
}
if (!posix_pending_close_tdb) {
posix_pending_close_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL,
read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644);
}
if (!posix_pending_close_tdb) {
DEBUG(0,("Failed to open POSIX pending close database.\n"));
return False;
}
return True;
}
BOOL posix_locking_end(void)
{
if (posix_pending_close_tdb && tdb_close(posix_pending_close_tdb) != 0) {
return False;
}
return True;
}
static void increment_windows_lock_ref_count(files_struct *fsp)
{
TDB_DATA kbuf = locking_ref_count_key_fsp(fsp);
TDB_DATA dbuf;
int lock_ref_count;
dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
if (dbuf.dptr == NULL) {
dbuf.dptr = (char *)SMB_MALLOC_P(int);
if (!dbuf.dptr) {
smb_panic("increment_windows_lock_ref_count: malloc fail.\n");
}
memset(dbuf.dptr, '\0', sizeof(int));
dbuf.dsize = sizeof(int);
}
memcpy(&lock_ref_count, dbuf.dptr, sizeof(int));
lock_ref_count++;
memcpy(dbuf.dptr, &lock_ref_count, sizeof(int));
if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
smb_panic("increment_windows_lock_ref_count: tdb_store_fail.\n");
}
SAFE_FREE(dbuf.dptr);
DEBUG(10,("increment_windows_lock_ref_count for file now %s = %d\n",
fsp->fsp_name, lock_ref_count ));
}
static void decrement_windows_lock_ref_count(files_struct *fsp)
{
TDB_DATA kbuf = locking_ref_count_key_fsp(fsp);
TDB_DATA dbuf;
int lock_ref_count;
dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
if (!dbuf.dptr) {
smb_panic("decrement_windows_lock_ref_count: logic error.\n");
}
memcpy(&lock_ref_count, dbuf.dptr, sizeof(int));
lock_ref_count--;
memcpy(dbuf.dptr, &lock_ref_count, sizeof(int));
if (lock_ref_count < 0) {
smb_panic("decrement_windows_lock_ref_count: lock_count logic error.\n");
}
if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
smb_panic("decrement_windows_lock_ref_count: tdb_store_fail.\n");
}
SAFE_FREE(dbuf.dptr);
DEBUG(10,("decrement_windows_lock_ref_count for file now %s = %d\n",
fsp->fsp_name, lock_ref_count ));
}
void reduce_windows_lock_ref_count(files_struct *fsp, unsigned int dcount)
{
TDB_DATA kbuf = locking_ref_count_key_fsp(fsp);
TDB_DATA dbuf;
int lock_ref_count;
dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
if (!dbuf.dptr) {
return;
}
memcpy(&lock_ref_count, dbuf.dptr, sizeof(int));
lock_ref_count -= dcount;
if (lock_ref_count < 0) {
smb_panic("reduce_windows_lock_ref_count: lock_count logic error.\n");
}
memcpy(dbuf.dptr, &lock_ref_count, sizeof(int));
if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
smb_panic("reduce_windows_lock_ref_count: tdb_store_fail.\n");
}
SAFE_FREE(dbuf.dptr);
DEBUG(10,("reduce_windows_lock_ref_count for file now %s = %d\n",
fsp->fsp_name, lock_ref_count ));
}
static int get_windows_lock_ref_count(files_struct *fsp)
{
TDB_DATA kbuf = locking_ref_count_key_fsp(fsp);
TDB_DATA dbuf;
int lock_ref_count;
dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
if (!dbuf.dptr) {
lock_ref_count = 0;
} else {
memcpy(&lock_ref_count, dbuf.dptr, sizeof(int));
}
SAFE_FREE(dbuf.dptr);
DEBUG(10,("get_windows_lock_count for file %s = %d\n",
fsp->fsp_name, lock_ref_count ));
return lock_ref_count;
}
static void delete_windows_lock_ref_count(files_struct *fsp)
{
TDB_DATA kbuf = locking_ref_count_key_fsp(fsp);
tdb_delete(posix_pending_close_tdb, kbuf);
DEBUG(10,("delete_windows_lock_ref_count for file %s\n", fsp->fsp_name));
}
static void add_fd_to_close_entry(files_struct *fsp)
{
TDB_DATA kbuf = fd_array_key_fsp(fsp);
TDB_DATA dbuf;
dbuf.dptr = NULL;
dbuf.dsize = 0;
dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
dbuf.dptr = (char *)SMB_REALLOC(dbuf.dptr, dbuf.dsize + sizeof(int));
if (!dbuf.dptr) {
smb_panic("add_fd_to_close_entry: Realloc fail !\n");
}
memcpy(dbuf.dptr + dbuf.dsize, &fsp->fh->fd, sizeof(int));
dbuf.dsize += sizeof(int);
if (tdb_store(posix_pending_close_tdb, kbuf, dbuf, TDB_REPLACE) == -1) {
smb_panic("add_fd_to_close_entry: tdb_store_fail.\n");
}
DEBUG(10,("add_fd_to_close_entry: added fd %d file %s\n",
fsp->fh->fd, fsp->fsp_name ));
SAFE_FREE(dbuf.dptr);
}
static void delete_close_entries(files_struct *fsp)
{
TDB_DATA kbuf = fd_array_key_fsp(fsp);
if (tdb_delete(posix_pending_close_tdb, kbuf) == -1) {
smb_panic("delete_close_entries: tdb_delete fail !\n");
}
}
static size_t get_posix_pending_close_entries(files_struct *fsp, int **entries)
{
TDB_DATA kbuf = fd_array_key_fsp(fsp);
TDB_DATA dbuf;
size_t count = 0;
*entries = NULL;
dbuf.dptr = NULL;
dbuf = tdb_fetch(posix_pending_close_tdb, kbuf);
if (!dbuf.dptr) {
return 0;
}
*entries = (int *)dbuf.dptr;
count = (size_t)(dbuf.dsize / sizeof(int));
return count;
}
NTSTATUS fd_close_posix(struct connection_struct *conn, files_struct *fsp)
{
int saved_errno = 0;
int ret;
int *fd_array = NULL;
size_t count, i;
if (!lp_locking(fsp->conn->params) || !lp_posix_locking(conn->params)) {
ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd);
fsp->fh->fd = -1;
return map_nt_error_from_unix(errno);
}
if (get_windows_lock_ref_count(fsp)) {
add_fd_to_close_entry(fsp);
fsp->fh->fd = -1;
return NT_STATUS_OK;
}
count = get_posix_pending_close_entries(fsp, &fd_array);
if (count) {
DEBUG(10,("fd_close_posix: doing close on %u fd's.\n", (unsigned int)count ));
for(i = 0; i < count; i++) {
if (SMB_VFS_CLOSE(fsp,fd_array[i]) == -1) {
saved_errno = errno;
}
}
delete_close_entries(fsp);
}
SAFE_FREE(fd_array);
delete_windows_lock_ref_count(fsp);
ret = SMB_VFS_CLOSE(fsp,fsp->fh->fd);
if (ret == 0 && saved_errno != 0) {
errno = saved_errno;
ret = -1;
}
fsp->fh->fd = -1;
if (ret == -1) {
return map_nt_error_from_unix(errno);
}
return NT_STATUS_OK;
}
struct lock_list {
struct lock_list *next;
struct lock_list *prev;
SMB_OFF_T start;
SMB_OFF_T size;
};
static struct lock_list *posix_lock_list(TALLOC_CTX *ctx,
struct lock_list *lhead,
const struct lock_context *lock_ctx,
files_struct *fsp,
const struct lock_struct *plocks,
int num_locks)
{
int i;
DEBUG(10,("posix_lock_list: curr: start=%.0f,size=%.0f\n",
(double)lhead->start, (double)lhead->size ));
for (i=0; i<num_locks && lhead; i++) {
const struct lock_struct *lock = &plocks[i];
struct lock_list *l_curr;
if (lock->lock_type != READ_LOCK && lock->lock_type != WRITE_LOCK) {
continue;
}
if (!procid_equal(&lock->context.pid, &lock_ctx->pid)) {
continue;
}
for (l_curr = lhead; l_curr;) {
DEBUG(10,("posix_lock_list: lock: fnum=%d: start=%.0f,size=%.0f:type=%s", lock->fnum,
(double)lock->start, (double)lock->size, posix_lock_type_name(lock->lock_type) ));
if ( (l_curr->start >= (lock->start + lock->size)) ||
(lock->start >= (l_curr->start + l_curr->size))) {
DEBUG(10,(" no overlap case.\n" ));
l_curr = l_curr->next;
} else if ( (l_curr->start >= lock->start) &&
(l_curr->start + l_curr->size <= lock->start + lock->size) ) {
struct lock_list *ul_next = l_curr->next;
DEBUG(10,(" delete case.\n" ));
DLIST_REMOVE(lhead, l_curr);
if(lhead == NULL) {
break;
}
l_curr = ul_next;
} else if ( (l_curr->start >= lock->start) &&
(l_curr->start < lock->start + lock->size) &&
(l_curr->start + l_curr->size > lock->start + lock->size) ) {
l_curr->size = (l_curr->start + l_curr->size) - (lock->start + lock->size);
l_curr->start = lock->start + lock->size;
DEBUG(10,(" truncate high case: start=%.0f,size=%.0f\n",
(double)l_curr->start, (double)l_curr->size ));
l_curr = l_curr->next;
} else if ( (l_curr->start < lock->start) &&
(l_curr->start + l_curr->size > lock->start) &&
(l_curr->start + l_curr->size <= lock->start + lock->size) ) {
l_curr->size = lock->start - l_curr->start;
DEBUG(10,(" truncate low case: start=%.0f,size=%.0f\n",
(double)l_curr->start, (double)l_curr->size ));
l_curr = l_curr->next;
} else if ( (l_curr->start < lock->start) &&
(l_curr->start + l_curr->size > lock->start + lock->size) ) {
struct lock_list *l_new = TALLOC_P(ctx, struct lock_list);
if(l_new == NULL) {
DEBUG(0,("posix_lock_list: talloc fail.\n"));
return NULL;
}
ZERO_STRUCTP(l_new);
l_new->start = lock->start + lock->size;
l_new->size = l_curr->start + l_curr->size - l_new->start;
l_curr->size = lock->start - l_curr->start;
DEBUG(10,(" split case: curr: start=%.0f,size=%.0f \
new: start=%.0f,size=%.0f\n", (double)l_curr->start, (double)l_curr->size,
(double)l_new->start, (double)l_new->size ));
l_new->prev = l_curr;
l_new->next = l_curr->next;
l_curr->next = l_new;
l_curr = l_new->next;
} else {
pstring msg;
slprintf(msg, sizeof(msg)-1, "logic flaw in cases: l_curr: start = %.0f, size = %.0f : \
lock: start = %.0f, size = %.0f\n", (double)l_curr->start, (double)l_curr->size, (double)lock->start, (double)lock->size );
smb_panic(msg);
}
}
}
return lhead;
}
BOOL set_posix_lock_windows_flavour(files_struct *fsp,
SMB_BIG_UINT u_offset,
SMB_BIG_UINT u_count,
enum brl_type lock_type,
const struct lock_context *lock_ctx,
const struct lock_struct *plocks,
int num_locks,
int *errno_ret)
{
SMB_OFF_T offset;
SMB_OFF_T count;
int posix_lock_type = map_posix_lock_type(fsp,lock_type);
BOOL ret = True;
size_t lock_count;
TALLOC_CTX *l_ctx = NULL;
struct lock_list *llist = NULL;
struct lock_list *ll = NULL;
DEBUG(5,("set_posix_lock_windows_flavour: File %s, offset = %.0f, count = %.0f, type = %s\n",
fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
increment_windows_lock_ref_count(fsp);
return True;
}
if ((l_ctx = talloc_init("set_posix_lock")) == NULL) {
DEBUG(0,("set_posix_lock_windows_flavour: unable to init talloc context.\n"));
return False;
}
if ((ll = TALLOC_P(l_ctx, struct lock_list)) == NULL) {
DEBUG(0,("set_posix_lock_windows_flavour: unable to talloc unlock list.\n"));
talloc_destroy(l_ctx);
return False;
}
ZERO_STRUCTP(ll);
ll->start = offset;
ll->size = count;
DLIST_ADD(llist, ll);
llist = posix_lock_list(l_ctx,
llist,
lock_ctx,
fsp,
plocks,
num_locks);
for (lock_count = 0, ll = llist; ll; ll = ll->next, lock_count++) {
offset = ll->start;
count = ll->size;
DEBUG(5,("set_posix_lock_windows_flavour: Real lock: Type = %s: offset = %.0f, count = %.0f\n",
posix_lock_type_name(posix_lock_type), (double)offset, (double)count ));
ret = posix_fcntl_lock(fsp,SMB_F_SETLK,offset,
count,posix_lock_type);
if (ret == False && errno != ENOTSUP) {
*errno_ret = errno;
DEBUG(5,("set_posix_lock_windows_flavour: Lock fail !: Type = %s: offset = %.0f, count = %.0f. Errno = %s\n",
posix_lock_type_name(posix_lock_type), (double)offset, (double)count, strerror(errno) ));
ret = False;
break;
}
ret = True;
}
if (!ret) {
for (ll = llist; lock_count; ll = ll->next, lock_count--) {
offset = ll->start;
count = ll->size;
DEBUG(5,("set_posix_lock_windows_flavour: Backing out locks: Type = %s: offset = %.0f, count = %.0f\n",
posix_lock_type_name(posix_lock_type), (double)offset, (double)count ));
posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK);
}
} else {
increment_windows_lock_ref_count(fsp);
}
talloc_destroy(l_ctx);
return ret;
}
BOOL release_posix_lock_windows_flavour(files_struct *fsp,
SMB_BIG_UINT u_offset,
SMB_BIG_UINT u_count,
enum brl_type deleted_lock_type,
const struct lock_context *lock_ctx,
const struct lock_struct *plocks,
int num_locks)
{
SMB_OFF_T offset;
SMB_OFF_T count;
BOOL ret = True;
TALLOC_CTX *ul_ctx = NULL;
struct lock_list *ulist = NULL;
struct lock_list *ul = NULL;
DEBUG(5,("release_posix_lock_windows_flavour: File %s, offset = %.0f, count = %.0f\n",
fsp->fsp_name, (double)u_offset, (double)u_count ));
decrement_windows_lock_ref_count(fsp);
if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
return True;
}
if ((ul_ctx = talloc_init("release_posix_lock")) == NULL) {
DEBUG(0,("release_posix_lock_windows_flavour: unable to init talloc context.\n"));
return False;
}
if ((ul = TALLOC_P(ul_ctx, struct lock_list)) == NULL) {
DEBUG(0,("release_posix_lock_windows_flavour: unable to talloc unlock list.\n"));
talloc_destroy(ul_ctx);
return False;
}
ZERO_STRUCTP(ul);
ul->start = offset;
ul->size = count;
DLIST_ADD(ulist, ul);
ulist = posix_lock_list(ul_ctx,
ulist,
lock_ctx,
fsp,
plocks,
num_locks);
if (deleted_lock_type == WRITE_LOCK &&
(!ulist || ulist->next != NULL || ulist->start != offset || ulist->size != count)) {
DEBUG(5,("release_posix_lock_windows_flavour: downgrading lock to READ: offset = %.0f, count = %.0f\n",
(double)offset, (double)count ));
ret = posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_RDLCK);
if (ret == False && errno != ENOTSUP) {
DEBUG(0,("release_posix_lock_windows_flavour: downgrade of lock failed with error %s !\n", strerror(errno) ));
talloc_destroy(ul_ctx);
return False;
}
}
ret = True;
for(; ulist; ulist = ulist->next) {
offset = ulist->start;
count = ulist->size;
DEBUG(5,("release_posix_lock_windows_flavour: Real unlock: offset = %.0f, count = %.0f\n",
(double)offset, (double)count ));
if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK)) {
if (errno != ENOTSUP) {
ret = False;
}
}
}
talloc_destroy(ul_ctx);
return ret;
}
BOOL set_posix_lock_posix_flavour(files_struct *fsp,
SMB_BIG_UINT u_offset,
SMB_BIG_UINT u_count,
enum brl_type lock_type,
int *errno_ret)
{
SMB_OFF_T offset;
SMB_OFF_T count;
int posix_lock_type = map_posix_lock_type(fsp,lock_type);
DEBUG(5,("set_posix_lock_posix_flavour: File %s, offset = %.0f, count = %.0f, type = %s\n",
fsp->fsp_name, (double)u_offset, (double)u_count, posix_lock_type_name(lock_type) ));
if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
return True;
}
if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,posix_lock_type)) {
if (errno == ENOTSUP) {
return True;
}
*errno_ret = errno;
DEBUG(5,("set_posix_lock_posix_flavour: Lock fail !: Type = %s: offset = %.0f, count = %.0f. Errno = %s\n",
posix_lock_type_name(posix_lock_type), (double)offset, (double)count, strerror(errno) ));
return False;
}
return True;
}
BOOL release_posix_lock_posix_flavour(files_struct *fsp,
SMB_BIG_UINT u_offset,
SMB_BIG_UINT u_count,
const struct lock_context *lock_ctx,
const struct lock_struct *plocks,
int num_locks)
{
BOOL ret = True;
SMB_OFF_T offset;
SMB_OFF_T count;
TALLOC_CTX *ul_ctx = NULL;
struct lock_list *ulist = NULL;
struct lock_list *ul = NULL;
DEBUG(5,("release_posix_lock_posix_flavour: File %s, offset = %.0f, count = %.0f\n",
fsp->fsp_name, (double)u_offset, (double)u_count ));
if(!posix_lock_in_range(&offset, &count, u_offset, u_count)) {
return True;
}
if ((ul_ctx = talloc_init("release_posix_lock")) == NULL) {
DEBUG(0,("release_posix_lock_windows_flavour: unable to init talloc context.\n"));
return False;
}
if ((ul = TALLOC_P(ul_ctx, struct lock_list)) == NULL) {
DEBUG(0,("release_posix_lock_windows_flavour: unable to talloc unlock list.\n"));
talloc_destroy(ul_ctx);
return False;
}
ZERO_STRUCTP(ul);
ul->start = offset;
ul->size = count;
DLIST_ADD(ulist, ul);
ulist = posix_lock_list(ul_ctx,
ulist,
lock_ctx,
fsp,
plocks,
num_locks);
for(; ulist; ulist = ulist->next) {
offset = ulist->start;
count = ulist->size;
DEBUG(5,("release_posix_lock_posix_flavour: Real unlock: offset = %.0f, count = %.0f\n",
(double)offset, (double)count ));
if (!posix_fcntl_lock(fsp,SMB_F_SETLK,offset,count,F_UNLCK)) {
if (errno != ENOTSUP) {
ret = False;
}
}
}
talloc_destroy(ul_ctx);
return ret;
}