wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath) { const wchar *DestPtr=SrcPath; for (const wchar *s=DestPtr;*s!=0;s++) if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3])) DestPtr=s+4; while (*DestPtr) { const wchar *s=DestPtr; if (s[0] && IsDriveDiv(s[1])) s+=2; if (s[0]=='\\' && s[1]=='\\') { const wchar *Slash=strchrw(s+2,'\\'); if (Slash!=NULL && (Slash=strchrw(Slash+1,'\\'))!=NULL) s=Slash+1; } for (const wchar *t=s;*t!=0;t++) if (IsPathDiv(*t)) s=t+1; else if (*t!='.') break; if (s==DestPtr) break; DestPtr=s; } if (DestPath!=NULL) { wchar TmpStr[NM]; strncpyw(TmpStr,DestPtr,sizeof(TmpStr)/sizeof(TmpStr[0])-1); strcpyw(DestPath,TmpStr); } return((wchar *)DestPtr); }
void MakeNameUsable(char *Name,bool Extended) { #ifdef _WIN_ALL // In Windows we also need to convert characters not defined in current // code page. This double conversion changes them to '?', which is // catched by code below. size_t NameLength=strlen(Name); wchar NameW[NM]; CharToWide(Name,NameW,ASIZE(NameW)); WideToChar(NameW,Name,NameLength+1); Name[NameLength]=0; #endif for (char *s=Name;*s!=0;s=charnext(s)) { if (strchr(Extended ? "?*<>|\"":"?*",*s)!=NULL || Extended && (byte)*s<32) *s='_'; #ifdef _EMX if (*s=='=') *s='_'; #endif #ifndef _UNIX if (s-Name>1 && *s==':') *s='_'; // Remove ' ' and '.' before path separator, but allow .\ and ..\. if ((*s==' ' || *s=='.' && s>Name && !IsPathDiv(s[-1]) && s[-1]!='.') && IsPathDiv(s[1])) *s='_'; #endif } }
// 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; }
bool IsFullPath(const char *Path) { char PathOnly[NM]; GetFilePath(Path,PathOnly); if (IsWildcard(PathOnly)) return(true); #if defined(_WIN_32) || defined(_EMX) return(Path[0]=='\\' && Path[1]=='\\' || IsDiskLetter(Path) && IsPathDiv(Path[2])); #else return(IsPathDiv(Path[0])); #endif }
bool IsFullPath(const wchar *Path) { /* wchar PathOnly[NM]; GetFilePath(Path,PathOnly,ASIZE(PathOnly)); if (IsWildcard(PathOnly)) return true; */ #if defined(_WIN_ALL) || defined(_EMX) return Path[0]=='\\' && Path[1]=='\\' || IsDiskLetter(Path) && IsPathDiv(Path[2]); #else return IsPathDiv(Path[0]); #endif }
bool CreatePath(const wchar *Path,bool SkipLastName) { if (Path==NULL || *Path==0) return false; #if defined(_WIN_ALL) || defined(_EMX) uint DirAttr=0; #else uint DirAttr=0777; #endif bool Success=true; for (const wchar *s=Path;*s!=0;s++) { wchar DirName[NM]; if (s-Path>=ASIZE(DirName)) break; // Process all kinds of path separators, so user can enter Unix style // path in Windows or Windows in Unix. s>Path check avoids attempting // creating an empty directory for paths starting from path separator. if (IsPathDiv(*s) && s>Path) { #ifdef _WIN_ALL // We must not attempt to create "D:" directory, because first // CreateDirectory will fail, so we'll use \\?\D:, which forces Wine // to create "D:" directory. if (s==Path+2 && Path[1]==':') continue; #endif wcsncpy(DirName,Path,s-Path); DirName[s-Path]=0; Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS; #ifndef GUI if (Success) { mprintf(St(MCreatDir),DirName); mprintf(L" %s",St(MOk)); } #endif } } if (!SkipLastName && !IsPathDiv(*PointToLastChar(Path))) Success=MakeDir(Path,true,DirAttr)==MKDIR_SUCCESS; return Success; }
void ConvertNameToFull(const char *Src,char *Dest) { #ifdef _WIN_32 #ifndef _WIN_CE char FullName[NM],*NamePtr; if (GetFullPathName(Src,sizeof(FullName),FullName,&NamePtr)) strcpy(Dest,FullName); else #endif if (Src!=Dest) strcpy(Dest,Src); #else char FullName[NM]; if (IsPathDiv(*Src) || IsDiskLetter(Src)) strcpy(FullName,Src); else { if (getcwd(FullName,sizeof(FullName))==NULL) *FullName=0; else AddEndSlash(FullName); strcat(FullName,Src); } strcpy(Dest,FullName); #endif }
wchar* PointToName(const wchar *Path) { for (int I=strlenw(Path)-1;I>=0;I--) if (IsPathDiv(Path[I])) return (wchar*)&Path[I+1]; return (wchar*)((*Path && IsDriveDiv(Path[1])) ? Path+2:Path); }
// Calculate a number of path components except \. and \.. static int CalcAllowedDepth(const wchar *Name) { int AllowedDepth=0; while (*Name!=0) { if (IsPathDiv(Name[0]) && Name[1]!=0 && !IsPathDiv(Name[1])) { bool Dot=Name[1]=='.' && (IsPathDiv(Name[2]) || Name[2]==0); bool Dot2=Name[1]=='.' && Name[2]=='.' && (IsPathDiv(Name[3]) || Name[3]==0); if (!Dot && !Dot2) AllowedDepth++; } Name++; } return AllowedDepth; }
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; }
void ConvertNameToFull(const char *Src,char *Dest) { #ifdef _WIN_32 //#ifndef _WIN_CE #if !defined(_WIN_CE) && !defined(_LINUX) char FullName[NM],*NamePtr; if (GetFullPathName(Src,sizeof(FullName),FullName,&NamePtr)) strcpy(Dest,FullName); else #endif if (Src!=Dest) strcpy(Dest,Src); #else char FullName[NM]; if (IsPathDiv(*Src) || IsDiskLetter(Src)) strcpy(FullName,Src); else { if (getcwd(FullName,sizeof(FullName))) { AddEndSlash(FullName); strcat(FullName,Src); } } strcpy(Dest,FullName); #endif }
char* ConvertPath(const char *SrcPath,char *DestPath) { const char *DestPtr=SrcPath; // Prevent \..\ in any part of path string. for (const char *s=DestPtr;*s!=0;s++) if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3])) DestPtr=s+4; // Remove any sequence of . and \ in the beginning of path string. while (*DestPtr) { const char *s=DestPtr; if (s[0] && IsDriveDiv(s[1])) s+=2; else if (s[0]=='\\' && s[1]=='\\') { const char *Slash=strchr(s+2,'\\'); if (Slash!=NULL && (Slash=strchr(Slash+1,'\\'))!=NULL) s=Slash+1; } for (const char *t=s;*t!=0;t++) if (IsPathDiv(*t)) s=t+1; else if (*t!='.') break; if (s==DestPtr) break; DestPtr=s; } // Code above does not remove last "..", doing here. if (DestPtr[0]=='.' && DestPtr[1]=='.' && DestPtr[2]==0) DestPtr+=2; if (DestPath!=NULL) { // SrcPath and DestPath can point to same memory area, // so we use the temporary buffer for copying. char TmpStr[NM]; strncpyz(TmpStr,DestPtr,ASIZE(TmpStr)); strcpy(DestPath,TmpStr); } return((char *)DestPtr); }
void MakeNameUsable(wchar *Name,bool Extended) { for (wchar *s=Name;*s!=0;s++) { if (wcschr(Extended ? L"?*<>|\"":L"?*",*s)!=NULL || Extended && (uint)*s<32) *s='_'; #ifndef _UNIX if (s-Name>1 && *s==':') *s='_'; #if 0 // We already can create such files. // Remove ' ' and '.' before path separator, but allow .\ and ..\. if (IsPathDiv(s[1]) && (*s==' ' || *s=='.' && s>Name && !IsPathDiv(s[-1]) && (s[-1]!='.' || s>Name+1 && !IsPathDiv(s[-2])))) *s='_'; #endif #endif } }
char* PointToName(const char *Path) { //const char *Found=NULL; for (const char *s=&Path[strlen(Path)-1];s>=Path;s--) if (IsPathDiv(*s)) return (char*)(s+1); // if (Found!=NULL) // return((char*)Found); return (char*)((*Path && IsDriveDiv(Path[1]) && charnext(Path)==Path+1) ? Path+2:Path); }
char* PointToName(const char *Path) { const char *Found=NULL; for (const char *s=Path;*s!=0;s=charnext(s)) if (IsPathDiv(*s)) Found=(char*)(s+1); if (Found!=NULL) return((char*)Found); return (char*)((*Path && IsDriveDiv(Path[1]) && charnext(Path)==Path+1) ? Path+2:Path); }
bool ScanTree::PrepareMasks() { ScanEntireDisk=false; if (!FileMasks->GetString(CurMask,CurMaskW,sizeof(CurMask))) return(false); CurMask[ASIZE(CurMask)-1]=0; CurMaskW[ASIZE(CurMaskW)-1]=0; #ifdef _WIN_32 UnixSlashToDos(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=IsDiskLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0; char *Name=PointToName(CurMask); if (*Name==0) strcat(CurMask,MASKALL); if (Name[0]=='.' && (Name[1]==0 || Name[1]=='.' && Name[2]==0)) { AddEndSlash(CurMask); strcat(CurMask,MASKALL); } SpecPathLength=Name-CurMask; // if (SpecPathLength>1) // SpecPathLength--; bool WideName=(*CurMaskW!=0); if (WideName) { wchar *NameW=PointToName(CurMaskW); if (*NameW==0) strcatw(CurMaskW,MASKALLW); if (NameW[0]=='.' && (NameW[1]==0 || NameW[1]=='.' && NameW[2]==0)) { AddEndSlash(CurMaskW); strcatw(CurMaskW,MASKALLW); } SpecPathLengthW=NameW-CurMaskW; } else { wchar WideMask[NM]; CharToWide(CurMask,WideMask); SpecPathLengthW=PointToName(WideMask)-WideMask; } Depth=0; strcpy(OrigCurMask,CurMask); strcpyw(OrigCurMaskW,CurMaskW); return(true); }
bool IsRelativeSymlinkSafe(const wchar *SrcName,const wchar *TargetName) { if (IsFullRootPath(SrcName)) return false; int AllowedDepth=0; while (*SrcName!=0) { if (IsPathDiv(SrcName[0]) && SrcName[1]!=0 && !IsPathDiv(SrcName[1])) { bool Dot=SrcName[1]=='.' && (IsPathDiv(SrcName[2]) || SrcName[2]==0); bool Dot2=SrcName[1]=='.' && SrcName[2]=='.' && (IsPathDiv(SrcName[3]) || SrcName[3]==0); if (!Dot && !Dot2) AllowedDepth++; } SrcName++; } if (IsFullRootPath(TargetName)) // Catch root dir based /path/file paths. return false; for (int Pos=0;*TargetName!=0;Pos++) { bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' && (IsPathDiv(TargetName[2]) || TargetName[2]==0) && (Pos==0 || IsPathDiv(*(TargetName-1))); if (Dot2) AllowedDepth--; TargetName++; } return AllowedDepth>=0; }
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName) { // Catch root dir based /path/file paths also as stuff like \\?\. // Do not check PrepSrcName here, it can be root based if destination path // is a root based. if (IsFullRootPath(SrcName) || IsFullRootPath(TargetName)) return false; // We could check just prepared src name, but for extra safety // we check both original (as from archive header) and prepared // (after applying the destination path and -ep switches) names. int AllowedDepth=CalcAllowedDepth(SrcName); // Original name depth. // Remove the destination path from prepared name if any. We should not // count the destination path depth, because the link target must point // inside of this path, not outside of it. size_t ExtrPathLength=wcslen(Cmd->ExtrPath); if (ExtrPathLength>0 && wcsncmp(PrepSrcName,Cmd->ExtrPath,ExtrPathLength)==0) { PrepSrcName+=ExtrPathLength; while (IsPathDiv(*PrepSrcName)) PrepSrcName++; } int PrepAllowedDepth=CalcAllowedDepth(PrepSrcName); // Number of ".." in link target. int UpLevels=0; for (int Pos=0;*TargetName!=0;Pos++) { bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' && (IsPathDiv(TargetName[2]) || TargetName[2]==0) && (Pos==0 || IsPathDiv(*(TargetName-1))); if (Dot2) UpLevels++; TargetName++; } return AllowedDepth>=UpLevels && PrepAllowedDepth>=UpLevels; }
void MakeNameUsable(wchar *Name,bool Extended) { for (wchar *s=Name;*s!=0;s++) { if (wcschr(Extended ? L"?*<>|\"":L"?*",*s)!=NULL || Extended && (uint)*s<32) *s='_'; #ifndef _UNIX if (s-Name>1 && *s==':') *s='_'; if ((*s==' ' || *s=='.') && IsPathDiv(s[1])) *s='_'; #endif } }
bool IsNameUsable(const wchar *Name) { #ifndef _UNIX if (Name[0] && Name[1] && wcschr(Name+2,':')!=NULL) return false; for (const wchar *s=Name;*s!=0;s++) { if ((uint)*s<32) return false; if ((*s==' ' || *s=='.') && IsPathDiv(s[1])) return false; } #endif return *Name!=0 && wcspbrk(Name,L"?*<>|\"")==NULL; }
bool IsNameUsable(const char *Name) { #ifndef _UNIX if (Name[0] && Name[1] && strchr(Name+2,':')!=NULL) return(false); for (const char *s=Name;*s!=0;s=charnext(s)) { if ((byte)*s<32) return(false); if (*s==' ' && IsPathDiv(s[1])) return(false); } #endif return(*Name!=0 && strpbrk(Name,"?*<>|\"")==NULL); }
// 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; }
void MakeNameUsable(char *Name,bool Extended) { for (char *s=Name;*s!=0;s=charnext(s)) { if (strchr(Extended ? "?*<>|\"":"?*",*s)!=NULL || Extended && (byte)*s<32) *s='_'; #ifdef _EMX if (*s=='=') *s='_'; #endif #ifndef _UNIX if (s-Name>1 && *s==':') *s='_'; if (*s==' ' && IsPathDiv(s[1])) *s='_'; #endif } }
bool CreatePath(const wchar *Path,bool SkipLastName) { if (Path==NULL || *Path==0) return(false); #if defined(_WIN_ALL) || defined(_EMX) uint DirAttr=0; #else uint DirAttr=0777; #endif bool Success=true; for (const wchar *s=Path;*s!=0;s++) { if (s-Path>=NM) break; if (*s==CPATHDIVIDER) { wchar DirName[NM]; wcsncpy(DirName,Path,s-Path); DirName[s-Path]=0; if (MakeDir(NULL,DirName,true,DirAttr)==MKDIR_SUCCESS) { #ifndef GUI char DirNameA[NM]; WideToChar(DirName,DirNameA,ASIZE(DirNameA)); DirNameA[ASIZE(DirNameA)-1]=0; mprintf(St(MCreatDir),DirNameA); mprintf(" %s",St(MOk)); #endif } else Success=false; } } if (!SkipLastName) if (!IsPathDiv(*PointToLastChar(Path))) if (MakeDir(NULL,Path,true,DirAttr)!=MKDIR_SUCCESS) Success=false; return(Success); }
// Return 'true' if we need to exclude the directory from archiving as result // of -x switch. We do not want -x*. switch to exclude all directories, // so when archiving we process exclusion arguments for directories specially. bool CommandData::ExclCheckDir(char *CheckName) { // If exclusion mask and directory name match exactly, return true. if (ExclCheckArgs(ExclArgs,CheckName,true,MATCH_EXACT)) return(true); // Now we want to allow wildcards in exclusion mask only if it has // '\' at the end. So 'dir*\' will exclude all dir* directories. // We append '\' to directory name, so it will match only masks having // '\' at the end. char DirName[NM+1]; ConvertPath(CheckName,DirName); AddEndSlash(DirName); char *CurMask; ExclArgs->Rewind(); while ((CurMask=ExclArgs->GetString())!=NULL) if (IsPathDiv(*PointToLastChar(CurMask))) if (CmpName(CurMask,DirName,MATCH_SUBPATH)) return(true); return(false); }
// 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; }
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; } } }
void CommandData::ParseArg(char *Arg,wchar *ArgW) { if (IsSwitch(*Arg) && !NoMoreSwitches) if (Arg[1]=='-') NoMoreSwitches=true; else ProcessSwitch(&Arg[1]); else if (*Command==0) { strncpy(Command,Arg,sizeof(Command)); if (ArgW!=NULL) strncpyw(CommandW,ArgW,sizeof(CommandW)/sizeof(CommandW[0])); if (toupper(*Command)=='S') { const char *SFXName=Command[1] ? Command+1:DefSFXName; if (PointToName(SFXName)!=SFXName || FileExist(SFXName)) strcpy(SFXModule,SFXName); else GetConfigName(SFXName,SFXModule,true); } #ifndef GUI *Command=toupper(*Command); if (*Command!='I' && *Command!='S') strupper(Command); #endif } else if (*ArcName==0) { strncpy(ArcName,Arg,sizeof(ArcName)); if (ArgW!=NULL) strncpyw(ArcNameW,ArgW,sizeof(ArcNameW)/sizeof(ArcNameW[0])); } else { int Length=strlen(Arg); char EndChar=Arg[Length-1]; char CmdChar=toupper(*Command); bool Add=strchr("AFUM",CmdChar)!=NULL; bool Extract=CmdChar=='X' || CmdChar=='E'; if ((IsDriveDiv(EndChar) || IsPathDiv(EndChar)) && !Add) strcpy(ExtrPath,Arg); else if ((Add || CmdChar=='T') && *Arg!='@') FileArgs->AddString(Arg); else { struct FindData FileData; bool Found=FindFile::FastFind(Arg,NULL,&FileData); if (!Found && *Arg=='@' && !IsWildcard(Arg)) { ReadTextFile(Arg+1,FileArgs,false,true,true,true,true); FileLists=true; } else if (Found && FileData.IsDir && Extract && *ExtrPath==0) { strcpy(ExtrPath,Arg); AddEndSlash(ExtrPath); } else FileArgs->AddString(Arg); } } }
void CommandData::ParseArg(char *Arg,wchar *ArgW) { if (IsSwitch(*Arg) && !NoMoreSwitches) if (Arg[1]=='-') NoMoreSwitches=true; else ProcessSwitch(Arg+1,(ArgW!=NULL && *ArgW!=0 ? ArgW+1:NULL)); else if (*Command==0) { strncpyz(Command,Arg,ASIZE(Command)); if (ArgW!=NULL) wcsncpy(CommandW,ArgW,ASIZE(CommandW)); #ifndef GUI *Command=etoupper(*Command); // 'I' and 'S' commands can contain case sensitive strings after // the first character, so we must not modify their case. // 'S' can contain SFX name, which case is important in Unix. if (*Command!='I' && *Command!='S') strupper(Command); #endif } else if (*ArcName==0 && *ArcNameW==0) { strncpyz(ArcName,Arg,ASIZE(ArcName)); if (ArgW!=NULL) wcsncpyz(ArcNameW,ArgW,ASIZE(ArcNameW)); } else { bool EndSeparator; // If last character is the path separator. if (ArgW!=NULL) { size_t Length=wcslen(ArgW); wchar EndChar=Length==0 ? 0:ArgW[Length-1]; EndSeparator=IsDriveDiv(EndChar) || IsPathDiv(EndChar); } else { size_t Length=strlen(Arg); char EndChar=Length==0 ? 0:Arg[Length-1]; EndSeparator=IsDriveDiv(EndChar) || IsPathDiv(EndChar); } char CmdChar=etoupper(*Command); bool Add=strchr("AFUM",CmdChar)!=NULL; bool Extract=CmdChar=='X' || CmdChar=='E'; if (EndSeparator && !Add) { strncpyz(ExtrPath,Arg,ASIZE(ExtrPath)); if (ArgW!=NULL) wcsncpyz(ExtrPathW,ArgW,ASIZE(ExtrPathW)); } else if ((Add || CmdChar=='T') && *Arg!='@') FileArgs->AddString(Arg,ArgW); else { FindData FileData; bool Found=FindFile::FastFind(Arg,ArgW,&FileData); if (!Found && *Arg=='@' && !IsWildcard(Arg,ArgW)) { FileLists=true; RAR_CHARSET Charset=FilelistCharset; #if defined(_WIN_ALL) && !defined(GUI) // for compatibility reasons we use OEM encoding // in Win32 console version by default if (Charset==RCH_DEFAULT) Charset=RCH_OEM; #endif wchar *WideArgName=(ArgW!=NULL && *ArgW!=0 ? ArgW+1:NULL); ReadTextFile(Arg+1,WideArgName,FileArgs.get(),false,true,Charset,true,true,true); } else if (Found && FileData.IsDir && Extract && *ExtrPath==0 && *ExtrPathW==0) { strncpyz(ExtrPath,Arg,ASIZE(ExtrPath)-1); AddEndSlash(ExtrPath); if (ArgW!=NULL) { wcsncpyz(ExtrPathW,ArgW,ASIZE(ExtrPathW)-1); AddEndSlash(ExtrPathW); } } else FileArgs->AddString(Arg,ArgW); } } }
bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,char *CheckName,bool CheckFullPath,int MatchMode) { char *Name=ConvertPath(CheckName,NULL); char FullName[NM]; char CurMask[NM+1]; // We reserve the space to append "*" to mask. *FullName=0; Args->Rewind(); while (Args->GetString(CurMask,ASIZE(CurMask)-1)) { char *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 { // 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. // When archiving, directory matched by "dirmask\" is excluded // from further scanning. if (DirMask) strcat(CurMask,"*"); } #ifndef SFX_MODULE if (CheckFullPath && IsFullPath(CurMask)) { // We do not need to do the special "*\" processing here, because // onlike 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); if (CmpName(CurMask,FullName,MatchMode)) return(true); } else #endif { char NewName[NM+2],*CurName=Name; if (CurMask[0]=='*' && IsPathDiv(CurMask[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; strncpyz(NewName+2,Name,ASIZE(NewName)-2); CurName=NewName; } if (CmpName(ConvertPath(CurMask,NULL),CurName,MatchMode)) return(true); } } return(false); }