1/* 7zFile.c -- File IO 22009-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 30void 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) 40static 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 60WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); } 61WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); } 62#endif 63 64#ifdef USE_WINDOWS_FILE 65static 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} 74WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); } 75WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); } 76#endif 77 78WRes 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 99WRes 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 134WRes 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 169WRes 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 212WRes 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 241static 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 247void FileSeqInStream_CreateVTable(CFileSeqInStream *p) 248{ 249 p->s.Read = FileSeqInStream_Read; 250} 251 252 253/* ---------- FileInStream ---------- */ 254 255static 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 261static 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 267void FileInStream_CreateVTable(CFileInStream *p) 268{ 269 p->s.Read = FileInStream_Read; 270 p->s.Seek = FileInStream_Seek; 271} 272 273 274/* ---------- FileOutStream ---------- */ 275 276static 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 283void FileOutStream_CreateVTable(CFileOutStream *p) 284{ 285 p->s.Write = FileOutStream_Write; 286} 287