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