/* 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 #include #include #include #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 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 */ share_unlock_all( fh->st_dev, fh->st_ino, fh->fd ); } close(fh->fd); if (fh->st_ino) { /* changed by: Ingmar Thiemann */ 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 */ 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 */ /* 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 * 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 */ 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 */ share_unlock_all( fh->st_dev, fh->st_ino, fh->fd ); } result=close(fh->fd); if (fh->st_ino) { /* changed by: Ingmar Thiemann */ 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]; snprintf(pipecommand, sizeof(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 * 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 * 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 * 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 * locks must be exclusiv, so it must always be F_WRLCK * * Hint from:Morio Taneda * dBase needs it * 03-Dec-96 * * flockd.l_start = (offset & 0x7fffffff); * * Changed by: Ingmar Thiemann 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); }