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 <sstream>
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<int>(
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