ulinks.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. static bool UnixSymlink(CommandData *Cmd,const char *Target,const wchar *LinkName,RarTime *ftm,RarTime *fta)
  2. {
  3. CreatePath(LinkName,true,Cmd->DisableNames);
  4. // Overwrite prompt was already issued and confirmed earlier, so we can
  5. // remove existing symlink or regular file here. PrepareToDelete was also
  6. // called earlier inside of uiAskReplaceEx.
  7. DelFile(LinkName);
  8. char LinkNameA[NM];
  9. WideToChar(LinkName,LinkNameA,ASIZE(LinkNameA));
  10. if (symlink(Target,LinkNameA)==-1) // Error.
  11. {
  12. if (errno==EEXIST)
  13. uiMsg(UIERROR_ULINKEXIST,LinkName);
  14. else
  15. {
  16. uiMsg(UIERROR_SLINKCREATE,UINULL,LinkName);
  17. ErrHandler.SetErrorCode(RARX_WARNING);
  18. }
  19. return false;
  20. }
  21. #ifdef USE_LUTIMES
  22. #ifdef UNIX_TIME_NS
  23. timespec times[2];
  24. times[0].tv_sec=fta->GetUnix();
  25. times[0].tv_nsec=fta->IsSet() ? long(fta->GetUnixNS()%1000000000) : UTIME_NOW;
  26. times[1].tv_sec=ftm->GetUnix();
  27. times[1].tv_nsec=ftm->IsSet() ? long(ftm->GetUnixNS()%1000000000) : UTIME_NOW;
  28. utimensat(AT_FDCWD,LinkNameA,times,AT_SYMLINK_NOFOLLOW);
  29. #else
  30. struct timeval tv[2];
  31. tv[0].tv_sec=fta->GetUnix();
  32. tv[0].tv_usec=long(fta->GetUnixNS()%1000000000/1000);
  33. tv[1].tv_sec=ftm->GetUnix();
  34. tv[1].tv_usec=long(ftm->GetUnixNS()%1000000000/1000);
  35. lutimes(LinkNameA,tv);
  36. #endif
  37. #endif
  38. return true;
  39. }
  40. static bool IsFullPath(const char *PathA) // Unix ASCII version.
  41. {
  42. return *PathA==CPATHDIVIDER;
  43. }
  44. bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
  45. {
  46. char Target[NM];
  47. if (IsLink(Arc.FileHead.FileAttr))
  48. {
  49. size_t DataSize=(size_t)Arc.FileHead.PackSize;
  50. if (DataSize>ASIZE(Target)-1)
  51. return false;
  52. if ((size_t)DataIO.UnpRead((byte *)Target,DataSize)!=DataSize)
  53. return false;
  54. Target[DataSize]=0;
  55. DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,1);
  56. DataIO.UnpHash.Update(Target,strlen(Target));
  57. DataIO.UnpHash.Result(&Arc.FileHead.FileHash);
  58. // Return true in case of bad checksum, so link will be processed further
  59. // and extraction routine will report the checksum error.
  60. if (!DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL))
  61. return true;
  62. wchar TargetW[NM];
  63. CharToWide(Target,TargetW,ASIZE(TargetW));
  64. // Check for *TargetW==0 to catch CharToWide failure.
  65. // Use Arc.FileHead.FileName instead of LinkName, since LinkName
  66. // can include the destination path as a prefix, which can
  67. // confuse IsRelativeSymlinkSafe algorithm.
  68. if (!Cmd->AbsoluteLinks && (*TargetW==0 || IsFullPath(TargetW) ||
  69. !IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW)))
  70. return false;
  71. return UnixSymlink(Cmd,Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime);
  72. }
  73. return false;
  74. }
  75. bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd)
  76. {
  77. char Target[NM];
  78. WideToChar(hd->RedirName,Target,ASIZE(Target));
  79. if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_JUNCTION)
  80. {
  81. // Cannot create Windows absolute path symlinks in Unix. Only relative path
  82. // Windows symlinks can be created here. RAR 5.0 used \??\ prefix
  83. // for Windows absolute symlinks, since RAR 5.1 /??/ is used.
  84. // We escape ? as \? to avoid "trigraph" warning
  85. if (strncmp(Target,"\\??\\",4)==0 || strncmp(Target,"/\?\?/",4)==0)
  86. return false;
  87. DosSlashToUnix(Target,Target,ASIZE(Target));
  88. }
  89. // Use hd->FileName instead of LinkName, since LinkName can include
  90. // the destination path as a prefix, which can confuse
  91. // IsRelativeSymlinkSafe algorithm.
  92. if (!Cmd->AbsoluteLinks && (IsFullPath(Target) ||
  93. !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName)))
  94. return false;
  95. return UnixSymlink(Cmd,Target,Name,&hd->mtime,&hd->atime);
  96. }