"Fossies" - the Fresh Open Source Software Archive

Member "unrar/win32lnk.cpp" (4 May 2022, 6505 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "win32lnk.cpp" see the Fossies "Dox" file reference documentation.

    1 #define SYMLINK_FLAG_RELATIVE 1
    2 
    3 typedef struct _REPARSE_DATA_BUFFER {
    4   ULONG  ReparseTag;
    5   USHORT ReparseDataLength;
    6   USHORT Reserved;
    7   union {
    8     struct {
    9       USHORT SubstituteNameOffset;
   10       USHORT SubstituteNameLength;
   11       USHORT PrintNameOffset;
   12       USHORT PrintNameLength;
   13       ULONG  Flags;
   14       WCHAR  PathBuffer[1];
   15     } SymbolicLinkReparseBuffer;
   16     struct {
   17       USHORT SubstituteNameOffset;
   18       USHORT SubstituteNameLength;
   19       USHORT PrintNameOffset;
   20       USHORT PrintNameLength;
   21       WCHAR  PathBuffer[1];
   22     } MountPointReparseBuffer;
   23     struct {
   24       UCHAR DataBuffer[1];
   25     } GenericReparseBuffer;
   26   };
   27 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
   28 
   29 
   30 
   31 
   32 bool CreateReparsePoint(CommandData *Cmd,const wchar *Name,FileHeader *hd)
   33 {
   34   static bool PrivSet=false;
   35   if (!PrivSet)
   36   {
   37     SetPrivilege(SE_RESTORE_NAME);
   38     // Not sure if we really need it, but let's request anyway.
   39     SetPrivilege(SE_CREATE_SYMBOLIC_LINK_NAME);
   40     PrivSet=true;
   41   }
   42 
   43   const DWORD BufSize=sizeof(REPARSE_DATA_BUFFER)+2*NM+1024;
   44   Array<byte> Buf(BufSize);
   45   REPARSE_DATA_BUFFER *rdb=(REPARSE_DATA_BUFFER *)&Buf[0];
   46 
   47   wchar SubstName[NM];
   48   wcsncpyz(SubstName,hd->RedirName,ASIZE(SubstName));
   49   size_t SubstLength=wcslen(SubstName);
   50 
   51   wchar PrintName[NM],*PrintNameSrc=SubstName,*PrintNameDst=PrintName;
   52   bool WinPrefix=wcsncmp(PrintNameSrc,L"\\??\\",4)==0;
   53   if (WinPrefix)
   54     PrintNameSrc+=4;
   55   if (WinPrefix && wcsncmp(PrintNameSrc,L"UNC\\",4)==0)
   56   {
   57     *(PrintNameDst++)='\\'; // Insert second \ in beginning of share name.
   58     PrintNameSrc+=3;
   59   }
   60   wcscpy(PrintNameDst,PrintNameSrc);
   61 
   62   size_t PrintLength=wcslen(PrintName);
   63 
   64   bool AbsPath=WinPrefix;
   65   // IsFullPath is not really needed here, AbsPath check is enough.
   66   // We added it just for extra safety, in case some Windows version would
   67   // allow to create absolute targets with SYMLINK_FLAG_RELATIVE.
   68   // Use hd->FileName instead of Name, since Name can include the destination
   69   // path as a prefix, which can confuse IsRelativeSymlinkSafe algorithm.
   70   if (!Cmd->AbsoluteLinks && (AbsPath || IsFullPath(hd->RedirName) ||
   71       !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName)))
   72     return false;
   73 
   74   CreatePath(Name,true,Cmd->DisableNames);
   75 
   76   // Overwrite prompt was already issued and confirmed earlier, so we can
   77   // remove existing symlink or regular file here. PrepareToDelete was also
   78   // called earlier inside of uiAskReplaceEx.
   79   if (FileExist(Name))
   80     if (IsDir(GetFileAttr(Name)))
   81       DelDir(Name);
   82     else
   83       DelFile(Name);
   84 
   85   // 'DirTarget' check is important for Unix symlinks to directories.
   86   // Unix symlinks do not have their own 'directory' attribute.
   87   if (hd->Dir || hd->DirTarget)
   88   {
   89     if (!CreateDirectory(Name,NULL))
   90     {
   91       uiMsg(UIERROR_DIRCREATE,UINULL,Name);
   92       ErrHandler.SetErrorCode(RARX_CREATE);
   93       return false;
   94     }
   95   }
   96   else
   97   {
   98     HANDLE hFile=CreateFile(Name,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
   99     if (hFile == INVALID_HANDLE_VALUE)
  100     {
  101       ErrHandler.CreateErrorMsg(Name);
  102       return false;
  103     }
  104     CloseHandle(hFile);
  105   }
  106 
  107 
  108   if (hd->RedirType==FSREDIR_JUNCTION)
  109   {
  110     rdb->ReparseTag=IO_REPARSE_TAG_MOUNT_POINT;
  111     rdb->ReparseDataLength=USHORT(
  112       sizeof(rdb->MountPointReparseBuffer.SubstituteNameOffset)+
  113       sizeof(rdb->MountPointReparseBuffer.SubstituteNameLength)+
  114       sizeof(rdb->MountPointReparseBuffer.PrintNameOffset)+
  115       sizeof(rdb->MountPointReparseBuffer.PrintNameLength)+
  116       (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR));
  117     rdb->Reserved=0;
  118 
  119     rdb->MountPointReparseBuffer.SubstituteNameOffset=0;
  120     rdb->MountPointReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR));
  121     wcscpy(rdb->MountPointReparseBuffer.PathBuffer,SubstName);
  122 
  123     rdb->MountPointReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR));
  124     rdb->MountPointReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR));
  125     wcscpy(rdb->MountPointReparseBuffer.PathBuffer+SubstLength+1,PrintName);
  126   }
  127   else
  128     if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_UNIXSYMLINK)
  129     {
  130       rdb->ReparseTag=IO_REPARSE_TAG_SYMLINK;
  131       rdb->ReparseDataLength=USHORT(
  132         sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset)+
  133         sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameLength)+
  134         sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameOffset)+
  135         sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameLength)+
  136         sizeof(rdb->SymbolicLinkReparseBuffer.Flags)+
  137         (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR));
  138       rdb->Reserved=0;
  139 
  140       rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset=0;
  141       rdb->SymbolicLinkReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR));
  142       wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer,SubstName);
  143 
  144       rdb->SymbolicLinkReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR));
  145       rdb->SymbolicLinkReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR));
  146       wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer+SubstLength+1,PrintName);
  147 
  148       rdb->SymbolicLinkReparseBuffer.Flags=AbsPath ? 0:SYMLINK_FLAG_RELATIVE;
  149     }
  150     else
  151       return false;
  152 
  153   HANDLE hFile=CreateFile(Name,GENERIC_READ|GENERIC_WRITE,0,NULL,
  154                OPEN_EXISTING,FILE_FLAG_OPEN_REPARSE_POINT| 
  155                FILE_FLAG_BACKUP_SEMANTICS,NULL);
  156   if (hFile==INVALID_HANDLE_VALUE)
  157   {
  158     ErrHandler.CreateErrorMsg(Name);
  159     ErrHandler.SetErrorCode(RARX_CREATE);
  160     return false;
  161   }
  162 
  163   DWORD Returned;
  164   if (!DeviceIoControl(hFile,FSCTL_SET_REPARSE_POINT,rdb, 
  165       FIELD_OFFSET(REPARSE_DATA_BUFFER,GenericReparseBuffer)+
  166       rdb->ReparseDataLength,NULL,0,&Returned,NULL))
  167   { 
  168     CloseHandle(hFile);
  169     uiMsg(UIERROR_SLINKCREATE,UINULL,Name);
  170 
  171     DWORD LastError=GetLastError();
  172     if ((LastError==ERROR_ACCESS_DENIED || LastError==ERROR_PRIVILEGE_NOT_HELD) &&
  173         !IsUserAdmin())
  174       uiMsg(UIERROR_NEEDADMIN);
  175     ErrHandler.SysErrMsg();
  176     ErrHandler.SetErrorCode(RARX_CREATE);
  177 
  178     if (hd->Dir)
  179       RemoveDirectory(Name);
  180     else
  181       DeleteFile(Name);
  182     return false;
  183   }
  184   File LinkFile;
  185   LinkFile.SetHandle(hFile);
  186   LinkFile.SetOpenFileTime(
  187     Cmd->xmtime==EXTTIME_NONE ? NULL:&hd->mtime,
  188     Cmd->xctime==EXTTIME_NONE ? NULL:&hd->ctime,
  189     Cmd->xatime==EXTTIME_NONE ? NULL:&hd->atime);
  190   LinkFile.Close();
  191   if (!Cmd->IgnoreGeneralAttr)
  192     SetFileAttr(Name,hd->FileAttr);
  193   return true;
  194 }