]> git.lyx.org Git - lyx.git/blob - src/support/fs_extras.C
Fix several filename and environment variable encoding problems
[lyx.git] / src / support / fs_extras.C
1 // -*- C++ -*-
2 /* \file fs_extras.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11
12 #include <config.h>
13
14 #include "fs_extras.h"
15
16 #include <boost/filesystem/config.hpp>
17 #include <boost/detail/workaround.hpp>
18 #include <boost/throw_exception.hpp>
19
20 #ifdef HAVE_SYS_TYPES_H
21 # include <sys/types.h>
22 #endif
23 #ifdef HAVE_SYS_STAT_H
24 # include <sys/stat.h>
25 #endif
26 #include <cerrno>
27 #include <fcntl.h>
28
29
30 // BOOST_POSIX or BOOST_WINDOWS specify which API to use.
31 # if !defined( BOOST_WINDOWS ) && !defined( BOOST_POSIX )
32 #   if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)
33 #     define BOOST_WINDOWS
34 #   else
35 #     define BOOST_POSIX
36 #   endif
37 # endif
38
39 #if defined (BOOST_WINDOWS)
40 # define WIN32_LEAN_AND_MEAN
41 # include <windows.h>
42 #endif
43
44 namespace fs = boost::filesystem;
45
46 namespace boost {
47 namespace filesystem {
48
49 bool is_readable(path const & ph)
50 {
51 #ifdef BOOST_POSIX
52         return ::access(ph.string().c_str(), R_OK) == 0;
53 #endif
54 #ifdef BOOST_WINDOWS
55         DWORD const attr = ::GetFileAttributes(ph.string().c_str());
56         return attr != INVALID_FILE_ATTRIBUTES &&
57                 (attr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY;
58 #endif
59 }
60
61
62 bool is_writable(path const & ph)
63 {
64 #ifdef BOOST_POSIX
65         return ::access(ph.string().c_str(), W_OK) == 0;
66 #endif
67 #ifdef BOOST_WINDOWS
68         DWORD const attr = ::GetFileAttributes(ph.string().c_str());
69         if (attr != INVALID_FILE_ATTRIBUTES &&
70             (attr & FILE_ATTRIBUTE_READONLY) != 0) {
71                 // Read-only - no write access
72                 return false;
73         }
74         return attr != INVALID_FILE_ATTRIBUTES &&
75                 (attr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY;
76 #endif
77 }
78
79
80 bool is_readonly(path const & ph)
81 {
82 #ifdef BOOST_POSIX
83         return is_readable(ph) && !is_writable(ph);
84 #endif
85 #ifdef BOOST_WINDOWS
86         DWORD const attr = ::GetFileAttributes(ph.string().c_str());
87         return (attr != INVALID_FILE_ATTRIBUTES
88                 && (attr & FILE_ATTRIBUTE_READONLY));
89 #endif
90 }
91
92
93 void copy_file(path const & source, path const & target, bool noclobber)
94 {
95
96 #ifdef BOOST_POSIX
97         int const infile = ::open(source.string().c_str(), O_RDONLY);
98         if (infile == -1) {
99                 boost::throw_exception(
100                         filesystem_path_error(
101                                 "boost::filesystem::copy_file",
102                                 source, target,
103                                 fs::lookup_errno(errno)));
104         }
105
106         struct stat source_stat;
107         int const ret = ::fstat(infile, &source_stat);
108         if (ret == -1) {
109                 int err = errno;
110                 ::close(infile);
111                 boost::throw_exception(
112                         filesystem_path_error(
113                                 "boost::filesystem::copy_file",
114                                 source, target,
115                                 fs::lookup_errno(err)));
116         }
117
118         int const flags = O_WRONLY | O_CREAT | (noclobber ? O_EXCL : O_TRUNC);
119
120         int const outfile = ::open(target.string().c_str(), flags, source_stat.st_mode);
121         if (outfile == -1) {
122                 int err = errno;
123                 ::close(infile);
124                 boost::throw_exception(
125                         filesystem_path_error(
126                                 "boost::filesystem::copy_file",
127                                 source, target,
128                                 fs::lookup_errno(err)));
129         }
130
131         std::size_t const buf_sz = 32768;
132         char buf[buf_sz];
133         ssize_t in = -1;
134         ssize_t out = -1;
135
136         while (true) {
137                 in = ::read(infile, buf, buf_sz);
138                 if (in == -1) {
139                         break;
140                 } else if (in == 0) {
141                         break;
142                 } else {
143                         out = ::write(outfile, buf, in);
144                         if (out == -1) {
145                                 break;
146                         }
147                 }
148         }
149
150         int err = errno;
151
152         ::close(infile);
153         ::close(outfile);
154
155         if (in == -1 || out == -1)
156                 boost::throw_exception(
157                         filesystem_path_error(
158                                 "boost::filesystem::copy_file",
159                                 source, target,
160                                 fs::lookup_errno(err)));
161 #endif
162 #ifdef BOOST_WINDOWS
163         if (::CopyFile(source.string().c_str(), target.string().c_str(), noclobber) == 0) {
164                 // CopyFile is probably not setting errno so this is most
165                 // likely wrong.
166                 boost::throw_exception(
167                         filesystem_path_error(
168                                 "boost::filesystem::copy_file",
169                                 source, target,
170                                 fs::lookup_error_code(errno)));
171         }
172 #endif
173 }
174
175 }
176 }
177