STXXL  1.4-dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ufs_file_base.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * lib/io/ufs_file_base.cpp
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 2002, 2005, 2008 Roman Dementiev <[email protected]>
7  * Copyright (C) 2008 Ilja Andronov <[email protected]>
8  * Copyright (C) 2008-2010 Andreas Beckmann <[email protected]>
9  * Copyright (C) 2009 Johannes Singler <[email protected]>
10  * Copyright (C) 2013 Timo Bingmann <[email protected]>
11  *
12  * Distributed under the Boost Software License, Version 1.0.
13  * (See accompanying file LICENSE_1_0.txt or copy at
14  * http://www.boost.org/LICENSE_1_0.txt)
15  **************************************************************************/
16 
19 #include <stxxl/bits/config.h>
20 #include <stxxl/bits/io/file.h>
22 #include <stxxl/bits/verbose.h>
23 #include "ufs_platform.h"
24 
26 
27 const char* ufs_file_base::io_type() const
28 {
29  return "ufs_base";
30 }
31 
32 ufs_file_base::ufs_file_base(
33  const std::string& filename,
34  int mode)
35  : file_des(-1), m_mode(mode), filename(filename)
36 {
37  int flags = 0;
38 
39  if (mode & RDONLY)
40  {
41  flags |= O_RDONLY;
42  }
43 
44  if (mode & WRONLY)
45  {
46  flags |= O_WRONLY;
47  }
48 
49  if (mode & RDWR)
50  {
51  flags |= O_RDWR;
52  }
53 
54  if (mode & CREAT)
55  {
56  flags |= O_CREAT;
57  }
58 
59  if (mode & TRUNC)
60  {
61  flags |= O_TRUNC;
62  }
63 
64  if ((mode & DIRECT) || (mode & REQUIRE_DIRECT))
65  {
66 #ifdef __APPLE__
67  // no additional open flags are required for Mac OS X
68 #elif !STXXL_DIRECT_IO_OFF
69  flags |= O_DIRECT;
70 #else
71  if (mode & REQUIRE_DIRECT) {
72  STXXL_ERRMSG("Error: open()ing " << filename << " with DIRECT mode required, but the system does not support it.");
73  file_des = -1;
74  return;
75  }
76  else {
77  STXXL_MSG("Warning: open()ing " << filename << " without DIRECT mode, as the system does not support it.");
78  }
79 #endif
80  }
81 
82  if (mode & SYNC)
83  {
84  flags |= O_RSYNC;
85  flags |= O_DSYNC;
86  flags |= O_SYNC;
87  }
88 
89 #if STXXL_WINDOWS
90  flags |= O_BINARY; // the default in MS is TEXT mode
91 #endif
92 
93 #if STXXL_WINDOWS || defined(__MINGW32__)
94  const int perms = S_IREAD | S_IWRITE;
95 #else
96  const int perms = S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP;
97 #endif
98 
99  if ((file_des = ::open(filename.c_str(), flags, perms)) >= 0)
100  {
101  _after_open();
102  return;
103  }
104 
105 #if !STXXL_DIRECT_IO_OFF
106  if ((mode & DIRECT) && !(mode & REQUIRE_DIRECT) && errno == EINVAL)
107  {
108  STXXL_MSG("open() error on path=" << filename << " flags=" << flags << ", retrying without O_DIRECT.");
109 
110  flags &= ~O_DIRECT;
111  m_mode &= ~DIRECT;
112 
113  if ((file_des = ::open(filename.c_str(), flags, perms)) >= 0)
114  {
115  _after_open();
116  return;
117  }
118  }
119 #endif
120 
121  STXXL_THROW_ERRNO(io_error, "open() rc=" << file_des << " path=" << filename << " flags=" << flags);
122 }
123 
125 {
126  close();
127 }
128 
130 {
131  // stat file type
132 #if STXXL_WINDOWS || defined(__MINGW32__)
133  struct _stat64 st;
134  STXXL_THROW_ERRNO_NE_0(::_fstat64(file_des, &st), io_error,
135  "_fstat64() path=" << filename << " fd=" << file_des);
136 #else
137  struct stat st;
139  "fstat() path=" << filename << " fd=" << file_des);
140 #endif
141  m_is_device = S_ISBLK(st.st_mode) ? true : false;
142 
143 #ifdef __APPLE__
144  if (m_mode & REQUIRE_DIRECT) {
145  STXXL_THROW_ERRNO_NE_0(fcntl(file_des, F_NOCACHE, 1), io_error,
146  "fcntl() path=" << filename << " fd=" << file_des);
147  STXXL_THROW_ERRNO_NE_0(fcntl(file_des, F_RDAHEAD, 0), io_error,
148  "fcntl() path=" << filename << " fd=" << file_des);
149  }
150  else if (m_mode & DIRECT) {
151  if (fcntl(file_des, F_NOCACHE, 1) != 0) {
152  STXXL_MSG("fcntl(fd,F_NOCACHE,1) failed on path=" << filename <<
153  " fd=" << file_des << " : " << strerror(errno));
154  }
155  if (fcntl(file_des, F_RDAHEAD, 0) != 0) {
156  STXXL_MSG("fcntl(fd,F_RDAHEAD,0) failed on path=" << filename <<
157  " fd=" << file_des << " : " << strerror(errno));
158  }
159  }
160 #endif
161 
162  // successfully opened file descriptor
163  if (!(m_mode & NO_LOCK))
164  lock();
165 }
166 
168 {
169  scoped_mutex_lock fd_lock(fd_mutex);
170 
171  if (file_des == -1)
172  return;
173 
174  if (::close(file_des) < 0)
175  STXXL_THROW_ERRNO(io_error, "close() fd=" << file_des);
176 
177  file_des = -1;
178 }
179 
181 {
182 #if STXXL_WINDOWS || defined(__MINGW32__)
183  // not yet implemented
184 #else
185  scoped_mutex_lock fd_lock(fd_mutex);
186  struct flock lock_struct;
187  lock_struct.l_type = (short)(m_mode & RDONLY ? F_RDLCK : F_RDLCK | F_WRLCK);
188  lock_struct.l_whence = SEEK_SET;
189  lock_struct.l_start = 0;
190  lock_struct.l_len = 0; // lock all bytes
191  if ((::fcntl(file_des, F_SETLK, &lock_struct)) < 0)
192  STXXL_THROW_ERRNO(io_error, "fcntl(,F_SETLK,) path=" << filename << " fd=" << file_des);
193 #endif
194 }
195 
197 {
198  // We use lseek SEEK_END to find the file size. This works for raw devices
199  // (where stat() returns zero), and we need not reset the position because
200  // serve() always lseek()s before read/write.
201 
202  off_t rc = ::lseek(file_des, 0, SEEK_END);
203  if (rc < 0)
204  STXXL_THROW_ERRNO(io_error, "lseek(fd,0,SEEK_END) path=" << filename << " fd=" << file_des);
205 
206  // return value is already the total size
207  return rc;
208 }
209 
211 {
212  scoped_mutex_lock fd_lock(fd_mutex);
213  return _size();
214 }
215 
217 {
218  scoped_mutex_lock fd_lock(fd_mutex);
219  return _set_size(newsize);
220 }
221 
223 {
224  offset_type cur_size = _size();
225 
226  if (!(m_mode & RDONLY) && !m_is_device)
227  {
228 #if STXXL_WINDOWS || defined(__MINGW32__)
229  HANDLE hfile = (HANDLE)::_get_osfhandle(file_des);
230  STXXL_THROW_ERRNO_NE_0((hfile == INVALID_HANDLE_VALUE), io_error,
231  "_get_osfhandle() path=" << filename << " fd=" << file_des);
232 
233  LARGE_INTEGER desired_pos;
234  desired_pos.QuadPart = newsize;
235 
236  if (!SetFilePointerEx(hfile, desired_pos, NULL, FILE_BEGIN))
238  "SetFilePointerEx in ufs_file_base::set_size(..) oldsize=" << cur_size <<
239  " newsize=" << newsize << " ");
240 
241  if (!SetEndOfFile(hfile))
243  "SetEndOfFile oldsize=" << cur_size <<
244  " newsize=" << newsize << " ");
245 #else
246  STXXL_THROW_ERRNO_NE_0(::ftruncate(file_des, newsize), io_error,
247  "ftruncate() path=" << filename << " fd=" << file_des);
248 #endif
249  }
250 
251 #if !STXXL_WINDOWS
252  if (newsize > cur_size)
253  STXXL_THROW_ERRNO_LT_0(::lseek(file_des, newsize - 1, SEEK_SET), io_error,
254  "lseek() path=" << filename << " fd=" << file_des << " pos=" << newsize - 1);
255 #endif
256 }
257 
259 {
260  close();
261 
262  if (m_is_device) {
263  STXXL_ERRMSG("remove() path=" << filename << " skipped as file is device node");
264  return;
265  }
266 
267  if (::remove(filename.c_str()) != 0)
268  STXXL_ERRMSG("remove() error on path=" << filename << " error=" << strerror(errno));
269 }
270 
272 {
273  if (m_is_device) {
274  STXXL_ERRMSG("unlink() path=" << filename << " skipped as file is device node");
275  return;
276  }
277 
278  if (::unlink(filename.c_str()) != 0)
279  STXXL_THROW_ERRNO(io_error, "unlink() path=" << filename << " fd=" << file_des);
280 }
281 
283 {
284  return m_is_device;
285 }
286 
288 // vim: et:ts=4:sw=4
read and write of the file are allowed
Definition: file.h:72
I/Os proceed bypassing file system buffers, i.e.
Definition: file.h:74
const std::string filename
Definition: ufs_file_base.h:39
#define STXXL_THROW_ERRNO_NE_0(expr, exception_type, error_message)
Throws exception_type if (expr != 0) with &quot;Error in [function] : [error_message] : [errno message]&quot;...
open the file with O_SYNC | O_DSYNC | O_RSYNC flags set
Definition: file.h:77
in case file does not exist no error occurs and file is newly created
Definition: file.h:73
#define lseek
Definition: ufs_platform.h:72
#define O_DSYNC
Definition: ufs_platform.h:52
#define off_t
Definition: ufs_platform.h:75
only writing of the file is allowed
Definition: file.h:71
void close_remove()
close and remove file
do not acquire an exclusive lock by default
Definition: file.h:78
implies DIRECT, fail if opening with DIRECT flag does not work.
Definition: file.h:79
void set_size(offset_type newsize)
#define STXXL_THROW_WIN_LASTERROR(exception_type, error_message)
Throws exception_type with &quot;Error in [function] : [error_message] : [formatted GetLastError()]&quot;.
only reading of the file is allowed
Definition: file.h:70
void unlink()
unlink file without closing it.
Aquire a lock that&#39;s valid until the end of scope.
Definition: mutex.h:123
#define STXXL_BEGIN_NAMESPACE
Definition: namespace.h:16
void lock()
Locks file for reading and writing (acquires a lock in the file system).
#define O_DIRECT
Definition: ufs_platform.h:66
#define STXXL_ERRMSG(x)
Definition: verbose.h:94
once file is opened its length becomes zero
Definition: file.h:76
#define STXXL_THROW_ERRNO_LT_0(expr, exception_type, error_message)
Throws exception_type if (expr &lt; 0) with &quot;Error in [function] : [error_message] : [errno message]&quot;...
bool m_is_device
is special device node
Definition: ufs_file_base.h:40
#define O_SYNC
Definition: ufs_platform.h:46
#define STXXL_THROW_ERRNO(exception_type, error_message)
Throws exception_type with &quot;Error in [function] : [error_message] : [errno message]&quot;.
#define STXXL_MSG(x)
Definition: verbose.h:73
#define O_RSYNC
Definition: ufs_platform.h:49
void _set_size(offset_type newsize)
request::offset_type offset_type
the offset of a request, also the size of the file
Definition: file.h:60
offset_type size()
Returns size of the file.
#define S_ISBLK(x)
Definition: ufs_platform.h:41
bool is_device() const
return true if file is special device node
#define STXXL_END_NAMESPACE
Definition: namespace.h:17