Hi,

I am trying to understand file locking and share modes.

I am using RedHat Enterprise Linux 4, with kernel 2.6.9-55.ELsmp,
samba-3.0.10-1.4E.11 and Windows XP.

In particular I am looking at a machine running Linux exporting its
local filesystem using Samba, with a Windows client accessing the
file share. If I use byte range locking (fcntl() on Linux, LockFile()
on Windows) things work as expected, and applications using the
file system locally and remotely see the locks set by the other.

However, if a program on the Windows client opens a file with a
share mode that denies access to other processes, I can't seem to
detect this in a local Linux process, either with fcntl() or with flock().
I included the test programs I used below. I have seen references
that this should be possible
(http://lists.samba.org/archive/samba...ry/080455.html
last paragraph) but I may be misunderstanding things.

strace on the smbd process handling the request from the Windows
client shows this (in part):

stat64("temp/test.txt", {st_mode=S_IFREG|0764, st_size=24, ...}) = 0
gettimeofday({1201195094, 16852}, NULL) = 0
fcntl64(12, F_SETLKW64, {type=F_WRLCK, whence=SEEK_SET,
start=256, len=1}, 0xbff6a890) = 0
open("temp/test.txt", O_RDWR|O_LARGEFILE) = 19
flock(19, 0x20 /* LOCK_??? */) = 0
fcntl64(19, F_SETSIG, 0x23) = 0
fcntl64(19, 0x400 /* F_??? */, 0x1) = 0


The second argument to flock() on the test file is 0x20, which is what
LOCK_MAND is defined as in the samba-3.0.28 source in the file
source/include/includes.h. This is the same value I find in
/usr/include/bits/fcntl.h and /usr/include/asm/fcntl.h.

So I wrote a test program (included below) that uses flock with this
value (instad of the usual LOCK_EX) but multiple instances of this
program couldn't even detect each other's locks. Nor did any
windows client having the file open with any share mode have an
effect. I also tried enabling mandatory locking with the mount option
and the chmod bits, since the flag is called LOCK_MAND, but that did
not change the results.

So the question is: is it supposed to be possible for a program running
locally on Linux to detect share modes applied by a Windows client,
and if so, how?

The test programs and my smb.conf file are below.

Thanks for any help,
Peter

Snippets:
1. smb.conf
2. Windows program (console app) to open with share
mode disallowing other processes
3. Linux program to open a file and lock it with flock():
4. Linux program to lock with fcntl():
5. Windows program (console app) to lock with byte
range locks: LockFile()
6. Linux program to lock the file using flock()
and LOCK_MAND, instead of the standard LOCK_EX


1. smb.conf
=============================================
[global]
netbios name = PFS-RHEL4-DEV
workgroup = MYGROUP
server string = Samba Server
printcap name = /etc/printcap
load printers = yes

cups options = raw

log file = /var/log/samba/%m.log
max log size = 50
security = user
socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
dns proxy = no

idmap uid = 16777216-33554431
idmap gid = 16777216-33554431
template shell = /bin/false
winbind use default domain = no
[homes]
comment = Home Directories
browseable = no
writable = yes

[printers]
comment = All Printers
path = /var/spool/samba
browseable = no
guest ok = no
writable = no
printable = yes
=============================================




Test programs:

2. Windows program (console app) to open with share
mode disallowing other processes
=============================================
#include
#include
#include

int _tmain(int argc, _TCHAR* argv[])
{
HANDLE handle;
TCHAR* filename = NULL;

if(argc < 2)
{
printf("No argument.\n");
return 2;
}
else
{
filename = argv[1];
}


printf("Try to open file with share mode\n");

while(1)
{

handle = CreateFile(
filename,
GENERIC_READ | GENERIC_WRITE, /* desired access */
0, /* share mode: no sharing */
NULL, /* security attributes */
OPEN_EXISTING, /* creation disposition - fail if not found */
0, /* dwFlagsAndAttributes - i think we can ignore this
since the file exists */
NULL /* template for attributes when creating file */
);

if(handle != INVALID_HANDLE_VALUE)
break;
else
Sleep(1000);
}

printf("Acquired Lock\n");

while(1)
Sleep(1000);

return 0;
}
=============================================



3. Linux program to open a file and lock it with flock():
=============================================
#include
#include
#include

main(int argc, char** argv)
{
int result;
int fd = -1;
char* filename = NULL;

if(argc < 2)
{
printf("No argument\n");
return 2;
}
else
{
filename = argv[1];
}

fd = open(filename, O_RDWR);
if(-1 == fd)
{
printf("open() failed\n");
return 1;
}

printf("Trying to lock...\n");

result = flock(fd, LOCK_EX);
if(result != 0)
{
printf("flock() failed\n");
return 1;
}

printf("Lock acquired\n");

while(1)
sleep(1);
}
=============================================



4. Linux program to lock with fcntl():
=============================================
#include
#include
#include

main(int argc, char** argv)
{
int result;
int fd = -1;
char* filename = NULL;

if(argc < 2)
{
printf("No argument\n");
return 2;
}
else
{
filename = argv[1];
}

fd = open(filename, O_RDWR);
if(-1 == fd)
{
printf("open() failed\n");
return 1;
}

{
struct flock lock_opts;
lock_opts.l_type = F_WRLCK;
lock_opts.l_whence = SEEK_SET;
lock_opts.l_start = 0;
lock_opts.l_len = 0;

printf("Trying to lock...\n");

result = fcntl(fd, F_SETLKW, &lock_opts);
if(result == -1)
{
printf("fcntl() failed\n");
return 1;
}
}

printf("Lock acquired\n");

while(1)
sleep(1);
}
=============================================



5. Windows program (console app) to lock with byte
range locks: LockFile()
=============================================
#include
#include
#include
#include


int _tmain(int argc, _TCHAR* argv[])
{
HANDLE handle;
TCHAR* filename = NULL;

if(argc < 2)
{
printf("No argument.\n");
return 2;
}
else
{
filename = argv[1];
}

handle = CreateFile(
filename,
GENERIC_READ | GENERIC_WRITE, /* desired access */
FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
/* share mode: no restrictions on other processes */
NULL, /* security attributes */
OPEN_EXISTING, /* creation disposition - fail if not found */
0, /* dwFlagsAndAttributes - i think we can ignore this
since the file exists */
NULL /* template for attributes when creating file */
);

if(handle == INVALID_HANDLE_VALUE)
{
printf("Unable to open file\n");
return 1;
}

printf("Trying to lock...\n");

while(1)
{
int result;

result = LockFile(handle, 0, 0, INT_MAX, 0);

if(result)
break;
else
Sleep(1000);
}

printf("Lock acquired\n");

while(1)
Sleep(1000);

return 0;
}
=============================================


6. Linux program to lock the file using flock()
and LOCK_MAND, instead of LOCK_EX
=============================================

#define _GNU_SOURCE

#include
#include
#include

main(int argc, char** argv)
{
int result;
int fd = -1;
char* filename = NULL;

if(argc < 2)
{
printf("No argument\n");
return 2;
}
else
{
filename = argv[1];
}

fd = open(filename, O_RDWR);
if(-1 == fd)
{
printf("open() failed\n");
return 1;
}

printf("Trying to lock...\n");

result = flock(fd, LOCK_MAND);
if(result != 0)
{
printf("flock() failed\n");
return 1;
}

printf("Lock acquired\n");

while(1)
sleep(1);
}

=============================================
--
To unsubscribe from this list go to the following URL and read the
instructions: https://lists.samba.org/mailman/listinfo/samba