Example #1
0
bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize)
{
  wchar NewName[NM];
  size_t NameLength=wcslen(Name);
#ifdef _ANDROID
  if (NameLength>ASIZE(NewName)-10)
    return false;
#endif
  wchar *Ext=GetExt(Name);
  if (Ext==NULL)
    Ext=Name+NameLength;
  for (uint FileVer=1;;FileVer++)
  {
#ifdef _ANDROID // No swprintf in Android NDK r9.
    uint NamePrefixLength=Ext-Name;
    wcsncpy(NewName,Name,NamePrefixLength);
    wcscpy(NewName+NamePrefixLength,L"(");
    itoa(FileVer,NewName+NamePrefixLength+1,ASIZE(NewName)-NamePrefixLength-1);
    wcsncatz(NewName,L")",ASIZE(NewName));
    wcsncatz(NewName,Ext,ASIZE(NewName));
#else
    swprintf(NewName,ASIZE(NewName),L"%.*ls(%u)%ls",uint(Ext-Name),Name,FileVer,Ext);
#endif
    if (!FileExist(NewName))
    {
      wcsncpyz(Name,NewName,MaxNameSize);
      break;
    }
    if (FileVer>=1000000)
      return false;
  }
  return true;
}
Example #2
0
bool ScanTree::GetNextMask()
{
  if (!GetFilteredMask())
    return false;
#ifdef _WIN_ALL
  UnixSlashToDos(CurMask,CurMask,ASIZE(CurMask));
#endif

  // We wish to scan entire disk if mask like c:\ is specified
  // regardless of recursion mode. Use c:\*.* mask when need to scan only 
  // the root directory.
  ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0;

  wchar *Name=PointToName(CurMask);
  if (*Name==0)
    wcsncatz(CurMask,MASKALL,ASIZE(CurMask));
  if (Name[0]=='.' && (Name[1]==0 || Name[1]=='.' && Name[2]==0))
  {
    AddEndSlash(CurMask,ASIZE(CurMask));
    wcsncatz(CurMask,MASKALL,ASIZE(CurMask));
  }
  SpecPathLength=Name-CurMask;
  Depth=0;

  wcsncpyz(OrigCurMask,CurMask,ASIZE(OrigCurMask));

  return true;
}
Example #3
0
void CommandData::ProcessCommand()
{
#ifndef SFX_MODULE

  const wchar *SingleCharCommands=L"FUADPXETK";
  if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || *ArcName==0)
    OutHelp(*Command==0 ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters.

#ifdef _UNIX
  if (GetExt(ArcName)==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
    wcsncatz(ArcName,L".rar",ASIZE(ArcName));
#else
  if (GetExt(ArcName)==NULL)
    wcsncatz(ArcName,L".rar",ASIZE(ArcName));
#endif

  if (wcschr(L"AFUMD",*Command)==NULL)
  {
    if (GenerateArcName)
      GenerateArchiveName(ArcName,ASIZE(ArcName),GenerateMask,false);

    StringList ArcMasks;
    ArcMasks.AddString(ArcName);
    ScanTree Scan(&ArcMasks,Recurse,SaveSymLinks,SCAN_SKIPDIRS);
    FindData FindData;
    while (Scan.GetNext(&FindData)==SCAN_SUCCESS)
      AddArcName(FindData.Name);
  }
  else
    AddArcName(ArcName);
#endif

  switch(Command[0])
  {
    case 'P':
    case 'X':
    case 'E':
    case 'T':
    case 'I':
      {
        CmdExtract Extract(this);
        Extract.DoExtract();
      }
      break;
#ifndef SILENT
    case 'V':
    case 'L':
      ListArchive(this);
      break;
    default:
      OutHelp(RARX_USERERROR);
#endif
  }
  if (!BareOutput)
    mprintf(L"\n");
}
Example #4
0
void SetExt(wchar *Name,const wchar *NewExt,size_t MaxSize)
{
  if (Name==NULL || *Name==0)
    return;
  wchar *Dot=GetExt(Name);
  if (Dot!=NULL)
    *Dot=0;
  if (NewExt!=NULL)
  {
    wcsncatz(Name,L".",MaxSize);
    wcsncatz(Name,NewExt,MaxSize);
  }
}
Example #5
0
// We should return 'true' even if resulting path is shorter than MAX_PATH,
// because we can also use this function to open files with non-standard
// characters, even if their path length is normal.
bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
{
  const wchar *Prefix=L"\\\\?\\";
  const size_t PrefixLength=4;
  bool FullPath=IsDiskLetter(Src) && IsPathDiv(Src[2]);
  size_t SrcLength=wcslen(Src);
  if (IsFullPath(Src)) // Paths in d:\path\name format.
  {
    if (IsDiskLetter(Src))
    {
      if (MaxSize<=PrefixLength+SrcLength)
        return false;
      wcsncpy(Dest,Prefix,PrefixLength);
      wcscpy(Dest+PrefixLength,Src);
      return true;
    }
    else
      if (Src[0]=='\\' && Src[1]=='\\')
      {
        if (MaxSize<=PrefixLength+SrcLength+2)
          return false;
        wcsncpy(Dest,Prefix,PrefixLength);
        wcscpy(Dest+PrefixLength,L"UNC");
        wcscpy(Dest+PrefixLength+3,Src+1);
        return true;
      }
    // We may be here only if we modify IsFullPath in the future.
    return false;
  }
  else
  {
    wchar CurDir[NM];
    DWORD DirCode=GetCurrentDirectory(ASIZE(CurDir)-1,CurDir);
    if (DirCode==0 || DirCode>ASIZE(CurDir)-1)
      return false;

    if (IsPathDiv(Src[0])) // Paths in \path\name format.
    {
      if (MaxSize<=PrefixLength+SrcLength+2)
        return false;
      wcsncpy(Dest,Prefix,PrefixLength);
      wcsncpy(Dest+PrefixLength,CurDir,2); // Copy drive letter 'd:'.
      wcscpy(Dest+PrefixLength+2,Src);
      return true;
    }
    else  // Paths in path\name format.
    {
      AddEndSlash(CurDir,ASIZE(CurDir));
      if (MaxSize<=PrefixLength+wcslen(CurDir)+SrcLength)
        return false;
      wcsncpy(Dest,Prefix,PrefixLength);
      wcscpy(Dest+PrefixLength,CurDir);
      wcsncatz(Dest,Src,MaxSize);
      return true;
    }
  }
  return false;
}
Example #6
0
void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize)
{
  // 'Name' and 'Pathname' can point to same memory area. This is why we use
  // the temporary buffer instead of constructing the name in 'Pathname'.
  wchar OutName[NM];
  wcsncpyz(OutName,Path,ASIZE(OutName));
  AddEndSlash(OutName,ASIZE(OutName));
  wcsncatz(OutName,Name,ASIZE(OutName));
  wcsncpyz(Pathname,OutName,MaxSize);
}
Example #7
0
void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckExist,bool Create)
{
  *FullName=0;
  for (uint I=0;EnumConfigPaths(I,FullName,MaxSize,Create);I++)
  {
    AddEndSlash(FullName,MaxSize);
    wcsncatz(FullName,Name,MaxSize);
    if (!CheckExist || WildFileExist(FullName))
      break;
  }
}
Example #8
0
void CommandData::OutTitle()
{
  if (BareOutput || DisableCopyright)
    return;
#if defined(__GNUC__) && defined(SFX_MODULE)
  mprintf(St(MCopyrightS));
#else
#ifndef SILENT
  static bool TitleShown=false;
  if (TitleShown)
    return;
  TitleShown=true;

  wchar Version[80];
  if (RARVER_BETA!=0)
    swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
  else
    swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
#if defined(_WIN_32) || defined(_WIN_64)
  wcsncatz(Version,L" ",ASIZE(Version));
#endif
#ifdef _WIN_32
  wcsncatz(Version,St(Mx86),ASIZE(Version));
#endif
#ifdef _WIN_64
  wcsncatz(Version,St(Mx64),ASIZE(Version));
#endif
  if (PrintVersion)
  {
    mprintf(L"%s",Version);
    exit(0);
  }
#ifdef UNRAR
  mprintf(St(MUCopyright),Version,RARVER_YEAR);
#else
#endif
#endif
#endif
}
Example #9
0
void ExtractStreams(Archive &Arc,const wchar *FileName,bool TestMode)
{
  wchar FullName[NM+2];
  if (FileName[0]!=0 && FileName[1]==0)
  {
    wcscpy(FullName,L".\\");
    wcsncpyz(FullName+2,FileName,ASIZE(FullName)-2);
  }
  else
    wcsncpyz(FullName,FileName,ASIZE(FullName));

  byte *Data=&Arc.SubHead.SubData[0];
  size_t DataSize=Arc.SubHead.SubData.Size();

  wchar StreamName[NM];
  GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName));
  if (*StreamName!=':')
  {
    uiMsg(UIERROR_STREAMBROKEN,Arc.FileName,FileName);
    ErrHandler.SetErrorCode(RARX_CRC);
    return;
  }

  if (TestMode)
  {
    Arc.ReadSubData(NULL,NULL);
    return;
  }

  wcsncatz(FullName,StreamName,ASIZE(FullName));

  FindData fd;
  bool Found=FindFile::FastFind(FileName,&fd);

  if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0)
    SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY);
  File CurFile;
  if (CurFile.WCreate(FullName) && Arc.ReadSubData(NULL,&CurFile))
    CurFile.Close();
  File HostFile;
  if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE))
    SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime,
                &fd.ftLastWriteTime);

  // Restoring original file attributes. Important if file was read only
  // or did not have "Archive" attribute
  SetFileAttr(FileName,fd.FileAttr);
}
Example #10
0
void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
{
  wchar *ChPtr;
  if ((ChPtr=GetExt(ArcName))==NULL)
  {
    wcsncatz(ArcName,L".rar",MaxLength);
    ChPtr=GetExt(ArcName);
  }
  else
    if (ChPtr[1]==0 && wcslen(ArcName)<MaxLength-3 || wcsicomp(ChPtr+1,L"exe")==0 || wcsicomp(ChPtr+1,L"sfx")==0)
      wcscpy(ChPtr+1,L"rar");
  if (!OldNumbering)
  {
    ChPtr=GetVolNumPart(ArcName);

    while ((++(*ChPtr))=='9'+1)
    {
      *ChPtr='0';
      ChPtr--;
      if (ChPtr<ArcName || !IsDigit(*ChPtr))
      {
        for (wchar *EndPtr=ArcName+wcslen(ArcName);EndPtr!=ChPtr;EndPtr--)
          *(EndPtr+1)=*EndPtr;
        *(ChPtr+1)='1';
        break;
      }
    }
  }
  else
    if (!IsDigit(*(ChPtr+2)) || !IsDigit(*(ChPtr+3)))
      wcscpy(ChPtr+2,L"00");
    else
    {
      ChPtr+=3;
      while ((++(*ChPtr))=='9'+1)
        if (*(ChPtr-1)=='.')
        {
          *ChPtr='A';
          break;
        }
        else
        {
          *ChPtr='0';
          ChPtr--;
        }
    }
}
Example #11
0
// For masks like dir1\dir2*\*.ext in non-recursive mode.
bool ScanTree::ExpandFolderMask()
{
  bool WildcardFound=false;
  uint SlashPos=0;
  for (int I=0;CurMask[I]!=0;I++)
  {
    if (CurMask[I]=='?' || CurMask[I]=='*')
      WildcardFound=true;
    if (WildcardFound && IsPathDiv(CurMask[I]))
    {
      // First path separator position after folder wildcard mask.
      // In case of dir1\dir2*\dir3\name.ext mask it may point not to file
      // name, so we cannot use PointToName() here.
      SlashPos=I; 
      break;
    }
  }

  wchar Mask[NM];
  wcsncpyz(Mask,CurMask,ASIZE(Mask));
  Mask[SlashPos]=0;

  // Prepare the list of all folders matching the wildcard mask.
  ExpandedFolderList.Reset();
  FindFile Find;
  Find.SetMask(Mask);
  FindData FD;
  while (Find.Next(&FD))
    if (FD.IsDir)
    {
      wcsncatz(FD.Name,CurMask+SlashPos,ASIZE(FD.Name));

      // Treat dir*\* or dir*\*.* as dir, so empty 'dir' is also matched
      // by such mask. Skipping empty dir with dir*\*.* confused some users.
      wchar *LastMask=PointToName(FD.Name);
      if (wcscmp(LastMask,L"*")==0 || wcscmp(LastMask,L"*.*")==0)
        RemoveNameFromPath(FD.Name);

      ExpandedFolderList.AddString(FD.Name);
    }
  if (ExpandedFolderList.ItemsCount()==0)
    return false;
  // Return the first matching folder name now.
  ExpandedFolderList.GetString(CurMask,ASIZE(CurMask));
  return true;
}
Example #12
0
bool GetAppDataPath(wchar *Path,size_t MaxSize,bool Create)
{
  LPMALLOC g_pMalloc;
  SHGetMalloc(&g_pMalloc);
  LPITEMIDLIST ppidl;
  *Path=0;
  bool Success=false;
  if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR &&
      SHGetPathFromIDList(ppidl,Path) && *Path!=0)
  {
    AddEndSlash(Path,MaxSize);
    wcsncatz(Path,L"WinRAR",MaxSize);
    Success=FileExist(Path);
    if (!Success && Create)
      Success=MakeDir(Path,false,0)==MKDIR_SUCCESS;
  }
  g_pMalloc->Free(ppidl);
  return Success;
}
Example #13
0
static void GetAppDataPath(wchar *Path,size_t MaxSize)
{
  LPMALLOC g_pMalloc;
  SHGetMalloc(&g_pMalloc);
  LPITEMIDLIST ppidl;
  *Path=0;
  bool Success=false;
  if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR &&
      SHGetPathFromIDList(ppidl,Path) && *Path!=0)
  {
    AddEndSlash(Path,MaxSize);
    wcsncatz(Path,L"WinRAR",MaxSize);
    Success=FileExist(Path) || MakeDir(Path,false,0)==MKDIR_SUCCESS;
  }
  if (!Success)
  {
    GetModuleFileName(NULL,Path,(DWORD)MaxSize);
    RemoveNameFromPath(Path);
  }
  g_pMalloc->Free(ppidl);
}
Example #14
0
void ConvertNameToFull(const wchar *Src,wchar *Dest,size_t MaxSize)
{
  if (Src==NULL || *Src==0)
  {
    if (MaxSize>0)
      *Dest=0;
    return;
  }
#ifdef _WIN_ALL
  {
    wchar FullName[NM],*NamePtr;
    DWORD Code=GetFullPathName(Src,ASIZE(FullName),FullName,&NamePtr);
    if (Code==0 || Code>ASIZE(FullName))
    {
      wchar LongName[NM];
      if (GetWinLongPath(Src,LongName,ASIZE(LongName)))
        Code=GetFullPathName(LongName,ASIZE(FullName),FullName,&NamePtr);
    }
    if (Code!=0 && Code<ASIZE(FullName))
      wcsncpyz(Dest,FullName,MaxSize);
    else
      if (Src!=Dest)
        wcsncpyz(Dest,Src,MaxSize);
  }
#elif defined(_UNIX)
  if (IsFullPath(Src))
    *Dest=0;
  else
  {
    char CurDirA[NM];
    if (getcwd(CurDirA,ASIZE(CurDirA))==NULL)
      *CurDirA=0;
    CharToWide(CurDirA,Dest,MaxSize);
    AddEndSlash(Dest,MaxSize);
  }
  wcsncatz(Dest,Src,MaxSize);
#else
  wcsncpyz(Dest,Src,MaxSize);
#endif
}
Example #15
0
SCAN_CODE ScanTree::FindProc(FindData *FD)
{
  if (*CurMask==0)
    return SCAN_NEXT;
  bool FastFindFile=false;
  
  if (FindStack[Depth]==NULL) // No FindFile object for this depth yet.
  {
    bool Wildcards=IsWildcard(CurMask);

    // If we have a file name without wildcards, we can try to use
    // FastFind to optimize speed. For example, in Unix it results in
    // stat call instead of opendir/readdir/closedir.
    bool FindCode=!Wildcards && FindFile::FastFind(CurMask,FD,GetLinks);

    // Link check is important for NTFS, where links can have "Directory"
    // attribute, but we do not want to recurse to them in "get links" mode.
    bool IsDir=FindCode && FD->IsDir && (!GetLinks || !FD->IsLink);

    // SearchAll means that we'll use "*" mask for search, so we'll find
    // subdirectories and will be able to recurse into them.
    // We do not use "*" for directories at any level or for files
    // at top level in recursion mode. We always comrpess the entire directory
    // if folder wildcard is specified.
    bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS ||
                   FolderWildcards && Recurse!=RECURSE_DISABLE || 
                   Wildcards && Recurse==RECURSE_WILDCARDS || 
                   ScanEntireDisk && Recurse!=RECURSE_DISABLE);
    if (Depth==0)
      SearchAllInRoot=SearchAll;
    if (SearchAll || Wildcards)
    {
      // Create the new FindFile object for wildcard based search.
      FindStack[Depth]=new FindFile;

      wchar SearchMask[NM];
      wcsncpyz(SearchMask,CurMask,ASIZE(SearchMask));
      if (SearchAll)
        SetName(SearchMask,MASKALL,ASIZE(SearchMask));
      FindStack[Depth]->SetMask(SearchMask);
    }
    else
    {
      // Either we failed to fast find or we found a file or we found
      // a directory in RECURSE_DISABLE mode, so we do not need to scan it.
      // We can return here and do not need to process further.
      // We need to process further only if we fast found a directory.
      if (!FindCode || !IsDir || Recurse==RECURSE_DISABLE)
      {
         // Return SCAN_SUCCESS if we found a file.
        SCAN_CODE RetCode=SCAN_SUCCESS;

        if (!FindCode)
        {
          // Return SCAN_ERROR if problem is more serious than just
          // "file not found".
          RetCode=FD->Error ? SCAN_ERROR:SCAN_NEXT;

          // If we failed to find an object, but our current mask is excluded,
          // we skip this object and avoid indicating an error.
          if (Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true))
            RetCode=SCAN_NEXT;
          else
          {
            ErrHandler.OpenErrorMsg(ErrArcName,CurMask);
            // User asked to return RARX_NOFILES and not RARX_OPEN here.
            ErrHandler.SetErrorCode(RARX_NOFILES);
          }
        }

        // If we searched only for one file or directory in "fast find" 
        // (without a wildcard) mode, let's set masks to zero, 
        // so calling function will know that current mask is used 
        // and next one must be read from mask list for next call.
        // It is not necessary for directories, because even in "fast find"
        // mode, directory recursing will quit by (Depth < 0) condition,
        // which returns SCAN_DONE to calling function.
        *CurMask=0;

        return RetCode;
      }

      // We found a directory using only FindFile::FastFind function.
      FastFindFile=true;
    }
  }

  if (!FastFindFile && !FindStack[Depth]->Next(FD,GetLinks))
  {
    // We cannot find anything more in directory either because of
    // some error or just as result of all directory entries already read.

    bool Error=FD->Error;
    if (Error)
      ScanError(Error);

    wchar DirName[NM];
    *DirName=0;

    // Going to at least one directory level higher.
    delete FindStack[Depth];
    FindStack[Depth--]=NULL;
    while (Depth>=0 && FindStack[Depth]==NULL)
      Depth--;
    if (Depth < 0)
    {
      // Directories scanned both in normal and FastFindFile mode,
      // finally exit from scan here, by (Depth < 0) condition.

      if (Error)
        Errors++;
      return SCAN_DONE;
    }

    wchar *Slash=wcsrchr(CurMask,CPATHDIVIDER);
    if (Slash!=NULL)
    {
      wchar Mask[NM];
      wcsncpyz(Mask,Slash,ASIZE(Mask));
      if (Depth<SetAllMaskDepth)
        wcsncpyz(Mask+1,PointToName(OrigCurMask),ASIZE(Mask)-1);
      *Slash=0;
      wcsncpyz(DirName,CurMask,ASIZE(DirName));
      wchar *PrevSlash=wcsrchr(CurMask,CPATHDIVIDER);
      if (PrevSlash==NULL)
        wcsncpyz(CurMask,Mask+1,ASIZE(CurMask));
      else
      {
        *(PrevSlash+1)=0;
        wcsncatz(CurMask,Mask,ASIZE(CurMask));
      }
    }
    if (GetDirs==SCAN_GETDIRSTWICE &&
        FindFile::FastFind(DirName,FD,GetLinks) && FD->IsDir)
    {
      FD->Flags|=FDDF_SECONDDIR;
      return Error ? SCAN_ERROR:SCAN_SUCCESS;
    }
    return Error ? SCAN_ERROR:SCAN_NEXT;
  }

  // Link check is required for NTFS links, not for Unix.
  if (FD->IsDir && (!GetLinks || !FD->IsLink))
  {
    // If we found the directory in top (Depth==0) directory
    // and if we are not in "fast find" (directory name only as argument)
    // or in recurse (SearchAll was set when opening the top directory) mode,
    // we do not recurse into this directory. We either return it by itself
    // or skip it.
    if (!FastFindFile && Depth==0 && !SearchAllInRoot)
      return GetDirs==SCAN_GETCURDIRS ? SCAN_SUCCESS:SCAN_NEXT;

    // Let's check if directory name is excluded, so we do not waste
    // time searching in directory, which will be excluded anyway.
    if (Cmd!=NULL && (Cmd->ExclCheck(FD->Name,true,false,false) ||
        Cmd->ExclDirByAttr(FD->FileAttr)))
    {
      // If we are here in "fast find" mode, it means that entire directory
      // specified in command line is excluded. Then we need to return
      // SCAN_DONE to go to next mask and avoid the infinite loop
      // in GetNext() function. Such loop would be possible in case of
      // SCAN_NEXT code and "rar a arc dir -xdir" command.

      return FastFindFile ? SCAN_DONE:SCAN_NEXT;
    }
    
    wchar Mask[NM];

    wcsncpyz(Mask,FastFindFile ? MASKALL:PointToName(CurMask),ASIZE(Mask));
    wcsncpyz(CurMask,FD->Name,ASIZE(CurMask));

    if (wcslen(CurMask)+wcslen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1)
    {
      uiMsg(UIERROR_PATHTOOLONG,CurMask,SPATHDIVIDER,Mask);
      return SCAN_ERROR;
    }

    AddEndSlash(CurMask,ASIZE(CurMask));
    wcsncatz(CurMask,Mask,ASIZE(CurMask));

    Depth++;

    // We need to use OrigCurMask for depths less than SetAllMaskDepth
    // and "*" for depths equal or larger than SetAllMaskDepth.
    // It is important when "fast finding" directories at Depth > 0.
    // For example, if current directory is RootFolder and we compress
    // the following directories structure:
    //   RootFolder
    //     +--Folder1
    //     |  +--Folder2
    //     |  +--Folder3
    //     +--Folder4
    // with 'rar a -r arcname Folder2' command, rar could add not only
    // Folder1\Folder2 contents, but also Folder1\Folder3 if we were using
    // "*" mask at all levels. We need to use "*" mask inside of Folder2,
    // but return to "Folder2" mask when completing scanning Folder2.
    // We can rewrite SearchAll expression above to avoid fast finding
    // directories at Depth > 0, but then 'rar a -r arcname Folder2'
    // will add the empty Folder2 and do not add its contents.

    if (FastFindFile)
      SetAllMaskDepth=Depth;
  }
  if (!FastFindFile && !CmpName(CurMask,FD->Name,MATCH_NAMES))
    return SCAN_NEXT;

  return SCAN_SUCCESS;
}
Example #16
0
void ExtractStreams20(Archive &Arc,const wchar *FileName)
{
  if (Arc.BrokenHeader)
  {
    uiMsg(UIERROR_STREAMBROKEN,Arc.FileName,FileName);
    ErrHandler.SetErrorCode(RARX_CRC);
    return;
  }

  if (Arc.StreamHead.Method<0x31 || Arc.StreamHead.Method>0x35 || Arc.StreamHead.UnpVer>VER_PACK)
  {
    uiMsg(UIERROR_STREAMUNKNOWN,Arc.FileName,FileName);
    ErrHandler.SetErrorCode(RARX_WARNING);
    return;
  }

  wchar StreamName[NM+2];
  if (FileName[0]!=0 && FileName[1]==0)
  {
    wcscpy(StreamName,L".\\");
    wcscpy(StreamName+2,FileName);
  }
  else
    wcscpy(StreamName,FileName);
  if (wcslen(StreamName)+strlen(Arc.StreamHead.StreamName)>=ASIZE(StreamName) ||
      Arc.StreamHead.StreamName[0]!=':')
  {
    uiMsg(UIERROR_STREAMBROKEN,Arc.FileName,FileName);
    ErrHandler.SetErrorCode(RARX_CRC);
    return;
  }

  wchar StoredName[NM];
  CharToWide(Arc.StreamHead.StreamName,StoredName,ASIZE(StoredName));
  ConvertPath(StoredName+1,StoredName+1);

  wcsncatz(StreamName,StoredName,ASIZE(StreamName));

  FindData fd;
  bool Found=FindFile::FastFind(FileName,&fd);

  if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0)
    SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY);

  File CurFile;
  if (CurFile.WCreate(StreamName))
  {
    ComprDataIO DataIO;
    Unpack Unpack(&DataIO);
    Unpack.Init(0x10000,false);

    DataIO.SetPackedSizeToRead(Arc.StreamHead.DataSize);
    DataIO.EnableShowProgress(false);
    DataIO.SetFiles(&Arc,&CurFile);
    DataIO.UnpHash.Init(HASH_CRC32,1);
    Unpack.SetDestSize(Arc.StreamHead.UnpSize);
    Unpack.DoUnpack(Arc.StreamHead.UnpVer,false);

    if (Arc.StreamHead.StreamCRC!=DataIO.UnpHash.GetCRC32())
    {
      uiMsg(UIERROR_STREAMBROKEN,Arc.FileName,StreamName);
      ErrHandler.SetErrorCode(RARX_CRC);
    }
    else
      CurFile.Close();
  }
  File HostFile;
  if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE))
    SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime,
                &fd.ftLastWriteTime);
  if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0)
    SetFileAttr(FileName,fd.FileAttr);
}
Example #17
0
// For masks like dir1\dir2*\file.ext this function sets 'dir1' recursive mask
// and '*\dir2*\file.ext' filter. Masks without folder wildcards are
// returned as is.
bool ScanTree::GetFilteredMask()
{
  // If we have some matching folders left for non-recursive folder wildcard
  // mask, we return it here.
  if (ExpandedFolderList.ItemsCount()>0 && ExpandedFolderList.GetString(CurMask,ASIZE(CurMask)))
    return true;

  FolderWildcards=false;
  FilterList.Reset();
  if (!FileMasks->GetString(CurMask,ASIZE(CurMask)))
    return false;

  // Check if folder wildcards present.
  bool WildcardFound=false;
  uint FolderWildcardCount=0;
  uint SlashPos=0;
  for (int I=0;CurMask[I]!=0;I++)
  {
    if (CurMask[I]=='?' || CurMask[I]=='*')
      WildcardFound=true;
    if (IsPathDiv(CurMask[I]) || IsDriveDiv(CurMask[I]))
    {
      if (WildcardFound)
      {
        // Calculate a number of folder wildcards in current mask.
        FolderWildcardCount++;
        WildcardFound=false;
      }
      if (FolderWildcardCount==0)
        SlashPos=I; // Slash position before first folder wildcard mask.
    }
  }
  if (FolderWildcardCount==0)
    return true;
  FolderWildcards=true; // Global folder wildcards flag.

  // If we have only one folder wildcard component and -r is missing or -r-
  // is specified, prepare matching folders in non-recursive mode.
  // We assume -r for masks like dir1*\dir2*\file*, because it is complicated
  // to fast find them using OS file find API call.
  if ((Recurse==RECURSE_NONE || Recurse==RECURSE_DISABLE) && FolderWildcardCount==1)
    return ExpandFolderMask();

  wchar Filter[NM];
  // Convert path\dir*\ to *\dir filter to search for 'dir' in all 'path' subfolders.
  wcscpy(Filter,L"*");
  AddEndSlash(Filter,ASIZE(Filter));
  // SlashPos might point or not point to path separator for masks like 'dir*', '\dir*' or 'd:dir*'
  wchar *WildName=IsPathDiv(CurMask[SlashPos]) || IsDriveDiv(CurMask[SlashPos]) ? CurMask+SlashPos+1 : CurMask+SlashPos;
  wcsncatz(Filter,WildName,ASIZE(Filter));

  // Treat dir*\* or dir*\*.* as dir\, so empty 'dir' is also matched
  // by such mask. Skipping empty dir with dir*\*.* confused some users.
  wchar *LastMask=PointToName(Filter);
  if (wcscmp(LastMask,L"*")==0 || wcscmp(LastMask,L"*.*")==0)
    *LastMask=0;

  FilterList.AddString(Filter);

  bool RelativeDrive=IsDriveDiv(CurMask[SlashPos]);
  if (RelativeDrive)
    SlashPos++; // Use "d:" instead of "d" for d:* mask.

  CurMask[SlashPos]=0;

  if (!RelativeDrive) // Keep d: mask as is, not convert to d:\*
  {
    // We need to append "\*" both for -ep1 to work correctly and to
    // convert d:\* masks previously truncated to d: back to original form.
    AddEndSlash(CurMask,ASIZE(CurMask));
    wcsncatz(CurMask,MASKALL,ASIZE(CurMask));
  }
  return true;
}
Example #18
0
void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize)
{
  wcsncpyz(DestName,Cmd->ExtrPath,DestSize);

  // We need IsPathDiv check here to correctly handle Unix forward slash
  // in the end of destination path in Windows: rar x arc dest/
  if (*Cmd->ExtrPath!=0 && !IsPathDiv(*PointToLastChar(Cmd->ExtrPath)))
  {
    // Destination path can be without trailing slash if it come from GUI shell.
    AddEndSlash(DestName,DestSize);
  }

#ifndef SFX_MODULE
  if (Cmd->AppendArcNameToPath)
  {
    wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize);
    SetExt(DestName,NULL,DestSize);
    AddEndSlash(DestName,DestSize);
  }
