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