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 total 0 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 ls -a . .. Huh? Let's see how this looks like on the Samba side: Samba$ ls -l ~/tmp/test total 0 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 to Windows. 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. Corinna (*) Related to this problem I found https://bugzilla.samba.org/show_bug.cgi?id=4536, but the solution doesn't seem to be in 3.0.28. Or was that somehow a different situation?
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. Jeremy.
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 http://lists.samba.org/archive/samba-technical/2008-February/057818.html 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?!? Corinna
Created attachment 3139 [details] Preliminary patch to use lstat for Windows clients