summaryrefslogtreecommitdiff
path: root/source/locking/locking.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/locking/locking.c')
-rw-r--r--source/locking/locking.c330
1 files changed, 330 insertions, 0 deletions
diff --git a/source/locking/locking.c b/source/locking/locking.c
new file mode 100644
index 00000000000..6ff3ab5d125
--- /dev/null
+++ b/source/locking/locking.c
@@ -0,0 +1,330 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ Locking functions
+ Copyright (C) Andrew Tridgell 1992-1995
+
+ 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 "includes.h"
+#include "loadparm.h"
+extern int DEBUGLEVEL;
+extern connection_struct Connections[];
+extern files_struct Files[];
+
+pstring share_del_pending="";
+
+
+/****************************************************************************
+ utility function called to see if a file region is locked
+****************************************************************************/
+BOOL is_locked(int fnum,int cnum,uint32 count,uint32 offset)
+{
+ int snum = SNUM(cnum);
+
+ if (count == 0)
+ return(False);
+
+ if (!lp_locking(snum) || !lp_strict_locking(snum))
+ return(False);
+
+ return(fcntl_lock(Files[fnum].fd,F_GETLK,offset,count,
+ (Files[fnum].can_write?F_WRLCK:F_RDLCK)));
+}
+
+
+/****************************************************************************
+ utility function called by locking requests
+****************************************************************************/
+BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
+{
+ BOOL ok = False;
+
+ if (!lp_locking(SNUM(cnum)))
+ return(True);
+
+ if (count == 0) {
+ *eclass = ERRDOS;
+ *ecode = ERRnoaccess;
+ return False;
+ }
+
+ if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
+ ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,
+ (Files[fnum].can_write?F_WRLCK:F_RDLCK));
+
+ if (!ok) {
+ *eclass = ERRDOS;
+ *ecode = ERRlock;
+ return False;
+ }
+ return True; /* Got lock */
+}
+
+
+/****************************************************************************
+ utility function called by unlocking requests
+****************************************************************************/
+BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode)
+{
+ BOOL ok = False;
+
+ if (!lp_locking(SNUM(cnum)))
+ return(True);
+
+ if (Files[fnum].can_lock && OPEN_FNUM(fnum) && (Files[fnum].cnum == cnum))
+ ok = fcntl_lock(Files[fnum].fd,F_SETLK,offset,count,F_UNLCK);
+
+ if (!ok) {
+ *eclass = ERRDOS;
+ *ecode = ERRlock;
+ return False;
+ }
+ return True; /* Did unlock */
+}
+
+/*******************************************************************
+ name a share file
+ ******************************************************************/
+static BOOL share_name(int cnum,struct stat *st,char *name)
+{
+ strcpy(name,lp_lockdir());
+ standard_sub(cnum,name);
+ trim_string(name,"","/");
+ if (!*name) return(False);
+ name += strlen(name);
+
+ sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
+ return(True);
+}
+
+/*******************************************************************
+ use the fnum to get the share file name
+ ******************************************************************/
+static BOOL share_name_fnum(int fnum,char *name)
+{
+ struct stat st;
+ if (fstat(Files[fnum].fd,&st) != 0) return(False);
+ return(share_name(Files[fnum].cnum,&st,name));
+}
+
+
+/*******************************************************************
+ get the share mode of a file using the fnum
+ ******************************************************************/
+int get_share_mode_by_fnum(int cnum,int fnum,int *pid)
+{
+ struct stat sbuf;
+ if (fstat(Files[fnum].fd,&sbuf) == -1) return(0);
+ return(get_share_mode(cnum,&sbuf,pid));
+}
+
+/*******************************************************************
+ get the share mode of a file using the files name
+ ******************************************************************/
+int get_share_mode_byname(int cnum,char *fname,int *pid)
+{
+ struct stat sbuf;
+ if (stat(fname,&sbuf) == -1) return(0);
+ return(get_share_mode(cnum,&sbuf,pid));
+}
+
+
+/*******************************************************************
+get the share mode of a file
+********************************************************************/
+int get_share_mode(int cnum,struct stat *sbuf,int *pid)
+{
+ pstring fname;
+ int fd2;
+ char buf[16];
+ int ret;
+ time_t t;
+
+ *pid = 0;
+
+ if (!share_name(cnum,sbuf,fname)) return(0);
+
+ fd2 = open(fname,O_RDONLY,0);
+ if (fd2 < 0) return(0);
+
+ if (read(fd2,buf,16) != 16) {
+ close(fd2);
+ unlink(fname);
+ return(0);
+ }
+ close(fd2);
+
+ t = IVAL(buf,0);
+ ret = IVAL(buf,4);
+ *pid = IVAL(buf,8);
+
+ if (IVAL(buf,12) != LOCKING_VERSION) {
+ if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
+ *pid = 0;
+ return(0);
+ }
+
+ if (*pid && !process_exists(*pid)) {
+ ret=0;
+ *pid = 0;
+ }
+
+ if (! *pid) unlink(fname); /* XXXXX race, race */
+
+ if (*pid)
+ DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
+
+ return(ret);
+}
+
+
+/*******************************************************************
+del the share mode of a file, if we set it last
+********************************************************************/
+void del_share_mode(int fnum)
+{
+ pstring fname;
+ int fd2;
+ char buf[16];
+ time_t t=0;
+ int pid=0;
+ BOOL del = False;
+
+ if (!share_name_fnum(fnum,fname)) return;
+
+ fd2 = open(fname,O_RDONLY,0);
+ if (fd2 < 0) return;
+ if (read(fd2,buf,16) != 16)
+ del = True;
+ close(fd2);
+
+ if (!del) {
+ t = IVAL(buf,0);
+ pid = IVAL(buf,8);
+ }
+
+ if (!del)
+ if (IVAL(buf,12) != LOCKING_VERSION || !pid || !process_exists(pid))
+ del = True;
+
+ if (!del && t == Files[fnum].open_time && pid==(int)getpid())
+ del = True;
+
+ if (del) {
+ if (!unlink(fname))
+ DEBUG(2,("Deleted share file %s\n",fname));
+ else {
+ DEBUG(3,("Pending delete share file %s\n",fname));
+ if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
+ strcpy(share_del_pending,fname);
+ }
+ }
+}
+
+
+/*******************************************************************
+set the share mode of a file
+********************************************************************/
+BOOL set_share_mode(int fnum,int mode)
+{
+ pstring fname;
+ int fd2;
+ char buf[16];
+ int pid = (int)getpid();
+
+ if (!share_name_fnum(fnum,fname)) return(False);
+
+ {
+ int old_umask = umask(0);
+ fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
+ umask(old_umask);
+ }
+ if (fd2 < 0) {
+ DEBUG(2,("Failed to create share file %s\n",fname));
+ return(False);
+ }
+
+ SIVAL(buf,0,Files[fnum].open_time);
+ SIVAL(buf,4,mode);
+ SIVAL(buf,8,pid);
+ SIVAL(buf,12,LOCKING_VERSION);
+
+ if (write(fd2,buf,16) != 16) {
+ close(fd2);
+ unlink(fname);
+ return(False);
+ }
+
+ write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
+
+ close(fd2);
+
+ DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
+
+ return(True);
+}
+
+
+/*******************************************************************
+cleanup any stale share files
+********************************************************************/
+void clean_share_files(void)
+{
+ char *lockdir = lp_lockdir();
+ void *dir;
+ char *s;
+
+ if (!*lockdir) return;
+
+ dir = opendir(lockdir);
+ if (!dir) return;
+
+ while ((s=readdirname(dir))) {
+ char buf[16];
+ int pid;
+ int fd;
+ pstring lname;
+ int dev,inode;
+
+ if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
+
+ strcpy(lname,lp_lockdir());
+ trim_string(lname,NULL,"/");
+ strcat(lname,"/");
+ strcat(lname,s);
+
+ fd = open(lname,O_RDONLY,0);
+ if (fd < 0) continue;
+
+ if (read(fd,buf,16) != 16) {
+ close(fd);
+ if (!unlink(lname))
+ printf("Deleted corrupt share file %s\n",s);
+ continue;
+ }
+ close(fd);
+
+ pid = IVAL(buf,8);
+
+ if (IVAL(buf,12) != LOCKING_VERSION || !process_exists(pid)) {
+ if (!unlink(lname))
+ printf("Deleted stale share file %s\n",s);
+ }
+ }
+
+ closedir(dir);
+}