1333 lines
39 KiB
C
1333 lines
39 KiB
C
/* nwfile.c 25-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.
|
|
*/
|
|
|
|
/* history since 21-Apr-00
|
|
*
|
|
* mst:25-Apr-00: nw_get_count_open_files()
|
|
*
|
|
*/
|
|
|
|
|
|
#include "net.h"
|
|
|
|
#include <dirent.h>
|
|
#include <utime.h>
|
|
|
|
#include <sys/errno.h>
|
|
#include <sys/time.h>
|
|
|
|
#include "nwvolume.h"
|
|
#include "nwshare.h"
|
|
#include "nwfile.h"
|
|
#include "connect.h"
|
|
#include "nwattrib.h"
|
|
#include "trustee.h"
|
|
#include "nwconn.h"
|
|
#include "unxfile.h"
|
|
|
|
# include <sys/mman.h>
|
|
|
|
static int got_sig_bus=0;
|
|
void sig_bus_mmap(int rsig)
|
|
{
|
|
got_sig_bus++;
|
|
XDPRINTF((2,0, "Got sig_bus"));
|
|
signal(SIGBUS, sig_bus_mmap);
|
|
}
|
|
|
|
|
|
static FILE_HANDLE file_handles[MAX_FILE_HANDLES_CONN];
|
|
#define HOFFS 0
|
|
#define USE_NEW_FD 1
|
|
static int count_fhandles=0;
|
|
|
|
#if USE_NEW_FD
|
|
static int last_fhandle=HOFFS;
|
|
#endif
|
|
|
|
static int new_file_handle(int volume, uint8 *unixname, int task)
|
|
{
|
|
#if USE_NEW_FD
|
|
int fhandle= -1 + last_fhandle++;
|
|
#else
|
|
int fhandle=HOFFS-1;
|
|
#endif
|
|
FILE_HANDLE *fh=NULL;
|
|
while (++fhandle < count_fhandles) {
|
|
fh=&(file_handles[fhandle]);
|
|
if (fh->fd == -1 && !(fh->fh_flags & FH_DO_NOT_REUSE)) { /* empty slot */
|
|
fhandle++;
|
|
break;
|
|
} else fh=NULL;
|
|
}
|
|
|
|
if (fh == NULL) {
|
|
if (count_fhandles < MAX_FILE_HANDLES_CONN) {
|
|
fh=&(file_handles[count_fhandles]);
|
|
fhandle = ++count_fhandles;
|
|
} else {
|
|
#if USE_NEW_FD
|
|
last_fhandle=HOFFS+1;
|
|
fhandle=HOFFS-1;
|
|
while (++fhandle < count_fhandles) {
|
|
fh=&(file_handles[fhandle]);
|
|
if (fh->fd == -1 && !(fh->fh_flags & FH_DO_NOT_REUSE)) { /* empty slot */
|
|
fhandle++;
|
|
break;
|
|
} else fh=NULL;
|
|
}
|
|
#endif
|
|
if (fh == NULL) {
|
|
XDPRINTF((1, 0, "No more free file handles"));
|
|
return(0); /* no free handle anymore */
|
|
}
|
|
}
|
|
}
|
|
/* init handle */
|
|
fh->task = task;
|
|
fh->fd = -2;
|
|
fh->offd = 0L;
|
|
fh->tmodi = 0L;
|
|
fh->modified = 0;
|
|
fh->st_ino = 0;
|
|
fh->access = 0;
|
|
fh->inuse = 0;
|
|
xstrcpy(fh->fname, (char*)unixname);
|
|
fh->fh_flags = 0;
|
|
fh->f = NULL;
|
|
fh->volume = volume;
|
|
XDPRINTF((5, 0, "new_file_handle=%d, count_fhandles=%d, fn=%s",
|
|
fhandle, count_fhandles, unixname));
|
|
return(fhandle);
|
|
}
|
|
|
|
static int free_file_handle(int fhandle)
|
|
{
|
|
int result=-0x88;
|
|
if (fhandle > HOFFS && (fhandle <= count_fhandles)) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle-1]);
|
|
if (fh->fd > -1) {
|
|
if (fh->fh_flags & FH_IS_PIPE_COMMAND) {
|
|
if (fh->f) ext_pclose(fh->f);
|
|
fh->f = NULL;
|
|
} else {
|
|
if (use_mmap && fh->p_mmap) {
|
|
munmap(fh->p_mmap, fh->size_mmap);
|
|
fh->p_mmap = NULL;
|
|
fh->size_mmap = 0;
|
|
}
|
|
if (fh->st_ino) {
|
|
/* changed by: Ingmar Thiemann <ingmar@gefas.com> */
|
|
share_unlock_all( fh->st_dev, fh->st_ino, fh->fd );
|
|
}
|
|
close(fh->fd);
|
|
if (fh->st_ino) {
|
|
/* changed by: Ingmar Thiemann <ingmar@gefas.com> */
|
|
share_file(fh->st_dev, fh->st_ino, fh->access&0xff, 0);
|
|
if (fh->modified) {
|
|
fh->modified=0;
|
|
#if NEW_ATTRIB_HANDLING
|
|
set_nw_archive_bit(fh->volume, fh->fname, fh->st_dev, fh->st_ino);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
if (fh->tmodi > 0L && !(FH_IS_PIPE_COMMAND & fh->fh_flags)
|
|
&& !(FH_IS_READONLY & fh->fh_flags) ) {
|
|
/* now set date and time */
|
|
struct utimbuf ut;
|
|
ut.actime = ut.modtime = fh->tmodi;
|
|
seteuid(0);
|
|
utime(fh->fname, &ut);
|
|
reseteuid();
|
|
fh->tmodi = 0L;
|
|
}
|
|
}
|
|
fh->fd = -1;
|
|
#if !USE_NEW_FD
|
|
while (count_fhandles > fhandle
|
|
&& file_handles[count_fhandles-1].fd == -1
|
|
&& !(file_handles[count_fhandles-1].fh_flags & FH_DO_NOT_REUSE) ) {
|
|
count_fhandles--;
|
|
}
|
|
#endif
|
|
result=0;
|
|
}
|
|
XDPRINTF((5, 0, "free_file_handle=%d, count_fhandles=%d, result=%d",
|
|
fhandle, count_fhandles, result));
|
|
return(result); /* wrong filehandle */
|
|
}
|
|
|
|
void init_file_module(int task)
|
|
/*
|
|
* if task == -1 all handles will be free'd
|
|
* else only handles of the task will be free'd
|
|
*/
|
|
{
|
|
int k = HOFFS;
|
|
if (task < 0) {
|
|
while (k++ < count_fhandles)
|
|
free_file_handle(k);
|
|
count_fhandles = HOFFS;
|
|
#if USE_NEW_FD
|
|
last_fhandle = HOFFS;
|
|
#endif
|
|
} else {
|
|
/* I hope next is ok, added 20-Oct-96 ( 0.98.pl5 ) */
|
|
while (k++ < count_fhandles) {
|
|
FILE_HANDLE *fh=&(file_handles[k-1]);
|
|
if (fh->task == task && fh->fd>-1) {
|
|
MDEBUG(D_FH_OPEN, {
|
|
char fname[400];
|
|
int r=fd_2_fname(k, fname, sizeof(fname));
|
|
xdprintf(1,0,"init_file_m fd=%3d, task=%d, fn=`%s`,r=%d",
|
|
k, task, fname, r);
|
|
})
|
|
free_file_handle(k);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int open_with_root_access(char *path, int mode)
|
|
/* open existing files */
|
|
{
|
|
int fd = open(path, mode);
|
|
if (fd < 0 && errno == EACCES) {
|
|
seteuid(0);
|
|
fd = open(path, mode);
|
|
reseteuid();
|
|
}
|
|
return(fd);
|
|
}
|
|
|
|
#if 0 /* not used */
|
|
static int reopen_file(int volume, uint8 *unixname, struct stat *stbuff,
|
|
int access, int task)
|
|
/* look for file already open and try to use it */
|
|
/* do not know whether this is real ok */
|
|
{
|
|
int fhandle=-1;
|
|
int result=0;
|
|
while (++fhandle < count_fhandles) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle]);
|
|
if (fh->fd > -1 && fh->task == task && fh->volume == volume
|
|
&& fh->st_dev == stbuff->st_dev && fh->st_ino == stbuff->st_ino) {
|
|
if ((fh->access&4) && (access&4))
|
|
return(-0x80); /* share error */
|
|
if ((fh->access&8) && (access&8))
|
|
return(-0x80); /* share error */
|
|
/* changed by: Ingmar Thiemann <ingmar@gefas.com> */
|
|
result=share_file(stbuff->st_dev, stbuff->st_ino, fh->access&0xff, 1);
|
|
if (result)
|
|
return(-0x80); /* share error */
|
|
if ((fh->access&2) || (access&2))
|
|
return(0);
|
|
fh->inuse++;
|
|
return(++fhandle);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
#endif
|
|
|
|
int file_creat_open(int volume, uint8 *unixname, struct stat *stbuff,
|
|
int attrib, int access, int creatmode, int task)
|
|
/*
|
|
* creatmode: 0 = open ( do not creat )
|
|
* | 1 = creat ( creat always )
|
|
* | 2 = creatnew ( creat if not exist else error )
|
|
* ---------
|
|
* & 4 == save handle (not reuse)
|
|
* & 8 == ignore rights (try to open as root)
|
|
* attrib ??
|
|
*
|
|
* access: 0x1=read,
|
|
* 0x2=write,
|
|
* 0x4=deny read, -> F_WRLCK, no other process can make
|
|
* a read or write lock
|
|
* can only be used if file is open for writing
|
|
* 0x8=deny write -> F_RDLCK, no other process can make a writelock
|
|
* can only be used if file is open for reading
|
|
* 0x10=SH_COMPAT
|
|
*
|
|
* 0x09 (O_RDONLY | O_DENYWRITE);
|
|
* 0x05 (O_RDONLY | O_DENYREAD);
|
|
*
|
|
* 0x0b (O_RDWR | O_DENYWRITE);
|
|
* 0x07 (O_RDWR | O_DENYREAD);
|
|
*
|
|
* 0x05 (O_RDONLY | O_DENYREAD | O_DENYWRITE);
|
|
* 0x07 (O_RDWR | O_DENYREAD | O_DENYWRITE);
|
|
*
|
|
*/
|
|
{
|
|
|
|
/* int dowrite = ((access & 2) || (creatmode & 3) ) ? 1 : 0; */
|
|
int dowrite;
|
|
int completition = 0; /* first ok */
|
|
int fhandle = -1;
|
|
int voloptions = get_volume_options(volume);
|
|
int volnamlen = get_volume_unixnamlen(volume);
|
|
int exist = stat(unixname, stbuff) ? 0 : 1;
|
|
int eff_rights = 0;
|
|
uint32 dwattrib;
|
|
|
|
if ( !(access&3) )
|
|
access |= 3; /* mst:04-Apr-00, default RW */
|
|
|
|
dowrite = ((access & 2) || (creatmode & 3) ) ? 1 : 0;
|
|
|
|
/* first we test accesses
|
|
* if something is wrong completition will become != 0
|
|
*/
|
|
|
|
if (!exist) {
|
|
/* we do it again as root to get always the correct information */
|
|
seteuid(0);
|
|
exist = stat(unixname, stbuff) ? 0 : 1;
|
|
reseteuid();
|
|
}
|
|
|
|
#if 0 /* mst:04-Apr-00, not needed here */
|
|
if ((!access) && dowrite){ /* create without access set */
|
|
access = 2; /* OK ? mst: 28-Sep-99 */
|
|
XDPRINTF((2,0,"file_creat_open creatmode=%d, access=0, fn=%s",
|
|
creatmode, unixname));
|
|
}
|
|
#endif
|
|
|
|
if (exist) { /* file exists */
|
|
if (S_ISDIR(stbuff->st_mode))
|
|
completition = -0xff; /* directory is total wrong here */
|
|
else {
|
|
eff_rights = tru_get_eff_rights(volume, unixname, stbuff);
|
|
dwattrib = get_nw_attrib_dword(volume, unixname, stbuff);
|
|
#if 0 // removed by lenz
|
|
/* mst: 12-Apr-00 */
|
|
if (access & 0x10) {
|
|
access &= ~0x10;
|
|
if (!(dwattrib & FILE_ATTR_SHARE)) {
|
|
access |= 0x8; /* deny write */
|
|
if (access & 2)
|
|
access |= 0x4; /* deny read */
|
|
}
|
|
}
|
|
#endif
|
|
#if 0
|
|
if ( (dwattrib & FILE_ATTR_SHARE) && (access & 0x10) ) {
|
|
access &= ~0x10;
|
|
if (dowrite)
|
|
access |= 0x8;
|
|
}
|
|
#endif
|
|
|
|
#if 0 /* deaktivated in 0.99.pl16, 23-May-99 */
|
|
/* because reopen_file do not handle share conditions correct */
|
|
if (!(creatmode&1) && !(voloptions & VOL_OPTION_IS_PIPE)) {
|
|
int fdx=reopen_file(volume, unixname, stbuff, access, task);
|
|
if (fdx != 0)
|
|
return(fdx);
|
|
}
|
|
#endif
|
|
|
|
if (creatmode&0x2) { /* creat if not exist */
|
|
if (S_ISFIFO(stbuff->st_mode)||(voloptions&VOL_OPTION_IS_PIPE)) {
|
|
/* fifo or pipe command always must exist */
|
|
if ((dwattrib&FILE_ATTR_R)||!(eff_rights & TRUSTEE_W)){
|
|
completition = -0x94; /* No write rights */
|
|
}
|
|
} else {
|
|
XDPRINTF((5,0,"CREAT File exist!! :%s:", unixname));
|
|
completition = -0x85; /* No Priv */
|
|
}
|
|
} else if (creatmode&0x1) { /* creat always*/
|
|
if (!(creatmode&0x8)){
|
|
if ((dwattrib&FILE_ATTR_R)
|
|
|| !(eff_rights & TRUSTEE_W))
|
|
completition = -0x86; /* creat file exists ro */
|
|
#if 0 // mst:14-Apr-00, for create no delete rights are necessary !?
|
|
else if (!(eff_rights & TRUSTEE_E))
|
|
completition = -0x85; /* creat file no delete rights */
|
|
#endif
|
|
else if (!(eff_rights & TRUSTEE_C)){
|
|
completition = -0x84; /* No creat rights */
|
|
}
|
|
}
|
|
} else { /* open */
|
|
if (dowrite) {
|
|
if (!(creatmode&0x8)) {
|
|
if ((dwattrib&FILE_ATTR_R)||!(eff_rights & TRUSTEE_W)){
|
|
if ((entry8_flags&2) && (eff_rights & TRUSTEE_R) ) {
|
|
/* we use strange compatibility modus if file is readable */
|
|
dowrite=0;
|
|
XDPRINTF((1, 0, "Uses strange open comp. mode for file `%s`",
|
|
unixname));
|
|
} else
|
|
completition = -0x94; /* No write rights */
|
|
}
|
|
}
|
|
} else { /* open to read */
|
|
if (!(creatmode&0x8)) {
|
|
if (!(eff_rights & TRUSTEE_R)){
|
|
completition = -0x93; /* No read rights */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( (!completition) && dowrite && !S_ISFIFO(stbuff->st_mode) &&
|
|
!(voloptions&VOL_OPTION_IS_PIPE)) {
|
|
/* is this file already opened write deny by other process */
|
|
/* changed by: Ingmar Thiemann <ingmar@gefas.com> */
|
|
/* if (-1 == share_file(stbuff->st_dev, stbuff->st_ino, 0x2, 2)) */
|
|
/* pcz: 14-Nov-99 */
|
|
if (-1 == share_file(stbuff->st_dev, stbuff->st_ino, access&0xff, 2))
|
|
completition=-0x80;
|
|
}
|
|
}
|
|
} else { /* do not exist, must be created */
|
|
if (voloptions&VOL_OPTION_IS_PIPE)
|
|
completition=-0xff; /* pipecommands always must exist */
|
|
else if (creatmode&0x3) { /* do creat */
|
|
uint8 *p=(uint8*)strrchr(unixname, '/');
|
|
if (NULL != p && ((p - unixname)+1) >= volnamlen ) { /* parent dir */
|
|
*p='\0';
|
|
seteuid(0);
|
|
completition=stat(unixname, stbuff);
|
|
reseteuid();
|
|
if (!completition) {
|
|
eff_rights = tru_get_eff_rights(volume, unixname, stbuff);
|
|
dwattrib = get_nw_attrib_dword(volume, unixname, stbuff);
|
|
if (creatmode&0x8)
|
|
eff_rights |= TRUSTEE_C|TRUSTEE_W|TRUSTEE_R;
|
|
if (!(eff_rights & TRUSTEE_C)){ /* no creat rights */
|
|
completition=-0x84;
|
|
}
|
|
} else
|
|
completition=-0x9c;
|
|
*p='/';
|
|
} else
|
|
completition=-0x9c;
|
|
if (completition==-0x9c)
|
|
errorp(0, "nwfile.c", "LINE=%d, unixname='%s', p-unx=%d, volnamlen=%d",
|
|
__LINE__, unixname, (p) ? (int)(p - unixname): 0, volnamlen );
|
|
} else
|
|
completition=-0xff; /* should, but do not exist */
|
|
}
|
|
|
|
/*
|
|
* Here all access tests are made and we can do the open as
|
|
* root (open_with_root_access).
|
|
*/
|
|
if (!completition) {
|
|
fhandle = new_file_handle(volume, unixname, task);
|
|
if (fhandle > HOFFS) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle-1]);
|
|
if (exist) {
|
|
if (S_ISFIFO(stbuff->st_mode)) { /* named pipes */
|
|
fh->fh_flags |= FH_IS_PIPE;
|
|
fh->fd = open_with_root_access(fh->fname, O_NONBLOCK
|
|
| (dowrite
|
|
? O_WRONLY
|
|
: O_RDONLY));
|
|
if (fh->fd < 0)
|
|
completition=-0x9c;
|
|
} else if (voloptions & VOL_OPTION_IS_PIPE) { /* 'pipe' volume */
|
|
fh->fh_flags |= FH_IS_PIPE;
|
|
fh->fh_flags |= FH_IS_PIPE_COMMAND;
|
|
fh->fd=-3;
|
|
#if 0
|
|
stbuff->st_mtime = (time(NULL)-255)+(rand()&0xff);
|
|
if (!dowrite)
|
|
stbuff->st_size = 0x7fff0000 | (rand() & 0xffff);
|
|
#else /* 03-Aug-98 better ? */
|
|
stbuff->st_mtime = time(NULL)+1000;
|
|
stbuff->st_size = 0x70000000|(stbuff->st_mtime&0xfffffff);
|
|
#endif
|
|
stbuff->st_atime = stbuff->st_mtime;
|
|
} else { /* 'normal' file */
|
|
/* Changed by: Ingmar Thiemann <ingmar@gefas.com>
|
|
* always RDWR for doing flock() with F_WRLCK
|
|
*/
|
|
#if 0
|
|
int acm = O_RDWR; /*(dowrite) ? O_RDWR : O_RDONLY;*/
|
|
#else /* mst: 26-Sep-99, readonly volumes must be opened O_RDONLY */
|
|
int acm = (voloptions & VOL_OPTION_READONLY) ? O_RDONLY : O_RDWR;
|
|
#endif
|
|
if (dowrite && (creatmode&0x3))
|
|
acm |= O_TRUNC;
|
|
fh->fd = open_with_root_access(fh->fname, acm);
|
|
if (fh->fd != -1){
|
|
if (acm&O_TRUNC) {
|
|
seteuid(0);
|
|
stat(fh->fname, stbuff);
|
|
reseteuid();
|
|
}
|
|
} else
|
|
completition=-0x9c;
|
|
if (completition==-0x9c)
|
|
errorp(0, "nwfile.c", "LINE=%d, unixname='%s'", __LINE__, unixname);
|
|
}
|
|
} else { /* needs to be created */
|
|
if (nw_creat_node(volume, fh->fname, 2|8))
|
|
completition=-0x9c;
|
|
else {
|
|
fh->fd = open_with_root_access(fh->fname, O_RDWR);
|
|
fh->offd = 0L;
|
|
if (fh->fd==-1)
|
|
completition=-0x9c;
|
|
else {
|
|
seteuid(0);
|
|
stat(fh->fname, stbuff);
|
|
reseteuid();
|
|
}
|
|
}
|
|
}
|
|
if (!completition && !(fh->fh_flags & FH_IS_PIPE)) {
|
|
/* We try sharing and mmaping if not a pipe */
|
|
int result=0;
|
|
fh->st_dev=stbuff->st_dev;
|
|
fh->st_ino=stbuff->st_ino;
|
|
/* changed by: Ingmar Thiemann <ingmar@gefas.com> */
|
|
result = share_file(stbuff->st_dev, stbuff->st_ino, access&0xff, 1);
|
|
|
|
if (result==-1) {
|
|
XDPRINTF((2, 0, "open share failed,fn='%s', access=0x%x, creatmode=0x%x, dowrite=%d",
|
|
fh->fname, access, creatmode, dowrite));
|
|
close(fh->fd);
|
|
fh->fd = -1;
|
|
completition = -0x80;
|
|
/* 0.99.pl0 changed -0xfe -> -0x80 */
|
|
}
|
|
|
|
if (use_mmap && fh->fd > -1 && !dowrite) {
|
|
fh->size_mmap = fh->offd=lseek(fh->fd, 0L, SEEK_END);
|
|
if (fh->size_mmap > 0) {
|
|
fh->p_mmap = mmap(NULL,
|
|
fh->size_mmap,
|
|
PROT_READ,
|
|
MAP_SHARED,
|
|
fh->fd, 0);
|
|
if (fh->p_mmap == (uint8*) -1) {
|
|
fh->p_mmap = NULL;
|
|
fh->size_mmap=0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!completition) {
|
|
fh->access = access;
|
|
if (fh->fd != -1) {
|
|
fh->inuse++;
|
|
if (!dowrite)
|
|
fh->fh_flags |= FH_OPENED_RO;
|
|
if (voloptions & VOL_OPTION_READONLY)
|
|
fh->fh_flags |= FH_IS_READONLY;
|
|
if (creatmode & 4)
|
|
fh->fh_flags |= FH_DO_NOT_REUSE;
|
|
}
|
|
} else {
|
|
XDPRINTF((5,0,"OPEN FILE not OK (-0x%x), fh->name:%s: fhandle=%d",
|
|
-completition, fh->fname, fhandle));
|
|
free_file_handle(fhandle);
|
|
fhandle=completition;
|
|
}
|
|
if (completition==-0x9c)
|
|
errorp(0, "nwfile.c", "LINE=%d, unixname='%s'", __LINE__, unixname);
|
|
} else fhandle=-0x81; /* no more File Handles */
|
|
} else fhandle=completition;
|
|
|
|
MDEBUG(D_FH_OPEN, {
|
|
char fname[200];
|
|
if (!fd_2_fname(fhandle, fname, sizeof(fname))){
|
|
FILE_HANDLE *fh=fd_2_fh(fhandle);
|
|
xdprintf(1,0,"Open/creat fd=%3d, task=%d, fn=`%s`, openmode=%s, access=0x%x, no reuse=%d",
|
|
fhandle, task, fname, (fh && (fh->fh_flags &FH_OPENED_RO)) ? "RO" : "RW",
|
|
access, fh->fh_flags & FH_DO_NOT_REUSE ? 1 :0 );
|
|
}
|
|
})
|
|
|
|
return(fhandle);
|
|
}
|
|
|
|
int nw_set_fdate_time(uint32 fhandle, uint8 *datum, uint8 *zeit)
|
|
{
|
|
if (fhandle > HOFFS && (--fhandle < count_fhandles) ) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle]);
|
|
if (fh->fd == -3 || (fh->fh_flags & FH_IS_PIPE)) return(0);
|
|
if (!(fh->fh_flags & FH_IS_READONLY)) {
|
|
fh->tmodi = nw_2_un_time(datum, zeit);
|
|
if (fh->fd == -1) { /* already closed */
|
|
#if 0
|
|
/* don't know whether we should do it in this way */
|
|
struct utimbuf ut;
|
|
if (!*(fh->fname))
|
|
return(-0x88); /* wrong filehandle */
|
|
ut.actime = ut.modtime = fh->tmodi;
|
|
utime(fh->fname, &ut);
|
|
#else
|
|
return(-0x88); /* wrong filehandle */
|
|
#endif
|
|
}
|
|
return(0);
|
|
} else return(-0x8c); /* no modify privileges */
|
|
}
|
|
return(-0x88); /* wrong filehandle */
|
|
}
|
|
|
|
int nw_close_file(int fhandle, int reset_reuse, int task)
|
|
{
|
|
XDPRINTF((5, 0, "nw_close_file handle=%d, count_fhandles=%d",
|
|
fhandle, count_fhandles));
|
|
|
|
MDEBUG(D_FH_OPEN, {
|
|
char fname[200];
|
|
int r=fd_2_fname(fhandle, fname, sizeof(fname));
|
|
xdprintf(1,0,"nw_close_f fd=%3d, task=%d, fn=`%s`,r=%d, rreuse=%d",
|
|
fhandle, task, fname, r, reset_reuse);
|
|
})
|
|
|
|
if (fhandle > HOFFS && (fhandle <= count_fhandles)) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle-1]);
|
|
if (reset_reuse) fh->fh_flags &= (~FH_DO_NOT_REUSE);
|
|
else if (fh->task != task) {
|
|
/* if close file's task is wrong the file will not be closed.
|
|
* I hope this is right !?
|
|
*/
|
|
char fname[200];
|
|
fd_2_fname(fhandle, fname, sizeof(fname));
|
|
xdprintf( (task && fh->task) ? 2 : 3, 0,
|
|
"%s close_file fd=%3d, task=%d differs fh->task=%d, fn=`%s`",
|
|
(task == 0 || fh->task == 0) ? "do" : "not",
|
|
fhandle, task, fh->task, fname);
|
|
|
|
/*
|
|
* return(0); 24-May-98 , 0.99.pl9
|
|
*/
|
|
|
|
/* 21-Oct-98: I think file must be closed always,
|
|
* got problem with pserver which opens the file with task =0
|
|
* and closes it with task <> 0.
|
|
*/
|
|
|
|
/* 23-May-99: 0.99.pl16 we only close file if task = 0 or
|
|
* file open task = 0.
|
|
*/
|
|
|
|
if ( task && fh->task )
|
|
return(0);
|
|
}
|
|
|
|
if (--fh->inuse > 0) /* 03-Dec-98 */
|
|
return(0);
|
|
|
|
if (fh->fd > -1 || (fh->fd == -3 && fh->fh_flags & FH_IS_PIPE_COMMAND)) {
|
|
int result = 0;
|
|
int result2;
|
|
if (fh->fh_flags & FH_IS_PIPE_COMMAND) {
|
|
if (fh->f) {
|
|
result=ext_pclose(fh->f);
|
|
if (result > 0) result = 0;
|
|
}
|
|
fh->f = NULL;
|
|
} else {
|
|
if (use_mmap && fh->p_mmap) {
|
|
munmap(fh->p_mmap, fh->size_mmap);
|
|
fh->p_mmap = NULL;
|
|
fh->size_mmap = 0;
|
|
}
|
|
if (fh->st_ino) {
|
|
/* changed by: Ingmar Thiemann <ingmar@gefas.com> */
|
|
share_unlock_all( fh->st_dev, fh->st_ino, fh->fd );
|
|
}
|
|
result=close(fh->fd);
|
|
if (fh->st_ino) {
|
|
/* changed by: Ingmar Thiemann <ingmar@gefas.com> */
|
|
share_file(fh->st_dev, fh->st_ino, fh->access&0xff, 0);
|
|
if (fh->modified) {
|
|
fh->modified=0;
|
|
#if NEW_ATTRIB_HANDLING
|
|
set_nw_archive_bit(fh->volume, fh->fname, fh->st_dev, fh->st_ino);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
fh->fd = -1;
|
|
if (fh->tmodi > 0L && !(fh->fh_flags & FH_IS_PIPE)
|
|
&& !(fh->fh_flags & FH_IS_READONLY)) {
|
|
struct utimbuf ut;
|
|
ut.actime = ut.modtime = fh->tmodi;
|
|
seteuid(0);
|
|
utime(fh->fname, &ut);
|
|
reseteuid();
|
|
fh->tmodi = 0L;
|
|
}
|
|
#ifdef TEST_FNAME
|
|
if (fhandle == test_handle) {
|
|
test_handle = -1;
|
|
nw_debug = -99;
|
|
}
|
|
#endif
|
|
result2=free_file_handle(fhandle);
|
|
return((result == -1) ? -0xff : result2);
|
|
} else return(free_file_handle(fhandle));
|
|
}
|
|
return(-0x88); /* wrong filehandle */
|
|
}
|
|
|
|
|
|
int nw_commit_file(int fhandle)
|
|
{
|
|
MDEBUG(D_FH_FLUSH, {
|
|
char fname[200];
|
|
int r=fd_2_fname(fhandle, fname, sizeof(fname));
|
|
xdprintf(1,0,"nw_commit_file: fd=%d, fn=`%s`,r=%d", fhandle, fname, r);
|
|
})
|
|
if (fhandle > HOFFS && (fhandle <= count_fhandles)) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle-1]);
|
|
if (fh->fd > -1 || (fh->fd == -3 && fh->fh_flags & FH_IS_PIPE_COMMAND)) {
|
|
if (!(fh->fh_flags & FH_IS_READONLY)) {
|
|
int result=0;
|
|
if (!(fh->fh_flags & FH_IS_PIPE) && fh->fd > -1) {
|
|
#if 0
|
|
/* 0.99.pl0
|
|
* this is not allowed because lockings will be removed
|
|
* hint from: Przemyslaw Czerpak
|
|
*/
|
|
int fd=dup(fh->fd);
|
|
if (fd > -1) {
|
|
if (!close(fh->fd)) {
|
|
if (fh->tmodi > 0L) {
|
|
struct utimbuf ut;
|
|
ut.actime = ut.modtime = fh->tmodi;
|
|
seteuid(0);
|
|
utime(fh->fname, &ut);
|
|
reseteuid();
|
|
fh->tmodi = 0L;
|
|
}
|
|
fh->fd=dup2(fd, fh->fd);
|
|
} else
|
|
result=-0x8c;
|
|
close(fd);
|
|
}
|
|
#else
|
|
if (fh->tmodi > 0L) {
|
|
struct utimbuf ut;
|
|
ut.actime = ut.modtime = fh->tmodi;
|
|
seteuid(0);
|
|
utime(fh->fname, &ut);
|
|
reseteuid();
|
|
}
|
|
#endif
|
|
}
|
|
return(result);
|
|
} else
|
|
return(-0x8c);
|
|
}
|
|
}
|
|
return(-0x88); /* wrong filehandle */
|
|
}
|
|
|
|
|
|
uint8 *file_get_unix_name(int fhandle)
|
|
{
|
|
if (fhandle > HOFFS && (--fhandle < count_fhandles)) {
|
|
return((uint8*)file_handles[fhandle].fname);
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
static void open_pipe_command(FILE_HANDLE *fh, int dowrite)
|
|
{
|
|
if (NULL == fh->f) {
|
|
char pipecommand[512];
|
|
sprintf(pipecommand, "%s %s %d %d",
|
|
fh->fname,
|
|
dowrite ? "WRITE" : "READ",
|
|
act_connection, act_pid);
|
|
fh->f = ext_popen(pipecommand, geteuid(), getegid(), 0);
|
|
}
|
|
fh->fd = (fh->f) ? fh->f->fds[dowrite ? 0 : 1] : -3;
|
|
}
|
|
|
|
int nw_read_file(int fhandle, uint8 *data, int size, uint32 offset)
|
|
{
|
|
if (fhandle > HOFFS && (--fhandle < count_fhandles)) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle]);
|
|
if (fh->fh_flags & FH_IS_PIPE_COMMAND)
|
|
open_pipe_command(fh, 0);
|
|
if (fh->fd > -1) {
|
|
if (fh->fh_flags & FH_IS_PIPE) { /* PIPE */
|
|
int readsize=size;
|
|
#if 1
|
|
fd_set fdin;
|
|
struct timeval t;
|
|
FD_ZERO(&fdin);
|
|
FD_SET(fh->fd, &fdin);
|
|
/* t.tv_sec = 5; */ /* should be enough */
|
|
t.tv_sec = 30; /* sometimes more time needed */
|
|
t.tv_usec = 0;
|
|
size = select(fh->fd+1, &fdin, NULL, NULL, &t);
|
|
if (size > 0)
|
|
size = read(fh->fd, data, readsize);
|
|
if (size == -1) size=0;
|
|
#elif 1
|
|
if (-1 == (size = read(fh->fd, data, readsize)) ) {
|
|
int k=2;
|
|
do {
|
|
sleep(1);
|
|
} while(k-- && -1 == (size = read(fh->fd, data, readsize)));
|
|
if (size == -1) size=0;
|
|
}
|
|
#else
|
|
int offset=0;
|
|
int k=2;
|
|
while ((size = read(fh->fd, data+offset, readsize)) < readsize) {
|
|
if (size>0) {
|
|
readsize-=size;
|
|
offset+=size;
|
|
} else if (!k-- || ((!size)&&readsize)) break;
|
|
else sleep(1);
|
|
}
|
|
size=offset;
|
|
#endif
|
|
#if 1
|
|
if ((fh->fh_flags & FH_IS_PIPE_COMMAND) && !size) {
|
|
if (fh->f->flags & 1) return(-0x57);
|
|
fh->f->flags |= 1;
|
|
}
|
|
#endif
|
|
} else if (use_mmap && fh->p_mmap) {
|
|
/* added by: Ingmar Thiemann <ingmar@gefas.com>
|
|
* Netware allows no read/write on locked sections
|
|
*/
|
|
/* check for lock */
|
|
struct flock flockd;
|
|
flockd.l_type = F_RDLCK; /* if file is not locked exclusive
|
|
* we should allow read it. /lenz */
|
|
flockd.l_whence = SEEK_SET;
|
|
flockd.l_start = offset;
|
|
flockd.l_len = size;
|
|
fcntl(fh->fd, F_GETLK, &flockd);
|
|
if (flockd.l_type != F_WRLCK) {
|
|
while (1) {
|
|
if (offset < fh->size_mmap) {
|
|
if (size + offset > fh->size_mmap)
|
|
size = fh->size_mmap - offset;
|
|
memcpy(data, fh->p_mmap+offset, size);
|
|
if (got_sig_bus) {
|
|
fh->size_mmap = lseek(fh->fd, 0L, SEEK_END);
|
|
got_sig_bus = 0;
|
|
} else
|
|
break;
|
|
} else {
|
|
size=-1;
|
|
break;
|
|
}
|
|
} /* while */
|
|
} else size = -0xa2; /* I/O lock error. /lenz */
|
|
} else {
|
|
if (fh->offd != (long)offset) {
|
|
fh->offd=lseek(fh->fd, offset, SEEK_SET);
|
|
if (fh->offd < 0) {
|
|
XDPRINTF((5,0,"read-file failed in lseek"));
|
|
}
|
|
}
|
|
if (fh->offd > -1L) {
|
|
/* added by: Ingmar Thiemann <ingmar@gefas.com>
|
|
* Netware allows no read/write on locked sections
|
|
*/
|
|
/* check for lock */
|
|
struct flock flockd;
|
|
flockd.l_type = F_WRLCK;
|
|
flockd.l_whence = SEEK_SET;
|
|
flockd.l_start = offset;
|
|
flockd.l_len = size;
|
|
fcntl(fh->fd, F_GETLK, &flockd);
|
|
if (flockd.l_type == F_UNLCK) {
|
|
if ((size = read(fh->fd, data, size)) > -1) {
|
|
fh->offd+=(long)size;
|
|
} else {
|
|
XDPRINTF((5,0,"read-file failed in read"));
|
|
}
|
|
} else size = -0xa2; /* I/O lock error. /lenz */
|
|
} else size = -1;
|
|
}
|
|
if (size == -1) size=0;
|
|
return(size);
|
|
} else if (fh->fd == -3) return(0);
|
|
}
|
|
return(-0x88); /* wrong filehandle */
|
|
}
|
|
|
|
int nw_seek_file(int fhandle, int modus)
|
|
{
|
|
if (fhandle > HOFFS && (--fhandle < count_fhandles)) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle]);
|
|
if (fh->fd > -1) {
|
|
if (fh->fh_flags & FH_IS_PIPE) { /* PIPE */
|
|
return(0x7fff0000 | (rand() & 0xffff) );
|
|
} else {
|
|
int size=-0xfb;
|
|
if (!modus) {
|
|
if ( (size=fh->offd=lseek(fh->fd, 0L, SEEK_END)) < 0L)
|
|
size = -1;
|
|
}
|
|
return(size);
|
|
}
|
|
} else if (fh->fd == -3) return(0x7fff0000 | (rand() & 0xffff) );
|
|
/* PIPE COMMAND */
|
|
}
|
|
return(-0x88); /* wrong filehandle */
|
|
}
|
|
|
|
|
|
int nw_write_file(int fhandle, uint8 *data, int size, uint32 offset)
|
|
{
|
|
if (fhandle > HOFFS && (--fhandle < count_fhandles)) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle]);
|
|
if (fh->fh_flags & FH_IS_PIPE_COMMAND)
|
|
open_pipe_command(fh, 1);
|
|
if (fh->fd > -1) {
|
|
if (fh->fh_flags & FH_OPENED_RO) return(-0x94);
|
|
if (fh->fh_flags & FH_IS_PIPE) { /* PIPE */
|
|
return(size ? write(fh->fd, data, size) : 0);
|
|
} else {
|
|
if (fh->offd != (long)offset)
|
|
fh->offd = lseek(fh->fd, offset, SEEK_SET);
|
|
if (size) {
|
|
if (fh->offd > -1L) {
|
|
/* added by: Ingmar Thiemann <ingmar@gefas.com>
|
|
* Netware allows no read/write on locked sections
|
|
*/
|
|
/* check for lock */
|
|
struct flock flockd;
|
|
flockd.l_type = F_WRLCK;
|
|
flockd.l_whence = SEEK_SET;
|
|
flockd.l_start = offset;
|
|
flockd.l_len = size;
|
|
fcntl(fh->fd, F_GETLK, &flockd);
|
|
if (flockd.l_type == F_UNLCK) {
|
|
/*if (share_lock( fh->st_dev, fh->st_ino, fh->fd, 2, offset, size ) == 0) {*/
|
|
|
|
size = write(fh->fd, data, size);
|
|
fh->offd+=(long)size;
|
|
if (!fh->modified)
|
|
fh->modified++;
|
|
} else size = -0xa2; /* I/O lock error. /lenz */
|
|
} else size = -1;
|
|
return(size);
|
|
} else { /* truncate FILE */
|
|
int result = unx_ftruncate(fh->fd, offset);
|
|
XDPRINTF((5,0,"File %s is truncated, result=%d", fh->fname, result));
|
|
fh->offd = -1L;
|
|
if (!fh->modified)
|
|
fh->modified++;
|
|
return(result);
|
|
}
|
|
}
|
|
} else if (fh->fd == -3) return(0);
|
|
}
|
|
return(- 0x88); /* wrong filehandle */
|
|
}
|
|
|
|
int nw_server_copy(int qfhandle, uint32 qoffset,
|
|
int zfhandle, uint32 zoffset,
|
|
uint32 size)
|
|
{
|
|
if (qfhandle > HOFFS && (--qfhandle < count_fhandles)
|
|
&& zfhandle > HOFFS && (--zfhandle < count_fhandles) ) {
|
|
FILE_HANDLE *fhq=&(file_handles[qfhandle]);
|
|
FILE_HANDLE *fhz=&(file_handles[zfhandle]);
|
|
int retsize = -1;
|
|
if (fhq->fd > -1 && fhz->fd > -1) {
|
|
char buff[4096];
|
|
int wsize;
|
|
if (fhz->fh_flags & FH_OPENED_RO) return(-0x94);
|
|
if (lseek(fhq->fd, qoffset, SEEK_SET) > -1L &&
|
|
lseek(fhz->fd, zoffset, SEEK_SET) > -1L) {
|
|
retsize = 0;
|
|
if (size && !fhz->modified)
|
|
fhz->modified++;
|
|
while (size) {
|
|
int xsize = read(fhq->fd, buff, min(size, (uint32)sizeof(buff)));
|
|
if (xsize > 0){
|
|
if ((wsize =write(fhz->fd, buff, xsize)) != xsize) {
|
|
retsize = -0x1; /* out of Disk Space */
|
|
break;
|
|
} else {
|
|
size -= (uint32)xsize;
|
|
retsize += wsize;
|
|
}
|
|
} else {
|
|
if (xsize < 0) retsize=-0x93; /* no read privilegs */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
fhq->offd = -1L;
|
|
fhz->offd = -1L;
|
|
return(retsize);
|
|
}
|
|
}
|
|
return(-0x88); /* wrong filehandle */
|
|
}
|
|
|
|
int nw_log_physical_record(int fhandle, uint32 offset,
|
|
uint32 size, uint16 timeout, int lock_flag)
|
|
{
|
|
int result=-0x88; /* wrong filehandle */
|
|
if (fhandle > HOFFS && (fhandle <= count_fhandles)) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle-1]);
|
|
if (fh->fd > -1) {
|
|
if (fh->fh_flags & FH_IS_PIPE) {
|
|
result=0;
|
|
goto leave;
|
|
}
|
|
/* Changed by: Ingmar Thiemann <ingmar@gefas.com>
|
|
* locks must be exclusiv, so it must always be F_WRLCK
|
|
*
|
|
* Hint from:Morio Taneda <morio@sozio.geist-soz.uni-karlsruhe.de>
|
|
* dBase needs it
|
|
* 03-Dec-96
|
|
*
|
|
* flockd.l_start = (offset & 0x7fffffff);
|
|
*
|
|
* Changed by: Ingmar Thiemann <ingmar@gefas.com> to 0x0fffffff
|
|
* Changed by mst: 05-Oct-99 to 0x7fffffff again.
|
|
*
|
|
* if (size == MAX_U32)
|
|
* size = 0;
|
|
* This is only a guess, but a size of 0xffffffff means to lock
|
|
* the rest of the file, starting from the offset, to do this with
|
|
* linux, a size of 0 has to be passed to the fcntl function.
|
|
* ( Peter Gerhard )
|
|
*/
|
|
result = share_lock( fh->st_dev,
|
|
fh->st_ino,
|
|
fh->fd,
|
|
(lock_flag < 0)
|
|
? 0 /* remove lock */
|
|
: 1, /* add lock */
|
|
|
|
(lock_flag < 0)
|
|
? lock_flag
|
|
: ( (fh->fh_flags & FH_IS_READONLY)
|
|
? 3 /* no exclusiv lock */
|
|
: lock_flag ),
|
|
|
|
offset & 0x7fffffff,
|
|
|
|
(size==MAX_U32)
|
|
? 0
|
|
: size & 0x7fffffff,
|
|
|
|
timeout);
|
|
|
|
XDPRINTF((4, 0, "nw_log_phy_rec:pid=%d uid=%d flag=%2d, result=%d, fh=%d, offset=%d, size=%d, timeout=%d",
|
|
getpid(), geteuid(), lock_flag, result, fhandle, offset, size, timeout));
|
|
|
|
} else if (fh->fd == -3) result=0;
|
|
}
|
|
leave:
|
|
MDEBUG(D_FH_LOCK, {
|
|
char fname[200];
|
|
(void)fd_2_fname(fhandle, fname, sizeof(fname));
|
|
xdprintf(1,0,"nw_log_phy_rec:flag=%2d, fd=%d, fn=`%s`,r=0x%x, offs=%d, len=%d",
|
|
lock_flag, fhandle, fname, -result, offset, size);
|
|
})
|
|
|
|
return(result);
|
|
}
|
|
|
|
int fd_2_fname(int fhandle, char *buf, int bufsize)
|
|
{
|
|
if (fhandle > HOFFS && (--fhandle < count_fhandles)) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle]);
|
|
strmaxcpy(buf, fh->fname, bufsize-1);
|
|
return(0);
|
|
}
|
|
if (bufsize)
|
|
*buf='\0';
|
|
return(-0x88);
|
|
}
|
|
|
|
FILE_HANDLE *fd_2_fh(int fhandle)
|
|
{
|
|
if (fhandle > HOFFS && (--fhandle < count_fhandles))
|
|
return(&(file_handles[fhandle]));
|
|
return(NULL);
|
|
}
|
|
|
|
int get_nwfd(int fhandle)
|
|
{
|
|
if (fhandle > HOFFS && (--fhandle < count_fhandles)) {
|
|
FILE_HANDLE *fh=&(file_handles[fhandle]);
|
|
return(fh ? fh->fd : -1);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
void log_file_module(FILE *f)
|
|
{
|
|
if (f) {
|
|
int k=HOFFS-1;
|
|
int handles=0;
|
|
while (++k < count_fhandles) {
|
|
FILE_HANDLE *fh=&(file_handles[k]);
|
|
if (fh && fh->fd != -1) {
|
|
fprintf(f,"%4d %2d %d %4d 0x%04x 0x%04x %2d %04d '%s'\n",
|
|
k+1, fh->inuse, fh->modified, fh->task,
|
|
fh->fh_flags, fh->access, fh->volume,
|
|
fh->fd, fh->fname);
|
|
dump_locks(fh->st_dev, fh->st_ino, fh->fd, f);
|
|
handles++;
|
|
}
|
|
}
|
|
fprintf(f, "count-open-files:%4d\n" , handles);
|
|
fflush(f);
|
|
}
|
|
}
|
|
|
|
int nw_get_count_open_files(uint8 *handlebuf, uint32 offset)
|
|
/* returns max. 100 handles */
|
|
{
|
|
int k = max(HOFFS-1, offset-1);
|
|
int handles = 0;
|
|
while (handles < 100 && ++k < count_fhandles) {
|
|
FILE_HANDLE *fh=&(file_handles[k]);
|
|
if (fh && fh->fd != -1) {
|
|
handles++;
|
|
if (handlebuf) {
|
|
U32_TO_BE32(k+1, handlebuf);
|
|
handlebuf+=4;
|
|
}
|
|
}
|
|
}
|
|
return(handles);
|
|
}
|
|
|
|
/* quick and dirty hack for 0.99.pl17, 25-May-99 */
|
|
|
|
typedef struct sLOCK_AREA {
|
|
int locks; /* count locks */
|
|
int exclusive; /* exclusive lock ? */
|
|
uint32 offset;
|
|
struct sLOCK_AREA *next;
|
|
} LOCK_AREA;
|
|
|
|
typedef struct sLOCK_FILE {
|
|
char *fn;
|
|
int fd;
|
|
LOCK_AREA *lock_area;
|
|
struct sLOCK_FILE *next;
|
|
} LOCK_FILE;
|
|
|
|
static LOCK_FILE *root_lf=NULL;
|
|
static LOCK_FILE *last_lf=NULL;
|
|
static LOCK_AREA *last_la=NULL;
|
|
|
|
static LOCK_AREA *find_lockarea(LOCK_FILE *lf, uint32 offset)
|
|
{
|
|
LOCK_AREA *la=lf->lock_area;
|
|
last_la = NULL;
|
|
while (la && la->offset != offset) {
|
|
last_la=la;
|
|
la=la->next;
|
|
}
|
|
return(la);
|
|
}
|
|
|
|
static LOCK_FILE *find_lockfile(char *fn)
|
|
{
|
|
LOCK_FILE *lf=root_lf;
|
|
last_lf = NULL;
|
|
while (lf && strcmp(lf->fn, fn)) {
|
|
last_lf=lf;
|
|
lf=lf->next;
|
|
}
|
|
return(lf);
|
|
}
|
|
|
|
int nw_log_logical_record(int lock_flag,
|
|
int timeout,
|
|
int len,
|
|
uint8 *data)
|
|
/*
|
|
* lock_flag
|
|
* -1 = remove lock
|
|
* -2 = remove lock + log
|
|
* 0 = log
|
|
* 1 = lock exclusive
|
|
* 3 = shared lock
|
|
*/
|
|
{
|
|
static char *path_share_lock_files=NULL;
|
|
uint8 fn[256];
|
|
uint8 fullpath[400];
|
|
uint32 offset;
|
|
LOCK_FILE *lf = NULL;
|
|
LOCK_AREA *la = NULL;
|
|
struct flock flockd;
|
|
flockd.l_whence = SEEK_SET;
|
|
flockd.l_len = 1;
|
|
|
|
if (lock_flag != -1) {
|
|
if (share_set_logrec_add_rm(lock_flag, timeout, len, data))
|
|
return (-0xff);
|
|
}
|
|
if (!lock_flag)
|
|
return(0); /* log only */
|
|
|
|
if (lock_flag == -1 || lock_flag == -2)
|
|
flockd.l_type = F_UNLCK;
|
|
else if (lock_flag == 1)
|
|
flockd.l_type = F_WRLCK; /* exclusive */
|
|
else if (lock_flag == 3)
|
|
flockd.l_type = F_RDLCK; /* shared */
|
|
else
|
|
return(-0xfb);
|
|
|
|
if (len < 4) {
|
|
uint8 buf[4];
|
|
memcpy(buf, data, len);
|
|
memset(buf+len, 0, 4 -len);
|
|
len = 0;
|
|
offset=GET_BE32(buf);
|
|
} else {
|
|
offset=GET_BE32(data);
|
|
len -= 4;
|
|
}
|
|
|
|
flockd.l_start = offset;
|
|
|
|
if (len > 0) {
|
|
int i=-1;
|
|
if (len > sizeof(fn))
|
|
len = sizeof(fn-1);
|
|
memcpy(fn, data+4, len);
|
|
while (++i < len) {
|
|
if (fn[i]=='/') {
|
|
fn[i] = '-';
|
|
if (len < sizeof(fn-1))
|
|
fn[len++] = '_';
|
|
} else if (fn[i] == '\0') {
|
|
fn[i] = '_';
|
|
if (len < sizeof(fn-1))
|
|
fn[len++] = '_';
|
|
}
|
|
}
|
|
fn[len]='\0';
|
|
} else {
|
|
strcpy(fn, "GENERIC_LOCKFILE");
|
|
}
|
|
|
|
if (NULL==path_share_lock_files) {
|
|
char buff[300];
|
|
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");
|
|
seteuid(0);
|
|
unx_xmkdir(path_share_lock_files, 0755);
|
|
reseteuid();
|
|
}
|
|
|
|
sprintf(fullpath,"%s/%s.k", path_share_lock_files, fn);
|
|
|
|
lf = find_lockfile(fn);
|
|
|
|
if (!lf) {
|
|
int fd;
|
|
if (lock_flag < 0) /* unlock */
|
|
return(-0xff);
|
|
|
|
seteuid(0);
|
|
fd = open(fullpath, O_RDWR|O_CREAT, 0600);
|
|
reseteuid();
|
|
|
|
if (fcntl(fd, F_SETLK, &flockd))
|
|
/* already locked by other process */
|
|
return(-0xfe);
|
|
|
|
lf=(LOCK_FILE*)xcmalloc(sizeof(LOCK_FILE));
|
|
lf->fd = fd;
|
|
new_str(lf->fn, fn);
|
|
if (last_lf)
|
|
last_lf->next = lf;
|
|
else
|
|
root_lf = lf;
|
|
}
|
|
|
|
la = find_lockarea(lf, offset);
|
|
|
|
if (!la) {
|
|
if (lock_flag < 0) /* unlock */
|
|
return (-0xff);
|
|
|
|
if (fcntl(lf->fd, F_SETLK, &flockd))
|
|
/* already locked by other process */
|
|
return(-0xfe);
|
|
|
|
la = (LOCK_AREA*)xcmalloc(sizeof(LOCK_AREA));
|
|
la->offset=offset;
|
|
if (last_la)
|
|
last_la->next = la;
|
|
else
|
|
lf->lock_area = la;
|
|
la->locks++;
|
|
if (lock_flag == 1)
|
|
la->exclusive++;
|
|
} else if (lock_flag > -1) {
|
|
if (la->exclusive || lock_flag == 1)
|
|
/* already locked */
|
|
return(-0xfe);
|
|
la->locks++;
|
|
}
|
|
|
|
if (lock_flag < 0) { /* remove lock */
|
|
if (--la->locks > 0)
|
|
return(0);
|
|
(void) fcntl(lf->fd, F_SETLK, &flockd);
|
|
if (last_la)
|
|
last_la->next = la->next;
|
|
else
|
|
lf->lock_area = la->next;
|
|
xfree(la);
|
|
|
|
if (!lf->lock_area) {
|
|
/* no more locks by this file */
|
|
close(lf->fd);
|
|
|
|
#if 0 /* TODO remove file if it is not opened/locked by other process */
|
|
seteuid(0);
|
|
unlink(fullpath);
|
|
reseteuid();
|
|
#endif
|
|
|
|
xfree(lf->fn);
|
|
if (last_lf)
|
|
last_lf->next = lf->next;
|
|
else
|
|
root_lf = lf->next;
|
|
xfree(lf);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|