Support Win32 Symbolic Links when indexing share

Bug #653295 reported by eMTee
10
This bug affects 1 person
Affects Status Importance Assigned to Milestone
DC++
Confirmed
Low
Unassigned

Bug Description

I want to share a directory which contains a number of files linked to via symbolic links (http://msdn.microsoft.com/en-us/library/aa365680%28VS.85%29.aspx). However the index/hashing thing seems to fail, skip, or otherwise just not work on large numbers of the files. The files physical locations the links target are spread across a number of physical locations (including some shared network locations) and also includes some personal files in the same directory (hence sym linking the files I want and not sharing the directory) that I do not wish to share.

Is there anything I can do about this? Symbolic links are supposed to be a file system feature and transparent so I don't really see why this is failing to work :(

Tags: core
Revision history for this message
eMTee (realprogger) wrote :

The answer is probably in the next page of your linked document (http://msdn.microsoft.com/en-us/library/aa365682%28v=VS.85%29.aspx).
What behaviour is written there for FindFirstFile, FindFirstFileEx, FindNextFile and the WIN32_FIND_DATA structure pointing to symlinks says the opposite than you claiming that 'Symbolic links are supposed to be a file system feature and transparent'.

Anyway, DC++ uses these functions for indexing and the code most probably does not handle the situation when symlinks returned in WIN32_FIND_DATA.

Revision history for this message
William Newbery (wn00009) wrote :

hmm, ok, perhaps not 100% transparent, always done what i expected before though...guess the library i used at the time did something for me I didn't know about.

So Im guessing then it just needs code adding to handle them in whichever bit of code makes the "list" of files to hash/index?

I could grab the current source and take a look at changing it if I know where to look (perhaps a "MakeFileList" in "windows/filesystem.cpp", not sure its that easy but you get the idea :) ) and submit the a patch, or at the very least get my copy to do what I want :)

Revision history for this message
eMTee (realprogger) wrote :

After your report I tried to check what'd need to follow symlinks, it'd need modifications in the FileFindIter class in dcpp/File.cpp and in the ShareManager::buildTree function. There are clear examples in the net about how to detect a symlink but it wasn't clear to me how to follow them (getting the real path the link points to).
Good luck :)

Changed in dcplusplus:
status: New → Confirmed
importance: Undecided → Low
Revision history for this message
William Newbery (wn00009) wrote :

Directory symbolic link already work fine so I will leave those alone. Not tested hardlinks or junctions, but I think they should work.

I came up with a solution (not fully tested yet). Its not a very clean solution, since it basically exploits the fact that CreateFile will resolve the reprase points, and then I can use the resulting file HANDLE to pull other data about the file (eg the actual path using GetFinalPathNameByHandle).

The basic concept is to have the following function that is called everytime the iterator gets a new file to overwrite some of the fields in the data struct, and also store a full path to the target file (which can then be used elsewhere as needed).

void FileFindIter::updateData()
{
 //only file symbolic links, not any other type
 if(!data.isDirectory() && (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (data.dwReserved0 & IO_REPARSE_TAG_SYMLINK))
 {
  //todo, error check. This may fail if the links target can not be accessed for some reason (eg simply doesnt exist).
  HANDLE file = CreateFileW((Text::toT(parentDir) + data.cFileName).c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
  //path
  char path[MAX_PATH];
  GetFinalPathNameByHandleA(file, path, MAX_PATH, FILE_NAME_NORMALIZED);
  data.linkTargetPath = path;
  //size
  data.nFileSizeLow = GetFileSize(file, &data.nFileSizeHigh);
                //time
  GetFileTime(file, &data.ftCreationTime, &data.ftLastAccessTime, &data.ftLastWriteTime);
  //done
  CloseHandle(file);
 }
}

It seems to work, although I need todo a major cleanup of a bunch of stuff I left lying around, and am not really sure this is an acceptable solution.

Revision history for this message
eMTee (realprogger) wrote :

Probably its an acceptable solution, you can find info on some websites describing this techinque as a possible solution (without any actual implementation though). If you can come up with a complete tested patch that integrate this to FileFindIter class and ShareManager::buildTree, that'd possibly be accepted.

Fredrik Ullner (ullner)
tags: added: core
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Related questions

Remote bug watches

Bug watches keep track of this bug in other bug trackers.