| 43 | |
| 44 | |
| 45 | bool File::Open(const wchar *Name,uint Mode) |
| 46 | { |
| 47 | ErrorType=FILE_SUCCESS; |
| 48 | FileHandle hNewFile; |
| 49 | bool OpenShared=File::OpenShared || (Mode & FMF_OPENSHARED)!=0; |
| 50 | bool UpdateMode=(Mode & FMF_UPDATE)!=0; |
| 51 | bool WriteMode=(Mode & FMF_WRITE)!=0; |
| 52 | #ifdef _WIN_ALL |
| 53 | uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ; |
| 54 | if (UpdateMode) |
| 55 | Access|=GENERIC_WRITE; |
| 56 | uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ; |
| 57 | if (OpenShared) |
| 58 | ShareMode|=FILE_SHARE_WRITE; |
| 59 | uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN; |
| 60 | FindData FD; |
| 61 | if (PreserveAtime) |
| 62 | Access|=FILE_WRITE_ATTRIBUTES; // Needed to preserve atime. |
| 63 | hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL); |
| 64 | |
| 65 | DWORD LastError; |
| 66 | if (hNewFile==FILE_BAD_HANDLE) |
| 67 | { |
| 68 | LastError=GetLastError(); |
| 69 | |
| 70 | wchar LongName[NM]; |
| 71 | if (GetWinLongPath(Name,LongName,ASIZE(LongName))) |
| 72 | { |
| 73 | hNewFile=CreateFile(LongName,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL); |
| 74 | |
| 75 | // For archive names longer than 260 characters first CreateFile |
| 76 | // (without \\?\) fails and sets LastError to 3 (access denied). |
| 77 | // We need the correct "file not found" error code to decide |
| 78 | // if we create a new archive or quit with "cannot create" error. |
| 79 | // So we need to check the error code after \\?\ CreateFile again, |
| 80 | // otherwise we'll fail to create new archives with long names. |
| 81 | // But we cannot simply assign the new code to LastError, |
| 82 | // because it would break "..\arcname.rar" relative names processing. |
| 83 | // First CreateFile returns the correct "file not found" code for such |
| 84 | // names, but "\\?\" CreateFile returns ERROR_INVALID_NAME treating |
| 85 | // dots as a directory name. So we check only for "file not found" |
| 86 | // error here and for other errors use the first CreateFile result. |
| 87 | if (GetLastError()==ERROR_FILE_NOT_FOUND) |
| 88 | LastError=ERROR_FILE_NOT_FOUND; |
| 89 | } |
| 90 | } |
| 91 | if (hNewFile==FILE_BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND) |
| 92 | ErrorType=FILE_NOTFOUND; |
| 93 | if (PreserveAtime && hNewFile!=FILE_BAD_HANDLE) |
| 94 | { |
| 95 | FILETIME ft={0xffffffff,0xffffffff}; // This value prevents atime modification. |
| 96 | SetFileTime(hNewFile,NULL,&ft,NULL); |
| 97 | } |
| 98 | |
| 99 | #else |
| 100 | int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY); |
| 101 | #ifdef O_BINARY |
| 102 | flags|=O_BINARY; |