Fennel: /home/pub/open/dev/fennel/device/FileDevice.cpp Source File (original) (raw)

00001 00002 00003 00004 00005 00006 00007 00008 00009 00010 00011 00012 00013 00014 00015 00016 00017 00018 00019 00020 00021 00022 00023 00024 #include "fennel/common/CommonPreamble.h" 00025 #include "fennel/device/FileDevice.h" 00026 #include "fennel/device/RandomAccessRequest.h" 00027 #include "fennel/common/SysCallExcn.h" 00028 #include <sys/types.h> 00029 #include <sys/stat.h> 00030 00031 #ifndef MSVC 00032 #include <sys/file.h> 00033 #endif 00034 00035 #include <fcntl.h> 00036 #include 00037 00038 #ifdef MSVC 00039 #include <windows.h> 00040 #endif 00041 00042 FENNEL_BEGIN_CPPFILE("$Id: //open/dev/fennel/device/FileDevice.cpp#14 $"); 00043 00044 FileDevice::FileDevice( 00045 std::string filenameInit,DeviceMode openMode,FileSize initialSize) 00046 { 00047 filename = filenameInit; 00048 mode = openMode; 00049 00050 #ifdef MSVC 00051 00052 DWORD fdwCreate = mode.create ? CREATE_ALWAYS : OPEN_EXISTING; 00053 00054 DWORD fdwFlags = FILE_FLAG_OVERLAPPED; 00055 00056 DWORD fdwAccess = GENERIC_READ; 00057 if (mode.readOnly) { 00058 fdwAccess |= GENERIC_WRITE; 00059 } 00060 if (mode.direct) { 00061 fdwFlags |= FILE_FLAG_NO_BUFFERING; 00062 } 00063 if (mode.sequential) { 00064 fdwFlags |= FILE_FLAG_SEQUENTIAL_SCAN; 00065 } else { 00066 fdwFlags |= FILE_FLAG_RANDOM_ACCESS; 00067 } 00068 if (mode.temporary) { 00069 fdwFlags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE; 00070 } else { 00071 fdwFlags |= FILE_ATTRIBUTE_NORMAL; 00072 } 00073 00074
00075
00076
00077
00078 00079 handle = reinterpret_cast( 00080 CreateFile( 00081 filename.c_str(), 00082 fdwAccess, 00083 FILE_SHARE_READ | FILE_SHARE_WRITE, 00084 NULL, 00085 fdwCreate, 00086 fdwFlags, 00087 NULL)); 00088 00089 if (isOpen()) { 00090 std::ostringstream oss; 00091 oss << "Failed to open file " << filename; 00092 throw SysCallExcn(oss.str()); 00093 } 00094 00095 DWORD cbHigh = 0; 00096 DWORD cbLow = GetFileSize(HANDLE(handle),&cbHigh); 00097 if (cbLow == INVALID_FILE_SIZE) { 00098 std::ostringstream oss; 00099 oss << "Failed to get size for file " << filename; 00100 throw SysCallExcn(oss.str()); 00101 } 00102 LARGE_INTEGER cbLarge; 00103 cbLarge.LowPart = cbLow; 00104 cbLarge.HighPart = cbHigh; 00105 cbFile = cbLarge.QuadPart; 00106 if (mode.create && initialSize > 0) { 00107 setSizeInBytes(initialSize); 00108 } 00109 00110 #else 00111 00112 int access = O_LARGEFILE; 00113 int permission = S_IRUSR; 00114 if (mode.readOnly) { 00115 access |= O_RDONLY; 00116 } else { 00117 access |= O_RDWR; 00118 permission |= S_IWUSR; 00119 } 00120 if (mode.create) { 00121 access |= O_CREAT | O_TRUNC; 00122 } 00123 00124 if (mode.direct) { 00125
00126
00127
00128
00129
00130 access |= O_SYNC; 00131
00132
00133
00134
00135 } 00136 00137 handle = ::open(filename.c_str(), access, permission); 00138 if (isOpen()) { 00139 std::ostringstream oss; 00140 oss << "Failed to open file " << filename; 00141 throw SysCallExcn(oss.str()); 00142 } 00143 if (flock(handle, LOCK_SH | LOCK_NB) < 0) { 00144 throw SysCallExcn("File lock failed"); 00145 } 00146 cbFile = ::lseek(handle,0,SEEK_END); 00147 00148
00149
00150 if (mode.create && initialSize > 0) { 00151 int rc = posix_fallocate(handle, 0, initialSize); 00152 if (rc) { 00153 throw SysCallExcn("File allocation failed", rc); 00154 } 00155 cbFile = initialSize; 00156 } 00157 00158 #endif 00159 } 00160 00161 FileDevice::~FileDevice() 00162 { 00163 if (isOpen()) { 00164 close(); 00165 } 00166 } 00167 00168 void FileDevice::close() 00169 { 00170 assert(isOpen()); 00171 #ifdef MSVC 00172 CloseHandle(HANDLE(handle)); 00173 #else 00174 ::close(handle); 00175 if (mode.temporary) { 00176 ::unlink(filename.c_str()); 00177 } 00178 #endif 00179 handle = -1; 00180 } 00181 00182 void FileDevice::flush() 00183 { 00184 if (mode.readOnly) { 00185 return; 00186 } 00187 #ifdef MSVC 00188 if (!FlushFileBuffers(HANDLE(handle))) { 00189 throw SysCallExcn("Flush failed"); 00190 } 00191 #else 00192 if (::fdatasync(handle)) { 00193 throw SysCallExcn("Flush failed"); 00194 } 00195 #endif 00196 } 00197 00198 void FileDevice::setSizeInBytes(FileSize cbFileNew) 00199 { 00200 #ifdef MSVC 00201 LARGE_INTEGER cbLarge; 00202 cbLarge.QuadPart = cbFileNew; 00203 if (!SetFilePointerEx(HANDLE(handle),cbLarge,NULL,FILE_BEGIN)) { 00204 throw SysCallExcn("Resize file failed: SetFilePointer"); 00205 } 00206 if (!SetEndOfFile(HANDLE(handle))) { 00207 throw SysCallExcn("Resize file failed: SetEndOfFile"); 00208 } 00209 #else 00210 if (::ftruncate(handle,cbFileNew)) { 00211 throw SysCallExcn("Resize file failed"); 00212 } 00213 #endif 00214 cbFile = cbFileNew; 00215 } 00216 00217 void FileDevice::transfer(RandomAccessRequest const &request) 00218 { 00219 FileSize cbActual; 00220 assert(request.bindingList.size() == 1); 00221 #ifdef MSVC 00222 LARGE_INTEGER largeInt; 00223 RandomAccessRequestBinding &binding = request.bindingList.front(); 00224 largeInt.QuadPart = request.cbOffset; 00225 binding.Offset = largeInt.LowPart; 00226 binding.OffsetHigh = largeInt.HighPart; 00227 00228 DWORD dwActual = 0; 00229 BOOL bCompleted; 00230 if (request.type == RandomAccessRequest::READ) { 00231 bCompleted = ReadFile( 00232 HANDLE(handle), 00233 request.bindingList.front().getBuffer(), 00234 request.cbTransfer, 00235 &dwActual, 00236 &binding); 00237 } else { 00238 bCompleted = WriteFile( 00239 HANDLE(handle), 00240 request.bindingList.front().getBuffer(), 00241 request.cbTransfer, 00242 &dwActual, 00243 &binding); 00244 } 00245 if (!bCompleted) { 00246 if (GetLastError() == ERROR_IO_PENDING) { 00247 if (!GetOverlappedResult( 00248 HANDLE(handle), 00249 &binding, 00250 &dwActual, 00251 TRUE)) 00252 { 00253 dwActual = 0; 00254 } 00255 } else { 00256 dwActual = 0; 00257 } 00258 } 00259 cbActual = dwActual; 00260 #else 00261 if (request.type == RandomAccessRequest::READ) { 00262 cbActual = ::pread( 00263 handle, 00264 request.bindingList.front().getBuffer(), 00265 request.cbTransfer, 00266 request.cbOffset); 00267 } else { 00268 cbActual = ::pwrite( 00269 handle, 00270 request.bindingList.front().getBuffer(), 00271 request.cbTransfer, 00272 request.cbOffset); 00273 } 00274 #endif 00275 request.bindingList.front().notifyTransferCompletion( 00276 cbActual == request.cbTransfer); 00277 } 00278 00279 FENNEL_END_CPPFILE("$Id: //open/dev/fennel/device/FileDevice.cpp#14 $"); 00280 00281