STXXL  1.4.0
 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) : file_des(-1), m_mode(mode), filename(filename)
35 {
36  int flags = 0;
37 
38  if (mode & RDONLY)
39  {
40  flags |= O_RDONLY;
41  }
42 
43  if (mode & WRONLY)
44  {
45  flags |= O_WRONLY;
46  }
47 
48  if (mode & RDWR)
49  {
50  flags |= O_RDWR;
51  }
52 
53  if (mode & CREAT)
54  {
55  flags |= O_CREAT;
56  }
57 
58  if (mode & TRUNC)
59  {
60  flags |= O_TRUNC;
61  }
62 
63  if ((mode & DIRECT) || (mode & REQUIRE_DIRECT))
64  {
65 #ifdef __APPLE__
66  // no additional open flags are required for Mac OS X
67 #elif !STXXL_DIRECT_IO_OFF
68  flags |= O_DIRECT;
69 #else
70  if (mode & REQUIRE_DIRECT) {
71  STXXL_ERRMSG("Error: open()ing " << filename << " with DIRECT mode required, but the system does not support it.");
72  file_des = -1;
73  return;
74  }
75  else {
76  STXXL_MSG("Warning: open()ing " << filename << " without DIRECT mode, as the system does not support it.");
77  }
78 #endif
79  }
80 
81  if (mode & SYNC)
82  {
83  flags |= O_RSYNC;
84  flags |= O_DSYNC;
85  flags |= O_SYNC;
86  }
87 
88 #if STXXL_WINDOWS
89  flags |= O_BINARY; // the default in MS is TEXT mode
90 #endif
91 
92 #if STXXL_WINDOWS || defined(__MINGW32__)
93  const int perms = S_IREAD | S_IWRITE;
94 #else
95  const int perms = S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP;
96 #endif
97 
98  if ((file_des = ::open(filename.c_str(), flags, perms)) >= 0)
99  {
100  _after_open();
101  return;
102  }
103 
104 #if !STXXL_DIRECT_IO_OFF
105  if ((mode & DIRECT) && !(mode & REQUIRE_DIRECT) && errno == EINVAL)
106  {
107  STXXL_MSG("open() error on path=" << filename << " flags=" << flags << ", retrying without O_DIRECT.");
108 
109  flags &= ~O_DIRECT;
110  m_mode &= ~DIRECT;
111 
112  if ((file_des = ::open(filename.c_str(), flags, perms)) >= 0)
113  {
114  _after_open();
115  return;
116  }
117  }
118 #endif
119 
120  STXXL_THROW_ERRNO(io_error, "open() rc=" << file_des << " path=" << filename << " flags=" << flags);
121 }
122 
124 {
125  close();
126 }
127 
129 {
130  // stat file type
131 #if STXXL_WINDOWS || defined(__MINGW32__)
132  struct _stat64 st;
133  STXXL_THROW_ERRNO_NE_0(::_fstat64(file_des, &st), io_error,
134  "_fstat64() path=" << filename << " fd=" << file_des);
135 #else
136  struct stat st;
138  "fstat() path=" << filename << " fd=" << file_des);
139 #endif
140  m_is_device = S_ISBLK(st.st_mode) ? true : false;
141 
142 #ifdef __APPLE__
143  if (m_mode & REQUIRE_DIRECT) {
144  STXXL_THROW_ERRNO_NE_0(fcntl(file_des, F_NOCACHE, 1), io_error,
145  "fcntl() path=" << filename << " fd=" << file_des);
146  STXXL_THROW_ERRNO_NE_0(fcntl(file_des, F_RDAHEAD, 0), io_error,
147  "fcntl() path=" << filename << " fd=" << file_des);
148  }
149  else if (m_mode & DIRECT) {
150  if (fcntl(file_des, F_NOCACHE, 1) != 0) {
151  STXXL_MSG("fcntl(fd,F_NOCACHE,1) failed on path=" << filename <<
152  " fd=" << file_des << " : " << strerror(errno));
153  }
154  if (fcntl(file_des, F_RDAHEAD, 0) != 0) {
155  STXXL_MSG("fcntl(fd,F_RDAHEAD,0) failed on path=" << filename <<
156  " fd=" << file_des << " : " << strerror(errno));
157  }
158  }
159 #endif
160 
161  // successfully opened file descriptor
162  if (!(m_mode & NO_LOCK))
163  lock();
164 }
165 
167 {
168  scoped_mutex_lock fd_lock(fd_mutex);
169 
170  if (file_des == -1)
171  return;
172 
173  if (::close(file_des) < 0)
174  STXXL_THROW_ERRNO(io_error, "close() fd=" << file_des);
175 
176  file_des = -1;
177 }
178 
180 {
181 #if STXXL_WINDOWS || defined(__MINGW32__)
182  // not yet implemented
183 #else
184  scoped_mutex_lock fd_lock(fd_mutex);
185  struct flock lock_struct;
186  lock_struct.l_type = (m_mode & RDONLY) ? F_RDLCK : F_RDLCK | F_WRLCK;
187  lock_struct.l_whence = SEEK_SET;
188  lock_struct.l_start = 0;
189  lock_struct.l_len = 0; // lock all bytes
190  if ((::fcntl(file_des, F_SETLK, &lock_struct)) < 0)
191  STXXL_THROW_ERRNO(io_error, "fcntl(,F_SETLK,) path=" << filename << " fd=" << file_des);
192 #endif
193 }
194 
196 {
197  // We use lseek SEEK_END to find the file size. This works for raw devices
198  // (where stat() returns zero), and we need not reset the position because
199  // serve() always lseek()s before read/write.
200 
201  off_t rc = ::lseek(file_des, 0, SEEK_END);
202  if (rc < 0)
203  STXXL_THROW_ERRNO(io_error, "lseek(fd,0,SEEK_END) path=" << filename << " fd=" << file_des);
204 
205  // return value is already the total size
206  return rc;
207 }
208 
210 {
211  scoped_mutex_lock fd_lock(fd_mutex);
212  return _size();
213 }
214 
216 {
217  scoped_mutex_lock fd_lock(fd_mutex);
218  return _set_size(newsize);
219 }
220 
222 {
223  offset_type cur_size = _size();
224 
225  if (!(m_mode & RDONLY) && !m_is_device)
226  {
227 #if STXXL_WINDOWS || defined(__MINGW32__)
228  HANDLE hfile = (HANDLE) ::_get_osfhandle(file_des);
229  STXXL_THROW_ERRNO_NE_0((hfile == INVALID_HANDLE_VALUE), io_error,
230  "_get_osfhandle() path=" << filename << " fd=" << file_des);
231 
232  LARGE_INTEGER desired_pos;
233  desired_pos.QuadPart = newsize;
234 
235  if (!SetFilePointerEx(hfile, desired_pos, NULL, FILE_BEGIN))
237  "SetFilePointerEx in ufs_file_base::set_size(..) oldsize=" << cur_size <<
238  " newsize=" << newsize << " ");
239 
240  if (!SetEndOfFile(hfile))
242  "SetEndOfFile oldsize=" << cur_size <<
243  " newsize=" << newsize << " ");
244 #else
245  STXXL_THROW_ERRNO_NE_0(::ftruncate(file_des, newsize), io_error,
246  "ftruncate() path=" << filename << " fd=" << file_des);
247 #endif
248  }
249 
250 #if !STXXL_WINDOWS
251  if (newsize > cur_size)
252  STXXL_THROW_ERRNO_LT_0(::lseek(file_des, newsize - 1, SEEK_SET), io_error,
253  "lseek() path=" << filename << " fd=" << file_des << " pos=" << newsize - 1);
254 #endif
255 }
256 
258 {
259  close();
260 
261  if (m_is_device) {
262  STXXL_ERRMSG("remove() path=" << filename << " skipped as file is device node");
263  return;
264  }
265 
266  if (::remove(filename.c_str()) != 0)
267  STXXL_ERRMSG("remove() error on path=" << filename << " error=" << strerror(errno));
268 }
269 
271 {
272  if (m_is_device) {
273  STXXL_ERRMSG("unlink() path=" << filename << " skipped as file is device node");
274  return;
275  }
276 
277  if (::unlink(filename.c_str()) != 0)
278  STXXL_THROW_ERRNO(io_error, "unlink() path=" << filename << " fd=" << file_des);
279 }
280 
282 {
283  return m_is_device;
284 }
285 
287 // vim: et:ts=4:sw=4
read and write of the file are allowed
Definition: file.h:76
I/Os proceed bypassing file system buffers, i.e.
Definition: file.h:78
const std::string filename
Definition: ufs_file_base.h:40
#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:81
in case file does not exist no error occurs and file is newly created
Definition: file.h:77
#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:75
void close_remove()
close and remove file
do not aquire an exclusive lock by default
Definition: file.h:82
implies DIRECT, fail if opening with DIRECT flag does not work.
Definition: file.h:83
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:74
void unlink()
unlink file without closing it.
Aquire a lock that&#39;s valid until the end of scope.
Definition: mutex.h:106
#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:79
once file is opened its length becomes zero
Definition: file.h:80
#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:41
#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:72
#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:64
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