libstdc++: Fix std::print test case for Windows
[official-gcc.git] / libstdc++-v3 / src / filesystem / ops-common.h
blob1f4060c3c4aa64c52c716c5e1d99ae4e80a99774
1 // Filesystem operation utilities -*- C++ -*-
3 // Copyright (C) 2014-2023 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
25 #ifndef _GLIBCXX_OPS_COMMON_H
26 #define _GLIBCXX_OPS_COMMON_H 1
28 #include <chrono>
29 #include <bits/move.h> // std::__exchange
31 #ifdef _GLIBCXX_HAVE_UNISTD_H
32 # include <unistd.h>
33 # ifdef _GLIBCXX_HAVE_FCNTL_H
34 # include <fcntl.h> // AT_FDCWD, O_TRUNC etc.
35 # endif
36 # if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H)
37 # include <sys/types.h>
38 # include <sys/stat.h> // mkdir, chmod
39 # endif
40 #endif
41 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
42 # include <utime.h> // utime
43 #endif
45 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
46 # include <wchar.h>
47 #endif
49 #ifdef NEED_DO_COPY_FILE
50 # include <filesystem>
51 # include <ext/stdio_filebuf.h>
52 # ifdef _GLIBCXX_USE_COPY_FILE_RANGE
53 # include <unistd.h> // copy_file_range
54 # endif
55 # ifdef _GLIBCXX_USE_SENDFILE
56 # include <sys/sendfile.h> // sendfile
57 # include <unistd.h> // lseek
58 # endif
59 #endif
61 namespace std _GLIBCXX_VISIBILITY(default)
63 _GLIBCXX_BEGIN_NAMESPACE_VERSION
65 // Get the last OS error (for POSIX this is just errno).
66 inline error_code
67 __last_system_error() noexcept
69 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
70 // N.B. use error_code::default_error_condition() to convert to generic.
71 return {(int)::GetLastError(), std::system_category()};
72 #else
73 return {errno, std::generic_category()};
74 #endif
77 // Get an error code indicating unsupported functionality.
79 // This should be used when a function is unable to behave as specified
80 // due to an incomplete or partial implementation, e.g.
81 // filesystem::equivalent(a, b) if is_other(a) && is_other(b) is true.
83 // Use errc::function_not_supported for functions that are entirely
84 // unimplemented, e.g. create_symlink on Windows.
86 // Use errc::invalid_argument for requests to perform operations outside
87 // the spec, e.g. trying to copy a directory using filesystem::copy_file.
88 inline error_code
89 __unsupported() noexcept
91 #if defined __AVR__
92 // avr-libc defines ENOTSUP and EOPNOTSUPP but with nonsense values.
93 // ENOSYS is defined though, so use an error_code corresponding to that.
94 // This contradicts the comment above, but we don't have much choice.
95 return std::make_error_code(std::errc::function_not_supported);
96 #elif defined ENOTSUP
97 return std::make_error_code(std::errc::not_supported);
98 #elif defined EOPNOTSUPP
99 // This is supposed to be for socket operations
100 return std::make_error_code(std::errc::operation_not_supported);
101 #else
102 return std::make_error_code(std::errc::invalid_argument);
103 #endif
106 namespace filesystem
108 namespace __gnu_posix
110 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
111 // Adapt the Windows _wxxx functions to look like POSIX xxx, but for wchar_t*.
112 inline int open(const wchar_t* path, int flags)
113 { return ::_wopen(path, flags); }
115 inline int open(const wchar_t* path, int flags, int mode)
116 { return ::_wopen(path, flags, mode); }
118 inline int close(int fd)
119 { return ::_close(fd); }
121 typedef struct ::__stat64 stat_type;
123 inline int stat(const wchar_t* path, stat_type* buffer)
124 { return ::_wstat64(path, buffer); }
126 inline int lstat(const wchar_t* path, stat_type* buffer)
128 // FIXME: symlinks not currently supported
129 return stat(path, buffer);
132 using ::mode_t;
134 inline int chmod(const wchar_t* path, mode_t mode)
135 { return ::_wchmod(path, mode); }
136 #define _GLIBCXX_USE_CHMOD 1
138 inline int mkdir(const wchar_t* path, mode_t)
139 { return ::_wmkdir(path); }
140 #define _GLIBCXX_USE_MKDIR 1
142 inline wchar_t* getcwd(wchar_t* buf, size_t size)
143 { return ::_wgetcwd(buf, size > (size_t)INT_MAX ? INT_MAX : (int)size); }
144 #define _GLIBCXX_USE_GETCWD 1
146 inline int chdir(const wchar_t* path)
147 { return ::_wchdir(path); }
148 #define _GLIBCXX_USE_CHDIR 1
150 #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
151 using utimbuf = _utimbuf;
153 inline int utime(const wchar_t* path, utimbuf* times)
154 { return ::_wutime(path, times); }
155 #endif
157 inline int rename(const wchar_t* oldname, const wchar_t* newname)
159 if (MoveFileExW(oldname, newname,
160 MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
161 return 0;
162 if (GetLastError() == ERROR_ACCESS_DENIED)
163 errno = EACCES;
164 else
165 errno = EIO;
166 return -1;
169 using off_t = _off64_t;
170 inline int truncate(const wchar_t* path, _off64_t length)
172 const int fd = ::_wopen(path, _O_BINARY|_O_RDWR);
173 if (fd == -1)
174 return fd;
175 const int ret = ::ftruncate64(fd, length);
176 int err;
177 ::_get_errno(&err);
178 ::_close(fd);
179 ::_set_errno(err);
180 return ret;
182 using char_type = wchar_t;
183 #elif defined _GLIBCXX_HAVE_UNISTD_H && ! defined __AVR__
184 using ::open;
185 using ::close;
186 # ifdef _GLIBCXX_HAVE_SYS_STAT_H
187 typedef struct ::stat stat_type;
188 using ::stat;
189 # ifdef _GLIBCXX_USE_LSTAT
190 using ::lstat;
191 # else
192 inline int lstat(const char* path, stat_type* buffer)
193 { return stat(path, buffer); }
194 # endif
195 # endif
196 using ::mode_t;
197 # if _GLIBCXX_USE_CHMOD
198 using ::chmod;
199 # endif
200 # if _GLIBCXX_USE_MKDIR
201 using ::mkdir;
202 # endif
203 # if _GLIBCXX_USE_GETCWD
204 using ::getcwd;
205 # endif
206 # if _GLIBCXX_USE_CHDIR
207 using ::chdir;
208 # endif
209 # if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_USE_UTIME
210 using ::utimbuf;
211 using ::utime;
212 # endif
213 using ::rename;
214 using ::off_t;
215 # ifdef _GLIBCXX_HAVE_TRUNCATE
216 using ::truncate;
217 # else
218 inline int truncate(const char* path, off_t length)
220 if (length == 0)
222 const int fd = ::open(path, O_WRONLY|O_TRUNC);
223 if (fd == -1)
224 return fd;
225 ::close(fd);
226 return 0;
228 errno = ENOTSUP;
229 return -1;
231 # endif
232 using char_type = char;
233 #else // ! _GLIBCXX_FILESYSTEM_IS_WINDOWS && ! _GLIBCXX_HAVE_UNISTD_H
234 inline int open(const char*, int, ...) { errno = ENOSYS; return -1; }
235 inline int close(int) { errno = ENOSYS; return -1; }
236 using mode_t = int;
237 inline int chmod(const char*, mode_t) { errno = ENOSYS; return -1; }
238 inline int mkdir(const char*, mode_t) { errno = ENOSYS; return -1; }
239 inline char* getcwd(char*, size_t) { errno = ENOSYS; return nullptr; }
240 inline int chdir(const char*) { errno = ENOSYS; return -1; }
241 inline int rename(const char*, const char*) { errno = ENOSYS; return -1; }
242 using off_t = long;
243 inline int truncate(const char*, off_t) { errno = ENOSYS; return -1; }
244 using char_type = char;
245 #endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
246 } // namespace __gnu_posix
248 template<typename Bitmask>
249 inline bool is_set(Bitmask obj, Bitmask bits)
251 return (obj & bits) != Bitmask::none;
254 inline bool
255 is_not_found_errno(int err) noexcept
257 return err == ENOENT || err == ENOTDIR;
260 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
261 using __gnu_posix::stat_type;
263 inline std::chrono::system_clock::time_point
264 file_time(const stat_type& st, std::error_code& ec) noexcept
266 using namespace std::chrono;
267 #ifdef _GLIBCXX_USE_ST_MTIM
268 time_t s = st.st_mtim.tv_sec;
269 nanoseconds ns{st.st_mtim.tv_nsec};
270 #else
271 time_t s = st.st_mtime;
272 nanoseconds ns{};
273 #endif
275 // FIXME
276 // There are possible timespec values which will overflow
277 // chrono::system_clock::time_point but would not overflow
278 // __file_clock::time_point, due to its different epoch.
280 // By checking for overflow of the intermediate system_clock::duration
281 // type, we report an error for values which are actually representable
282 // in the file_time_type result type.
284 // Howard Hinnant's solution for this problem is to use
285 // duration<__int128>{s} + ns, which doesn't overflow.
286 // An alternative would be to do the epoch correction on s before
287 // the addition, and then go straight to file_time_type instead of
288 // going via chrono::system_clock::time_point.
290 // (This only applies to the C++17 Filesystem library, because for the
291 // Filesystem TS we don't have a distinct __file_clock, we just use the
292 // system clock for file timestamps).
293 if (seconds{s} >= floor<seconds>(system_clock::duration::max()))
295 ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW
296 return system_clock::time_point::min();
298 ec.clear();
299 return system_clock::time_point{seconds{s} + ns};
302 struct copy_options_existing_file
304 bool skip, update, overwrite;
307 #endif // _GLIBCXX_HAVE_SYS_STAT_H
309 } // namespace filesystem
311 // BEGIN/END macros must be defined before including this file.
312 _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
314 #ifdef _GLIBCXX_HAVE_SYS_STAT_H
315 using std::filesystem::__gnu_posix::stat_type;
316 using std::filesystem::__gnu_posix::char_type;
318 bool
319 do_copy_file(const char_type* from, const char_type* to,
320 std::filesystem::copy_options_existing_file options,
321 stat_type* from_st, stat_type* to_st,
322 std::error_code& ec) noexcept;
324 void
325 do_space(const char_type* pathname,
326 uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
327 std::error_code&);
330 inline file_type
331 make_file_type(const stat_type& st) noexcept
333 #ifdef _GLIBCXX_HAVE_S_ISREG
334 if (S_ISREG(st.st_mode))
335 return file_type::regular;
336 else if (S_ISDIR(st.st_mode))
337 return file_type::directory;
338 else if (S_ISCHR(st.st_mode))
339 return file_type::character;
340 else if (S_ISBLK(st.st_mode))
341 return file_type::block;
342 else if (S_ISFIFO(st.st_mode))
343 return file_type::fifo;
344 #ifdef S_ISLNK // not present in mingw
345 else if (S_ISLNK(st.st_mode))
346 return file_type::symlink;
347 #endif
348 #ifdef S_ISSOCK // not present until POSIX:2001
349 else if (S_ISSOCK(st.st_mode))
350 return file_type::socket;
351 #endif
352 #endif
353 return file_type::unknown;
356 inline file_status
357 make_file_status(const stat_type& st) noexcept
359 return file_status{
360 make_file_type(st),
361 static_cast<perms>(st.st_mode) & perms::mask
365 inline std::filesystem::copy_options_existing_file
366 copy_file_options(copy_options opt)
368 using std::filesystem::is_set;
369 return {
370 is_set(opt, copy_options::skip_existing),
371 is_set(opt, copy_options::update_existing),
372 is_set(opt, copy_options::overwrite_existing)
376 #ifdef NEED_DO_COPY_FILE
377 #ifdef _GLIBCXX_USE_COPY_FILE_RANGE
378 bool
379 copy_file_copy_file_range(int fd_in, int fd_out, size_t length) noexcept
381 // a zero-length file is either empty, or not copyable by this syscall
382 // return early to avoid the syscall cost
383 if (length == 0)
385 errno = EINVAL;
386 return false;
388 size_t bytes_left = length;
389 loff_t off_in = 0, off_out = 0;
390 ssize_t bytes_copied;
393 bytes_copied = ::copy_file_range(fd_in, &off_in, fd_out, &off_out,
394 bytes_left, 0);
395 bytes_left -= bytes_copied;
397 while (bytes_left > 0 && bytes_copied > 0);
398 if (bytes_copied < 0)
399 return false;
400 return true;
402 #endif
403 #if defined _GLIBCXX_USE_SENDFILE && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
404 bool
405 copy_file_sendfile(int fd_in, int fd_out, size_t length) noexcept
407 // a zero-length file is either empty, or not copyable by this syscall
408 // return early to avoid the syscall cost
409 if (length == 0)
411 errno = EINVAL;
412 return false;
414 size_t bytes_left = length;
415 off_t offset = 0;
416 ssize_t bytes_copied;
419 bytes_copied = ::sendfile(fd_out, fd_in, &offset, bytes_left);
420 bytes_left -= bytes_copied;
422 while (bytes_left > 0 && bytes_copied > 0);
423 if (bytes_copied < 0)
425 ::lseek(fd_out, 0, SEEK_SET);
426 return false;
428 return true;
430 #endif
431 bool
432 do_copy_file(const char_type* from, const char_type* to,
433 std::filesystem::copy_options_existing_file options,
434 stat_type* from_st, stat_type* to_st,
435 std::error_code& ec) noexcept
437 namespace fs = std::filesystem;
438 namespace posix = fs::__gnu_posix;
440 stat_type st1, st2;
441 file_status t, f;
443 if (to_st == nullptr)
445 if (posix::stat(to, &st1))
447 const int err = errno;
448 if (!fs::is_not_found_errno(err))
450 ec.assign(err, std::generic_category());
451 return false;
454 else
455 to_st = &st1;
457 else if (to_st == from_st)
458 to_st = nullptr;
460 if (to_st == nullptr)
461 t = file_status{file_type::not_found};
462 else
463 t = make_file_status(*to_st);
465 if (from_st == nullptr)
467 if (posix::stat(from, &st2))
469 ec.assign(errno, std::generic_category());
470 return false;
472 else
473 from_st = &st2;
475 f = make_file_status(*from_st);
476 // _GLIBCXX_RESOLVE_LIB_DEFECTS
477 // 2712. copy_file() has a number of unspecified error conditions
478 if (!is_regular_file(f))
480 ec = std::make_error_code(std::errc::invalid_argument);
481 return false;
484 if (exists(t))
486 if (!is_regular_file(t))
488 ec = std::make_error_code(std::errc::invalid_argument);
489 return false;
492 if (to_st->st_dev == from_st->st_dev
493 && to_st->st_ino == from_st->st_ino)
495 ec = std::make_error_code(std::errc::file_exists);
496 return false;
499 if (options.skip)
501 ec.clear();
502 return false;
504 else if (options.update)
506 const auto from_mtime = fs::file_time(*from_st, ec);
507 if (ec)
508 return false;
509 if ((from_mtime <= fs::file_time(*to_st, ec)) || ec)
510 return false;
512 else if (!options.overwrite)
514 ec = std::make_error_code(std::errc::file_exists);
515 return false;
517 else if (!is_regular_file(t))
519 ec = std::make_error_code(std::errc::invalid_argument);
520 return false;
524 struct CloseFD {
525 ~CloseFD() { if (fd != -1) posix::close(fd); }
526 bool close() { return posix::close(std::__exchange(fd, -1)) == 0; }
527 int fd;
530 int common_flags = 0;
531 #ifdef O_CLOEXEC
532 common_flags |= O_CLOEXEC;
533 #endif
534 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
535 common_flags |= O_BINARY;
536 #endif
538 const int iflag = O_RDONLY | common_flags;
539 CloseFD in = { posix::open(from, iflag) };
540 if (in.fd == -1)
542 ec.assign(errno, std::generic_category());
543 return false;
545 int oflag = O_WRONLY | O_CREAT | common_flags;
546 if (options.overwrite || options.update)
547 oflag |= O_TRUNC;
548 else
549 oflag |= O_EXCL;
550 CloseFD out = { posix::open(to, oflag, S_IWUSR) };
551 if (out.fd == -1)
553 if (errno == EEXIST && options.skip)
554 ec.clear();
555 else
556 ec.assign(errno, std::generic_category());
557 return false;
560 #if defined _GLIBCXX_USE_FCHMOD && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
561 if (::fchmod(out.fd, from_st->st_mode))
562 #elif defined _GLIBCXX_USE_FCHMODAT && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
563 if (::fchmodat(AT_FDCWD, to, from_st->st_mode, 0))
564 #elif defined _GLIBCXX_USE_CHMOD
565 if (posix::chmod(to, from_st->st_mode))
566 #else
567 if (false)
568 #endif
570 ec.assign(errno, std::generic_category());
571 return false;
574 bool has_copied = false;
576 #ifdef _GLIBCXX_USE_COPY_FILE_RANGE
577 if (!has_copied)
578 has_copied = copy_file_copy_file_range(in.fd, out.fd, from_st->st_size);
579 if (!has_copied)
581 // EINVAL: src and dst are the same file (this is not cheaply
582 // detectable from userspace)
583 // EINVAL: copy_file_range is unsupported for this file type by the
584 // underlying filesystem
585 // ENOTSUP: undocumented, can arise with old kernels and NFS
586 // EOPNOTSUPP: filesystem does not implement copy_file_range
587 // ETXTBSY: src or dst is an active swapfile (nonsensical, but allowed
588 // with normal copying)
589 // EXDEV: src and dst are on different filesystems that do not support
590 // cross-fs copy_file_range
591 // ENOENT: undocumented, can arise with CIFS
592 // ENOSYS: unsupported by kernel or blocked by seccomp
593 if (errno != EINVAL && errno != ENOTSUP && errno != EOPNOTSUPP
594 && errno != ETXTBSY && errno != EXDEV && errno != ENOENT
595 && errno != ENOSYS)
597 ec.assign(errno, std::generic_category());
598 return false;
601 #endif
603 #if defined _GLIBCXX_USE_SENDFILE && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
604 if (!has_copied)
605 has_copied = copy_file_sendfile(in.fd, out.fd, from_st->st_size);
606 if (!has_copied)
608 if (errno != ENOSYS && errno != EINVAL)
610 ec.assign(errno, std::generic_category());
611 return false;
614 #endif
616 if (has_copied)
618 if (!out.close() || !in.close())
620 ec.assign(errno, std::generic_category());
621 return false;
623 ec.clear();
624 return true;
627 using std::ios;
628 __gnu_cxx::stdio_filebuf<char> sbin(in.fd, ios::in|ios::binary);
629 __gnu_cxx::stdio_filebuf<char> sbout(out.fd, ios::out|ios::binary);
631 if (sbin.is_open())
632 in.fd = -1;
633 if (sbout.is_open())
634 out.fd = -1;
636 // ostream::operator<<(streambuf*) fails if it extracts no characters,
637 // so don't try to use it for empty files. But from_st->st_size == 0 for
638 // some special files (e.g. procfs, see PR libstdc++/108178) so just try
639 // to read a character to decide whether there is anything to copy or not.
640 if (sbin.sgetc() != char_traits<char>::eof())
641 if (!(std::ostream(&sbout) << &sbin))
643 ec = std::make_error_code(std::errc::io_error);
644 return false;
647 if (!sbout.close() || !sbin.close())
649 ec.assign(errno, std::generic_category());
650 return false;
652 ec.clear();
653 return true;
655 #endif // NEED_DO_COPY_FILE
657 #ifdef NEED_DO_SPACE
658 #pragma GCC diagnostic push
659 #pragma GCC diagnostic ignored "-Wunused-parameter"
660 void
661 do_space(const char_type* pathname,
662 uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
663 std::error_code& ec)
665 #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
666 struct ::statvfs f;
667 if (::statvfs(pathname, &f))
668 ec.assign(errno, std::generic_category());
669 else
671 if (f.f_frsize != (unsigned long)-1)
673 const uintmax_t fragment_size = f.f_frsize;
674 const fsblkcnt_t unknown = -1;
675 if (f.f_blocks != unknown)
676 capacity = f.f_blocks * fragment_size;
677 if (f.f_bfree != unknown)
678 free = f.f_bfree * fragment_size;
679 if (f.f_bavail != unknown)
680 available = f.f_bavail * fragment_size;
682 ec.clear();
684 #elif _GLIBCXX_FILESYSTEM_IS_WINDOWS
685 ULARGE_INTEGER bytes_avail = {}, bytes_total = {}, bytes_free = {};
686 if (GetDiskFreeSpaceExW(pathname, &bytes_avail, &bytes_total, &bytes_free))
688 if (bytes_total.QuadPart != 0)
689 capacity = bytes_total.QuadPart;
690 if (bytes_free.QuadPart != 0)
691 free = bytes_free.QuadPart;
692 if (bytes_avail.QuadPart != 0)
693 available = bytes_avail.QuadPart;
694 ec.clear();
696 else
697 ec = std::__last_system_error();
698 #else
699 ec = std::make_error_code(std::errc::function_not_supported);
700 #endif
702 #pragma GCC diagnostic pop
703 #endif // NEED_DO_SPACE
705 #endif // _GLIBCXX_HAVE_SYS_STAT_H
707 // Find OS-specific name of temporary directory from the environment,
708 // Caller must check that the path is an accessible directory.
709 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
710 inline wstring
711 get_temp_directory_from_env(error_code& ec)
713 unsigned len = 1024;
714 std::wstring buf;
717 buf.__resize_and_overwrite(len, [&len](wchar_t* p, unsigned n) {
718 len = GetTempPathW(n, p);
719 return len > n ? 0 : len;
722 while (len > buf.size());
724 if (len == 0)
725 ec = __last_system_error();
726 else
727 ec.clear();
729 return buf;
731 #else
732 inline const char*
733 get_temp_directory_from_env(error_code& ec) noexcept
735 ec.clear();
736 for (auto env : { "TMPDIR", "TMP", "TEMP", "TEMPDIR" })
738 #if _GLIBCXX_HAVE_SECURE_GETENV
739 auto tmpdir = ::secure_getenv(env);
740 #else
741 auto tmpdir = ::getenv(env);
742 #endif
743 if (tmpdir)
744 return tmpdir;
746 return "/tmp";
748 #endif
750 _GLIBCXX_END_NAMESPACE_FILESYSTEM
752 _GLIBCXX_END_NAMESPACE_VERSION
753 } // namespace std
755 #endif // _GLIBCXX_OPS_COMMON_H