00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #pragma once
00019
00020 #if !defined(_WIN32)
00021 #include "errno.h"
00022 #include <sys/mman.h>
00023 #include <sys/types.h>
00024 #include <sys/stat.h>
00025 #include <fcntl.h>
00026 #include <sys/statvfs.h>
00027 #endif
00028 #include "text.h"
00029
00030 namespace mongo {
00031
00032 #ifndef __sunos__
00033 typedef uint64_t fileofs;
00034 #else
00035 typedef boost::uint64_t fileofs;
00036 #endif
00037
00038
00039
00040 class FileInterface {
00041 public:
00042 void open(const char *fn) {}
00043 void write(fileofs o, const char *data, unsigned len) {}
00044 void read(fileofs o, char *data, unsigned len) {}
00045 bool bad() {return false;}
00046 bool is_open() {return false;}
00047 fileofs len() { return 0; }
00048 void fsync() { assert(false); }
00049
00050
00051 void truncate(fileofs size);
00052
00054 static boost::intmax_t freeSpace(const string &path) { assert(false); return -1; }
00055 };
00056
00057 #if defined(_WIN32)
00058 #include <io.h>
00059
00060 class File : public FileInterface {
00061 HANDLE fd;
00062 bool _bad;
00063 string _name;
00064 void err(BOOL b=false) {
00065 if( !b && !_bad ) {
00066 _bad = true;
00067 log() << "File " << _name << "I/O error " << GetLastError() << '\n';
00068 }
00069 }
00070 public:
00071 File() {
00072 fd = INVALID_HANDLE_VALUE;
00073 _bad = true;
00074 }
00075 ~File() {
00076 if( is_open() ) CloseHandle(fd);
00077 fd = INVALID_HANDLE_VALUE;
00078 }
00079 void open(const char *filename, bool readOnly=false , bool direct=false) {
00080 _name = filename;
00081 fd = CreateFile(
00082 toNativeString(filename).c_str(),
00083 ( readOnly ? 0 : GENERIC_WRITE ) | GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ,
00084 NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
00085 if( !is_open() ) {
00086 DWORD e = GetLastError();
00087 log() << "Create/Open File failed " << filename << ' ' << errnoWithDescription(e) << endl;
00088 }
00089 else
00090 _bad = false;
00091 }
00092 static boost::intmax_t freeSpace(const string &path) {
00093 ULARGE_INTEGER avail;
00094 if( GetDiskFreeSpaceEx(toNativeString(path.c_str()).c_str(), &avail, NULL, NULL) ) {
00095 return avail.QuadPart;
00096 }
00097 DWORD e = GetLastError();
00098 log() << "GetDiskFreeSpaceEx fails errno: " << e << endl;
00099 return -1;
00100 }
00101 void write(fileofs o, const char *data, unsigned len) {
00102 LARGE_INTEGER li;
00103 li.QuadPart = o;
00104 SetFilePointerEx(fd, li, NULL, FILE_BEGIN);
00105 DWORD written;
00106 err( WriteFile(fd, data, len, &written, NULL) );
00107 }
00108 void read(fileofs o, char *data, unsigned len) {
00109 DWORD read;
00110 LARGE_INTEGER li;
00111 li.QuadPart = o;
00112 SetFilePointerEx(fd, li, NULL, FILE_BEGIN);
00113 int ok = ReadFile(fd, data, len, &read, 0);
00114 if( !ok )
00115 err(ok);
00116 else
00117 massert( 10438 , "ReadFile error - truncated file?", read == len);
00118 }
00119 bool bad() { return _bad; }
00120 bool is_open() { return fd != INVALID_HANDLE_VALUE; }
00121 fileofs len() {
00122 LARGE_INTEGER li;
00123 li.LowPart = GetFileSize(fd, (DWORD *) &li.HighPart);
00124 if( li.HighPart == 0 && li.LowPart == INVALID_FILE_SIZE ) {
00125 err( false );
00126 return 0;
00127 }
00128 return li.QuadPart;
00129 }
00130 void fsync() { FlushFileBuffers(fd); }
00131
00132 void truncate(fileofs size) {
00133 if (len() <= size)
00134 return;
00135
00136 LARGE_INTEGER li;
00137 li.QuadPart = size;
00138 if (SetFilePointerEx(fd, li, NULL, FILE_BEGIN) == 0){
00139 err(false);
00140 return;
00141 }
00142
00143 err(SetEndOfFile(fd));
00144 }
00145 };
00146
00147 #else
00148
00149 class File : public FileInterface {
00150 public:
00151 int fd;
00152 private:
00153 bool _bad;
00154 void err(bool ok) {
00155 if( !ok && !_bad ) {
00156 _bad = true;
00157 log() << "File I/O " << errnoWithDescription() << '\n';
00158 }
00159 }
00160 public:
00161 File() {
00162 fd = -1;
00163 _bad = true;
00164 }
00165 ~File() {
00166 if( is_open() ) ::close(fd);
00167 fd = -1;
00168 }
00169
00170 #ifndef O_NOATIME
00171 #define O_NOATIME 0
00172 #endif
00173
00174 void open(const char *filename, bool readOnly=false , bool direct=false) {
00175 fd = ::open(filename,
00176 O_CREAT | ( readOnly ? 0 : ( O_RDWR | O_NOATIME ) )
00177 #if defined(O_DIRECT)
00178 | ( direct ? O_DIRECT : 0 )
00179 #endif
00180 ,
00181 S_IRUSR | S_IWUSR);
00182 if ( fd <= 0 ) {
00183 out() << "couldn't open " << filename << ' ' << errnoWithDescription() << endl;
00184 return;
00185 }
00186 _bad = false;
00187 }
00188 void write(fileofs o, const char *data, unsigned len) {
00189 err( ::pwrite(fd, data, len, o) == (int) len );
00190 }
00191 void read(fileofs o, char *data, unsigned len) {
00192 ssize_t s = ::pread(fd, data, len, o);
00193 if( s == -1 ) {
00194 err(false);
00195 }
00196 else if( s != (int) len ) {
00197 _bad = true;
00198 log() << "File error read:" << s << " bytes, wanted:" << len << " ofs:" << o << endl;
00199 }
00200 }
00201 bool bad() { return _bad; }
00202 bool is_open() { return fd > 0; }
00203 fileofs len() {
00204 off_t o = lseek(fd, 0, SEEK_END);
00205 if( o != (off_t) -1 )
00206 return o;
00207 err(false);
00208 return 0;
00209 }
00210 void fsync() { ::fsync(fd); }
00211 static boost::intmax_t freeSpace ( const string &path ) {
00212 struct statvfs info;
00213 assert( !statvfs( path.c_str() , &info ) );
00214 return boost::intmax_t( info.f_bavail ) * info.f_frsize;
00215 }
00216
00217 void truncate(fileofs size) {
00218 if (len() <= size)
00219 return;
00220
00221 err(ftruncate(fd, size) == 0);
00222 }
00223 };
00224
00225
00226 #endif
00227
00228
00229 }
00230