Add physical-record entries to the shared synchronization set table. The Novell SDK documents the physical-record set calls as operating on the caller's logged data byte range table: Log Physical Record adds byte ranges, Lock Physical Record Set locks all logged ranges, Release Physical Record Set unlocks them while keeping them logged, and Clear Physical Record Set unlocks and removes them. MARS-NWE already used the shared set handler for file and logical-record sets. Extend the same table with type 4 entries for physical records, storing the NetWare file handle, start offset, record length, timeout, lock directive, and current locked state. Add a type 4 handler that reuses nw_log_physical_record() for set lock and release operations, and export share_set_physrec_add_rm() so nwconn can maintain the set table when individual physical-record calls log or clear ranges. This prepares the documented Physical Record Set endpoints to use the existing byte-range lock implementation.
867 lines
23 KiB
C
867 lines
23 KiB
C
|
|
/* nwshare.c, 13-Apr-00 */
|
|
/* (C)opyright (C) 1993-2000 Martin Stover, Marburg, Germany
|
|
*
|
|
* 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 "net.h"
|
|
#include <inttypes.h>
|
|
|
|
#include "nwvolume.h"
|
|
#include "nwfile.h"
|
|
#include "connect.h"
|
|
|
|
#include "unxfile.h"
|
|
#include "nwshare.h"
|
|
|
|
/* changed by: Ingmar Thiemann <ingmar@gefas.com>
|
|
* share_file() is now always called, when a file is opened.
|
|
* The open_mode is the access mode of the file open function.
|
|
*/
|
|
|
|
typedef struct _tagShareLock {
|
|
int l_start;
|
|
int l_len;
|
|
int fd;
|
|
int exclusive; /* exclusive lock */
|
|
struct _tagShareLock *next;
|
|
} ShareLock;
|
|
|
|
typedef struct _tagShareINode {
|
|
ino_t inode;
|
|
int or; /* open read */
|
|
int ow; /* open write */
|
|
int dr; /* deny read */
|
|
int dw; /* deny write */
|
|
#if 0
|
|
int cm; /* compatible mode */
|
|
#endif
|
|
/* ------------ */
|
|
int fl; /* file lock */
|
|
int ex; /* exlusive file lock */
|
|
ShareLock *first_lock;
|
|
struct _tagShareINode *next;
|
|
} ShareINode;
|
|
|
|
typedef struct _tagShareDev {
|
|
dev_t dev;
|
|
|
|
int fd_sm; /* semaphor for locking operation */
|
|
int fd_or; /* open read */
|
|
int fd_ow; /* open write */
|
|
int fd_dr; /* deny read */
|
|
int fd_dw; /* deny write */
|
|
#if 0
|
|
int fd_cm; /* compatible mode */
|
|
#endif
|
|
int fd_fl; /* file lock */
|
|
ShareINode *first_inode;
|
|
struct _tagShareDev *next;
|
|
} ShareDev;
|
|
|
|
static ShareDev *first_dev = NULL;
|
|
|
|
static char *path_share_lock_files=NULL;
|
|
|
|
int share_file(dev_t dev, ino_t inode, int open_mode, int action)
|
|
/* open_mode is the same as 'access' in file_creat_open():
|
|
* 0x001 = open for read
|
|
* 0x002 = open for write
|
|
* 0x004 = deny read
|
|
* 0x008 = deny write
|
|
|
|
********* 0x010 = compatible mode
|
|
|
|
* next are 'open_modes' by nw_log_file() routine.
|
|
* 0x100 = file lock ( normally exclusive )
|
|
* 0x200 = file lock shared ro flag
|
|
* action:
|
|
* 0 = remove
|
|
* 1 = add
|
|
* 2 = only test
|
|
*/
|
|
{
|
|
ShareDev *sd = NULL, **psd;
|
|
ShareINode *si = NULL, **psi;
|
|
int result = 0, act_mode = 0;
|
|
struct flock flockd;
|
|
char tbuf[200];
|
|
sprintf(tbuf,
|
|
"dev=0x%" PRIxMAX ",inode=%" PRIuMAX ",open_mode=0x%x,action=%d",
|
|
(uintmax_t)dev, (uintmax_t)inode,
|
|
open_mode, action);
|
|
if (open_mode==0) {
|
|
XDPRINTF((1, 0, "Wrong openmode in share_file %s", tbuf));
|
|
return(-1);
|
|
}
|
|
|
|
#if 0
|
|
/* mst: 06-Apr-00, map compatible modes */
|
|
/* mst: 13-Apr-00 removed */
|
|
if (access & 0x10) {
|
|
if (!(acces&2)) { /* readonly */
|
|
if (entry31_flags&1)
|
|
access &= ~0x10;
|
|
} else {
|
|
if (entry31_flags&2) {
|
|
access &= ~0x10;
|
|
access |= 0x8;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* look for open device */
|
|
for (psd=&first_dev; *psd; psd=&(*psd)->next) {
|
|
if ((*psd)->dev == dev) {
|
|
sd = *psd;
|
|
break;
|
|
}
|
|
}
|
|
if (action==0 && !sd) {
|
|
XDPRINTF((1, 0, "Could not find share device to remove %s", tbuf));
|
|
return(-1);
|
|
}
|
|
if (!sd) {
|
|
/* new device */
|
|
sd = (ShareDev*) xcmalloc( sizeof(ShareDev) );
|
|
if (!sd) {
|
|
XDPRINTF((1, 0, "Could not allocate new share device %s", tbuf));
|
|
return(-1);
|
|
}
|
|
sd->next = *psd;
|
|
*psd = sd;
|
|
sd->first_inode = NULL;
|
|
sd->fd_sm = -1;
|
|
sd->dev = dev;
|
|
}
|
|
|
|
/* look for open inode */
|
|
for (psi=&sd->first_inode; *psi; psi=&(*psi)->next) {
|
|
if ((*psi)->inode == inode) {
|
|
si = *psi;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (action==0 && !si) {
|
|
XDPRINTF((1, 0, "Could not find share inode to remove %s", tbuf));
|
|
if (!sd->first_inode) {
|
|
*psd = sd->next;
|
|
xfree( sd );
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
if (!si) {
|
|
/* new inode */
|
|
si = (ShareINode*) xcmalloc( sizeof(ShareINode) );
|
|
if (!si) {
|
|
XDPRINTF((1, 0, "Could not allocate new share inode %s", tbuf));
|
|
if (!sd->first_inode) {
|
|
*psd = sd->next;
|
|
xfree( sd );
|
|
}
|
|
return(-1);
|
|
}
|
|
si->next = *psi;
|
|
*psi = si;
|
|
si->first_lock = NULL;
|
|
si->inode = inode;
|
|
}
|
|
|
|
if (sd->fd_sm == -1) {
|
|
/* open share files */
|
|
char buff[300];
|
|
int l;
|
|
if (NULL==path_share_lock_files) {
|
|
/* get path for share files */
|
|
if (get_ini_entry(NULL, 41, buff, sizeof(buff)) && *buff)
|
|
new_str(path_share_lock_files, buff);
|
|
else
|
|
new_str(path_share_lock_files, "/var/spool/nwserv/.locks");
|
|
if (seteuid(0))
|
|
return(-1);
|
|
unx_xmkdir(path_share_lock_files, 0755);
|
|
} else
|
|
if (seteuid(0))
|
|
return(-1);
|
|
l=sprintf(buff, "%s/%" PRIxMAX ".sm", path_share_lock_files,
|
|
(uintmax_t)dev);
|
|
sd->fd_sm = open(buff, O_RDWR|O_CREAT, 0600);
|
|
#if 0
|
|
buff[l-2]='c';
|
|
sd->fd_cm = open(buff, O_RDWR|O_CREAT, 0600);
|
|
#endif
|
|
buff[l-2]='o'; buff[l-1]='r';
|
|
sd->fd_or = open(buff, O_RDWR|O_CREAT, 0600);
|
|
buff[l-2]='d';
|
|
sd->fd_dr = open(buff, O_RDWR|O_CREAT, 0600);
|
|
buff[l-1]='w';
|
|
sd->fd_dw = open(buff, O_RDWR|O_CREAT, 0600);
|
|
buff[l-2]='o';
|
|
sd->fd_ow = open(buff, O_RDWR|O_CREAT, 0600);
|
|
/* lock file */
|
|
buff[l-2]='f'; buff[l-1]='l';
|
|
sd->fd_fl = open(buff, O_RDWR|O_CREAT, 0600);
|
|
reseteuid();
|
|
|
|
if (sd->fd_sm<0 || sd->fd_or<0 || sd->fd_dr<0 ||
|
|
sd->fd_ow<0 || sd->fd_dw<0
|
|
#if 0
|
|
|| sd->fd_cm<0
|
|
#endif
|
|
|| sd->fd_fl<0
|
|
)
|
|
{
|
|
if (sd->fd_sm>-1) close(sd->fd_sm);
|
|
if (sd->fd_or>-1) close(sd->fd_or);
|
|
if (sd->fd_dr>-1) close(sd->fd_dr);
|
|
if (sd->fd_ow>-1) close(sd->fd_ow);
|
|
if (sd->fd_dw>-1) close(sd->fd_dw);
|
|
#if 0
|
|
if (sd->fd_cm>-1) close(sd->fd_cm);
|
|
#endif
|
|
if (sd->fd_fl>-1) close(sd->fd_fl);
|
|
xfree( si );
|
|
*psd = sd->next;
|
|
xfree( sd );
|
|
buff[l-2]='\0';
|
|
XDPRINTF((1, 0, "Cannot open sharefile=`%s`", buff));
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
flockd.l_whence = SEEK_SET;
|
|
flockd.l_start = inode;
|
|
flockd.l_len = 1;
|
|
|
|
flockd.l_type = F_WRLCK;
|
|
fcntl(sd->fd_sm, F_SETLKW, &flockd); /* set semaphor */
|
|
|
|
if (action==1 || action==2) { /* TEST */
|
|
|
|
if (si->or ) act_mode |= 0x01;
|
|
if (si->ow ) act_mode |= 0x02;
|
|
if (si->dr ) act_mode |= 0x04;
|
|
if (si->dw ) act_mode |= 0x08;
|
|
#if 0
|
|
if (si->cm ) act_mode |= 0x10;
|
|
#endif
|
|
if (si->fl ) act_mode |= 0x100;
|
|
if (si->ex ) act_mode |= 0x200;
|
|
|
|
if (open_mode & 0xff) {
|
|
if (!(act_mode & 0x01)) {
|
|
/* do not set flockd.l_whence because after F_GETLK kernel
|
|
* set it as SEEK_SET */
|
|
flockd.l_type = F_WRLCK;
|
|
flockd.l_start = inode;
|
|
flockd.l_len = 1;
|
|
fcntl(sd->fd_or, F_GETLK, &flockd); /* read */
|
|
if (flockd.l_type != F_UNLCK)
|
|
act_mode |= 0x01;
|
|
}
|
|
if (!(act_mode & 0x04)) {
|
|
flockd.l_type = F_WRLCK;
|
|
flockd.l_start = inode;
|
|
flockd.l_len = 1;
|
|
fcntl(sd->fd_dr, F_GETLK, &flockd); /* deny read */
|
|
if (flockd.l_type != F_UNLCK)
|
|
act_mode |= 0x04;
|
|
}
|
|
if (!(act_mode & 0x02)) {
|
|
flockd.l_type = F_WRLCK;
|
|
flockd.l_start = inode;
|
|
flockd.l_len = 1;
|
|
fcntl(sd->fd_ow, F_GETLK, &flockd); /* write */
|
|
if (flockd.l_type != F_UNLCK)
|
|
act_mode |= 0x02;
|
|
}
|
|
if (!(act_mode & 0x08)) {
|
|
flockd.l_type = F_WRLCK;
|
|
flockd.l_start = inode;
|
|
flockd.l_len = 1;
|
|
fcntl(sd->fd_dw, F_GETLK, &flockd); /* deny write */
|
|
if (flockd.l_type != F_UNLCK)
|
|
act_mode |= 0x08;
|
|
}
|
|
#if 0
|
|
if (!(act_mode & 0x10)) {
|
|
flockd.l_type = F_WRLCK;
|
|
flockd.l_start = inode;
|
|
flockd.l_len = 1;
|
|
fcntl(sd->fd_cm, F_GETLK, &flockd); /* compatible mode */
|
|
if (flockd.l_type != F_UNLCK)
|
|
act_mode |= 0x10;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if ((open_mode & 0x300) && !(act_mode & 0x100)) {
|
|
flockd.l_type = F_WRLCK;
|
|
flockd.l_start = inode;
|
|
flockd.l_len = 1;
|
|
fcntl(sd->fd_fl, F_GETLK, &flockd); /* lock file */
|
|
if (flockd.l_type != F_UNLCK)
|
|
act_mode |= (flockd.l_type == F_WRLCK) ? 0x100|0x200 : 0x100;
|
|
}
|
|
|
|
if (act_mode & 0xff) { // already opened by other
|
|
|
|
#if 0 /* mst:13-Apr-00, I think this is all NOT needed. */
|
|
if (entry8_flags & 0x100) { /* dos ? mode */
|
|
if ((open_mode & 0x10) != (act_mode & 0x10))
|
|
result=-1;
|
|
} else { /* Standard Novell mode mode, i hope */
|
|
if ( (open_mode & 0x10) ? !(act_mode & 0x10) && (act_mode & 0x06) :
|
|
(act_mode & 0x10) && (open_mode & 0x06))
|
|
result = -1; /* if one file opened compatible then all files
|
|
must be opened compatible */
|
|
#if 0
|
|
else if ( (!(act_mode & 0xc)) && (open_mode & 0xc) )
|
|
result = -1; /* already opened DENYNO but now DENYXY wanted */
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
if (!result && (((open_mode & 0x01) && (act_mode & 0x04)) ||
|
|
((open_mode & 0x02) && (act_mode & 0x08)) ||
|
|
((open_mode & 0x04) && (act_mode & 0x01)) ||
|
|
((open_mode & 0x08) && (act_mode & 0x02))))
|
|
result=-1;
|
|
}
|
|
|
|
if (!result && /* lock file */
|
|
(((open_mode & 0x100) && (act_mode & 0x200)) ||
|
|
((open_mode & 0x200) && (act_mode & 0x100))))
|
|
result = -1;
|
|
|
|
if (action==1 && !result) { /* ADD */
|
|
flockd.l_type = F_RDLCK;
|
|
flockd.l_start = inode;
|
|
flockd.l_len = 1;
|
|
if (open_mode & 0x01) { /* read */
|
|
if (!si->or) {
|
|
fcntl(sd->fd_or, F_SETLK, &flockd);
|
|
}
|
|
si->or ++;
|
|
}
|
|
if (open_mode & 0x04) { /* deny read */
|
|
if (!si->dr) {
|
|
fcntl(sd->fd_dr, F_SETLK, &flockd);
|
|
}
|
|
si->dr ++;
|
|
}
|
|
if (open_mode & 0x02) { /* write */
|
|
if (!si->ow) {
|
|
fcntl(sd->fd_ow, F_SETLK, &flockd);
|
|
}
|
|
si->ow ++;
|
|
}
|
|
if (open_mode & 0x08) { /* deny write */
|
|
if (!si->dw) {
|
|
fcntl(sd->fd_dw, F_SETLK, &flockd);
|
|
}
|
|
si->dw ++;
|
|
}
|
|
#if 0
|
|
if (open_mode & 0x10) { /* compatible mode */
|
|
if (!si->cm) {
|
|
fcntl(sd->fd_cm, F_SETLK, &flockd);
|
|
}
|
|
si->cm ++;
|
|
}
|
|
#endif
|
|
if (open_mode & 0x100) { /* lock file */
|
|
if (!si->fl) {
|
|
flockd.l_type = (open_mode & 0x200) ? F_RDLCK : F_WRLCK;
|
|
fcntl(sd->fd_fl, F_SETLK, &flockd);
|
|
}
|
|
si->fl ++;
|
|
if (!(open_mode & 0x200)) /* exclusive */
|
|
si->ex ++;
|
|
}
|
|
}
|
|
} else if (action==0) { /* REMOVE */
|
|
flockd.l_start = inode;
|
|
flockd.l_len = 1;
|
|
flockd.l_type = F_UNLCK;
|
|
if (open_mode & 0x01) /* read */
|
|
if (si->or && !(--si->or))
|
|
fcntl(sd->fd_or, F_SETLK, &flockd);
|
|
if (open_mode & 0x04) /* deny read */
|
|
if (si->dr && !(--si->dr))
|
|
fcntl(sd->fd_dr, F_SETLK, &flockd);
|
|
if (open_mode & 0x02) /* write */
|
|
if (si->ow && !(--si->ow))
|
|
fcntl(sd->fd_ow, F_SETLK, &flockd);
|
|
if (open_mode & 0x08) /* deny write */
|
|
if (si->dw && !(--si->dw))
|
|
fcntl(sd->fd_dw, F_SETLK, &flockd);
|
|
#if 0
|
|
if (open_mode & 0x10) /* compatible mode */
|
|
if (si->cm && !(--si->cm))
|
|
fcntl(sd->fd_cm, F_SETLK, &flockd);
|
|
#endif
|
|
if (open_mode & 0x100) /* file lock */
|
|
if (si->fl && !(--si->fl)) {
|
|
fcntl(sd->fd_fl, F_SETLK, &flockd);
|
|
si->ex = 0;
|
|
}
|
|
}
|
|
|
|
flockd.l_type = F_UNLCK;
|
|
flockd.l_start = inode;
|
|
flockd.l_len = 1;
|
|
fcntl(sd->fd_sm, F_SETLK, &flockd); /* realise semaphor */
|
|
|
|
if (!si->or && !si->ow && !si->dr && !si->dw
|
|
#if 0
|
|
&& !si->cm
|
|
#endif
|
|
&& !si->fl ) {
|
|
/* release inode */
|
|
while (si->first_lock) {
|
|
ShareLock *p = si->first_lock;
|
|
si->first_lock = p->next;
|
|
xfree( p );
|
|
}
|
|
*psi = si->next;
|
|
xfree( si );
|
|
}
|
|
|
|
if (!sd->first_inode) {
|
|
/* release device */
|
|
close(sd->fd_sm);
|
|
close(sd->fd_or);
|
|
close(sd->fd_ow);
|
|
close(sd->fd_dr);
|
|
close(sd->fd_dw);
|
|
#if 0
|
|
close(sd->fd_cm);
|
|
#endif
|
|
close(sd->fd_fl);
|
|
*psd = sd->next;
|
|
xfree( sd );
|
|
}
|
|
XDPRINTF((3, 0, "share_file result=%d %s,act_mode=%x", result, tbuf, act_mode));
|
|
return(result);
|
|
}
|
|
|
|
static int _get_inode( int dev, int inode, ShareDev **psd, ShareINode **psi )
|
|
{
|
|
for (*psd=first_dev; *psd; *psd=(*psd)->next)
|
|
if ((*psd)->dev == dev)
|
|
break;
|
|
if (!*psd)
|
|
return 0;
|
|
for (*psi=(*psd)->first_inode; *psi; *psi=(*psi)->next)
|
|
if ((*psi)->inode == inode)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
void catch_alarm (int sig)
|
|
{
|
|
signal(sig, SIG_IGN);
|
|
}
|
|
|
|
#define OFFSET_MAX 0x7fffffff
|
|
|
|
int share_lock(dev_t dev, ino_t inode, int fd, int action,
|
|
int lock_flag, int l_start, int l_len, int timeout)
|
|
/*
|
|
* action:
|
|
* 0 = unlock
|
|
* 1 = lock
|
|
* 2 = testonly
|
|
*
|
|
* lock_flag:
|
|
* <0 = unlock
|
|
* 1 = exclusive
|
|
* 3 = shared ro
|
|
*/
|
|
|
|
{
|
|
ShareDev *sd;
|
|
ShareINode *si;
|
|
ShareLock *sl = NULL, **psl;
|
|
int result = 0;
|
|
struct flock flockd;
|
|
char tbuf[200];
|
|
sprintf(tbuf,
|
|
"dev=0x%" PRIxMAX ",inode=%" PRIuMAX ",fd=%d,action=%d,lock_flag=%d",
|
|
(uintmax_t)dev, (uintmax_t)inode,
|
|
fd, action, lock_flag);
|
|
|
|
#if 0
|
|
/* pcz: 30-Jul-01 different locking conversion from 32Bit space
|
|
Now it's a dirty hack only, It should be an option in nwserv.conf */
|
|
if (l_start & 0x80000000)
|
|
l_start |= 0x40000000; /* 0x20000000 - other possible value */
|
|
#endif
|
|
|
|
l_start &= 0x7fffffff;
|
|
|
|
if (l_len==MAX_U32)
|
|
l_len = 0;
|
|
|
|
if (!_get_inode( dev, inode, &sd, &si )) {
|
|
XDPRINTF((1, 0, "Could not find share for lock %s", tbuf));
|
|
return -1;
|
|
}
|
|
|
|
flockd.l_whence = SEEK_SET;
|
|
flockd.l_start = l_start;
|
|
flockd.l_len = l_len;
|
|
|
|
/* find lock */
|
|
/* pcz: 23-Aug-2001
|
|
1) some application remove locks using offset only and len=0
|
|
2) we cannot compare offset1 < offset2 + size2 because the
|
|
sum can be signed (minus) eg. 0x7fffffff + 1 = 0x80000000
|
|
It should be offset1 - offset2 < size2 */
|
|
for (psl=&si->first_lock; *psl; psl=&(*psl)->next) {
|
|
if ((*psl)->l_start - l_start < l_len
|
|
|| (!l_len && ( action ? (*psl)->l_start <= l_start
|
|
: (*psl)->l_start == l_start))) {
|
|
sl = *psl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!action) {
|
|
/* unlock */
|
|
if (sl && sl->fd == fd && sl->l_start == l_start &&
|
|
(sl->l_len == l_len || l_len ==0)) {
|
|
flockd.l_len = sl->l_len;
|
|
flockd.l_type = F_UNLCK;
|
|
fcntl( fd, F_SETLK, &flockd );
|
|
*psl = sl->next;
|
|
xfree( sl );
|
|
} else {
|
|
XDPRINTF((2, 0, "unlock: can't find proper lock pid=%d uid=%d fd=%d %d, %d", getpid(), geteuid(), fd, l_start, l_len));
|
|
result = -0xff;
|
|
}
|
|
} else {
|
|
/* lock or test */
|
|
if (sl && (l_start - sl->l_start < sl->l_len || !sl->l_len)
|
|
&& (sl->exclusive || lock_flag == 1) )
|
|
result = -0xfd; /* collision */
|
|
else {
|
|
flockd.l_type = (lock_flag == 1) ? F_WRLCK : F_RDLCK;
|
|
if (action==1 && timeout > 17) {/* if timeout is relatively short
|
|
* do not set the alarm. /lenz */
|
|
signal( SIGALRM, catch_alarm );
|
|
alarm( timeout / 18 );
|
|
result = fcntl( fd, F_SETLKW, &flockd );
|
|
alarm( 0 );
|
|
signal( SIGALRM, SIG_IGN );
|
|
} else {
|
|
result = fcntl( fd, (action==1) ? F_SETLK : F_GETLK, &flockd );
|
|
}
|
|
if (result) {
|
|
if (!timeout) /* my NW 3.12 returns 0xff if timeout == 0. /lenz */
|
|
result = -0xff;
|
|
else
|
|
result = -0xfe;
|
|
}
|
|
if (!result) {
|
|
if (action == 1) {
|
|
/* add to list */
|
|
sl = (ShareLock*) xmalloc( sizeof(ShareLock) );
|
|
sl->next = *psl;
|
|
*psl = sl;
|
|
sl->l_start = l_start;
|
|
sl->l_len = l_len;
|
|
sl->fd = fd;
|
|
sl->exclusive = (lock_flag == 1) ? 1 : 0;
|
|
} else
|
|
if (flockd.l_type != F_UNLCK)
|
|
result = -1;
|
|
}
|
|
}
|
|
}
|
|
XDPRINTF((3, 0, "share_lock result=%d %s", result, tbuf));
|
|
return result;
|
|
}
|
|
|
|
int share_unlock_all(dev_t dev, ino_t inode, int fd)
|
|
{
|
|
ShareDev *sd;
|
|
ShareINode *si;
|
|
ShareLock **psl;
|
|
int result = 0;
|
|
struct flock flockd;
|
|
char tbuf[200];
|
|
sprintf(tbuf,
|
|
"dev=0x%" PRIxMAX ",inode=%" PRIuMAX ",fd=%d",
|
|
(uintmax_t)dev, (uintmax_t)inode, fd);
|
|
|
|
if (!_get_inode( dev, inode, &sd, &si )) {
|
|
XDPRINTF((1, 0, "Could not find share for unlock_all %s", tbuf));
|
|
return -1;
|
|
}
|
|
|
|
flockd.l_type = F_UNLCK;
|
|
flockd.l_whence = SEEK_SET;
|
|
|
|
for (psl=&si->first_lock; *psl; ) {
|
|
if ((*psl)->fd == fd) {
|
|
ShareLock *sl = *psl;
|
|
flockd.l_start = sl->l_start;
|
|
flockd.l_len = sl->l_len;
|
|
fcntl( fd, F_SETLK, &flockd );
|
|
*psl = sl->next;
|
|
xfree( sl );
|
|
} else
|
|
psl=&(*psl)->next;
|
|
}
|
|
XDPRINTF((3, 0, "share_unlock_all,result=%d %s", result, tbuf));
|
|
return result;
|
|
}
|
|
|
|
void dump_locks(dev_t dev, ino_t inode, int fd, FILE* f)
|
|
{
|
|
ShareDev *sd;
|
|
ShareINode *si;
|
|
ShareLock *psl;
|
|
char tbuf[200];
|
|
sprintf(tbuf,
|
|
"dev=0x%" PRIxMAX ",inode=%" PRIuMAX ",fd=%d",
|
|
(uintmax_t)dev, (uintmax_t)inode, fd);
|
|
|
|
if (!_get_inode( dev, inode, &sd, &si )) {
|
|
XDPRINTF((1, 0, "Could not find share for unlock_all %s", tbuf));
|
|
}
|
|
|
|
for (psl=si->first_lock; psl; ) {
|
|
fprintf(f, "fd=%d %d-%d ", psl->fd, psl->l_start, psl->l_len);
|
|
psl = psl->next;
|
|
}
|
|
fprintf(f, "\n");
|
|
}
|
|
|
|
|
|
typedef struct S_SHARESET{
|
|
int type;
|
|
int lock_flag;
|
|
int timeout; /* not used yet */
|
|
int locked; /* is entry locked */
|
|
|
|
dev_t dev;
|
|
ino_t inode;
|
|
|
|
int datalen;
|
|
char *data; /* used for Logical Records */
|
|
|
|
int fhandle; /* used for Physical Records */
|
|
uint32 offset;
|
|
uint32 size;
|
|
|
|
struct S_SHARESET *next;
|
|
} SHARESET;
|
|
|
|
static SHARESET *first_set = NULL;
|
|
|
|
static int lock_unlock_pset(SHARESET *ps, int lock_flag)
|
|
{
|
|
int result;
|
|
switch (ps->type)
|
|
{
|
|
case 1: /* file share */
|
|
if (lock_flag>-1)
|
|
result = share_file(ps->dev, ps->inode,
|
|
lock_flag ? lock_flag
|
|
: (ps->lock_flag
|
|
? ps->lock_flag
|
|
: 1),
|
|
1);
|
|
else
|
|
result = share_file(ps->dev, ps->inode, 0x300, 0);
|
|
break;
|
|
|
|
case 2: /* logical records */
|
|
if (lock_flag>-1)
|
|
result = nw_log_logical_record(
|
|
lock_flag ? lock_flag
|
|
: (ps->lock_flag
|
|
? ps->lock_flag
|
|
: 1),
|
|
ps->timeout, /* timeout not used yet */
|
|
ps->datalen,
|
|
ps->data);
|
|
else
|
|
result = nw_log_logical_record(
|
|
-1,
|
|
ps->timeout, /* timeout not used yet */
|
|
ps->datalen,
|
|
ps->data);
|
|
break;
|
|
|
|
case 4: /* physical records */
|
|
if (lock_flag>-1)
|
|
result = nw_log_physical_record(
|
|
ps->fhandle,
|
|
ps->offset,
|
|
ps->size,
|
|
ps->timeout,
|
|
lock_flag ? lock_flag
|
|
: (ps->lock_flag
|
|
? ps->lock_flag
|
|
: 1));
|
|
else
|
|
result = nw_log_physical_record(
|
|
ps->fhandle,
|
|
ps->offset,
|
|
ps->size,
|
|
ps->timeout,
|
|
-1);
|
|
break;
|
|
|
|
default :
|
|
result = -1;
|
|
}
|
|
return(result);
|
|
}
|
|
|
|
int share_set_file_add_rm(int lock_flag, dev_t dev, ino_t inode)
|
|
{
|
|
if (lock_flag > -1) {
|
|
SHARESET *ps = (SHARESET*)xcmalloc(sizeof(SHARESET));
|
|
ps->next = first_set;
|
|
first_set = ps;
|
|
ps->type = 1;
|
|
ps->dev = dev;
|
|
ps->inode = inode;
|
|
ps->lock_flag = lock_flag;
|
|
} else if (lock_flag == -2) {
|
|
SHARESET **pset = &first_set;
|
|
while (*pset) {
|
|
SHARESET *ps = *pset;
|
|
*pset = (*pset)->next;
|
|
if (1 == ps->type) {
|
|
xfree(ps);
|
|
}
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int share_set_logrec_add_rm(int lock_flag, int timeout, int len, char *data)
|
|
{
|
|
if (lock_flag > -1) {
|
|
SHARESET *ps = (SHARESET*)xcmalloc(sizeof(SHARESET));
|
|
ps->next = first_set;
|
|
first_set = ps;
|
|
ps->type = 2;
|
|
ps->datalen = len;
|
|
ps->data = xcmalloc(len+1);
|
|
memcpy(ps->data, data, len);
|
|
ps->lock_flag = lock_flag;
|
|
} else if (lock_flag == -2) {
|
|
SHARESET **pset = &first_set;
|
|
while (*pset) {
|
|
SHARESET *ps = *pset;
|
|
*pset = (*pset)->next;
|
|
if (2 == ps->type) {
|
|
xfree(ps->data);
|
|
xfree(ps);
|
|
}
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
int share_set_physrec_add_rm(int lock_flag, int fhandle, uint32 offset,
|
|
uint32 size, uint16 timeout)
|
|
{
|
|
if (lock_flag > -1) {
|
|
SHARESET *ps = (SHARESET*)xcmalloc(sizeof(SHARESET));
|
|
ps->next = first_set;
|
|
first_set = ps;
|
|
ps->type = 4;
|
|
ps->fhandle = fhandle;
|
|
ps->offset = offset;
|
|
ps->size = size;
|
|
ps->timeout = timeout;
|
|
ps->lock_flag = lock_flag;
|
|
ps->locked = lock_flag ? 1 : 0;
|
|
} else if (lock_flag == -2) {
|
|
SHARESET **pset = &first_set;
|
|
while (*pset) {
|
|
SHARESET *ps = *pset;
|
|
if (4 == ps->type &&
|
|
ps->fhandle == fhandle &&
|
|
ps->offset == offset &&
|
|
ps->size == size) {
|
|
*pset = ps->next;
|
|
xfree(ps);
|
|
continue;
|
|
}
|
|
pset = &ps->next;
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int share_handle_lock_sets(int type, int lock_flag, int timeout)
|
|
/* type:
|
|
* 1 = file share
|
|
* 2 = logical record
|
|
* 4 = physical record
|
|
*
|
|
* lock_flag:
|
|
* -2 = clear (delete) set
|
|
* -1 = release (unshare/unlock) set
|
|
* 0/1/3 = lock/share set
|
|
*
|
|
* timeout: not used yet. !!
|
|
*/
|
|
{
|
|
SHARESET **pset = &first_set;
|
|
while (*pset) {
|
|
SHARESET *ps = *pset;
|
|
|
|
if (type & ps->type) {
|
|
if (ps->locked && (lock_flag < 0)) {
|
|
if (!lock_unlock_pset(ps, -1))
|
|
ps->locked = 0;
|
|
} else if ((!ps->locked) && lock_flag > -1){
|
|
if (lock_unlock_pset(ps, lock_flag)){
|
|
/* release locks already acquired for this set operation */
|
|
share_handle_lock_sets(type, -1, 0);
|
|
return(-1);
|
|
} else
|
|
ps->locked = 1;
|
|
}
|
|
if (lock_flag == -2) { /* remove matching node */
|
|
*pset = ps->next;
|
|
xfree(ps->data);
|
|
xfree(ps);
|
|
continue;
|
|
}
|
|
}
|
|
pset = &ps->next;
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
|
|
|