Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » U++ Library support » U++ Core » Symlink/Shortcut support
Symlink/Shortcut support [message #24830] Mon, 01 February 2010 08:02 Go to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
Hello all

Now symlinks-shortcuts are supported in Core only in Linux with:
FindFile::IsSymLink();


It would be good to have a wider support in Linux and Windows.

The proposal is to add IsSymlink() for both OS and a new function like
bool GetSymLinkPath(const char *linkPath, String &filePath);
to get the real path of the symlink.

The implementation could be (some parts has been borrowed from U++):

bool IsSymLink(const char *path) {
#ifdef PLATFORM_WIN32	
	return GetFileExt(path) == ".lnk";
#else
	struct stat stf;
	lstat(path, &stf);
	return S_ISLNK(stf.st_mode);
#endif
}

bool GetSymLinkPath(const char *linkPath, String &filePath)
{
#ifdef PLATFORM_WIN32	
	HRESULT hres;
	IShellLink* psl;
	IPersistFile* ppf;
	CoInitialize(NULL);
	hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
	                        (PVOID *) &psl);
	if(SUCCEEDED(hres)) {
		hres = psl->QueryInterface(IID_IPersistFile, (PVOID *) &ppf);
		if(SUCCEEDED(hres)) {
			hres = ppf->Load(ToSystemCharsetW(linkPath), STGM_READ);
			if(SUCCEEDED(hres)) {
				char fileW[_MAX_PATH] = {0};
				psl->GetPath(fileW, _MAX_PATH, NULL, 0); 
				filePath = FromSystemCharset(fileW);
			} else
				return false;
			ppf->Release();
		} else
			return false;
		psl->Release();
	} else
		return false;
	CoUninitialize();
	return true;
#else
	char buff[_MAX_PATH + 1];
	bool ret;
	int len = readlink(linkPath, buff, _MAX_PATH);
	if (ret = (len > 0 && len < _MAX_PATH))
		buff[len] = '\0';
	else 
		*buff = '\0';
	filePath = buff;
	return ret;
#endif
}


