mirror of
https://github.com/samba-team/samba.git
synced 2024-12-25 23:21:54 +03:00
6835bd679c
SLOW_SHARE_MODES - duh !).
Jeremy (jallison@whistle.com)
(This used to be commit d38ac4f3a2
)
1248 lines
36 KiB
C
1248 lines
36 KiB
C
/*
|
|
Unix SMB/Netbios implementation.
|
|
Version 1.9.
|
|
Locking functions
|
|
Copyright (C) Andrew Tridgell 1992-1997
|
|
|
|
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.
|
|
|
|
Revision History:
|
|
|
|
12 aug 96: Erik.Devriendt@te6.siemens.be
|
|
added support for shared memory implementation of share mode locking
|
|
|
|
May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
|
|
locking to deal with multiple share modes per open file.
|
|
*/
|
|
|
|
#include "includes.h"
|
|
extern int DEBUGLEVEL;
|
|
extern connection_struct Connections[];
|
|
extern files_struct Files[];
|
|
|
|
/****************************************************************************
|
|
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_ptr->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_ptr->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_ptr->fd,F_SETLK,offset,count,F_UNLCK);
|
|
|
|
if (!ok) {
|
|
*eclass = ERRDOS;
|
|
*ecode = ERRlock;
|
|
return False;
|
|
}
|
|
return True; /* Did unlock */
|
|
}
|
|
|
|
#ifdef 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 smb_shm_open(shmem_file_name, lp_shmem_size());
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
deinitialize the shared memory for share_mode management
|
|
******************************************************************/
|
|
BOOL stop_share_mode_mgmt(void)
|
|
{
|
|
return smb_shm_close();
|
|
}
|
|
|
|
/*******************************************************************
|
|
lock a hash bucket entry in shared memory for share_mode management
|
|
******************************************************************/
|
|
BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok)
|
|
{
|
|
return smb_shm_lock_hash_entry(HASH_ENTRY(dev, inode));
|
|
}
|
|
|
|
/*******************************************************************
|
|
unlock a hash bucket entry in shared memory for share_mode management
|
|
******************************************************************/
|
|
BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
|
|
{
|
|
return smb_shm_unlock_hash_entry(HASH_ENTRY(dev, inode));
|
|
}
|
|
|
|
/*******************************************************************
|
|
get all share mode entries in shared memory for a dev/inode pair.
|
|
********************************************************************/
|
|
int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode,
|
|
min_share_mode_entry **old_shares)
|
|
{
|
|
smb_shm_offset_t *mode_array;
|
|
unsigned int hash_entry = HASH_ENTRY(dev, inode);
|
|
share_mode_record *file_scanner_p;
|
|
share_mode_record *file_prev_p;
|
|
share_mode_entry *entry_scanner_p;
|
|
share_mode_entry *entry_prev_p;
|
|
int num_entries;
|
|
int num_entries_copied;
|
|
BOOL found = False;
|
|
min_share_mode_entry *share_array = (min_share_mode_entry *)0;
|
|
|
|
*old_shares = 0;
|
|
|
|
if(hash_entry > lp_shmem_hash_size() )
|
|
{
|
|
DEBUG(0,
|
|
("PANIC ERROR : get_share_modes (FAST_SHARE_MODES): hash_entry %d too large \
|
|
(max = %d)\n",
|
|
hash_entry, lp_shmem_hash_size() ));
|
|
return 0;
|
|
}
|
|
|
|
mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
|
|
|
|
if(mode_array[hash_entry] == NULL_OFFSET)
|
|
{
|
|
DEBUG(5,("get_share_modes (FAST_SHARE_MODES): hash bucket %d empty\n", hash_entry));
|
|
return 0;
|
|
}
|
|
|
|
file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
|
|
file_prev_p = file_scanner_p;
|
|
while(file_scanner_p)
|
|
{
|
|
if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
|
|
{
|
|
found = True;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
file_prev_p = file_scanner_p ;
|
|
file_scanner_p = (share_mode_record *)smb_shm_offset2addr(
|
|
file_scanner_p->next_offset);
|
|
}
|
|
}
|
|
|
|
if(!found)
|
|
{
|
|
DEBUG(5,("get_share_modes (FAST_SHARE_MODES): no entry for \
|
|
file dev = %d, ino = %d in hash_bucket %d\n", dev, inode, hash_entry));
|
|
return (0);
|
|
}
|
|
|
|
if(file_scanner_p->locking_version != LOCKING_VERSION)
|
|
{
|
|
DEBUG(0,("ERROR:get_share_modes (FAST_SHARE_MODES): Deleting old share mode \
|
|
record due to old locking version %d for file dev = %d, inode = %d in hash \
|
|
bucket %d",file_scanner_p->locking_version, dev, inode, hash_entry));
|
|
if(file_prev_p == file_scanner_p)
|
|
mode_array[hash_entry] = file_scanner_p->next_offset;
|
|
else
|
|
file_prev_p->next_offset = file_scanner_p->next_offset;
|
|
smb_shm_free(smb_shm_addr2offset(file_scanner_p));
|
|
return (0);
|
|
}
|
|
|
|
/* Allocate the old_shares array */
|
|
num_entries = file_scanner_p->num_share_mode_entries;
|
|
if(num_entries)
|
|
{
|
|
*old_shares = share_array = (min_share_mode_entry *)
|
|
malloc(num_entries * sizeof(min_share_mode_entry));
|
|
if(*old_shares == 0)
|
|
{
|
|
DEBUG(0,("get_share_modes (FAST_SHARE_MODES): malloc fail !\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
num_entries_copied = 0;
|
|
|
|
entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
|
|
file_scanner_p->share_mode_entries);
|
|
entry_prev_p = entry_scanner_p;
|
|
while(entry_scanner_p)
|
|
{
|
|
int pid = entry_scanner_p->pid;
|
|
|
|
if (pid && !process_exists(pid))
|
|
{
|
|
/* Delete this share mode entry */
|
|
share_mode_entry *delete_entry_p = entry_scanner_p;
|
|
|
|
if(entry_prev_p == entry_scanner_p)
|
|
{
|
|
/* We are at start of list */
|
|
file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
|
|
entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
|
|
file_scanner_p->share_mode_entries);
|
|
entry_prev_p = entry_scanner_p;
|
|
}
|
|
else
|
|
{
|
|
entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
|
|
entry_scanner_p = (share_mode_entry*)
|
|
smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
|
|
}
|
|
/* Decrement the number of share mode entries on this share mode record */
|
|
file_scanner_p->num_share_mode_entries -= 1;
|
|
|
|
/* PARANOIA TEST */
|
|
if(file_scanner_p->num_share_mode_entries < 0)
|
|
{
|
|
DEBUG(0,("PANIC ERROR:get_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
|
|
for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
|
|
dev, inode, hash_entry));
|
|
return 0;
|
|
}
|
|
|
|
DEBUG(0,("get_share_modes (FAST_SHARE_MODES): process %d no longer exists and \
|
|
it left a share mode entry with mode 0x%X for file dev = %d, ino = %d in hash \
|
|
bucket (number of entries now = %d)\n",
|
|
pid, entry_scanner_p->share_mode, dev, inode, hash_entry,
|
|
file_scanner_p->num_share_mode_entries));
|
|
|
|
smb_shm_free(smb_shm_addr2offset(delete_entry_p));
|
|
}
|
|
else
|
|
{
|
|
/* This is a valid share mode entry and the process that
|
|
created it still exists. Copy it into the output array.
|
|
*/
|
|
share_array[num_entries_copied].pid = entry_scanner_p->pid;
|
|
share_array[num_entries_copied].share_mode = entry_scanner_p->share_mode;
|
|
memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->time,
|
|
sizeof(struct timeval));
|
|
num_entries_copied++;
|
|
DEBUG(5,("get_share_modes (FAST_SHARE_MODES): Read share mode \
|
|
record mode 0x%X pid=%d\n", entry_scanner_p->share_mode, entry_scanner_p->pid));
|
|
entry_prev_p = entry_scanner_p;
|
|
entry_scanner_p = (share_mode_entry *)
|
|
smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
|
|
}
|
|
}
|
|
|
|
/* If no valid share mode entries were found then this record shouldn't exist ! */
|
|
if(num_entries_copied == 0)
|
|
{
|
|
DEBUG(0,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
|
|
hash bucket %d has a share mode record but no entries - deleting\n",
|
|
dev, inode, hash_entry));
|
|
if(*old_shares)
|
|
free((char *)*old_shares);
|
|
*old_shares = 0;
|
|
|
|
if(file_prev_p == file_scanner_p)
|
|
mode_array[hash_entry] = file_scanner_p->next_offset;
|
|
else
|
|
file_prev_p->next_offset = file_scanner_p->next_offset;
|
|
smb_shm_free(smb_shm_addr2offset(file_scanner_p));
|
|
}
|
|
|
|
DEBUG(5,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
|
|
hash bucket %d returning %d entries\n", dev, inode, hash_entry,
|
|
num_entries_copied));
|
|
|
|
return(num_entries_copied);
|
|
}
|
|
|
|
/*******************************************************************
|
|
del the share mode of a file.
|
|
********************************************************************/
|
|
void del_share_mode(share_lock_token token, int fnum)
|
|
{
|
|
uint32 dev, inode;
|
|
smb_shm_offset_t *mode_array;
|
|
unsigned int hash_entry;
|
|
share_mode_record *file_scanner_p;
|
|
share_mode_record *file_prev_p;
|
|
share_mode_entry *entry_scanner_p;
|
|
share_mode_entry *entry_prev_p;
|
|
BOOL found = False;
|
|
int pid = getpid();
|
|
|
|
dev = Files[fnum].fd_ptr->dev;
|
|
inode = Files[fnum].fd_ptr->inode;
|
|
|
|
hash_entry = HASH_ENTRY(dev, inode);
|
|
|
|
if(hash_entry > lp_shmem_hash_size() )
|
|
{
|
|
DEBUG(0,
|
|
("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
|
|
(max = %d)\n",
|
|
hash_entry, lp_shmem_hash_size() ));
|
|
return;
|
|
}
|
|
|
|
mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
|
|
|
|
if(mode_array[hash_entry] == NULL_OFFSET)
|
|
{
|
|
DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash bucket %d empty\n",
|
|
hash_entry));
|
|
return;
|
|
}
|
|
|
|
file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
|
|
file_prev_p = file_scanner_p;
|
|
|
|
while(file_scanner_p)
|
|
{
|
|
if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
|
|
{
|
|
found = True;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
file_prev_p = file_scanner_p ;
|
|
file_scanner_p = (share_mode_record *)
|
|
smb_shm_offset2addr(file_scanner_p->next_offset);
|
|
}
|
|
}
|
|
|
|
if(!found)
|
|
{
|
|
DEBUG(0,("ERROR:del_share_mode (FAST_SHARE_MODES): no entry found for dev %d, \
|
|
inode %d in hash bucket %d\n", dev, inode, hash_entry));
|
|
return;
|
|
}
|
|
|
|
if(file_scanner_p->locking_version != LOCKING_VERSION)
|
|
{
|
|
DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): Deleting old share mode \
|
|
record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
|
|
file_scanner_p->locking_version, dev, inode, hash_entry ));
|
|
if(file_prev_p == file_scanner_p)
|
|
mode_array[hash_entry] = file_scanner_p->next_offset;
|
|
else
|
|
file_prev_p->next_offset = file_scanner_p->next_offset;
|
|
smb_shm_free(smb_shm_addr2offset(file_scanner_p));
|
|
return;
|
|
}
|
|
|
|
found = False;
|
|
entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
|
|
file_scanner_p->share_mode_entries);
|
|
entry_prev_p = entry_scanner_p;
|
|
while(entry_scanner_p)
|
|
{
|
|
if( (pid == entry_scanner_p->pid) &&
|
|
(memcmp(&entry_scanner_p->time,
|
|
&Files[fnum].open_time,sizeof(struct timeval)) == 0) )
|
|
{
|
|
found = True;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
entry_prev_p = entry_scanner_p;
|
|
entry_scanner_p = (share_mode_entry *)
|
|
smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
|
|
}
|
|
}
|
|
|
|
if (found)
|
|
{
|
|
/* Decrement the number of entries in the record. */
|
|
file_scanner_p->num_share_mode_entries -= 1;
|
|
|
|
DEBUG(2,("del_share_modes (FAST_SHARE_MODES): \
|
|
Deleting share mode entry dev = %d, inode = %d in hash bucket %d (num entries now = %d)\n",
|
|
dev, inode, hash_entry, file_scanner_p->num_share_mode_entries));
|
|
if(entry_prev_p == entry_scanner_p)
|
|
/* We are at start of list */
|
|
file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
|
|
else
|
|
entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
|
|
smb_shm_free(smb_shm_addr2offset(entry_scanner_p));
|
|
|
|
/* PARANOIA TEST */
|
|
if(file_scanner_p->num_share_mode_entries < 0)
|
|
{
|
|
DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
|
|
for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
|
|
dev, inode, hash_entry));
|
|
return;
|
|
}
|
|
|
|
/* If we deleted the last share mode entry then remove the share mode record. */
|
|
if(file_scanner_p->num_share_mode_entries == 0)
|
|
{
|
|
DEBUG(2,("del_share_modes (FAST_SHARE_MODES): num entries = 0, deleting share_mode \
|
|
record dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
|
|
if(file_prev_p == file_scanner_p)
|
|
mode_array[hash_entry] = file_scanner_p->next_offset;
|
|
else
|
|
file_prev_p->next_offset = file_scanner_p->next_offset;
|
|
smb_shm_free(smb_shm_addr2offset(file_scanner_p));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): No share mode record found \
|
|
dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
set the share mode of a file. Return False on fail, True on success.
|
|
********************************************************************/
|
|
BOOL set_share_mode(share_lock_token token, int fnum)
|
|
{
|
|
files_struct *fs_p = &Files[fnum];
|
|
int32 dev, inode;
|
|
smb_shm_offset_t *mode_array;
|
|
unsigned int hash_entry;
|
|
share_mode_record *file_scanner_p;
|
|
share_mode_record *file_prev_p;
|
|
share_mode_entry *new_entry_p;
|
|
smb_shm_offset_t new_entry_offset;
|
|
BOOL found = False;
|
|
|
|
dev = fs_p->fd_ptr->dev;
|
|
inode = fs_p->fd_ptr->inode;
|
|
|
|
hash_entry = HASH_ENTRY(dev, inode);
|
|
if(hash_entry > lp_shmem_hash_size() )
|
|
{
|
|
DEBUG(0,
|
|
("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
|
|
(max = %d)\n",
|
|
hash_entry, lp_shmem_hash_size() ));
|
|
return False;
|
|
}
|
|
|
|
mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
|
|
|
|
file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
|
|
file_prev_p = file_scanner_p;
|
|
|
|
while(file_scanner_p)
|
|
{
|
|
if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
|
|
{
|
|
found = True;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
file_prev_p = file_scanner_p ;
|
|
file_scanner_p = (share_mode_record *)
|
|
smb_shm_offset2addr(file_scanner_p->next_offset);
|
|
}
|
|
}
|
|
|
|
if(!found)
|
|
{
|
|
/* We must create a share_mode_record */
|
|
share_mode_record *new_mode_p = NULL;
|
|
smb_shm_offset_t new_offset = smb_shm_alloc( sizeof(share_mode_record) +
|
|
strlen(fs_p->name) + 1);
|
|
if(new_offset == NULL_OFFSET)
|
|
{
|
|
DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail !\n"));
|
|
return False;
|
|
}
|
|
new_mode_p = smb_shm_offset2addr(new_offset);
|
|
new_mode_p->locking_version = LOCKING_VERSION;
|
|
new_mode_p->st_dev = dev;
|
|
new_mode_p->st_ino = inode;
|
|
new_mode_p->num_share_mode_entries = 0;
|
|
new_mode_p->share_mode_entries = NULL_OFFSET;
|
|
strcpy(new_mode_p->file_name, fs_p->name);
|
|
|
|
/* Chain onto the start of the hash chain (in the hope we will be used first). */
|
|
new_mode_p->next_offset = mode_array[hash_entry];
|
|
mode_array[hash_entry] = new_offset;
|
|
|
|
file_scanner_p = new_mode_p;
|
|
|
|
DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share record for %s (dev %d \
|
|
inode %d in hash bucket %d\n", fs_p->name, dev, inode, hash_entry));
|
|
}
|
|
|
|
/* Now create the share mode entry */
|
|
new_entry_offset = smb_shm_alloc( sizeof(share_mode_entry));
|
|
if(new_entry_offset == NULL_OFFSET)
|
|
{
|
|
smb_shm_offset_t delete_offset = mode_array[hash_entry];
|
|
DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail 1!\n"));
|
|
/* Unlink the damaged record */
|
|
mode_array[hash_entry] = file_scanner_p->next_offset;
|
|
/* And delete it */
|
|
smb_shm_free( delete_offset );
|
|
return False;
|
|
}
|
|
|
|
new_entry_p = smb_shm_offset2addr(new_entry_offset);
|
|
|
|
new_entry_p->pid = getpid();
|
|
new_entry_p->share_mode = fs_p->share_mode;
|
|
memcpy( (char *)&new_entry_p->time, (char *)&fs_p->open_time, sizeof(struct timeval));
|
|
|
|
/* Chain onto the share_mode_record */
|
|
new_entry_p->next_share_mode_entry = file_scanner_p->share_mode_entries;
|
|
file_scanner_p->share_mode_entries = new_entry_offset;
|
|
|
|
/* PARANOIA TEST */
|
|
if(file_scanner_p->num_share_mode_entries < 0)
|
|
{
|
|
DEBUG(0,("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
|
|
for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
|
|
dev, inode, hash_entry));
|
|
return False;
|
|
}
|
|
|
|
/* Increment the share_mode_entries counter */
|
|
file_scanner_p->num_share_mode_entries += 1;
|
|
|
|
DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share entry for %s with mode \
|
|
0x%X pid=%d (num_entries now = %d)\n",fs_p->name, fs_p->share_mode, new_entry_p->pid,
|
|
file_scanner_p->num_share_mode_entries));
|
|
|
|
return(True);
|
|
}
|
|
|
|
#else /* FAST_SHARE_MODES */
|
|
|
|
/* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
|
|
|
|
/*******************************************************************
|
|
name a share file
|
|
******************************************************************/
|
|
static BOOL share_name(int cnum, uint32 dev, uint32 inode, char *name)
|
|
{
|
|
strcpy(name,lp_lockdir());
|
|
standard_sub(cnum,name);
|
|
trim_string(name,"","/");
|
|
if (!*name) return(False);
|
|
name += strlen(name);
|
|
|
|
sprintf(name,"/share.%u.%u",dev,inode);
|
|
return(True);
|
|
}
|
|
|
|
/*******************************************************************
|
|
lock a share mode file.
|
|
******************************************************************/
|
|
BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok)
|
|
{
|
|
pstring fname;
|
|
int fd;
|
|
|
|
*ptok = (share_lock_token)-1;
|
|
|
|
if(!share_name(cnum, dev, inode, fname))
|
|
return False;
|
|
|
|
{
|
|
int old_umask;
|
|
unbecome_user();
|
|
old_umask = umask(0);
|
|
#ifdef SECURE_SHARE_MODES
|
|
fd = (share_lock_token)open(fname,O_RDWR|O_CREAT,0600);
|
|
#else /* SECURE_SHARE_MODES */
|
|
fd = (share_lock_token)open(fname,O_RDWR|O_CREAT,0644);
|
|
#endif /* SECURE_SHARE_MODES */
|
|
umask(old_umask);
|
|
if(!become_user(cnum,Connections[cnum].vuid))
|
|
{
|
|
DEBUG(0,("lock_share_entry: Can't become connected user!\n"));
|
|
close(fd);
|
|
return False;
|
|
}
|
|
/* We need to change directory back to the connection root. */
|
|
if (ChDir(Connections[cnum].connectpath) != 0)
|
|
{
|
|
DEBUG(0,("lock_share_entry: Can't change directory to %s (%s)\n",
|
|
Connections[cnum].connectpath, strerror(errno)));
|
|
close(fd);
|
|
return False;
|
|
}
|
|
}
|
|
|
|
/* At this point we have an open fd to the share mode file.
|
|
Lock the first byte exclusively to signify a lock. */
|
|
if(fcntl_lock(fd, F_SETLKW, 0, 1, F_WRLCK) == False)
|
|
{
|
|
DEBUG(0,("ERROR lock_share_entry: fcntl_lock failed with %s\n",
|
|
strerror(errno)));
|
|
close(fd);
|
|
return False;
|
|
}
|
|
|
|
*ptok = (share_lock_token)fd;
|
|
return True;
|
|
}
|
|
|
|
/*******************************************************************
|
|
unlock a share mode file.
|
|
******************************************************************/
|
|
BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
|
|
{
|
|
int fd = (int)token;
|
|
int ret = True;
|
|
|
|
/* token is the fd of the open share mode file. */
|
|
/* Unlock the first byte. */
|
|
if(fcntl_lock(fd, F_SETLKW, 0, 1, F_UNLCK) == False)
|
|
{
|
|
DEBUG(0,("ERROR unlock_share_entry: fcntl_lock failed with %s\n",
|
|
strerror(errno)));
|
|
ret = False;
|
|
}
|
|
|
|
close((int)token);
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Force a share file to be deleted.
|
|
********************************************************************/
|
|
|
|
static int delete_share_file( int cnum, char *fname )
|
|
{
|
|
unbecome_user();
|
|
if(unlink(fname) != 0)
|
|
{
|
|
DEBUG(0,("delete_share_file: Can't delete share file %s (%s)\n",
|
|
fname, strerror(errno)));
|
|
}
|
|
|
|
DEBUG(5,("delete_share_file: Deleted share file %s\n", fname));
|
|
|
|
if(!become_user(cnum,Connections[cnum].vuid))
|
|
{
|
|
DEBUG(0,("delete_share_file: Can't become connected user!\n"));
|
|
return -1;
|
|
}
|
|
/* We need to change directory back to the connection root. */
|
|
if (ChDir(Connections[cnum].connectpath) != 0)
|
|
{
|
|
DEBUG(0,("delete_share_file: Can't change directory to %s (%s)\n",
|
|
Connections[cnum].connectpath, strerror(errno)));
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************
|
|
Read a share file into a buffer.
|
|
********************************************************************/
|
|
|
|
static int read_share_file(int cnum, int fd, char *fname, char **out, BOOL *p_new_file)
|
|
{
|
|
struct stat sb;
|
|
char *buf;
|
|
int size;
|
|
|
|
*out = 0;
|
|
*p_new_file = False;
|
|
|
|
if(fstat(fd, &sb) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: read_share_file: Failed to do stat on share file %s (%s)\n",
|
|
fname, strerror(errno)));
|
|
return -1;
|
|
}
|
|
|
|
if(sb.st_size == 0)
|
|
{
|
|
*p_new_file = True;
|
|
return 0;
|
|
}
|
|
|
|
/* Allocate space for the file */
|
|
if((buf = (char *)malloc(sb.st_size)) == NULL)
|
|
{
|
|
DEBUG(0,("read_share_file: malloc for file size %d fail !\n", sb.st_size));
|
|
return -1;
|
|
}
|
|
|
|
if(lseek(fd, 0, SEEK_SET) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: read_share_file: Failed to reset position to 0 \
|
|
for share file %s (%s)\n", fname, strerror(errno)));
|
|
if(buf)
|
|
free(buf);
|
|
return -1;
|
|
}
|
|
|
|
if (read(fd,buf,sb.st_size) != sb.st_size)
|
|
{
|
|
DEBUG(0,("ERROR: read_share_file: Failed to read share file %s (%s)\n",
|
|
fname, strerror(errno)));
|
|
if(buf)
|
|
free(buf);
|
|
return -1;
|
|
}
|
|
|
|
if (IVAL(buf,0) != LOCKING_VERSION) {
|
|
DEBUG(0,("ERROR: read_share_file: share file %s has incorrect \
|
|
locking version (was %d, should be %d).\n",fname, IVAL(buf,0), LOCKING_VERSION));
|
|
if(buf)
|
|
free(buf);
|
|
delete_share_file(cnum, fname);
|
|
return -1;
|
|
}
|
|
|
|
/* Sanity check for file contents */
|
|
size = sb.st_size;
|
|
size -= 10; /* Remove the header */
|
|
|
|
/* Remove the filename component. */
|
|
size -= SVAL(buf, 8);
|
|
|
|
/* The remaining size must be a multiple of 16 - error if not. */
|
|
if((size % 16) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: read_share_file: share file %s is an incorrect length - \
|
|
deleting it.\n", fname));
|
|
if(buf)
|
|
free(buf);
|
|
delete_share_file(cnum, fname);
|
|
return -1;
|
|
}
|
|
|
|
*out = buf;
|
|
return 0;
|
|
}
|
|
|
|
/*******************************************************************
|
|
get all share mode entries in a share file for a dev/inode pair.
|
|
********************************************************************/
|
|
int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode,
|
|
min_share_mode_entry **old_shares)
|
|
{
|
|
int fd = (int)token;
|
|
pstring fname;
|
|
int i;
|
|
int num_entries;
|
|
int num_entries_copied;
|
|
int newsize;
|
|
min_share_mode_entry *share_array;
|
|
char *buf = 0;
|
|
char *base = 0;
|
|
BOOL new_file;
|
|
|
|
*old_shares = 0;
|
|
|
|
/* Read the share file header - this is of the form:
|
|
0 - locking version.
|
|
4 - number of share mode entries.
|
|
8 - 2 byte name length
|
|
[n bytes] file name (zero terminated).
|
|
|
|
Followed by <n> share mode entries of the form :
|
|
|
|
0 - tv_sec
|
|
4 - tv_usec
|
|
8 - share_mode
|
|
12 - pid
|
|
|
|
*/
|
|
|
|
share_name(cnum, dev, inode, fname);
|
|
|
|
if(read_share_file( cnum, fd, fname, &buf, &new_file) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: get_share_modes: Failed to read share file %s\n",
|
|
fname));
|
|
return 0;
|
|
}
|
|
|
|
if(new_file == True)
|
|
return 0;
|
|
|
|
num_entries = IVAL(buf,4);
|
|
|
|
DEBUG(5,("get_share_modes: share file %s has %d share mode entries.\n",
|
|
fname, num_entries));
|
|
|
|
/* PARANOIA TEST */
|
|
if(num_entries < 0)
|
|
{
|
|
DEBUG(0,("PANIC ERROR:get_share_mode: num_share_mode_entries < 0 (%d) \
|
|
for share file %d\n", num_entries, fname));
|
|
return 0;
|
|
}
|
|
|
|
if(num_entries)
|
|
{
|
|
*old_shares = share_array = (min_share_mode_entry *)
|
|
malloc(num_entries * sizeof(min_share_mode_entry));
|
|
if(*old_shares == 0)
|
|
{
|
|
DEBUG(0,("get_share_modes: malloc fail !\n"));
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No entries - just delete the file. */
|
|
DEBUG(0,("get_share_modes: share file %s has no share mode entries - deleting.\n",
|
|
fname));
|
|
if(buf)
|
|
free(buf);
|
|
delete_share_file(cnum, fname);
|
|
return 0;
|
|
}
|
|
|
|
num_entries_copied = 0;
|
|
base = buf + 10 + SVAL(buf,8);
|
|
|
|
for( i = 0; i < num_entries; i++)
|
|
{
|
|
int pid;
|
|
char *p = base + (i*16);
|
|
|
|
pid = IVAL(p,12);
|
|
|
|
if(!process_exists(pid))
|
|
{
|
|
DEBUG(0,("get_share_modes: process %d no longer exists and \
|
|
it left a share mode entry with mode 0x%X in share file %s\n",
|
|
pid, IVAL(p,8), fname));
|
|
continue;
|
|
}
|
|
share_array[num_entries_copied].time.tv_sec = IVAL(p,0);
|
|
share_array[num_entries_copied].time.tv_usec = IVAL(p,4);
|
|
share_array[num_entries_copied].share_mode = IVAL(p,8);
|
|
share_array[num_entries_copied].pid = pid;
|
|
|
|
num_entries_copied++;
|
|
}
|
|
|
|
if(num_entries_copied == 0)
|
|
{
|
|
/* Delete the whole file. */
|
|
DEBUG(0,("get_share_modes: share file %s had no valid entries - deleting it !\n",
|
|
fname));
|
|
if(*old_shares)
|
|
free((char *)*old_shares);
|
|
*old_shares = 0;
|
|
if(buf)
|
|
free(buf);
|
|
delete_share_file(cnum, fname);
|
|
return 0;
|
|
}
|
|
|
|
/* If we deleted some entries we need to re-write the whole number of
|
|
share mode entries back into the file. */
|
|
|
|
if(num_entries_copied != num_entries)
|
|
{
|
|
if(lseek(fd, 0, SEEK_SET) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: get_share_modes: lseek failed to reset to \
|
|
position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
|
|
if(*old_shares)
|
|
free((char *)*old_shares);
|
|
*old_shares = 0;
|
|
if(buf)
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
|
|
SIVAL(buf, 4, num_entries_copied);
|
|
for( i = 0; i < num_entries_copied; i++)
|
|
{
|
|
char *p = base + (i*16);
|
|
|
|
SIVAL(p,12,share_array[i].pid);
|
|
SIVAL(p,8,share_array[i].share_mode);
|
|
SIVAL(p,0,share_array[i].time.tv_sec);
|
|
SIVAL(p,4,share_array[i].time.tv_usec);
|
|
}
|
|
|
|
newsize = (base - buf) + (16*num_entries_copied);
|
|
if(write(fd, buf, newsize) != newsize)
|
|
{
|
|
DEBUG(0,("ERROR: get_share_modes: failed to re-write share \
|
|
mode file %s (%s)\n", fname, strerror(errno)));
|
|
if(*old_shares)
|
|
free((char *)*old_shares);
|
|
*old_shares = 0;
|
|
if(buf)
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
/* Now truncate the file at this point. */
|
|
if(ftruncate(fd, newsize)!= 0)
|
|
{
|
|
DEBUG(0,("ERROR: get_share_modes: failed to ftruncate share \
|
|
mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
|
|
if(*old_shares)
|
|
free((char *)*old_shares);
|
|
*old_shares = 0;
|
|
if(buf)
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if(buf)
|
|
free(buf);
|
|
|
|
DEBUG(5,("get_share_modes: Read share file %s returning %d entries\n",fname,
|
|
num_entries_copied));
|
|
|
|
return num_entries_copied;
|
|
}
|
|
|
|
/*******************************************************************
|
|
del a share mode from a share mode file.
|
|
********************************************************************/
|
|
void del_share_mode(share_lock_token token, int fnum)
|
|
{
|
|
pstring fname;
|
|
int fd = (int)token;
|
|
char *buf = 0;
|
|
char *base = 0;
|
|
int num_entries;
|
|
int newsize;
|
|
int i;
|
|
files_struct *fs_p = &Files[fnum];
|
|
int pid;
|
|
BOOL deleted = False;
|
|
BOOL new_file;
|
|
|
|
share_name(fs_p->cnum, fs_p->fd_ptr->dev,
|
|
fs_p->fd_ptr->inode, fname);
|
|
|
|
if(read_share_file( fs_p->cnum, fd, fname, &buf, &new_file) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: del_share_mode: Failed to read share file %s\n",
|
|
fname));
|
|
return;
|
|
}
|
|
|
|
if(new_file == True)
|
|
{
|
|
DEBUG(0,("ERROR:del_share_mode: share file %s is new (size zero), deleting it.\n",
|
|
fname));
|
|
delete_share_file(fs_p->cnum, fname);
|
|
return;
|
|
}
|
|
|
|
num_entries = IVAL(buf,4);
|
|
|
|
DEBUG(5,("del_share_mode: share file %s has %d share mode entries.\n",
|
|
fname, num_entries));
|
|
|
|
/* PARANOIA TEST */
|
|
if(num_entries < 0)
|
|
{
|
|
DEBUG(0,("PANIC ERROR:del_share_mode: num_share_mode_entries < 0 (%d) \
|
|
for share file %d\n", num_entries, fname));
|
|
return;
|
|
}
|
|
|
|
if(num_entries == 0)
|
|
{
|
|
/* No entries - just delete the file. */
|
|
DEBUG(0,("del_share_mode: share file %s has no share mode entries - deleting.\n",
|
|
fname));
|
|
if(buf)
|
|
free(buf);
|
|
delete_share_file(fs_p->cnum, fname);
|
|
return;
|
|
}
|
|
|
|
pid = getpid();
|
|
|
|
/* Go through the entries looking for the particular one
|
|
we have set - delete it.
|
|
*/
|
|
|
|
base = buf + 10 + SVAL(buf,8);
|
|
|
|
for(i = 0; i < num_entries; i++)
|
|
{
|
|
char *p = base + (i*16);
|
|
|
|
if((IVAL(p,0) != fs_p->open_time.tv_sec) || (IVAL(p,4) != fs_p->open_time.tv_usec) ||
|
|
(IVAL(p,8) != fs_p->share_mode) || (IVAL(p,12) != pid))
|
|
continue;
|
|
|
|
DEBUG(5,("del_share_mode: deleting entry number %d (of %d) from the share file %s\n",
|
|
i, num_entries, fname));
|
|
|
|
/* Remove this entry. */
|
|
if(i != num_entries - 1)
|
|
memcpy(p, p + 16, (num_entries - i - 1)*16);
|
|
|
|
deleted = True;
|
|
break;
|
|
}
|
|
|
|
if(!deleted)
|
|
{
|
|
DEBUG(0,("del_share_mode: entry not found in share file %s\n", fname));
|
|
if(buf)
|
|
free(buf);
|
|
return;
|
|
}
|
|
|
|
num_entries--;
|
|
SIVAL(buf,4, num_entries);
|
|
|
|
if(num_entries == 0)
|
|
{
|
|
/* Deleted the last entry - remove the file. */
|
|
DEBUG(5,("del_share_mode: removed last entry in share file - deleting share file %s\n",
|
|
fname));
|
|
if(buf)
|
|
free(buf);
|
|
delete_share_file(fs_p->cnum,fname);
|
|
return;
|
|
}
|
|
|
|
/* Re-write the file - and truncate it at the correct point. */
|
|
if(lseek(fd, 0, SEEK_SET) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: del_share_mode: lseek failed to reset to \
|
|
position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
|
|
if(buf)
|
|
free(buf);
|
|
return;
|
|
}
|
|
|
|
newsize = (base - buf) + (16*num_entries);
|
|
if(write(fd, buf, newsize) != newsize)
|
|
{
|
|
DEBUG(0,("ERROR: del_share_mode: failed to re-write share \
|
|
mode file %s (%s)\n", fname, strerror(errno)));
|
|
if(buf)
|
|
free(buf);
|
|
return;
|
|
}
|
|
/* Now truncate the file at this point. */
|
|
if(ftruncate(fd, newsize) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: del_share_mode: failed to ftruncate share \
|
|
mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
|
|
if(buf)
|
|
free(buf);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
set the share mode of a file
|
|
********************************************************************/
|
|
BOOL set_share_mode(share_lock_token token,int fnum)
|
|
{
|
|
files_struct *fs_p = &Files[fnum];
|
|
pstring fname;
|
|
int fd = (int)token;
|
|
int pid = (int)getpid();
|
|
struct stat sb;
|
|
char *buf;
|
|
int num_entries;
|
|
int header_size;
|
|
char *p;
|
|
|
|
share_name(fs_p->cnum, fs_p->fd_ptr->dev,
|
|
fs_p->fd_ptr->inode, fname);
|
|
|
|
if(fstat(fd, &sb) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: set_share_mode: Failed to do stat on share file %s\n",
|
|
fname));
|
|
return False;
|
|
}
|
|
|
|
/* Sanity check for file contents (if it's not a new share file). */
|
|
if(sb.st_size != 0)
|
|
{
|
|
int size = sb.st_size;
|
|
|
|
/* Allocate space for the file plus one extra entry */
|
|
if((buf = (char *)malloc(sb.st_size + 16)) == NULL)
|
|
{
|
|
DEBUG(0,("set_share_mode: malloc for file size %d fail !\n", sb.st_size + 16));
|
|
return False;
|
|
}
|
|
|
|
if(lseek(fd, 0, SEEK_SET) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: set_share_mode: Failed to reset position \
|
|
to 0 for share file %s (%s)\n", fname, strerror(errno)));
|
|
if(buf)
|
|
free(buf);
|
|
return False;
|
|
}
|
|
|
|
if (read(fd,buf,sb.st_size) != sb.st_size)
|
|
{
|
|
DEBUG(0,("ERROR: set_share_mode: Failed to read share file %s (%s)\n",
|
|
fname, strerror(errno)));
|
|
if(buf)
|
|
free(buf);
|
|
return False;
|
|
}
|
|
|
|
if (IVAL(buf,0) != LOCKING_VERSION)
|
|
{
|
|
DEBUG(0,("ERROR: set_share_mode: share file %s has incorrect \
|
|
locking version (was %d, should be %d).\n",fname, IVAL(buf,0), LOCKING_VERSION));
|
|
if(buf)
|
|
free(buf);
|
|
delete_share_file(fs_p->cnum, fname);
|
|
return False;
|
|
}
|
|
|
|
size -= (10 + SVAL(buf, 8)); /* Remove the header */
|
|
|
|
/* The remaining size must be a multiple of 16 - error if not. */
|
|
if((size % 16) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: set_share_mode: share file %s is an incorrect length - \
|
|
deleting it.\n", fname));
|
|
if(buf)
|
|
free(buf);
|
|
delete_share_file(fs_p->cnum, fname);
|
|
return False;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
/* New file - just use a single_entry. */
|
|
if((buf = (char *)malloc(10 + strlen(fs_p->name) + 1 + 16)) == NULL)
|
|
{
|
|
DEBUG(0,("ERROR: set_share_mode: malloc failed for single entry.\n"));
|
|
return False;
|
|
}
|
|
SIVAL(buf,0,LOCKING_VERSION);
|
|
SIVAL(buf,4,0);
|
|
SSVAL(buf,8,strlen(fs_p->name) + 1);
|
|
strcpy(buf + 10, fs_p->name);
|
|
}
|
|
|
|
num_entries = IVAL(buf,4);
|
|
header_size = 10 + SVAL(buf,8);
|
|
p = buf + header_size + (num_entries * 16);
|
|
SIVAL(p,0,fs_p->open_time.tv_sec);
|
|
SIVAL(p,4,fs_p->open_time.tv_usec);
|
|
SIVAL(p,8,fs_p->share_mode);
|
|
SIVAL(p,12,pid);
|
|
|
|
num_entries++;
|
|
|
|
SIVAL(buf,4,num_entries);
|
|
|
|
if(lseek(fd, 0, SEEK_SET) != 0)
|
|
{
|
|
DEBUG(0,("ERROR: set_share_mode: (1) Failed to reset position to \
|
|
0 for share file %s (%s)\n", fname, strerror(errno)));
|
|
if(buf)
|
|
free(buf);
|
|
return False;
|
|
}
|
|
|
|
if (write(fd,buf,header_size + (num_entries*16)) != (header_size + (num_entries*16)))
|
|
{
|
|
DEBUG(2,("ERROR: set_share_mode: Failed to write share file %s - \
|
|
deleting it (%s).\n",fname, strerror(errno)));
|
|
delete_share_file(fs_p->cnum, fname);
|
|
if(buf)
|
|
free(buf);
|
|
return False;
|
|
}
|
|
|
|
/* Now truncate the file at this point - just for safety. */
|
|
if(ftruncate(fd, header_size + (16*num_entries))!= 0)
|
|
{
|
|
DEBUG(0,("ERROR: set_share_mode: failed to ftruncate share \
|
|
mode file %s to size %d (%s)\n", fname, header_size + (16*num_entries), strerror(errno)));
|
|
if(buf)
|
|
free(buf);
|
|
return False;
|
|
}
|
|
|
|
if(buf)
|
|
free(buf);
|
|
|
|
DEBUG(3,("set_share_mode: Created share file %s with \
|
|
mode 0x%X pid=%d\n",fname,fs_p->share_mode,pid));
|
|
|
|
return True;
|
|
}
|
|
#endif /* FAST_SHARE_MODES */
|