diff options
Diffstat (limited to 'source/locking/locking.c')
-rw-r--r-- | source/locking/locking.c | 382 |
1 files changed, 379 insertions, 3 deletions
diff --git a/source/locking/locking.c b/source/locking/locking.c index 6ff3ab5d125..04f4a4b1975 100644 --- a/source/locking/locking.c +++ b/source/locking/locking.c @@ -2,7 +2,7 @@ Unix SMB/Netbios implementation. Version 1.9. Locking functions - Copyright (C) Andrew Tridgell 1992-1995 + Copyright (C) Andrew Tridgell 1992-1996 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 @@ -17,10 +17,14 @@ 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. + + Revision History: + + 12 aug 96: Erik.Devriendt@te6.siemens.be + added support for shared memory implementation of share mode locking */ #include "includes.h" -#include "loadparm.h" extern int DEBUGLEVEL; extern connection_struct Connections[]; extern files_struct Files[]; @@ -29,6 +33,137 @@ pstring share_del_pending=""; /**************************************************************************** +routine to do file locking +****************************************************************************/ +BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type) +{ +#if HAVE_FCNTL_LOCK + struct flock lock; + int ret; + +#if 1 + uint32 mask = 0xC0000000; + + /* make sure the count is reasonable, we might kill the lockd otherwise */ + count &= ~mask; + + /* the offset is often strange - remove 2 of its bits if either of + the top two bits are set. Shift the top ones by two bits. This + still allows OLE2 apps to operate, but should stop lockd from + dieing */ + if ((offset & mask) != 0) + offset = (offset & ~mask) | ((offset & mask) >> 2); +#else + uint32 mask = ((unsigned)1<<31); + + /* interpret negative counts as large numbers */ + if (count < 0) + count &= ~mask; + + /* no negative offsets */ + offset &= ~mask; + + /* count + offset must be in range */ + while ((offset < 0 || (offset + count < 0)) && mask) + { + offset &= ~mask; + mask = mask >> 1; + } +#endif + + + DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type)); + + lock.l_type = type; + lock.l_whence = SEEK_SET; + lock.l_start = (int)offset; + lock.l_len = (int)count; + lock.l_pid = 0; + + errno = 0; + + ret = fcntl(fd,op,&lock); + + if (errno != 0) + DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno))); + + /* a lock query */ + if (op == F_GETLK) + { + if ((ret != -1) && + (lock.l_type != F_UNLCK) && + (lock.l_pid != 0) && + (lock.l_pid != getpid())) + { + DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid)); + return(True); + } + + /* it must be not locked or locked by me */ + return(False); + } + + /* a lock set or unset */ + if (ret == -1) + { + DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n", + offset,count,op,type,strerror(errno))); + + /* perhaps it doesn't support this sort of locking?? */ + if (errno == EINVAL) + { + DEBUG(3,("locking not supported? returning True\n")); + return(True); + } + + return(False); + } + + /* everything went OK */ + DEBUG(5,("Lock call successful\n")); + + return(True); +#else + return(False); +#endif +} + +/******************************************************************* +lock a file - returning a open file descriptor or -1 on failure +The timeout is in seconds. 0 means no timeout +********************************************************************/ +int file_lock(char *name,int timeout) +{ + int fd = open(name,O_RDWR|O_CREAT,0666); + time_t t=0; + if (fd < 0) return(-1); + +#if HAVE_FCNTL_LOCK + if (timeout) t = time(NULL); + while (!timeout || (time(NULL)-t < timeout)) { + if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd); + msleep(LOCK_RETRY_TIMEOUT); + } + return(-1); +#else + return(fd); +#endif +} + +/******************************************************************* +unlock a file locked by file_lock +********************************************************************/ +void file_unlock(int fd) +{ + if (fd<0) return; +#if HAVE_FCNTL_LOCK + fcntl_lock(fd,F_SETLK,0,1,F_UNLCK); +#endif + close(fd); +} + + +/**************************************************************************** utility function called to see if a file region is locked ****************************************************************************/ BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset) @@ -96,6 +231,36 @@ BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 * return True; /* Did unlock */ } +#if FAST_SHARE_MODES +/******************************************************************* + initialize the shared memory for share_mode management + ******************************************************************/ +BOOL start_share_mode_mgmt(void) +{ + pstring shmem_file_name; + + strcpy(shmem_file_name,lp_lockdir()); + if (!directory_exist(shmem_file_name,NULL)) + mkdir(shmem_file_name,0755); + trim_string(shmem_file_name,"","/"); + if (!*shmem_file_name) return(False); + strcat(shmem_file_name, "/SHARE_MEM_FILE"); + return shm_open(shmem_file_name, SHMEM_SIZE); +} + + +/******************************************************************* + deinitialize the shared memory for share_mode management + ******************************************************************/ +BOOL stop_share_mode_mgmt(void) +{ + return shm_close(); +} + +#else + +/* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */ + /******************************************************************* name a share file ******************************************************************/ @@ -121,6 +286,7 @@ static BOOL share_name_fnum(int fnum,char *name) return(share_name(Files[fnum].cnum,&st,name)); } +#endif /******************************************************************* get the share mode of a file using the fnum @@ -148,6 +314,78 @@ get the share mode of a file ********************************************************************/ int get_share_mode(int cnum,struct stat *sbuf,int *pid) { +#if FAST_SHARE_MODES + share_mode_record *scanner_p; + share_mode_record *prev_p; + int ret; + BOOL found = False; + + *pid = 0; + + if(!shm_lock()) return (0); + + scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off()); + prev_p = scanner_p; + while(scanner_p) + { + if( (scanner_p->st_dev == sbuf->st_dev) && (scanner_p->st_ino == sbuf->st_ino) ) + { + found = True; + break; + } + else + { + prev_p = scanner_p ; + scanner_p = (share_mode_record *)shm_offset2addr(scanner_p->next_offset); + } + } + + if(!found) + { + shm_unlock(); + return (0); + } + + if(scanner_p->locking_version != LOCKING_VERSION) + { + DEBUG(2,("Deleting old share mode record due to old locking version %d",scanner_p->locking_version)); + if(prev_p == scanner_p) + shm_set_userdef_off(scanner_p->next_offset); + else + prev_p->next_offset = scanner_p->next_offset; + shm_free(shm_addr2offset(scanner_p)); + *pid = 0; + + shm_unlock(); + return (0); + } + + *pid = scanner_p->pid; + ret = scanner_p->share_mode; + + if (*pid && !process_exists(*pid)) + { + ret = 0; + *pid = 0; + } + + if (! *pid) + { + if(prev_p == scanner_p) + shm_set_userdef_off(scanner_p->next_offset); + else + prev_p->next_offset = scanner_p->next_offset; + shm_free(shm_addr2offset(scanner_p)); + } + + if (*pid) + DEBUG(5,("Read share mode record mode 0x%X pid=%d\n",ret,*pid)); + + if(!shm_unlock()) return (0); + + return(ret); + +#else pstring fname; int fd2; char buf[16]; @@ -189,6 +427,7 @@ int get_share_mode(int cnum,struct stat *sbuf,int *pid) DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid)); return(ret); +#endif } @@ -197,6 +436,67 @@ del the share mode of a file, if we set it last ********************************************************************/ void del_share_mode(int fnum) { +#if FAST_SHARE_MODES + struct stat st; + time_t t=0; + int pid=0; + BOOL del = False; + share_mode_record *scanner_p; + share_mode_record *prev_p; + BOOL found = False; + + + + if (fstat(Files[fnum].fd,&st) != 0) return; + + if (!shm_lock()) return; + + scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off()); + prev_p = scanner_p; + while(scanner_p) + { + if( (scanner_p->st_dev == st.st_dev) && (scanner_p->st_ino == st.st_ino) ) + { + found = True; + break; + } + else + { + prev_p = scanner_p ; + scanner_p = (share_mode_record *)shm_offset2addr(scanner_p->next_offset); + } + } + + if(!found) + { + shm_unlock(); + return; + } + + t = scanner_p->time; + pid = scanner_p->pid; + + if( (scanner_p->locking_version != LOCKING_VERSION) || !pid || !process_exists(pid)) + del = True; + + if (!del && t == Files[fnum].open_time && pid==(int)getpid()) + del = True; + + if (del) + { + DEBUG(2,("Deleting share mode record\n")); + if(prev_p == scanner_p) + shm_set_userdef_off(scanner_p->next_offset); + else + prev_p->next_offset = scanner_p->next_offset; + shm_free(shm_addr2offset(scanner_p)); + + } + + shm_unlock(); + return; + +#else pstring fname; int fd2; char buf[16]; @@ -233,6 +533,7 @@ void del_share_mode(int fnum) strcpy(share_del_pending,fname); } } +#endif } @@ -241,6 +542,36 @@ set the share mode of a file ********************************************************************/ BOOL set_share_mode(int fnum,int mode) { +#if FAST_SHARE_MODES + int pid = (int)getpid(); + struct stat st; + shm_offset_t new_off; + share_mode_record *new_p; + + + if (fstat(Files[fnum].fd,&st) != 0) return(False); + + if (!shm_lock()) return (False); + new_off = shm_alloc(sizeof(share_mode_record) + strlen(Files[fnum].name) ); + if (new_off == NULL_OFFSET) return (False); + new_p = (share_mode_record *)shm_offset2addr(new_off); + new_p->locking_version = LOCKING_VERSION; + new_p->share_mode = mode; + new_p->time = Files[fnum].open_time; + new_p->pid = pid; + new_p->st_dev = st.st_dev; + new_p->st_ino = st.st_ino; + strcpy(new_p->file_name,Files[fnum].name); + new_p->next_offset = shm_get_userdef_off(); + shm_set_userdef_off(new_off); + + + DEBUG(3,("Created share record for %s with mode 0x%X pid=%d\n",Files[fnum].name,mode,pid)); + + if (!shm_unlock()) return (False); + return(True); + +#else pstring fname; int fd2; char buf[16]; @@ -276,14 +607,58 @@ BOOL set_share_mode(int fnum,int mode) DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid)); return(True); +#endif } /******************************************************************* cleanup any stale share files ********************************************************************/ -void clean_share_files(void) +void clean_share_modes(void) { +#ifdef USE_SHMEM + share_mode_record *scanner_p; + share_mode_record *prev_p; + int pid; + + if (!shm_lock()) return; + + scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off()); + prev_p = scanner_p; + while(scanner_p) + { + pid = scanner_p->pid; + + if( (scanner_p->locking_version != LOCKING_VERSION) || !process_exists(pid)) + { + DEBUG(2,("Deleting stale share mode record")); + if(prev_p == scanner_p) + { + shm_set_userdef_off(scanner_p->next_offset); + shm_free(shm_addr2offset(scanner_p)); + scanner_p = (share_mode_record *)shm_offset2addr(shm_get_userdef_off()); + prev_p = scanner_p; + } + else + { + prev_p->next_offset = scanner_p->next_offset; + shm_free(shm_addr2offset(scanner_p)); + scanner_p = (share_mode_record *)shm_offset2addr(prev_p->next_offset); + } + + } + else + { + prev_p = scanner_p ; + scanner_p = (share_mode_record *)shm_offset2addr(scanner_p->next_offset); + } + } + + + shm_unlock(); + return; + +#else char *lockdir = lp_lockdir(); void *dir; char *s; @@ -327,4 +702,5 @@ void clean_share_files(void) } closedir(dir); +#endif } |