When a Windows client fetches file information from Samba, then Samba always
uses stat(2) instead of lstat(2), that way resolving symlinks to their target
if it exists. That's fine for the normal content of the file information
given to Windows clients, which don't understand symlinks.
However, there are a couple of problems with this. For instance, consider the
following situation on the Samba side:
Samba$ mkdir -p ~/tmp/test
Samba$ cd ~/tmp/test
Samba$ mkdir subdir
Samba$ ln -s subdir symlink
When using Cygwin on the Windows side, the FileIndex returned by Samba is used
as the i-node number of the file. When calling ls -li from Cygwin, something
like this is printed:
Cygwin$ ls -li //samba-box/tmp/test
8808978157900 drwxr-xr-x 1 corinna root 0 Jan 15 14:46 subdir
8808978157900 drwxr-xr-x 1 corinna root 0 Jan 15 14:46 symlink
So, we have two directories with the same i-node number. If you try to copy
these files under Cygwin from the Samba share to a local directory, cp(1)
from recent coreutils will print:
Cygwin$ cp -rp //samba-box/tmp/test .
cp: will not create hard link `./test/symlink' to directory `./test/subdir'
Another problem occurs if you try to delete the parent directory from Cygwin:
Cygwin$ cd //samba-box/tmp
Cygwin$ rm -rf test
rm: cannot remove directory `test': Directory not empty
Cygwin$ cd test
Huh? Let's see how this looks like on the Samba side:
Samba$ ls -l ~/tmp/test
lrwxrwxrwx 1 corinna users 6 Jan 15 14:47 symlink -> subdir
This is not only a problem in Cygwin. Using Windows explorer to delete
the symlink results in a dialog(*):
"Are you sure you want to remove the folder 'symlink' and all its contents?"
After confirming you'll get another dialog:
"Cannot remove the folder symlink: Directory name invalid."
Anyway, the intransparency of symlinks is a real problem. It looks like
both problems could be solved like this: Always call lstat(2) first. Only
call stat(2) afterwards if it's a symlink, and only call it to find out
if it's a file or a directory, to set the file type correctly for the reply
In calls which manipulate files, manipulate the symlink itself, never the
target. That means, deleting a symlink from Windows should also only
delete the symlink, not the target file or directory.
If this is something to consider, I'd gladly help out with code.
(*) Related to this problem I found
but the solution doesn't seem to be in 3.0.28. Or was that somehow a
The problem with this solution is that it doubles the number of [l]stat calls in the common case (Windows clients accessing). This would cause a performance problem for us.
The POSIX solution for this is to use the UNIX extensions trans2 calls, but being stuck on Windows you don't get to select the calls the redirector makes.
Handling of symlinks from Windows clients is not currently ideal. Let me think about this some more.
I'm not convinced using lstat results in a big performance hit. For
every non-symlink file, the number of calls is still one. You only need
a single lstat call in the common case, and only for symlinks you need
another call to stat. I attached a preliminary patch against the
3.2-test repo to this bug.
OTOH, this approach does still not allow to identify symlinks from
Cygwin so it helps only marginally. That's why I proposed to add
symlink information in EAs in
However, this EA approach alone has the disadvantage to slow down
Cygwin, because it would require to retrieve EAs for every file from a
Samba share to see if a symlink EA is available. This is not such a
good solution unless we have another trick to guess on a file being a
symlink from the SMB_FILE_NETWORK_OPEN_INFORMATION block.
Maybe we can set the allocation size to some distinct value?!?
Created attachment 3139 [details]
Preliminary patch to use lstat for Windows clients