1 /* 7zFile.c -- File IO 2 2009-11-24 : Igor Pavlov : Public domain */ 3 4 #include "Precomp.h" 5 6 #include "7zFile.h" 7 8 #ifndef USE_WINDOWS_FILE 9 10 #ifndef UNDER_CE 11 #include <errno.h> 12 #endif 13 14 #else 15 16 /* 17 ReadFile and WriteFile functions in Windows have BUG: 18 If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) 19 from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES 20 (Insufficient system resources exist to complete the requested service). 21 Probably in some version of Windows there are problems with other sizes: 22 for 32 MB (maybe also for 16 MB). 23 And message can be "Network connection was lost" 24 */ 25 26 #define kChunkSizeMax (1 << 22) 27 28 #endif 29 30 void File_Construct(CSzFile *p) 31 { 32 #ifdef USE_WINDOWS_FILE 33 p->handle = INVALID_HANDLE_VALUE; 34 #else 35 p->file = NULL; 36 #endif 37 } 38 39 #if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE) 40 static WRes File_Open(CSzFile *p, const char *name, int writeMode) 41 { 42 #ifdef USE_WINDOWS_FILE 43 p->handle = CreateFileA(name, 44 writeMode ? GENERIC_WRITE : GENERIC_READ, 45 FILE_SHARE_READ, NULL, 46 writeMode ? CREATE_ALWAYS : OPEN_EXISTING, 47 FILE_ATTRIBUTE_NORMAL, NULL); 48 return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); 49 #else 50 p->file = fopen(name, writeMode ? "wb+" : "rb"); 51 return (p->file != 0) ? 0 : 52 #ifdef UNDER_CE 53 2; /* ENOENT */ 54 #else 55 errno; 56 #endif 57 #endif 58 } 59 60 WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } 61 WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); } 62 #endif 63 64 #ifdef USE_WINDOWS_FILE 65 static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode) 66 { 67 p->handle = CreateFileW(name, 68 writeMode ? GENERIC_WRITE : GENERIC_READ, 69 FILE_SHARE_READ, NULL, 70 writeMode ? CREATE_ALWAYS : OPEN_EXISTING, 71 FILE_ATTRIBUTE_NORMAL, NULL); 72 return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError(); 73 } 74 WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } 75 WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } 76 #endif 77 78 WRes File_Close(CSzFile *p) 79 { 80 #ifdef USE_WINDOWS_FILE 81 if (p->handle != INVALID_HANDLE_VALUE) 82 { 83 if (!CloseHandle(p->handle)) 84 return GetLastError(); 85 p->handle = INVALID_HANDLE_VALUE; 86 } 87 #else 88 if (p->file != NULL) 89 { 90 int res = fclose(p->file); 91 if (res != 0) 92 return res; 93 p->file = NULL; 94 } 95 #endif 96 return 0; 97 } 98 99 WRes File_Read(CSzFile *p, void *data, size_t *size) 100 { 101 size_t originalSize = *size; 102 if (originalSize == 0) 103 return 0; 104 105 #ifdef USE_WINDOWS_FILE 106 107 *size = 0; 108 do 109 { 110 DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; 111 DWORD processed = 0; 112 BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); 113 data = (void *)((Byte *)data + processed); 114 originalSize -= processed; 115 *size += processed; 116 if (!res) 117 return GetLastError(); 118 if (processed == 0) 119 break; 120 } 121 while (originalSize > 0); 122 return 0; 123 124 #else 125 126 *size = fread(data, 1, originalSize, p->file); 127 if (*size == originalSize) 128 return 0; 129 return ferror(p->file); 130 131 #endif 132 } 133 134 WRes File_Write(CSzFile *p, const void *data, size_t *size) 135 { 136 size_t originalSize = *size; 137 if (originalSize == 0) 138 return 0; 139 140 #ifdef USE_WINDOWS_FILE 141 142 *size = 0; 143 do 144 { 145 DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; 146 DWORD processed = 0; 147 BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL); 148 data = (void *)((Byte *)data + processed); 149 originalSize -= processed; 150 *size += processed; 151 if (!res) 152 return GetLastError(); 153 if (processed == 0) 154 break; 155 } 156 while (originalSize > 0); 157 return 0; 158 159 #else 160 161 *size = fwrite(data, 1, originalSize, p->file); 162 if (*size == originalSize) 163 return 0; 164 return ferror(p->file); 165 166 #endif 167 } 168 169 WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin) 170 { 171 #ifdef USE_WINDOWS_FILE 172 173 LARGE_INTEGER value; 174 DWORD moveMethod; 175 value.LowPart = (DWORD)*pos; 176 value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */ 177 switch (origin) 178 { 179 case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break; 180 case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break; 181 case SZ_SEEK_END: moveMethod = FILE_END; break; 182 default: return ERROR_INVALID_PARAMETER; 183 } 184 value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); 185 if (value.LowPart == 0xFFFFFFFF) 186 { 187 WRes res = GetLastError(); 188 if (res != NO_ERROR) 189 return res; 190 } 191 *pos = ((Int64)value.HighPart << 32) | value.LowPart; 192 return 0; 193 194 #else 195 196 int moveMethod; 197 int res; 198 switch (origin) 199 { 200 case SZ_SEEK_SET: moveMethod = SEEK_SET; break; 201 case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break; 202 case SZ_SEEK_END: moveMethod = SEEK_END; break; 203 default: return 1; 204 } 205 res = fseek(p->file, (long)*pos, moveMethod); 206 *pos = ftell(p->file); 207 return res; 208 209 #endif 210 } 211 212 WRes File_GetLength(CSzFile *p, UInt64 *length) 213 { 214 #ifdef USE_WINDOWS_FILE 215 216 DWORD sizeHigh; 217 DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); 218 if (sizeLow == 0xFFFFFFFF) 219 { 220 DWORD res = GetLastError(); 221 if (res != NO_ERROR) 222 return res; 223 } 224 *length = (((UInt64)sizeHigh) << 32) + sizeLow; 225 return 0; 226 227 #else 228 229 long pos = ftell(p->file); 230 int res = fseek(p->file, 0, SEEK_END); 231 *length = ftell(p->file); 232 fseek(p->file, pos, SEEK_SET); 233 return res; 234 235 #endif 236 } 237 238 239 /* ---------- FileSeqInStream ---------- */ 240 241 static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size) 242 { 243 CFileSeqInStream *p = (CFileSeqInStream *)pp; 244 return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ; 245 } 246 247 void FileSeqInStream_CreateVTable(CFileSeqInStream *p) 248 { 249 p->s.Read = FileSeqInStream_Read; 250 } 251 252 253 /* ---------- FileInStream ---------- */ 254 255 static SRes FileInStream_Read(void *pp, void *buf, size_t *size) 256 { 257 CFileInStream *p = (CFileInStream *)pp; 258 return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; 259 } 260 261 static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin) 262 { 263 CFileInStream *p = (CFileInStream *)pp; 264 return File_Seek(&p->file, pos, origin); 265 } 266 267 void FileInStream_CreateVTable(CFileInStream *p) 268 { 269 p->s.Read = FileInStream_Read; 270 p->s.Seek = FileInStream_Seek; 271 } 272 273 274 /* ---------- FileOutStream ---------- */ 275 276 static size_t FileOutStream_Write(void *pp, const void *data, size_t size) 277 { 278 CFileOutStream *p = (CFileOutStream *)pp; 279 File_Write(&p->file, data, &size); 280 return size; 281 } 282 283 void FileOutStream_CreateVTable(CFileOutStream *p) 284 { 285 p->s.Write = FileOutStream_Write; 286 } 287