1 // ==========================================================================
2 // SeqAn - The Library for Sequence Analysis
3 // ==========================================================================
4 // Copyright (c) 2006-2018, 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 STDLIB_VS
45 # include <io.h> // read(..) ..
46 #else
47 # include <cstdlib>
48 # include <cerrno>
49 # include <unistd.h>
50 #endif
51
52
53 /* IOREV
54 *
55 * _tested_
56 * _nodoc_
57 *
58 * contains third way of file-io, low level platform specific, i.e. fd for
59 * POSIX and handles for WINDOWS
60 *
61 * not clear in which places this is used exactly
62 *
63 * SEQAN_DIRECTIO used on UNIX, not sure exactly what it does
64 * use of other macros unclear aswell
65 *
66 */
67
68
69
70 //////////////////////////////////////////////////////////////////////////////
71
72 namespace seqan
73 {
74
75
76 template <typename TSpec /* = void */>
77 struct Sync {};
78
79
80 #ifdef STDLIB_VS
81
82 //////////////////////////////////////////////////////////////////////////////
83 // Windows rtl file access
84 template <typename TSpec>
85 class File<Sync<TSpec> >
86 {
87 //IOREV _windows_ _nodoc_
88 public:
89
90 typedef int64_t FilePtr;
91 typedef int64_t SizeType; // type of file size
92 typedef unsigned int SizeType_; // type of transfer size (for read or write)
93 typedef int Handle;
94
95 Handle handle;
96
97 File(void * /*dummy*/ = NULL) : // to be compatible with the FILE*(NULL) constructor
98 handle(-1) {}
99
~File()100 virtual ~File()
101 {
102 close();
103 }
104
105 //File(int posixHandle) : handle(posixHandle) {}
106
_getOFlag(int openMode)107 inline int _getOFlag(int openMode) const
108 {
109 int result;
110 bool canWrite = false;
111
112 switch (openMode & OPEN_MASK)
113 {
114 case OPEN_RDONLY:
115 result = _O_RDONLY;
116 break;
117
118 case OPEN_WRONLY:
119 canWrite = true;
120 result = _O_WRONLY;
121 break;
122
123 case OPEN_RDWR:
124 default:
125 canWrite = true;
126 result = _O_RDWR;
127 break;
128 }
129
130 if (openMode & OPEN_CREATE) result |= _O_CREAT;
131 if (canWrite && !(openMode & OPEN_APPEND)) result |= _O_TRUNC;
132 if (openMode & OPEN_TEMPORARY) result |= _O_TEMPORARY;
133 return result | _O_BINARY;
134 }
135
136 bool open(char const * fileName, int openMode = DefaultOpenMode<File>::VALUE)
137 {
138 handle = ::_open(fileName, _getOFlag(openMode), _S_IREAD | _S_IWRITE);
139 if (handle == -1)
140 {
141 if (!(openMode & OPEN_QUIET))
142 std::cerr << "Open failed on file " << fileName << ". (" << ::strerror(errno) << ")" << std::endl;
143 return false;
144 }
145 SEQAN_PROADD(SEQAN_PROOPENFILES, 1);
146 return true;
147 }
148
149 bool openTemp(int openMode = DefaultOpenTempMode<File>::VALUE)
150 {
151 #ifdef SEQAN_DEFAULT_TMPDIR
152 char * fileName = _tempnam(SEQAN_DEFAULT_TMPDIR, "SQN");
153 #else // #ifdef SEQAN_DEFAULT_TMPDIR
154 char * fileName = _tempnam(NULL, "SQN");
155 #endif // #ifdef SEQAN_DEFAULT_TMPDIR
156 if (!fileName)
157 {
158 if (!(openMode & OPEN_QUIET))
159 std::cerr << "Cannot create a unique temporary filename" << std::endl;
160 return false;
161 }
162 bool result = open(fileName, openMode | OPEN_TEMPORARY);
163 ::free(fileName);
164 return result;
165 }
166
close()167 inline bool close()
168 {
169 if (_close(handle) != 0)
170 return false;
171
172 handle = -1;
173 SEQAN_PROSUB(SEQAN_PROOPENFILES, 1);
174 return true;
175 }
176
read(void * buffer,SizeType_ count)177 inline int read(void * buffer, SizeType_ count) const
178 {
179 SEQAN_PROADD(SEQAN_PROIO, (count + SEQAN_PROPAGESIZE - 1) / SEQAN_PROPAGESIZE);
180 SEQAN_PROTIMESTART(tw);
181 int result = ::_read(handle, buffer, count);
182 SEQAN_PROADD(SEQAN_PROCWAIT, SEQAN_PROTIMEDIFF(tw));
183 return result;
184 }
185
write(void const * buffer,SizeType_ count)186 inline int write(void const * buffer, SizeType_ count) const
187 {
188 SEQAN_PROADD(SEQAN_PROIO, (count + SEQAN_PROPAGESIZE - 1) / SEQAN_PROPAGESIZE);
189 SEQAN_PROTIMESTART(tw);
190 int result = ::_write(handle, buffer, count);
191 SEQAN_PROADD(SEQAN_PROCWAIT, SEQAN_PROTIMEDIFF(tw));
192 return result;
193 }
194
195 inline FilePtr seek(FilePtr pos, int origin = SEEK_SET) const
196 {
197 return _lseeki64(handle, pos, origin);
198 }
199
tell()200 inline FilePtr tell() const
201 {
202 return _telli64(handle);
203 }
204
error()205 static int error()
206 {
207 return errno;
208 }
209
210 operator bool() const
211 {
212 return handle != -1;
213 }
214 };
215
fileExists(const char * fileName)216 inline bool fileExists(const char * fileName)
217 {
218 //IOREV _windows_ _nodoc_
219 struct _stat buf;
220 return _stat(fileName, &buf) == 0;
221 }
222
fileUnlink(const char * fileName)223 inline bool fileUnlink(const char * fileName)
224 {
225 //IOREV _windows_ _nodoc_
226 return _unlink(fileName) == 0;
227 }
228
229 #else
230
231 //////////////////////////////////////////////////////////////////////////////
232 // Unix file access
233 template <typename TSpec>
234 class File<Sync<TSpec> >
235 {
236 //IOREV __nodoc_
237 public:
238
239 typedef off_t FilePtr;
240 typedef off_t SizeType; // type of file size
241 typedef size_t SizeType_; // type of transfer size (for read or write)
242 typedef int Handle;
243
244 Handle handle;
245
246 File(void * /*dummy*/ = NULL) : // to be compatible with the FILE*(NULL) constructor
247 handle(-1) {}
248
249 ///File(int posixHandle) : handle(posixHandle) {}
250
~File()251 virtual ~File()
252 {
253 this->close();
254 }
255
_getOFlag(int openMode)256 inline int _getOFlag(int openMode) const
257 {
258 int result = O_LARGEFILE;
259
260 switch (openMode & OPEN_MASK)
261 {
262 case OPEN_RDONLY:
263 result |= O_RDONLY;
264 break;
265
266 case OPEN_WRONLY:
267 result |= O_WRONLY;
268 if (!(openMode & OPEN_APPEND)) result |= O_TRUNC;
269 break;
270
271 case OPEN_RDWR:
272 result |= O_RDWR;
273 if (!(openMode & OPEN_APPEND)) result |= O_TRUNC;
274 break;
275 }
276
277 if (openMode & OPEN_CREATE) result |= O_CREAT;
278 // if (openMode & OPEN_TEMPORARY) result |= O_TEMPORARY;
279 #ifdef SEQAN_DIRECTIO
280 if (openMode & OPEN_ASYNC) result |= O_DIRECT;
281 #endif
282 return result;
283 }
284
285 virtual bool open(char const * fileName, int openMode = DefaultOpenMode<File>::VALUE)
286 {
287 handle = ::open(fileName, _getOFlag(openMode), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
288 if (handle == -1 && errno == EINVAL) // fall back to cached access
289 {
290 #ifdef SEQAN_DEBUG_OR_TEST_
291 if (!(openMode & OPEN_QUIET))
292 std::cerr << "Warning: Direct access openening failed: " << fileName << "." << std::endl;
293 #endif
294 handle = ::open(fileName, _getOFlag(openMode & ~OPEN_ASYNC), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
295 }
296
297 if (handle == -1)
298 {
299 if (!(openMode & OPEN_QUIET))
300 std::cerr << "Open failed on file " << fileName << ". (" << ::strerror(errno) << ")" << std::endl;
301 return false;
302 }
303
304 if (sizeof(FilePtr) < 8 && !(openMode & OPEN_QUIET))
305 // To remove this warning, you have to options:
306 // 1. include the following line before including anything in your application
307 // #define _FILE_OFFSET_BITS 64
308 // 2. include <seqan/platform.h> or <seqan/sequence.h> before any other include
309 std::cerr << "WARNING: FilePtr is not 64bit wide" << std::endl;
310
311 SEQAN_PROADD(SEQAN_PROOPENFILES, 1);
312 return true;
313 }
314
315 bool openTemp(int openMode = DefaultOpenTempMode<File>::VALUE)
316 {
317 // Construct the pattern for the temporary file.
318 //
319 // First, try to get the temporary directory from the environment
320 // variables TMPDIR, TMP.
321 std::string tmpDir;
322 if ((getuid() == geteuid()) && (getgid() == getegid()))
323 {
324 char * res;
325 if ((res = getenv("TMPDIR")) != NULL)
326 tmpDir = res;
327 else if ((res = getenv("TMP")) != NULL)
328 tmpDir = res;
329 }
330 // If this does not work, try to use the constant
331 // SEQAN_DEFAULT_TMPDIR, fall back to "/tmp", if this does not
332 // work.
333 #ifdef SEQAN_DEFAULT_TMPDIR
334 if (empty(tmpDir))
335 tmpDir = SEQAN_DEFAULT_TMPDIR;
336 #else // #ifdef SEQAN_DEFAULT_TMPDIR
337 if (empty(tmpDir))
338 tmpDir = "/tmp";
339 #endif // #ifdef SEQAN_DEFAULT_TMPDIR
340
341 // At this point, we have a temporary directory. Now, we add the
342 // file name template to get the full path template.
343 tmpDir += "/SQNXXXXXX";
344 // Open temporary file and unlink it immediately afterwards so the
345 // memory is released when the program exits.
346 int oldMode = umask(077); // Create with restrictive permissions.
347 if ((handle = ::mkstemp((char *)tmpDir.c_str())) == -1)
348 {
349 umask(oldMode); // Reset umask mode.
350 if (!(openMode & OPEN_QUIET))
351 std::cerr << "Couldn't create temporary file " << tmpDir << ". (" << ::strerror(errno) << ")" << std::endl;
352 return false;
353 }
354 if (!(close() && open(toCString(tmpDir), openMode)))
355 {
356 umask(oldMode); // Reset umask mode.
357 return false;
358 }
359 umask(oldMode); // Reset umask mode.
360 #ifdef SEQAN_DEBUG
361 if (::unlink(toCString(tmpDir)) == -1 && !(openMode & OPEN_QUIET))
362 std::cerr << "Couldn't unlink temporary file " << tmpDir << ". (" << ::strerror(errno) << ")" << std::endl;
363 #else
364 ::unlink(toCString(tmpDir));
365 #endif
366 return true;
367 }
368
close()369 virtual bool close()
370 {
371 if (::close(this->handle) == -1) return false;
372
373 handle = -1;
374 SEQAN_PROSUB(SEQAN_PROOPENFILES, 1);
375 return true;
376 }
377
read(void * buffer,SizeType_ count)378 inline ssize_t read(void * buffer, SizeType_ count) const
379 {
380 SEQAN_PROADD(SEQAN_PROIO, (count + SEQAN_PROPAGESIZE - 1) / SEQAN_PROPAGESIZE);
381 SEQAN_PROTIMESTART(tw);
382 ssize_t result = ::read(handle, buffer, count);
383 SEQAN_PROADD(SEQAN_PROCWAIT, SEQAN_PROTIMEDIFF(tw));
384 return result;
385 }
386
write(void const * buffer,SizeType_ count)387 inline ssize_t write(void const * buffer, SizeType_ count) const
388 {
389 SEQAN_PROADD(SEQAN_PROIO, (count + SEQAN_PROPAGESIZE - 1) / SEQAN_PROPAGESIZE);
390 SEQAN_PROTIMESTART(tw);
391 ssize_t result = ::write(handle, buffer, count);
392 SEQAN_PROADD(SEQAN_PROCWAIT, SEQAN_PROTIMEDIFF(tw));
393 return result;
394 }
395
396 inline FilePtr seek(FilePtr pos, int origin = SEEK_SET) const
397 {
398 FilePtr result = ::lseek(handle, pos, origin);
399 // #ifdef SEQAN_DEBUG
400 if (result < 0)
401 std::cerr << "lseek returned " << result << ". (" << ::strerror(errno) << ")" << std::endl;
402 // #endif
403 return result;
404 }
405
tell()406 inline FilePtr tell() const
407 {
408 return seek(0, SEEK_CUR);
409 }
410
resize(SizeType new_length)411 inline bool resize(SizeType new_length) const
412 {
413 return ftruncate(handle, new_length) == 0;
414 }
415
error()416 static int error()
417 {
418 return errno;
419 }
420
421 operator bool() const {
422 return handle != -1;
423 }
424 };
425
fileExists(const char * fileName)426 inline bool fileExists(const char * fileName)
427 {
428 //IOREV _nodoc_
429 struct stat buf;
430 return stat(fileName, &buf) != -1;
431 }
432
fileUnlink(const char * fileName)433 inline bool fileUnlink(const char * fileName)
434 {
435 //IOREV _noddoc_
436 return unlink(fileName) == 0;
437 }
438
439 template <typename TSpec, typename TSize>
resize(File<Sync<TSpec>> & me,TSize new_length)440 inline void resize(File<Sync<TSpec> > & me, TSize new_length)
441 {
442 //IOREV _doc_
443 if (!me.resize(new_length))
444 SEQAN_FAIL(
445 "resize(%d, %d) failed: \"%s\"",
446 me.handle, new_length, strerror(errno));
447 }
448
449 #endif
450
451 //////////////////////////////////////////////////////////////////////////////
452 // global functions
453
454 template <typename TSpec>
455 struct Size<File<Sync<TSpec> > >
456 {
457 //IOREV
458 typedef typename File<Sync<TSpec> >::SizeType Type;
459 };
460
461 template <typename TSpec>
462 struct Position<File<Sync<TSpec> > >
463 {
464 //IOREV
465 typedef typename File<Sync<TSpec> >::FilePtr Type;
466 };
467
468 template <typename TSpec>
469 struct Difference<File<Sync<TSpec> > >
470 {
471 //IOREV
472 typedef typename File<Sync<TSpec> >::FilePtr Type;
473 };
474
475 template <typename TSpec, typename TValue, typename TSize>
476 inline bool read(File<Sync<TSpec> > & me, TValue * memPtr, TSize const count)
477 {
478 return (size_t)me.read(memPtr, count * sizeof(TValue)) == (size_t)(count * sizeof(TValue));
479 }
480
481 template <typename TSpec, typename TValue, typename TSize>
482 inline bool write(File<Sync<TSpec> > & me, TValue * memPtr, TSize const count)
483 {
484 return (size_t)me.write(memPtr, count * sizeof(TValue)) == (size_t)(count * sizeof(TValue));
485 }
486
487 template <typename TSpec, typename TValue, typename TSize>
488 inline bool write(File<Sync<TSpec> > & me, TValue const * memPtr, TSize const count)
489 {
490 return (size_t)me.write(memPtr, count * sizeof(TValue)) == (size_t)(count * sizeof(TValue));
491 }
492
493 }
494
495 #endif
496