Best regards
Iñaki
Re: Symlink/Shortcut support [message #24847 is a reply to message #24830] Mon, 01 February 2010 14:42 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
This sounds quite good. Before applying patch, however, I would like to hear more from others about the idea

	return GetFileExt(path) == ".lnk";


I am not quite convinced that file extension is equivalent to file flag.... (Maybe just give me a couple of hours to think about it Smile

Also, maybe GetSymLinkPath should simply return String and Null in the case of error?

Mirek



Re: Symlink/Shortcut support [message #24852 is a reply to message #24847] Mon, 01 February 2010 15:49 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
I am not quite convinced that file extension is equivalent to file flag.... (Maybe just give me a couple of hours to think about it Smile

Also, maybe GetSymLinkPath should simply return String and Null in the case of error?

Fully agree


Best regards
Iñaki
Re: Symlink/Shortcut support [message #24853 is a reply to message #24852] Mon, 01 February 2010 15:54 Go to previous messageGo to next message
cbpporter is currently offline  cbpporter
Messages: 1401
Registered: September 2007
Ultimate Contributor
koldo wrote on Mon, 01 February 2010 16:49

I am not quite convinced that file extension is equivalent to file flag.... (Maybe just give me a couple of hours to think about it Smile

Also, maybe GetSymLinkPath should simply return String and Null in the case of error?

Fully agree

Solution would be to load the .lnk file and see if has the correct format, like the UNIX "file" utility does for files, but I don't think we want to do that.
Re: Symlink/Shortcut support [message #24855 is a reply to message #24853] Mon, 01 February 2010 16:24 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
Quote:

Solution would be to load the .lnk file and see if has the correct format, like the UNIX "file" utility does for files, but I don't think we want to do that.
In fact this is done in function GetSymLinkPath.

However there is nothing for free... it would require a little time.


Best regards
Iñaki
Re: Symlink/Shortcut support [message #24860 is a reply to message #24830] Mon, 01 February 2010 21:40 Go to previous messageGo to next message
fudadmin is currently offline  fudadmin
Messages: 1321
Registered: November 2005
Location: Kaunas, Lithuania
Ultimate Contributor
Administrator
Hi guys, sorry for big breaks but life sometimes make crude corrections... But I've never stopped working on u++. Hopefully I'll to start posting my contributions if... ok, we will see. And, sorry, I've had symlink in my u++ version for windows for some time.
Some of my code if that helps:
bool FindFile::IsShellLinkDir() const //aris002 wrong name? tmp
{
	if (!GetName().EndsWith(".lnk")) //aris002 shell we check ext somewhere outside?
		return false;
//	char linkpath[MAX_PATH];
	LPCSTR linkpath=~path;
		LLOG("IsShellLinkDir getname="<<GetName());
	char szGotPath[MAX_PATH];
	char szDescription[MAX_PATH];
 //   WIN32_FIND_DATA wfd;
	HRESULT hres;
	IShellLink* psl;
	CoInitialize(NULL);
	hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
	                                 IID_IShellLink, (LPVOID *) &psl);
	if(SUCCEEDED(hres)) {
		IPersistFile* ppf;
		psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
		if(SUCCEEDED(hres)) {
			
			WCHAR szPath[_MAX_PATH] = { 0 };
			MultiByteToWideChar(CP_ACP, 0, linkpath, (int)strlen(linkpath), szPath, _MAX_PATH);
		//not correct? - might be links with diffrerent extensions
		//get shortcuts extension from registry? how?
			
			hres = ppf->Load(szPath, STGM_READ); //Load the shortcut.
			if (SUCCEEDED(hres)) {
			//	LLOG("ppf->Load ok!! "<<linkpath);
				hres = psl->GetPath((LPSTR)szGotPath, MAX_PATH,
				         NULL,  SLGP_UNCPRIORITY );
					LLOG("name "<<GetName()<<" target "<<szGotPath);
//				if(SUCCEEDED(hres))
//					LLOG("SUCCEEDED link ");
				ppf->Release();
			}
		psl->Release();
		}
	}

	CoUninitialize();
	if(SUCCEEDED(hres)) {
		LLOG("SUCCEEDED2 link ");
		return true;
	}
	else
		return false;
	//return SUCCEEDED(hres);
}



bool ResolveShellLink(const String& path, String& linked) //aris002 
{
//	char linkpath[MAX_PATH];
	LPCSTR linkpath=path;
	                   LLOG("IsShellLinkDir getname="<<path);
	char szGotPath[MAX_PATH];
	HRESULT hres;
	IShellLink* psl;
	CoInitialize(NULL);
	hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
	                                 IID_IShellLink, (LPVOID *) &psl);
	if(SUCCEEDED(hres)) {
		IPersistFile* ppf;
		psl->QueryInterface(IID_IPersistFile, (void**)&ppf);
		if(SUCCEEDED(hres)) {
			
			WCHAR szPath[_MAX_PATH] = { 0 };
			MultiByteToWideChar(CP_ACP, 0, linkpath, (int)strlen(linkpath), szPath, _MAX_PATH);
		//not correct? - might be links with diffrerent extensions
		//get shortcuts extension from registry? how?
			
			hres = ppf->Load(szPath, STGM_READ); //Load the shortcut.
			if (SUCCEEDED(hres)) {
			//	LLOG("ppf->Load ok!! "<<linkpath);
				hres = psl->GetPath((LPSTR)szGotPath, MAX_PATH,
				         NULL,  SLGP_UNCPRIORITY );
					LLOG("name "<<linkpath<<" target "<<szGotPath);
					linked=szGotPath;
//				if(SUCCEEDED(hres))
//					LLOG("SUCCEEDED link ");
				ppf->Release();
			}
		psl->Release();
		}
	}

	CoUninitialize();
	if(SUCCEEDED(hres)) {
		LLOG("SUCCEEDED2 RESOLVED link ");
		return true;
	}
	else
		return false;
	//return SUCCEEDED(hres);
}


they are not optimal and might need above or somewhere else switching off the check of target existance if I can remember.
Below the whole files attached.
P.S I've got also adapted for older version of FileSel for those with icon overlays. And, sorry i don't use svn because because that's too dificult for me, esp, merging.
Huge thanks to all of you!
  • Attachment: Path.h
    (Size: 8.85KB, Downloaded 295 times)
  • Attachment: Path.cpp
    (Size: 29.86KB, Downloaded 237 times)
Re: Symlink/Shortcut support [message #24861 is a reply to message #24860] Mon, 01 February 2010 22:29 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
fudadmin wrote on Mon, 01 February 2010 15:40

Hi guys, sorry for big breaks but life sometimes make crude corrections...



Oh, welcome back!

How long was that? Only 3 years? Smile

Mirek
Re: Symlink/Shortcut support [message #24938 is a reply to message #24830] Fri, 05 February 2010 10:22 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member

		hres = psl->QueryInterface(IID_IPersistFile, (PVOID *) &ppf);
		if(SUCCEEDED(hres)) {
			hres = ppf->Load(ToSystemCharsetW(linkPath), STGM_READ);
			if(SUCCEEDED(hres)) {
				char fileW[_MAX_PATH] = {0};
				psl->GetPath(fileW, _MAX_PATH, NULL, 0); 
				filePath = FromSystemCharset(fileW);
			} else
				return false;


Is not a memory leak there? Smile (no release for ppf upon return false).

Mirek
Re: Symlink/Shortcut support [message #24939 is a reply to message #24938] Fri, 05 February 2010 10:25 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Please check my altered version:

String GetSymLinkPath(const char *linkpath)
{
#ifdef PLATFORM_WIN32
	String path;
	HRESULT hres;
	IShellLink* psl;
	IPersistFile* ppf;
	CoInitialize(NULL);
	hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
	                        (PVOID *) &psl);
	if(SUCCEEDED(hres)) {
		hres = psl->QueryInterface(IID_IPersistFile, (PVOID *) &ppf);
		if(SUCCEEDED(hres)) {
			hres = ppf->Load(ToSystemCharsetW(linkPath), STGM_READ);
			if(SUCCEEDED(hres)) {
				char fileW[_MAX_PATH] = {0};
				psl->GetPath(fileW, _MAX_PATH, NULL, 0); 
				path = FromSystemCharset(fileW);
			}
			ppf->Release();
		}
		psl->Release();
	}
	CoUninitialize();
	return path;
#else
	char buff[_MAX_PATH + 1];
	bool ret;
	int len = readlink(linkPath, buff, _MAX_PATH);
	if(len > 0 && len < _MAX_PATH)
		return String(buff, len);
	return Null;
#endif
}



(now in U++, thanks).
Re: Symlink/Shortcut support [message #24941 is a reply to message #24939] Fri, 05 February 2010 11:42 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
Hello Mirek

Thanks. It works OK for me Smile

Please do not forget IsSymlink(). Fudamin way seems to be the most complete.


Best regards
Iñaki
Re: Symlink/Shortcut support [message #24966 is a reply to message #24941] Sat, 06 February 2010 12:49 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
koldo wrote on Fri, 05 February 2010 05:42

Hello Mirek

Thanks. It works OK for me Smile

Please do not forget IsSymlink(). Fudamin way seems to be the most complete.


What about to recycle GetSymLinkPath there?

Mirek
Re: Symlink/Shortcut support [message #24967 is a reply to message #24966] Sat, 06 February 2010 13:20 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Like this:

bool FindFile::IsSymLink() const
{
	String name = GetName();
	if(GetFileExt(name) != ".lnk")
		return false;
	return !IsNull(GetSymLinkPath(AppendFileName(path, name)));
}


Mirek
Re: Symlink/Shortcut support [message #24971 is a reply to message #24967] Sat, 06 February 2010 14:30 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
luzr wrote on Sat, 06 February 2010 13:20

Like this:

bool FindFile::IsSymLink() const
{
	String name = GetName();
	if(GetFileExt(name) != ".lnk")
		return false;
	return !IsNull(GetSymLinkPath(AppendFileName(path, name)));
}


Mirek

Well. It is not the most efficient possible but it is very valid.


Best regards
Iñaki
Re: Symlink/Shortcut support [message #24976 is a reply to message #24971] Sat, 06 February 2010 19:40 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
koldo wrote on Sat, 06 February 2010 08:30

luzr wrote on Sat, 06 February 2010 13:20

Like this:

bool FindFile::IsSymLink() const
{
	String name = GetName();
	if(GetFileExt(name) != ".lnk")
		return false;
	return !IsNull(GetSymLinkPath(AppendFileName(path, name)));
}


Mirek

Well. It is not the most efficient possible but it is very valid.


Why? System calls appear to be equivalent for the test and for obtaining the path.

Mirek
Re: Symlink/Shortcut support [message #24995 is a reply to message #24976] Sat, 06 February 2010 23:13 Go to previous messageGo to next message
koldo is currently offline  koldo
Messages: 3357
Registered: August 2008
Senior Veteran
luzr wrote on Sat, 06 February 2010 19:40

koldo wrote on Sat, 06 February 2010 08:30

luzr wrote on Sat, 06 February 2010 13:20

Like this:

bool FindFile::IsSymLink() const
{
	String name = GetName();
	if(GetFileExt(name) != ".lnk")
		return false;
	return !IsNull(GetSymLinkPath(AppendFileName(path, name)));
}


Mirek

Well. It is not the most efficient possible but it is very valid.


Why? System calls appear to be equivalent for the test and for obtaining the path.

Mirek

Hello Mirek

Being punctilious Smile these is not necessary:

char fileW[_MAX_PATH] = {0};
psl->GetPath(fileW, _MAX_PATH, NULL, 0); 
path = FromSystemCharset(fileW);




Best regards
Iñaki
Re: Symlink/Shortcut support [message #24997 is a reply to message #24995] Sat, 06 February 2010 23:19 Go to previous messageGo to next message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
koldo wrote on Sat, 06 February 2010 17:13

luzr wrote on Sat, 06 February 2010 19:40

koldo wrote on Sat, 06 February 2010 08:30

luzr wrote on Sat, 06 February 2010 13:20

Like this:

bool FindFile::IsSymLink() const
{
	String name = GetName();
	if(GetFileExt(name) != ".lnk")
		return false;
	return !IsNull(GetSymLinkPath(AppendFileName(path, name)));
}


Mirek

Well. It is not the most efficient possible but it is very valid.


Why? System calls appear to be equivalent for the test and for obtaining the path.

Mirek

Hello Mirek

Being punctilious Smile these is not necessary:

char fileW[_MAX_PATH] = {0};
psl->GetPath(fileW, _MAX_PATH, NULL, 0); 
path = FromSystemCharset(fileW);





I have to admit I have only considered fudadmin code.

OK, I will change it...

Mirek
Re: Symlink/Shortcut support [message #24998 is a reply to message #24997] Sat, 06 February 2010 23:26 Go to previous message
mirek is currently offline  mirek
Messages: 13975
Registered: November 2005
Ultimate Member
Optimized.

Btw, uppdev/SymLinkTest used for developing this..
Previous Topic: T* Detach() for ArrayMap
Next Topic: XmlParser patch
Goto Forum:
  


Current Time: Fri Apr 26 15:11:11 CEST 2024

Total time taken to generate the page: 0.02650 seconds