#endif

#ifndef SFX_MODULE
  size_t ArcPathLength=wcslen(Cmd->ArcPath);
  if (ArcPathLength>0)
  {
    size_t NameLength=wcslen(ArcFileName);
    ArcFileName+=Min(ArcPathLength,NameLength);
    while (*ArcFileName==CPATHDIVIDER)
      ArcFileName++;
    if (*ArcFileName==0) // Excessive -ap switch.
    {
      *DestName=0;
      return;
    }
  }
#endif

  wchar Command=Cmd->Command[0];
  // Use -ep3 only in systems, where disk letters are exist, not in Unix.
  bool AbsPaths=Cmd->ExclPath==EXCL_ABSPATH && Command=='X' && IsDriveDiv(':');

  // We do not use any user specified destination paths when extracting
  // absolute paths in -ep3 mode.
  if (AbsPaths)
    *DestName=0;

  if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
    wcsncatz(DestName,PointToName(ArcFileName),DestSize);
  else
    wcsncatz(DestName,ArcFileName,DestSize);

  wchar DiskLetter=toupperw(DestName[0]);

  if (AbsPaths)
  {
    if (DestName[1]=='_' && IsPathDiv(DestName[2]) &&
        DiskLetter>='A' && DiskLetter<='Z')
      DestName[1]=':';
    else
      if (DestName[0]=='_' && DestName[1]=='_')
      {
        // Convert __server\share to \\server\share.
        DestName[0]=CPATHDIVIDER;
        DestName[1]=CPATHDIVIDER;
      }
  }
}
Example #19
0
bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
{
  wchar *Name=ConvertPath(CheckName,NULL);
  wchar FullName[NM];
  wchar CurMask[NM];
  *FullName=0;
  Args->Rewind();
  while (Args->GetString(CurMask,ASIZE(CurMask)))
  {
    wchar *LastMaskChar=PointToLastChar(CurMask);
    bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.

    if (Dir)
    {
      // CheckName is a directory.
      if (DirMask)
      {
        // We process the directory and have the directory exclusion mask.
        // So let's convert "mask\" to "mask" and process it normally.
        
        *LastMaskChar=0;
      }
      else
      {
        // REMOVED, we want -npath\* to match empty folders too.
        // If mask has wildcards in name part and does not have the trailing
        // '\' character, we cannot use it for directories.
      
        // if (IsWildcard(PointToName(CurMask)))
        //  continue;
      }
    }
    else
    {
      // If we process a file inside of directory excluded by "dirmask\".
      // we want to exclude such file too. So we convert "dirmask\" to
      // "dirmask\*". It is important for operations other than archiving
      // with -x. When archiving with -x, directory matched by "dirmask\"
      // is excluded from further scanning.

      if (DirMask)
        wcsncatz(CurMask,L"*",ASIZE(CurMask));
    }

#ifndef SFX_MODULE
    if (CheckFullPath && IsFullPath(CurMask))
    {
      // We do not need to do the special "*\" processing here, because
      // unlike the "else" part of this "if", now we convert names to full
      // format, so they all include the path, which is matched by "*\"
      // correctly. Moreover, removing "*\" from mask would break
      // the comparison, because now all names have the path.

      if (*FullName==0)
        ConvertNameToFull(CheckName,FullName,ASIZE(FullName));
      if (CmpName(CurMask,FullName,MatchMode))
        return true;
    }
    else
#endif
    {
      wchar NewName[NM+2],*CurName=Name;

      // Important to convert before "*\" check below, so masks like
      // d:*\something are processed properly.
      wchar *CmpMask=ConvertPath(CurMask,NULL);

      if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
      {
        // We want "*\name" to match 'name' not only in subdirectories,
        // but also in the current directory. We convert the name
        // from 'name' to '.\name' to be matched by "*\" part even if it is
        // in current directory.
        NewName[0]='.';
        NewName[1]=CPATHDIVIDER;
        wcsncpyz(NewName+2,Name,ASIZE(NewName)-2);
        CurName=NewName;
      }

      if (CmpName(CmpMask,CurName,MatchMode))
        return true;
    }
  }
  return false;
}
Example #20
0
static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent)
{
  bool Prefix=false;
  if (*GenerateMask=='+')
  {
    Prefix=true;    // Add the time string before the archive name.
    GenerateMask++; // Skip '+' in the beginning of time mask.
  }

  wchar Mask[MAX_GENERATE_MASK];
  wcsncpyz(Mask,*GenerateMask!=0 ? GenerateMask:L"yyyymmddhhmmss",ASIZE(Mask));

  bool QuoteMode=false,Hours=false;
  for (uint I=0;Mask[I]!=0;I++)
  {
    if (Mask[I]=='{' || Mask[I]=='}')
    {
      QuoteMode=(Mask[I]=='{');
      continue;
    }
    if (QuoteMode)
      continue;
    int CurChar=toupperw(Mask[I]);
    if (CurChar=='H')
      Hours=true;

    if (Hours && CurChar=='M')
    {
      // Replace minutes with 'I'. We use 'M' both for months and minutes,
      // so we treat as minutes only those 'M' which are found after hours.
      Mask[I]='I';
    }
    if (CurChar=='N')
    {
      uint Digits=GetDigits(ArcNumber);
      uint NCount=0;
      while (toupperw(Mask[I+NCount])=='N')
        NCount++;

      // Here we ensure that we have enough 'N' characters to fit all digits
      // of archive number. We'll replace them by actual number later
      // in this function.
      if (NCount<Digits)
      {
        wmemmove(Mask+I+Digits,Mask+I+NCount,wcslen(Mask+I+NCount)+1);
        wmemset(Mask+I,'N',Digits);
      }
      I+=Max(Digits,NCount)-1;
      ArcNumPresent=true;
      continue;
    }
  }

  RarTime CurTime;
  CurTime.SetCurrentTime();
  RarLocalTime rlt;
  CurTime.GetLocal(&rlt);

  wchar Ext[NM],*Dot=GetExt(ArcName);
  *Ext=0;
  if (Dot==NULL)
    wcscpy(Ext,*PointToName(ArcName)==0 ? L".rar":L"");
  else
  {
    wcsncpyz(Ext,Dot,ASIZE(Ext));
    *Dot=0;
  }

  int WeekDay=rlt.wDay==0 ? 6:rlt.wDay-1;
  int StartWeekDay=rlt.yDay-WeekDay;
  if (StartWeekDay<0)
    if (StartWeekDay<=-4)
      StartWeekDay+=IsLeapYear(rlt.Year-1) ? 366:365;
    else
      StartWeekDay=0;
  int CurWeek=StartWeekDay/7+1;
  if (StartWeekDay%7>=4)
    CurWeek++;

  char Field[10][6];

  sprintf(Field[0],"%04d",rlt.Year);
  sprintf(Field[1],"%02d",rlt.Month);
  sprintf(Field[2],"%02d",rlt.Day);
  sprintf(Field[3],"%02d",rlt.Hour);
  sprintf(Field[4],"%02d",rlt.Minute);
  sprintf(Field[5],"%02d",rlt.Second);
  sprintf(Field[6],"%02d",CurWeek);
  sprintf(Field[7],"%d",WeekDay+1);
  sprintf(Field[8],"%03d",rlt.yDay+1);
  sprintf(Field[9],"%05d",ArcNumber);

  const wchar *MaskChars=L"YMDHISWAEN";

  int CField[sizeof(Field)/sizeof(Field[0])];
  memset(CField,0,sizeof(CField));
  QuoteMode=false;
  for (int I=0;Mask[I]!=0;I++)
  {
    if (Mask[I]=='{' || Mask[I]=='}')
    {
      QuoteMode=(Mask[I]=='{');
      continue;
    }
    if (QuoteMode)
      continue;
    const wchar *ChPtr=wcschr(MaskChars,toupperw(Mask[I]));
    if (ChPtr!=NULL)
      CField[ChPtr-MaskChars]++;
   }

  wchar DateText[MAX_GENERATE_MASK];
  *DateText=0;
  QuoteMode=false;
  for (size_t I=0,J=0;Mask[I]!=0 && J<ASIZE(DateText)-1;I++)
  {
    if (Mask[I]=='{' || Mask[I]=='}')
    {
      QuoteMode=(Mask[I]=='{');
      continue;
    }
    const wchar *ChPtr=wcschr(MaskChars,toupperw(Mask[I]));
    if (ChPtr==NULL || QuoteMode)
    {
      DateText[J]=Mask[I];
#ifdef _WIN_ALL
      // We do not allow ':' in Windows because of NTFS streams.
      // Users had problems after specifying hh:mm mask.
      if (DateText[J]==':')
        DateText[J]='_';
#endif
    }
    else
    {
      size_t FieldPos=ChPtr-MaskChars;
      int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--;
      if (FieldPos==1 && toupperw(Mask[I+1])=='M' && toupperw(Mask[I+2])=='M')
      {
        wcsncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J);
        J=wcslen(DateText);
        I+=2;
        continue;
      }
      if (CharPos<0)
        DateText[J]=Mask[I];
      else
        DateText[J]=Field[FieldPos][CharPos];
    }
    DateText[++J]=0;
  }

  if (Prefix)
  {
    wchar NewName[NM];
    GetFilePath(ArcName,NewName,ASIZE(NewName));
    AddEndSlash(NewName,ASIZE(NewName));
    wcsncatz(NewName,DateText,ASIZE(NewName));
    wcsncatz(NewName,PointToName(ArcName),ASIZE(NewName));
    wcscpy(ArcName,NewName);
  }
  else
    wcscat(ArcName,DateText);
  wcscat(ArcName,Ext);
}