libclamunrar/ulinks.cpp
01eebc13
 
 
 static bool UnixSymlink(const char *Target,const wchar *LinkName,RarTime *ftm,RarTime *fta)
 {
   CreatePath(LinkName,true);
   DelFile(LinkName);
   char LinkNameA[NM];
   WideToChar(LinkName,LinkNameA,ASIZE(LinkNameA));
   if (symlink(Target,LinkNameA)==-1) // Error.
   {
     if (errno==EEXIST)
       uiMsg(UIERROR_ULINKEXIST,LinkName);
     else
     {
       uiMsg(UIERROR_SLINKCREATE,UINULL,LinkName);
       ErrHandler.SetErrorCode(RARX_WARNING);
     }
     return false;
   }
 #ifdef USE_LUTIMES
 #ifdef UNIX_TIME_NS
   timespec times[2];
   times[0].tv_sec=fta->GetUnix();
   times[0].tv_nsec=fta->IsSet() ? long(fta->GetUnixNS()%1000000000) : UTIME_NOW;
   times[1].tv_sec=ftm->GetUnix();
   times[1].tv_nsec=ftm->IsSet() ? long(ftm->GetUnixNS()%1000000000) : UTIME_NOW;
   utimensat(AT_FDCWD,LinkNameA,times,AT_SYMLINK_NOFOLLOW);
 #else
   struct timeval tv[2];
   tv[0].tv_sec=fta->GetUnix();
   tv[0].tv_usec=long(fta->GetUnixNS()%1000000000/1000);
   tv[1].tv_sec=ftm->GetUnix();
   tv[1].tv_usec=long(ftm->GetUnixNS()%1000000000/1000);
   lutimes(LinkNameA,tv);
 #endif
 #endif
 
   return true;
 }
 
 
 static bool IsFullPath(const char *PathA) // Unix ASCII version.
 {
   return *PathA==CPATHDIVIDER;
 }
 
 
 bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
 {
   char Target[NM];
   if (IsLink(Arc.FileHead.FileAttr))
   {
     size_t DataSize=(size_t)Arc.FileHead.PackSize;
     if (DataSize>ASIZE(Target)-1)
       return false;
     if ((size_t)DataIO.UnpRead((byte *)Target,DataSize)!=DataSize)
       return false;
     Target[DataSize]=0;
 
     DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,1);
     DataIO.UnpHash.Update(Target,strlen(Target));
     DataIO.UnpHash.Result(&Arc.FileHead.FileHash);
 
     // Return true in case of bad checksum, so link will be processed further
     // and extraction routine will report the checksum error.
     if (!DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL))
       return true;
 
     wchar TargetW[NM];
     CharToWide(Target,TargetW,ASIZE(TargetW));
     // Check for *TargetW==0 to catch CharToWide failure.
     // Use Arc.FileHead.FileName instead of LinkName, since LinkName
     // can include the destination path as a prefix, which can
     // confuse IsRelativeSymlinkSafe algorithm.
     if (!Cmd->AbsoluteLinks && (*TargetW==0 || IsFullPath(TargetW) ||
         !IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW)))
       return false;
     return UnixSymlink(Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime);
   }
   return false;
 }
 
 
 bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd)
 {
   char Target[NM];
   WideToChar(hd->RedirName,Target,ASIZE(Target));
   if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_JUNCTION)
   {
     // Cannot create Windows absolute path symlinks in Unix. Only relative path
     // Windows symlinks can be created here. RAR 5.0 used \??\ prefix
     // for Windows absolute symlinks, since RAR 5.1 /??/ is used.
     // We escape ? as \? to avoid "trigraph" warning
     if (strncmp(Target,"\\??\\",4)==0 || strncmp(Target,"/\?\?/",4)==0)
       return false;
     DosSlashToUnix(Target,Target,ASIZE(Target));
   }
   // Use hd->FileName instead of LinkName, since LinkName can include
   // the destination path as a prefix, which can confuse
   // IsRelativeSymlinkSafe algorithm.
   if (!Cmd->AbsoluteLinks && (IsFullPath(Target) ||
       !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName)))
     return false;
   return UnixSymlink(Target,Name,&hd->mtime,&hd->atime);
 }