Visible symlinks under Windows

Corinna Vinschen corinna at vinschen.de
Thu Feb 14 10:45:08 GMT 2008


To follow up on this...  [Beware!  It's somewhat long...]

On Feb  7 12:04, Corinna Vinschen wrote:
> On Feb  6 13:41, James Peach wrote:
> > With your EA proposal, I think the server would have to restrict symlinks 
> > to be relative to the SMB share and to point to a file within the share. 
> > You'd need this because some clients will follow the symlink on the server, 
> > and some will resolve the target on the client side and you want both 
> > methods to end up at the same place.
> 
> I guess you're right.  Otherwise the non-EA file information returned
> by calls to ZwQueryInformationFile would point to another file than
> the symlink path in the EA, and an application trying to access a file
> gotten by a call to readlink would fail.  That sounds rather... medium
> well.
> 
> > So, yeh I'm convinced that EA symlinks are worthwhile ...

...on second thought it turns out that the EAs alone are not very
helpful as far as the Cygwin side is concerned.

The problem is that the information if EAs are available is only
accessible when opening the file.  This would be a big performance
problem.  Right now, Cygwin only requests file information which is
available without having to open a file.  Only if that information hints
to a file being a symlink, *then* Cygwin opens the file and retrieves
the information from the file.

For instance, the old-style faked symlinks on Cygwin have the SYSTEM
attribute bit set, the new-style symlinks are actually Windows shortcuts
with the R/O attribute bit set.  So the code which tries to figure out
if a file is a symlink works basically like this:

  NtQueryAttributesFile ();
  if (attributes & FILE_ATTRIBUTE_SYSTEM)
    maybe_symlink = true;
  else if ((filename ends in ".lnk") && attributes & FILE_ATTRIBUTE_READONLY)
    maybe_symlink = true;
  if (maybe_symlink)
    {
      NtOpenFile();
      get_symlink_info();
      NtClose();
    }

Assuming we get only the EAs from Samba, we would have to open *every*
single file on Samba to retrieve EAs:

  else if (is_samba ())
    {
      NtOpenFile ();
      NtQueryEaFile ();
      if (has_symlink_ea)
        get_symlink_info();
      NtClose();
    }

I guess the performance hit would be a real show stopper.  What we need
is some way to retrieve file information without having to open the file
and to get a hint that this file might be a symlink.

Mulling about this problem, I stumbled over the NtQueryFullAttributesFile
function, which is the NT function retrieving the NT equivalent of the
SMB_FILE_NETWORK_OPEN_INFORMATION block.  It's the maximum amount of 
information available to a Windows client without opening a file.  The
structure consists of

  birthtime
  atime
  mtime
  ctime
  allocation_size
  file_size
  dos_attributes

Is it possible to sneak in the information that the file or dir is
actually a symlink into the above structure?

Two members of this structure are not used by Win32 clients, ctime and
allocation_size, because the Win32 equivalent of the
NtQueryFullAttributesFile function, GetFileAttributesEx, does not expose
them.  But ctime is retrieved by Cygwin as... ctime.

So, I had the following idea:  Since the allocation_size isn't used
anyway, what if it simply gets set to st_size?

This would be different from the allocation_size for directories (0)
as well as different from the allocation_size of files (st_size rounded
up to some blocksize value) most of the time.  That would allow Cygwin
to retrieve EAs only when it's really a symlink, in 99.9% of the cases.

Does that makes sense?


Thanks,
Corinna


More information about the samba-technical mailing list