Thrill  0.1
wfs_file_base.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * foxxll/io/wfs_file_base.cpp
3  *
4  * Part of FOXXLL. See http://foxxll.org
5  *
6  * Copyright (C) 2005 Roman Dementiev <[email protected]>
7  * Copyright (C) 2008, 2010 Andreas Beckmann <[email protected]>
8  * Copyright (C) 2009, 2010 Johannes Singler <[email protected]>
9  *
10  * Distributed under the Boost Software License, Version 1.0.
11  * (See accompanying file LICENSE_1_0.txt or copy at
12  * http://www.boost.org/LICENSE_1_0.txt)
13  **************************************************************************/
14 
15 #include <tlx/logger/core.hpp>
16 
19 
20 #if FOXXLL_WINDOWS
21 
22 #ifndef NOMINMAX
23  #define NOMINMAX
24 #endif
25 #include <windows.h>
26 
27 namespace foxxll {
28 
29 const char* wfs_file_base::io_type() const
30 {
31  return "wfs_base";
32 }
33 
34 static HANDLE open_file_impl(const std::string& filename, int mode)
35 {
36  DWORD dwDesiredAccess = 0;
37  DWORD dwShareMode = 0;
38  DWORD dwCreationDisposition = 0;
39  DWORD dwFlagsAndAttributes = 0;
40 
41  if (mode & file::RDONLY)
42  {
43  dwFlagsAndAttributes |= FILE_ATTRIBUTE_READONLY;
44  dwDesiredAccess |= GENERIC_READ;
45  }
46 
47  if (mode & file::WRONLY)
48  {
49  dwDesiredAccess |= GENERIC_WRITE;
50  }
51 
52  if (mode & file::RDWR)
53  {
54  dwDesiredAccess |= (GENERIC_READ | GENERIC_WRITE);
55  }
56 
57  if (mode & file::CREAT)
58  {
59  // ignored
60  }
61 
62  if (mode & file::TRUNC)
63  {
64  dwCreationDisposition |= TRUNCATE_EXISTING;
65  }
66  else
67  {
68  dwCreationDisposition |= OPEN_ALWAYS;
69  }
70 
71  if (mode & file::DIRECT)
72  {
73 #if !FOXXLL_DIRECT_IO_OFF
74  dwFlagsAndAttributes |= FILE_FLAG_NO_BUFFERING;
75  // TODO: try also FILE_FLAG_WRITE_THROUGH option ?
76 #else
77  if (mode & file::REQUIRE_DIRECT) {
78  TLX_LOG1 << "Error: open()ing " << filename << " with DIRECT mode required, but the system does not support it.";
79  return INVALID_HANDLE_VALUE;
80  }
81  else {
82  TLX_LOG1 << "Warning: open()ing " << filename << " without DIRECT mode, as the system does not support it.";
83  }
84 #endif
85  }
86 
87  if (mode & file::SYNC)
88  {
89  // ignored
90  }
91 
92  HANDLE file_des_ = ::CreateFileA(
93  filename.c_str(), dwDesiredAccess, dwShareMode, nullptr,
94  dwCreationDisposition, dwFlagsAndAttributes, nullptr
95  );
96 
97  if (file_des_ != INVALID_HANDLE_VALUE)
98  return file_des_;
99 
100 #if !FOXXLL_DIRECT_IO_OFF
101  if ((mode& file::DIRECT) && !(mode & file::REQUIRE_DIRECT))
102  {
103  TLX_LOG1 << "CreateFile() error on path=" << filename << " mode=" << mode << ", retrying without DIRECT mode.";
104 
105  dwFlagsAndAttributes &= ~FILE_FLAG_NO_BUFFERING;
106 
107  HANDLE file_des2 = ::CreateFileA(
108  filename.c_str(), dwDesiredAccess, dwShareMode, nullptr,
109  dwCreationDisposition, dwFlagsAndAttributes, nullptr
110  );
111 
112  if (file_des2 != INVALID_HANDLE_VALUE)
113  return file_des2;
114  }
115 #endif
116 
117  FOXXLL_THROW_WIN_LASTERROR(io_error, "CreateFile() path=" << filename << " mode=" << mode);
118 }
119 
120 wfs_file_base::wfs_file_base(const std::string& filename, int mode)
121  : file_des_(INVALID_HANDLE_VALUE),
122  mode_(mode), filename_(filename), locked_(false)
123 {
124  file_des_ = open_file_impl(filename, mode);
125  need_alignment_ = (mode& file::DIRECT) != 0;
126 
127  if (!(mode & NO_LOCK))
128  {
129  lock();
130  }
131 
132  if (!(mode_ & RDONLY) && (mode & DIRECT))
133  {
134  char buf[32768], * part;
135  if (!GetFullPathNameA(filename.c_str(), sizeof(buf), buf, &part))
136  {
137  TLX_LOG1 << "wfs_file_base::wfs_file_base(): GetFullPathNameA() error for file " << filename;
138  bytes_per_sector_ = 512;
139  }
140  else
141  {
142  part[0] = char();
143  DWORD bytes_per_sector_;
144  if (!GetDiskFreeSpaceA(buf, nullptr, &bytes_per_sector_, nullptr, nullptr))
145  {
146  TLX_LOG1 << "wfs_file_base::wfs_file_base(): GetDiskFreeSpaceA() error for path " << buf;
147  bytes_per_sector_ = 512;
148  }
149  else
150  bytes_per_sector_ = bytes_per_sector_;
151  }
152  }
153 }
154 
155 wfs_file_base::~wfs_file_base()
156 {
157  close();
158 }
159 
160 void wfs_file_base::close()
161 {
162  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
163 
164  if (file_des_ == INVALID_HANDLE_VALUE)
165  return;
166 
167  if (!CloseHandle(file_des_))
168  FOXXLL_THROW_WIN_LASTERROR(io_error, "CloseHandle() of file fd=" << file_des_);
169 
170  file_des_ = INVALID_HANDLE_VALUE;
171 }
172 
173 void wfs_file_base::lock()
174 {
175  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
176  if (locked_)
177  return; // already locked
178  if (LockFile(file_des_, 0, 0, 0xffffffff, 0xffffffff) == 0)
179  FOXXLL_THROW_WIN_LASTERROR(io_error, "LockFile() fd=" << file_des_);
180  locked_ = true;
181 }
182 
183 file::offset_type wfs_file_base::_size()
184 {
185  LARGE_INTEGER result;
186  if (!GetFileSizeEx(file_des_, &result))
187  FOXXLL_THROW_WIN_LASTERROR(io_error, "GetFileSizeEx() fd=" << file_des_);
188 
189  return result.QuadPart;
190 }
191 
192 file::offset_type wfs_file_base::size()
193 {
194  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
195  return _size();
196 }
197 
198 void wfs_file_base::set_size(offset_type newsize)
199 {
200  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
201  offset_type cur_size = _size();
202 
203  if (!(mode_ & RDONLY))
204  {
205  LARGE_INTEGER desired_pos;
206  desired_pos.QuadPart = newsize;
207 
208  bool direct_with_bad_size = (mode_& file::DIRECT) && (newsize % bytes_per_sector_);
209  if (direct_with_bad_size)
210  {
211  if (!CloseHandle(file_des_))
212  FOXXLL_THROW_WIN_LASTERROR(io_error, "closing file (call of ::CloseHandle() from set_size) ");
213 
214  file_des_ = INVALID_HANDLE_VALUE;
215  file_des_ = open_file_impl(filename_, WRONLY);
216  }
217 
218  if (!SetFilePointerEx(file_des_, desired_pos, nullptr, FILE_BEGIN))
219  FOXXLL_THROW_WIN_LASTERROR(
220  io_error,
221  "SetFilePointerEx() in wfs_file_base::set_size(..) oldsize=" << cur_size <<
222  " newsize=" << newsize << " "
223  );
224 
225  if (!SetEndOfFile(file_des_))
226  FOXXLL_THROW_WIN_LASTERROR(
227  io_error, "SetEndOfFile() oldsize=" << cur_size <<
228  " newsize=" << newsize << " "
229  );
230 
231  if (direct_with_bad_size)
232  {
233  if (!CloseHandle(file_des_))
234  FOXXLL_THROW_WIN_LASTERROR(io_error, "closing file (call of ::CloseHandle() from set_size) ");
235 
236  file_des_ = INVALID_HANDLE_VALUE;
237  file_des_ = open_file_impl(filename_, mode_ & ~TRUNC);
238  }
239  }
240 }
241 
242 void wfs_file_base::close_remove()
243 {
244  close();
245  ::DeleteFileA(filename_.c_str());
246 }
247 
248 } // namespace foxxll
249 
250 #endif // FOXXLL_WINDOWS
251 
252 /**************************************************************************/
only reading of the file is allowed
Definition: file.hpp:67
only writing of the file is allowed
Definition: file.hpp:69
implies DIRECT, fail if opening with DIRECT flag does not work.
Definition: file.hpp:86
FOXXLL library namespace
std::basic_string< char, std::char_traits< char >, Allocator< char > > string
string with Manager tracking
Definition: allocator.hpp:220
#define TLX_LOG1
Definition: core.hpp:145
once file is opened its length becomes zero
Definition: file.hpp:80
read and write of the file are allowed
Definition: file.hpp:71
open the file with O_SYNC | O_DSYNC | O_RSYNC flags set
Definition: file.hpp:82