Main Page | File List | Globals

src/shortcut.cc

Go to the documentation of this file.
00001 /*
00002      This file is part of PlibC.
00003      (C) 2005 Nils Durner (and other contributing authors)
00004 
00005            This library is free software; you can redistribute it and/or
00006            modify it under the terms of the GNU Lesser General Public
00007            License as published by the Free Software Foundation; either
00008            version 2.1 of the License, or (at your option) any later version.
00009         
00010            This library is distributed in the hope that it will be useful,
00011            but WITHOUT ANY WARRANTY; without even the implied warranty of
00012            MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013            Lesser General Public License for more details.
00014         
00015            You should have received a copy of the GNU Lesser General Public
00016            License along with this library; if not, write to the Free Software
00017            Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 */
00019 
00025 #include "plibc_private.h"
00026 
00027 #include <shlobj.h>
00028 #include <objbase.h>
00029 
00030 extern "C" {
00031 
00032 BOOL _plibc_CreateShortcut(const char *pszSrc, const char *pszDest)
00033 {
00034     /* Create shortcut */
00035     IShellLink *pLink;
00036     IPersistFile *pFile;
00037     WCHAR *pwszDest;
00038     char *pszFileLnk;
00039     HRESULT hRes;
00040     
00041     CoInitialize(NULL);
00042     
00043     if ((strlen(pszSrc) > _MAX_PATH) || (strlen(pszDest) + 4 > _MAX_PATH))
00044     {
00045       CoUninitialize();
00046       errno = ENAMETOOLONG;
00047       
00048       return FALSE;
00049     }
00050     
00051     /* Create Shortcut-Object */
00052     if (CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
00053         IID_IShellLink, (void **) &pLink) != S_OK)
00054     {
00055       CoUninitialize();
00056       errno = ESTALE;
00057       
00058       return FALSE;
00059     }
00060   
00061     /* Set target path */
00062     pLink->SetPath(pszSrc);
00063   
00064     /* Get File-Object */
00065     if (pLink->QueryInterface(IID_IPersistFile, (void **) &pFile) != S_OK)
00066     {
00067       free(pwszDest);
00068       pLink->Release();
00069       CoUninitialize();
00070       errno = ESTALE;
00071      
00072       return FALSE;
00073     }
00074 
00075     /* shortcuts have the extension .lnk */
00076     pszFileLnk = (char *) malloc(strlen(pszDest) + 5);
00077     sprintf(pszFileLnk, "%s.lnk", pszDest);
00078   
00079     /* Turn filename into widechars */
00080     pwszDest = (WCHAR *) malloc((_MAX_PATH + 5) * sizeof(WCHAR));
00081     MultiByteToWideChar(CP_ACP, 0, pszFileLnk, -1, pwszDest, _MAX_PATH);
00082     
00083     free(pszFileLnk);
00084     
00085     /* Save shortcut */
00086     if (FAILED(hRes = pFile->Save((LPCOLESTR) pwszDest, TRUE)))
00087     {
00088       free(pwszDest);
00089       pLink->Release();
00090       pFile->Release();
00091       CoUninitialize();
00092       SetErrnoFromHRESULT(hRes);
00093   
00094       return FALSE;
00095     }
00096   
00097     free(pwszDest);
00098     
00099     pFile->Release();
00100     pLink->Release();
00101     CoUninitialize();
00102     errno = 0;
00103       
00104     return TRUE;
00105 }
00106 
00107 BOOL _plibc_DereferenceShortcut(char *pszShortcut)
00108 {
00109   IShellLink *pLink;
00110   IPersistFile *pFile;
00111   WCHAR *pwszShortcut;
00112   char *pszLnk;
00113   int iErr, iLen;
00114   HRESULT hRes;
00115   HANDLE hLink;
00116   char szTarget[_MAX_PATH + 1];
00117 
00118   if (! *pszShortcut)
00119     return TRUE;
00120 
00121   CoInitialize(NULL);
00122   szTarget[0] = 0;
00123   
00124   /* Create Shortcut-Object */
00125   if (CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
00126       IID_IShellLink, (void **) &pLink) != S_OK)
00127   {
00128     CoUninitialize();
00129     errno = ESTALE;
00130     
00131     return FALSE;
00132   }
00133 
00134   /* Get File-Object */
00135   if (pLink->QueryInterface(IID_IPersistFile, (void **) &pFile) != S_OK)
00136   {
00137     pLink->Release();
00138     CoUninitialize();
00139     errno = ESTALE;
00140     
00141     return FALSE;
00142   }
00143 
00144   pwszShortcut = (WCHAR *) malloc((_MAX_PATH + 1) * sizeof(WCHAR));
00145 
00146   /* Shortcuts have the extension .lnk
00147      If it isn't there, append it */
00148   iLen = strlen(pszShortcut);
00149   if (iLen > 4 && (strcmp(pszShortcut + iLen - 4, ".lnk") != 0))
00150   {
00151     HANDLE hLink;
00152     
00153     pszLnk = (char *) malloc(iLen + 5);
00154     sprintf(pszLnk, "%s.lnk", pszShortcut);
00155   }
00156   else
00157     pszLnk = strdup(pszShortcut);
00158 
00159   /* Make sure the path refers to a file */
00160   hLink = CreateFile(pszLnk, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
00161                    NULL, OPEN_EXISTING, 0, NULL);
00162   if (hLink == INVALID_HANDLE_VALUE)
00163   {
00164     free(pszLnk);
00165     SetErrnoFromWinError(GetLastError());
00166     
00167     if (errno == ENOENT)
00168     {
00169       /* There's no path with the ".lnk" extension.
00170          We don't quit here, because we have to decide whether the path doesn't
00171          exist or the path isn't a link. */
00172 
00173       /* Is it a directory? */
00174       if (GetFileAttributes(pszShortcut) & FILE_ATTRIBUTE_DIRECTORY)
00175       {
00176         errno = EINVAL;
00177         
00178         pLink->Release();
00179         pFile->Release();
00180         free(pwszShortcut);
00181         CoUninitialize();
00182         
00183         return FALSE;
00184       }
00185 
00186       pszLnk = strdup(pszShortcut);
00187       
00188       hLink = CreateFile(pszLnk, GENERIC_READ, FILE_SHARE_READ |
00189                 FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
00190       SetErrnoFromWinError(GetLastError());      
00191     }
00192     else
00193     {
00194       pLink->Release();
00195       pFile->Release();
00196       free(pwszShortcut);
00197       CoUninitialize();
00198       
00199       return FALSE; /* File/link is there but unaccessible */
00200     }
00201   }
00202     
00203   MultiByteToWideChar(CP_ACP, 0, pszLnk, -1, pwszShortcut, _MAX_PATH);
00204   
00205   /* Open shortcut */
00206   if (FAILED(hRes = pFile->Load((LPCOLESTR) pwszShortcut, STGM_READ)))
00207   {
00208     pLink->Release();
00209     pFile->Release();
00210     free(pwszShortcut);
00211     CoUninitialize();
00212     
00213     /* For some reason, opening an invalid link sometimes fails with ACCESSDENIED.
00214        Since we have opened the file previously, insufficient priviledges
00215        are rather not the problem. */
00216     if (hRes == E_FAIL || hRes == E_ACCESSDENIED)
00217     {
00218       /* Check file magic */
00219       if (hLink != INVALID_HANDLE_VALUE)
00220       {
00221         DWORD dwRead;
00222         char pMagic[4] = {0, 0, 0, 0};
00223         
00224         ReadFile(hLink, pMagic, 4, &dwRead, NULL);
00225         if (memcmp(pMagic, "L\0\0\0", 4) == 0)
00226           SetErrnoFromHRESULT(hRes);
00227         else
00228           errno = EINVAL; /* No link */
00229       }
00230       /* else: errno was set above! */
00231     }
00232     else
00233       SetErrnoFromHRESULT(hRes);
00234 
00235     free(pszLnk);
00236           
00237     CloseHandle(hLink);
00238     return FALSE;
00239   }
00240   
00241   CloseHandle(hLink);
00242   free(pszLnk);
00243   free(pwszShortcut);
00244   
00245   /* Get target file */
00246   if (FAILED(hRes = pLink->GetPath(szTarget, _MAX_PATH, NULL, 0)))
00247   {
00248     pLink->Release();
00249     pFile->Release();
00250     CoUninitialize();
00251     
00252     if (hRes == E_FAIL)
00253       errno = EINVAL; /* Not a symlink */
00254     else
00255       SetErrnoFromHRESULT(hRes);
00256     
00257     return FALSE;
00258   }
00259 
00260   pFile->Release();
00261   pLink->Release();
00262   CoUninitialize();
00263   errno = 0;
00264   
00265   if (szTarget[0] != 0)
00266   {
00267         strcpy(pszShortcut, szTarget);
00268         return TRUE;
00269   }
00270   else
00271   {
00272     /* GetPath() did not return a valid path */
00273     errno = EINVAL;
00274     return FALSE;
00275   }
00276 }
00277 
00281 int __win_deref(char *path)
00282 {
00283   int iDepth = 0;
00284 
00285   errno = 0;
00286 
00287   while (_plibc_DereferenceShortcut(path))
00288   {
00289     if (iDepth++ > 10)
00290     {
00291       errno = ELOOP;
00292       return -1;
00293     }
00294   }
00295 
00296   return errno ? -1 : 0;
00297 }
00298 
00299 } // extern "C"
00300 
00301 /* end of shortcut.cc */

Generated on Sun Sep 4 11:16:47 2005 for PlibC by  doxygen 1.4.2