Apache Mesos
stat.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_OS_WINDOWS_STAT_HPP__
14 #define __STOUT_OS_WINDOWS_STAT_HPP__
15 
16 #include <string>
17 #include <type_traits>
18 
19 #include <stout/bytes.hpp>
20 #include <stout/try.hpp>
21 #include <stout/unreachable.hpp>
22 #include <stout/windows.hpp>
23 
24 #include <stout/os/int_fd.hpp>
25 
30 
31 namespace os {
32 namespace stat {
33 
34 // Forward declaration.
35 inline bool islink(const std::string& path);
36 
37 inline bool isdir(
38  const std::string& path,
40 {
41  // A symlink itself is not a directory.
42  // If it's not a link, we ignore `follow`.
43  if (follow == FollowSymlink::DO_NOT_FOLLOW_SYMLINK && islink(path)) {
44  return false;
45  }
46 
49 
50  if (attributes.isError()) {
51  return false;
52  }
53 
54  return attributes.get() & FILE_ATTRIBUTE_DIRECTORY;
55 }
56 
57 
58 // TODO(andschwa): Refactor `GetFileInformationByHandle` into its own function.
59 inline bool isdir(const int_fd& fd)
60 {
61  BY_HANDLE_FILE_INFORMATION info;
62  const BOOL result = ::GetFileInformationByHandle(fd, &info);
63  if (result == FALSE) {
64  return false;
65  }
66 
67  return info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
68 }
69 
70 
71 inline bool isfile(
72  const std::string& path,
74 {
75  // A symlink itself is a file, but not a regular file.
76  // On POSIX, this check is done with `S_IFREG`, which
77  // returns false for symbolic links.
78  // If it's not a link, we ignore `follow`.
79  if (follow == FollowSymlink::DO_NOT_FOLLOW_SYMLINK && islink(path)) {
80  return false;
81  }
82 
85 
86  if (attributes.isError()) {
87  return false;
88  }
89 
90  // NOTE: Windows files attributes do not define a flag for "regular"
91  // files. Instead, this call will only return successfully iff the
92  // given file or directory exists. Checking against the directory
93  // flag determines if the path is a file or directory.
94  return !(attributes.get() & FILE_ATTRIBUTE_DIRECTORY);
95 }
96 
97 
98 inline bool islink(const std::string& path)
99 {
102 
103  return symlink.isSome();
104 }
105 
106 
107 // Returns the size in Bytes of a given file system entry. When applied to a
108 // symbolic link with `follow` set to `DO_NOT_FOLLOW_SYMLINK`, this will return
109 // zero because that's what Windows says.
110 inline Try<Bytes> size(
111  const std::string& path,
113 {
114  const Try<SharedHandle> handle = (follow == FollowSymlink::FOLLOW_SYMLINK)
117  if (handle.isError()) {
118  return Error("Error obtaining handle to file: " + handle.error());
119  }
120 
121  LARGE_INTEGER file_size;
122 
123  if (::GetFileSizeEx(handle->get_handle(), &file_size) == 0) {
124  return WindowsError();
125  }
126 
127  return Bytes(file_size.QuadPart);
128 }
129 
130 
131 inline Try<Bytes> size(const int_fd& fd)
132 {
133  LARGE_INTEGER file_size;
134 
135  if (::GetFileSizeEx(fd, &file_size) == 0) {
136  return WindowsError();
137  }
138 
139  return Bytes(file_size.QuadPart);
140 }
141 
142 
143 inline Try<long> mtime(
144  const std::string& path,
146 {
147  if (follow == FollowSymlink::DO_NOT_FOLLOW_SYMLINK && islink(path)) {
148  return Error(
149  "Requested mtime for '" + path +
150  "', but symbolic links don't have an mtime on Windows");
151  }
152 
153  Try<SharedHandle> handle =
157  if (handle.isError()) {
158  return Error(handle.error());
159  }
160 
161  FILETIME filetime;
162  // The last argument is file write time, AKA modification time.
163  const BOOL result =
164  ::GetFileTime(handle->get_handle(), nullptr, nullptr, &filetime);
165  if (result == FALSE) {
166  return WindowsError();
167  }
168 
169  // Convert to 64-bit integer using Windows magic.
170  ULARGE_INTEGER largetime;
171  largetime.LowPart = filetime.dwLowDateTime;
172  largetime.HighPart = filetime.dwHighDateTime;
173  // Now the `QuadPart` field is the 64-bit representation due to the
174  // layout of the `ULARGE_INTEGER` struct.
175  static_assert(
176  sizeof(largetime.QuadPart) == sizeof(__int64),
177  "Expected `QuadPart` to be of type `__int64`");
178  const __int64 windowstime = largetime.QuadPart;
179  // A file time is a 64-bit value that represents the number of
180  // 100-nanosecond intervals that have elapsed since 1601-01-01
181  // 00:00:00 +0000. However, users of this function expect UNIX time,
182  // which is seconds elapsed since the Epoch, 1970-01-01 00:00:00
183  // +0000.
184  //
185  // So first we convert 100-nanosecond intervals into seconds by
186  // doing `(x * 100) / (1,000^3)`, or `x / 10,000,000`, and then
187  // substracting the number of seconds between 1601-01-01 and
188  // 1970-01-01, or `11,644,473,600`.
189  const __int64 unixtime = (windowstime / 10000000) - 11644473600;
190  // We choose to make this conversion explicit because we expect the
191  // truncation to not cause information loss.
192  return static_cast<long>(unixtime);
193 }
194 
195 
196 // NOTE: The following are deleted because implementing them would use
197 // the CRT API `_stat`, which we want to avoid, and they're not
198 // currently used on Windows.
199 inline Try<mode_t> mode(
200  const std::string& path,
201  const FollowSymlink follow) = delete;
202 
203 
204 inline Try<dev_t> dev(
205  const std::string& path,
206  const FollowSymlink follow) = delete;
207 
208 
209 inline Try<ino_t> inode(
210  const std::string& path,
211  const FollowSymlink follow) = delete;
212 
213 } // namespace stat {
214 } // namespace os {
215 
216 #endif // __STOUT_OS_WINDOWS_STAT_HPP__
Definition: path.hpp:26
Try< SharedHandle > get_handle_no_follow(const std::string &absolute_path)
Definition: reparsepoint.hpp:215
bool isfile(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:108
Definition: errorbase.hpp:36
Try< Bytes > size(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:121
T & get()&
Definition: try.hpp:73
HANDLE get_handle() const
Definition: windows.hpp:90
bool islink(const std::string &path)
Definition: stat.hpp:80
Definition: check.hpp:33
Try< DWORD > get_file_attributes(const std::wstring &path)
Definition: attributes.hpp:27
Try< Nothing > symlink(const std::string &original, const std::string &link)
Definition: fs.hpp:54
Definition: error.hpp:108
Try< long > mtime(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:146
Definition: posix_signalhandler.hpp:23
Try< ino_t > inode(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:202
FollowSymlink
Definition: reparsepoint.hpp:35
Try< SymbolicLink > query_symbolic_link_data(const std::string &path)
Definition: symlink.hpp:79
Try< dev_t > dev(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:172
bool isSome() const
Definition: try.hpp:70
Try< struct::stat > stat(const int_fd fd)
Definition: stat.hpp:68
static Try error(const E &e)
Definition: try.hpp:42
Try< SharedHandle > get_handle_follow(const std::string &absolute_path)
Definition: reparsepoint.hpp:155
bool isError() const
Definition: try.hpp:71
bool isdir(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:91
Try< mode_t > mode(const std::string &path, const FollowSymlink follow=FollowSymlink::FOLLOW_SYMLINK)
Definition: stat.hpp:159
std::wstring longpath(const std::string &path)
Definition: longpath.hpp:38
Definition: bytes.hpp:30
int int_fd
Definition: int_fd.hpp:35