1 // ========================================================================== 2 // SeqAn - The Library for Sequence Analysis 3 // ========================================================================== 4 // Copyright (c) 2006-2015, Knut Reinert, FU Berlin 5 // All rights reserved. 6 // 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions are met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above copyright 13 // notice, this list of conditions and the following disclaimer in the 14 // documentation and/or other materials provided with the distribution. 15 // * Neither the name of Knut Reinert or the FU Berlin nor the names of 16 // its contributors may be used to endorse or promote products derived 17 // from this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE 23 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 29 // DAMAGE. 30 // 31 // ========================================================================== 32 // Author: David Weese <david.weese@fu-berlin.de> 33 // ========================================================================== 34 35 //SEQAN_NO_GENERATED_FORWARDS: no forwards are generated for this file 36 37 #ifndef SEQAN_HEADER_FILE_SIMPLE_H 38 #define SEQAN_HEADER_FILE_SIMPLE_H 39 40 #include <fcntl.h> // O_CREAT .. 41 #include <sys/stat.h> // 42 #include <cstdio> // tmpnam(..) 43 44 #ifdef PLATFORM_WINDOWS 45 # include <io.h> // read(..) .. 46 # ifdef PLATFORM_WINDOWS_MINGW 47 # include <stdio.h> 48 # endif // #ifdef PLATFORM_WINDOWS_MINGW 49 #else 50 # include <cstdlib> 51 # include <cerrno> 52 # include <unistd.h> 53 #endif 54 55 56 /* IOREV 57 * 58 * _tested_ 59 * _nodoc_ 60 * 61 * contains third way of file-io, low level platform specific, i.e. fd for 62 * POSIX and handles for WINDOWS 63 * 64 * not clear in which places this is used exactly 65 * 66 * SEQAN_DIRECTIO used on UNIX, not sure exactly what it does 67 * use of other macros unclear aswell 68 * 69 */ 70 71 72 73 ////////////////////////////////////////////////////////////////////////////// 74 75 namespace SEQAN_NAMESPACE_MAIN 76 { 77 78 79 template <typename TSpec /* = void */> 80 struct Sync; 81 82 83 #ifdef PLATFORM_WINDOWS 84 85 ////////////////////////////////////////////////////////////////////////////// 86 // Windows rtl file access 87 template <typename TSpec> 88 class File<Sync<TSpec> > 89 { 90 //IOREV _windows_ _nodoc_ 91 public: 92 93 typedef __int64 FilePtr; 94 typedef __int64 SizeType; // type of file size 95 typedef unsigned int SizeType_; // type of transfer size (for read or write) 96 typedef int Handle; 97 98 Handle handle; 99 100 File(void * /*dummy*/ = NULL): // to be compatible with the FILE*(NULL) constructor 101 handle(-1) {} 102 103 //File(int posixHandle) : handle(posixHandle) {} 104 _getOFlag(int openMode)105 inline int _getOFlag(int openMode) const 106 { 107 int result; 108 bool canWrite = false; 109 110 switch (openMode & OPEN_MASK) { 111 case OPEN_RDONLY: 112 result = _O_RDONLY; 113 break; 114 case OPEN_WRONLY: 115 canWrite = true; 116 result = _O_WRONLY; 117 break; 118 case OPEN_RDWR: 119 default: 120 canWrite = true; 121 result = _O_RDWR; 122 break; 123 } 124 125 if (openMode & OPEN_CREATE) result |= _O_CREAT; 126 if (canWrite && !(openMode & OPEN_APPEND)) result |= _O_TRUNC; 127 if (openMode & OPEN_TEMPORARY) result |= _O_TEMPORARY; 128 return result | _O_BINARY; 129 } 130 131 bool open(char const *fileName, int openMode = DefaultOpenMode<File>::VALUE) 132 { 133 handle = ::_open(fileName, _getOFlag(openMode), _S_IREAD | _S_IWRITE); 134 if (handle == -1) { 135 if (!(openMode & OPEN_QUIET)) 136 std::cerr << "Open failed on file " << fileName << ". (" << ::strerror(errno) << ")" << std::endl; 137 return false; 138 } 139 SEQAN_PROADD(SEQAN_PROOPENFILES, 1); 140 return true; 141 } 142 143 bool openTemp(int openMode = DefaultOpenTempMode<File>::VALUE) 144 { 145 #ifdef PLATFORM_WINDOWS_MINGW 146 char fileNameBuffer[L_tmpnam + 1]; 147 char * fileName = tmpnam(&fileNameBuffer[0]); 148 #else // #ifdef PLATFORM_WINDOWS_MINGW 149 # ifdef SEQAN_DEFAULT_TMPDIR 150 char *fileName = _tempnam(SEQAN_DEFAULT_TMPDIR, "SQN"); 151 # else // #ifdef SEQAN_DEFAULT_TMPDIR 152 char *fileName = _tempnam(NULL, "SQN"); 153 # endif // #ifdef SEQAN_DEFAULT_TMPDIR 154 #endif // #ifdef PLATFORM_WINDOWS_MINGW 155 if (!fileName) { 156 if (!(openMode & OPEN_QUIET)) 157 std::cerr << "Cannot create a unique temporary filename" << std::endl; 158 return false; 159 } 160 bool result = open(fileName, openMode | OPEN_TEMPORARY); 161 ::free(fileName); 162 return result; 163 } 164 close()165 inline bool close() 166 { 167 if (_close(handle) != 0) 168 return false; 169 handle = -1; 170 SEQAN_PROSUB(SEQAN_PROOPENFILES, 1); 171 return true; 172 } 173 read(void * buffer,SizeType_ count)174 inline int read(void *buffer, SizeType_ count) const 175 { 176 SEQAN_PROADD(SEQAN_PROIO, (count + SEQAN_PROPAGESIZE - 1) / SEQAN_PROPAGESIZE); 177 SEQAN_PROTIMESTART(tw); 178 int result = ::_read(handle, buffer, count); 179 SEQAN_PROADD(SEQAN_PROCWAIT, SEQAN_PROTIMEDIFF(tw)); 180 return result; 181 } 182 write(void const * buffer,SizeType_ count)183 inline int write(void const *buffer, SizeType_ count) const 184 { 185 SEQAN_PROADD(SEQAN_PROIO, (count + SEQAN_PROPAGESIZE - 1) / SEQAN_PROPAGESIZE); 186 SEQAN_PROTIMESTART(tw); 187 int result = ::_write(handle, buffer, count); 188 SEQAN_PROADD(SEQAN_PROCWAIT, SEQAN_PROTIMEDIFF(tw)); 189 return result; 190 } 191 192 inline FilePtr seek(FilePtr pos, int origin = SEEK_SET) const 193 { 194 return _lseeki64(handle, pos, origin); 195 } 196 tell()197 inline FilePtr tell() const 198 { 199 return _telli64(handle); 200 } 201 error()202 static int error() 203 { 204 return errno; 205 } 206 207 operator bool () const 208 { 209 return handle != -1; 210 } 211 }; 212 fileExists(const char * fileName)213 inline bool fileExists(const char *fileName) 214 { 215 //IOREV _windows_ _nodoc_ 216 struct _stat buf; 217 return _stat(fileName, &buf) == 0; 218 } 219 fileUnlink(const char * fileName)220 inline bool fileUnlink(const char *fileName) 221 { 222 //IOREV _windows_ _nodoc_ 223 return _unlink(fileName) == 0; 224 } 225 226 #else 227 228 ////////////////////////////////////////////////////////////////////////////// 229 // Unix file access 230 template <typename TSpec> 231 class File<Sync<TSpec> > 232 { 233 //IOREV __nodoc_ 234 public: 235 236 typedef off_t FilePtr; 237 typedef off_t SizeType; // type of file size 238 typedef size_t SizeType_; // type of transfer size (for read or write) 239 typedef int Handle; 240 241 Handle handle; 242 243 File(void * /*dummy*/ = NULL): // to be compatible with the FILE*(NULL) constructor 244 handle(-1) {} 245 246 ///File(int posixHandle) : handle(posixHandle) {} 247 ~File()248 virtual ~File() {} 249 _getOFlag(int openMode)250 inline int _getOFlag(int openMode) const { 251 int result = O_LARGEFILE; 252 253 switch (openMode & OPEN_MASK) { 254 case OPEN_RDONLY: 255 result |= O_RDONLY; 256 break; 257 case OPEN_WRONLY: 258 result |= O_WRONLY; 259 if (!(openMode & OPEN_APPEND)) result |= O_TRUNC; 260 break; 261 case OPEN_RDWR: 262 result |= O_RDWR; 263 if (!(openMode & OPEN_APPEND)) result |= O_TRUNC; 264 break; 265 } 266 267 if (openMode & OPEN_CREATE) result |= O_CREAT; 268 // if (openMode & OPEN_TEMPORARY) result |= O_TEMPORARY; 269 #ifdef SEQAN_DIRECTIO 270 if (openMode & OPEN_ASYNC) result |= O_DIRECT; 271 #endif 272 return result; 273 } 274 275 virtual bool open(char const *fileName, int openMode = DefaultOpenMode<File>::VALUE) { 276 handle = ::open(fileName, _getOFlag(openMode), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 277 if (handle == -1 && errno == EINVAL) { // fall back to cached access 278 #ifdef SEQAN_DEBUG_OR_TEST_ 279 if (!(openMode & OPEN_QUIET)) 280 std::cerr << "Warning: Direct access openening failed: " << fileName << "." << std::endl; 281 #endif 282 handle = ::open(fileName, _getOFlag(openMode & ~OPEN_ASYNC), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 283 } 284 285 if (handle == -1) { 286 if (!(openMode & OPEN_QUIET)) 287 std::cerr << "Open failed on file " << fileName << ". (" << ::strerror(errno) << ")" << std::endl; 288 return false; 289 } 290 291 if (sizeof(FilePtr) < 8 && !(openMode & OPEN_QUIET)) 292 // To remove this warning, you have to options: 293 // 1. include the following line before including anything in your application 294 // #define _FILE_OFFSET_BITS 64 295 // 2. include <seqan/platform.h> or <seqan/sequence.h> before any other include 296 std::cerr << "WARNING: FilePtr is not 64bit wide" << std::endl; 297 298 SEQAN_PROADD(SEQAN_PROOPENFILES, 1); 299 return true; 300 } 301 302 bool openTemp(int openMode = DefaultOpenTempMode<File>::VALUE) 303 { 304 // Construct the pattern for the temporary file. 305 // 306 // First, try to get the temporary directory from the environment 307 // variables TMPDIR, TMP. 308 std::string tmpDir; 309 if ((getuid() == geteuid()) && (getgid() == getegid())) 310 { 311 char * res; 312 if ((res = getenv("TMPDIR")) != NULL) 313 tmpDir = res; 314 else 315 if ((res = getenv("TMP")) != NULL) 316 tmpDir = res; 317 } 318 // If this does not work, try to use the constant 319 // SEQAN_DEFAULT_TMPDIR, fall back to "/tmp", if this does not 320 // work. 321 #ifdef SEQAN_DEFAULT_TMPDIR 322 if (empty(tmpDir)) 323 tmpDir = SEQAN_DEFAULT_TMPDIR; 324 #else // #ifdef SEQAN_DEFAULT_TMPDIR 325 if (empty(tmpDir)) 326 tmpDir = "/tmp"; 327 #endif // #ifdef SEQAN_DEFAULT_TMPDIR 328 329 // At this point, we have a temporary directory. Now, we add the 330 // file name template to get the full path template. 331 tmpDir += "/SQNXXXXXX"; 332 // Open temporary file and unlink it immediately afterwards so the 333 // memory is released when the program exits. 334 int oldMode = umask(077); // Create with restrictive permissions. 335 if ((handle = ::mkstemp((char*)tmpDir.c_str())) == -1) 336 { 337 umask(oldMode); // Reset umask mode. 338 if (!(openMode & OPEN_QUIET)) 339 std::cerr << "Couldn't create temporary file " << tmpDir << ". (" << ::strerror(errno) << ")" << std::endl; 340 return false; 341 } 342 if (!(close() && open(toCString(tmpDir), openMode))) 343 { 344 umask(oldMode); // Reset umask mode. 345 return false; 346 } 347 umask(oldMode); // Reset umask mode. 348 #ifdef SEQAN_DEBUG 349 if (::unlink(toCString(tmpDir)) == -1 && !(openMode & OPEN_QUIET)) 350 std::cerr << "Couldn't unlink temporary file " << tmpDir << ". (" << ::strerror(errno) << ")" << std::endl; 351 #else 352 ::unlink(toCString(tmpDir)); 353 #endif 354 return true; 355 } 356 357 close()358 virtual bool close() { 359 if (::close(this->handle) == -1) return false; 360 handle = -1; 361 SEQAN_PROSUB(SEQAN_PROOPENFILES, 1); 362 return true; 363 } 364 read(void * buffer,SizeType_ count)365 inline ssize_t read(void *buffer, SizeType_ count) const { 366 SEQAN_PROADD(SEQAN_PROIO, (count + SEQAN_PROPAGESIZE - 1) / SEQAN_PROPAGESIZE); 367 SEQAN_PROTIMESTART(tw); 368 ssize_t result = ::read(handle, buffer, count); 369 SEQAN_PROADD(SEQAN_PROCWAIT, SEQAN_PROTIMEDIFF(tw)); 370 return result; 371 } 372 write(void const * buffer,SizeType_ count)373 inline ssize_t write(void const *buffer, SizeType_ count) const { 374 SEQAN_PROADD(SEQAN_PROIO, (count + SEQAN_PROPAGESIZE - 1) / SEQAN_PROPAGESIZE); 375 SEQAN_PROTIMESTART(tw); 376 ssize_t result = ::write(handle, buffer, count); 377 SEQAN_PROADD(SEQAN_PROCWAIT, SEQAN_PROTIMEDIFF(tw)); 378 return result; 379 } 380 381 inline FilePtr seek(FilePtr pos, int origin = SEEK_SET) const { 382 FilePtr result = ::lseek(handle, pos, origin); 383 // #ifdef SEQAN_DEBUG 384 if (result < 0) 385 std::cerr << "lseek returned " << result << ". (" << ::strerror(errno) << ")" << std::endl; 386 // #endif 387 return result; 388 } 389 tell()390 inline FilePtr tell() const { 391 return seek(0, SEEK_CUR); 392 } 393 resize(SizeType new_length)394 inline bool resize(SizeType new_length) const { 395 return ftruncate(handle, new_length) == 0; 396 } 397 error()398 static int error() { 399 return errno; 400 } 401 402 operator bool () const { 403 return handle != -1; 404 } 405 }; 406 fileExists(const char * fileName)407 inline bool fileExists(const char *fileName) 408 { 409 //IOREV _nodoc_ 410 struct stat buf; 411 return stat(fileName, &buf) != -1; 412 } 413 fileUnlink(const char * fileName)414 inline bool fileUnlink(const char *fileName) 415 { 416 //IOREV _noddoc_ 417 return unlink(fileName) == 0; 418 } 419 420 template < typename TSpec, typename TSize > resize(File<Sync<TSpec>> & me,TSize new_length)421 inline void resize(File<Sync<TSpec> > &me, TSize new_length) 422 { 423 //IOREV _doc_ 424 if (!me.resize(new_length)) 425 SEQAN_FAIL( 426 "resize(%d, %d) failed: \"%s\"", 427 me.handle, new_length, strerror(errno)); 428 } 429 430 #endif 431 432 ////////////////////////////////////////////////////////////////////////////// 433 // global functions 434 435 template <typename TSpec> 436 struct Size< File<Sync<TSpec> > > 437 { 438 //IOREV 439 typedef typename File<Sync<TSpec> >::SizeType Type; 440 }; 441 442 template <typename TSpec> 443 struct Position< File<Sync<TSpec> > > 444 { 445 //IOREV 446 typedef typename File<Sync<TSpec> >::FilePtr Type; 447 }; 448 449 template <typename TSpec> 450 struct Difference< File<Sync<TSpec> > > 451 { 452 //IOREV 453 typedef typename File<Sync<TSpec> >::FilePtr Type; 454 }; 455 456 template < typename TSpec, typename TValue, typename TSize > 457 inline bool read(File<Sync<TSpec> > & me, TValue *memPtr, TSize const count) 458 { 459 return (size_t)me.read(memPtr, count * sizeof(TValue)) == (size_t)(count * sizeof(TValue)); 460 } 461 462 template < typename TSpec, typename TValue, typename TSize > 463 inline bool write(File<Sync<TSpec> > & me, TValue *memPtr, TSize const count) 464 { 465 return (size_t)me.write(memPtr, count * sizeof(TValue)) == (size_t)(count * sizeof(TValue)); 466 } 467 468 template < typename TSpec, typename TValue, typename TSize > 469 inline bool write(File<Sync<TSpec> > & me, TValue const *memPtr, TSize const count) 470 { 471 return (size_t)me.write(memPtr, count * sizeof(TValue)) == (size_t)(count * sizeof(TValue)); 472 } 473 474 } 475 476 #endif 477