]> git.lyx.org Git - lyx.git/blob - src/support/FileInfo.C
Writing code in the presence of preprocessing blocks can be tricky.
[lyx.git] / src / support / FileInfo.C
1 /**
2  * \file FileInfo.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 #include <config.h>
12
13 #include "support/FileInfo.h"
14 #include "support/lstrings.h"
15
16 #include <boost/assert.hpp>
17
18 #include <cerrno>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21
22
23 using std::string;
24
25
26 #if !S_IRUSR
27 # if S_IREAD
28 #  define S_IRUSR S_IREAD
29 # else
30 #  define S_IRUSR 00400
31 # endif
32 #endif
33
34 #if !S_IWUSR
35 # if S_IWRITE
36 #  define S_IWUSR S_IWRITE
37 # else
38 #  define S_IWUSR 00200
39 # endif
40 #endif
41
42 #if !S_IXUSR
43 # if S_IEXEC
44 #  define S_IXUSR S_IEXEC
45 # else
46 #  define S_IXUSR 00100
47 # endif
48 #endif
49
50 #ifdef STAT_MACROS_BROKEN
51 #undef S_ISBLK
52 #undef S_ISCHR
53 #undef S_ISDIR
54 #undef S_ISFIFO
55 #undef S_ISLNK
56 #undef S_ISMPB
57 #undef S_ISMPC
58 #undef S_ISNWK
59 #undef S_ISREG
60 #undef S_ISSOCK
61 #endif
62
63 #if !defined(S_ISBLK) && defined(S_IFBLK)
64 #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
65 #endif
66 #if !defined(S_ISCHR) && defined(S_IFCHR)
67 #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
68 #endif
69 #if !defined(S_ISDIR) && defined(S_IFDIR)
70 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
71 #endif
72 #if !defined(S_ISREG) && defined(S_IFREG)
73 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
74 #endif
75 #if !defined(S_ISFIFO) && defined(S_IFIFO)
76 #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
77 #endif
78 #if !defined(S_ISLNK) && defined(S_IFLNK)
79 #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
80 #endif
81 #if !defined(S_ISSOCK) && defined(S_IFSOCK)
82 #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
83 #endif
84 #if !defined(S_ISMPB) && defined(S_IFMPB) /* V7 */
85 #define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
86 #define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
87 #endif
88 #if !defined(S_ISNWK) && defined(S_IFNWK) /* HP/UX */
89 #define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
90 #endif
91
92
93 namespace {
94
95 // builds 'rwx' string describing file access rights
96 void flagRWX(mode_t i, char * str)
97 {
98         str[0] = (i & S_IRUSR) ? 'r' : '-';
99         str[1] = (i & S_IWUSR) ? 'w' : '-';
100         str[2] = (i & S_IXUSR) ? 'x' : '-';
101 }
102
103 // updates mode string to match suid/sgid/sticky bits
104 void setSticky(mode_t i, char * str)
105 {
106 #ifdef S_ISUID
107         if (i & S_ISUID)
108                 str[3] = (str[3] == 'x') ? 's' : 'S';
109 #endif
110 #ifdef S_ISGID
111         if (i & S_ISGID)
112                 str[6] = (str[6] == 'x') ? 's' : 'S';
113 #endif
114 #ifdef S_ISVTX
115         if (i & S_ISVTX)
116                 str[9] = (str[9] == 'x') ? 's' : 'S';
117 #endif
118 }
119
120 // returns a letter describing a file type (ls style)
121 char typeLetter(mode_t i)
122 {
123 #ifdef S_ISBLK
124         if (S_ISBLK(i)) return 'b';
125 #endif
126         if (S_ISCHR(i)) return 'c';
127         if (S_ISDIR(i)) return 'd';
128         if (S_ISREG(i)) return '-';
129 #ifdef S_ISFIFO
130         if (S_ISFIFO(i)) return 'p';
131 #endif
132 #ifdef S_ISLNK
133         if (S_ISLNK(i)) return 'l';
134 #endif
135 #ifdef S_ISSOCK
136         if (S_ISSOCK(i)) return 's';
137 #endif
138 #ifdef S_ISMPC
139         if (S_ISMPC(i)) return 'm';
140 #endif
141 #ifdef S_ISNWK
142         if (S_ISNWK(i)) return 'n';
143 #endif
144         return '?';
145 }
146
147 } // namespace anon
148
149
150 namespace lyx {
151 namespace support {
152
153 FileInfo::FileInfo()
154 {
155         init();
156 }
157
158
159 FileInfo::FileInfo(string const & path, bool link)
160         // Win32 stat() doesn't dig trailing slashes.
161         // Posix stat() doesn't care, but we'll remove it anyway.
162         : fname_(rtrim(path, "/"))
163 {
164         init();
165         dostat(link);
166 }
167
168
169 FileInfo::FileInfo(int fildes)
170 {
171         init();
172         status_ = fstat(fildes, &buf_);
173         if (status_)
174                 err_ = errno;
175 }
176
177
178 void FileInfo::init()
179 {
180         status_ = 0;
181         err_ = NoErr;
182 }
183
184
185 void FileInfo::dostat(bool link)
186 {
187 #ifdef HAVE_LSTAT
188         if (link)
189                 status_ = ::lstat(fname_.c_str(), &buf_);
190         else
191                 status_ = ::stat(fname_.c_str(), &buf_);
192 #else
193         status_ = ::stat(fname_.c_str(), &buf_);
194 #endif
195
196         if (status_)
197                 err_ = errno;
198 }
199
200
201 FileInfo & FileInfo::newFile(string const & path, bool link)
202 {
203         // Win32 stat() doesn't dig trailing slashes.
204         // Posix stat() doesn't care, but we'll remove it anyway.
205         fname_  = rtrim(path, "/");
206         status_ = 0;
207         err_    = NoErr;
208         dostat(link);
209         return *this;
210 }
211
212
213 FileInfo & FileInfo::newFile(int fildes)
214 {
215         status_ = 0;
216         err_    = NoErr;
217         status_ = fstat(fildes, &buf_);
218         if (status_)
219                 err_ = errno;
220         return *this;
221 }
222
223
224 // should not be in FileInfo
225 char FileInfo::typeIndicator() const
226 {
227         BOOST_ASSERT(isOK());
228         if (S_ISDIR(buf_.st_mode))
229                 return '/';
230 #ifdef S_ISLNK
231         if (S_ISLNK(buf_.st_mode))
232                 return '@';
233 #endif
234 #ifdef S_ISFIFO
235         if (S_ISFIFO(buf_.st_mode))
236                 return '|';
237 #endif
238 #ifdef S_ISSOCK
239         if (S_ISSOCK(buf_.st_mode))
240                 return '=';
241 #endif
242         return ' ';
243 }
244
245
246 mode_t FileInfo::getMode() const
247 {
248         BOOST_ASSERT(isOK());
249         return buf_.st_mode;
250 }
251
252
253 // should not be in FileInfo
254 string FileInfo::modeString() const
255 {
256         BOOST_ASSERT(isOK());
257         char str[11];
258         str[0] = typeLetter(buf_.st_mode);
259         flagRWX((buf_.st_mode & 0700) << 0, &str[1]);
260         flagRWX((buf_.st_mode & 0070) << 3, &str[4]);
261         flagRWX((buf_.st_mode & 0007) << 6, &str[7]);
262         setSticky(buf_.st_mode, str);
263         str[10] = 0;
264         return str;
265 }
266
267
268
269 time_t FileInfo::getModificationTime() const
270 {
271         BOOST_ASSERT(isOK());
272         return buf_.st_mtime;
273 }
274
275
276 time_t FileInfo::getAccessTime() const
277 {
278         BOOST_ASSERT(isOK());
279         return buf_.st_atime;
280 }
281
282
283 time_t FileInfo::getStatusChangeTime() const
284 {
285         BOOST_ASSERT(isOK());
286         return buf_.st_ctime;
287 }
288
289
290 uid_t FileInfo::getUid() const
291 {
292         BOOST_ASSERT(isOK());
293         return buf_.st_uid;
294 }
295
296
297 gid_t FileInfo::getGid() const
298 {
299         BOOST_ASSERT(isOK());
300         return buf_.st_gid;
301 }
302
303
304 off_t FileInfo::getSize() const
305 {
306         BOOST_ASSERT(isOK());
307         return buf_.st_size;
308 }
309
310
311 int FileInfo::getError() const
312 {
313         return err_;
314 }
315
316
317 bool FileInfo::isOK() const
318 {
319         return status_ == 0;
320 }
321
322
323 bool FileInfo::isLink() const
324 {
325         BOOST_ASSERT(isOK());
326 #ifdef S_ISLNK
327         return S_ISLNK(buf_.st_mode);
328 #else
329         return false;
330 #endif
331 }
332
333
334 bool FileInfo::isRegular() const
335 {
336         BOOST_ASSERT(isOK());
337         return S_ISREG(buf_.st_mode);
338 }
339
340
341 bool FileInfo::isDir() const
342 {
343         BOOST_ASSERT(isOK());
344         return S_ISDIR(buf_.st_mode);
345 }
346
347
348 bool FileInfo::isChar() const
349 {
350         BOOST_ASSERT(isOK());
351         return S_ISCHR(buf_.st_mode);
352 }
353
354
355 bool FileInfo::isBlock() const
356 {
357         BOOST_ASSERT(isOK());
358         return S_ISBLK(buf_.st_mode);
359 }
360
361
362 bool FileInfo::isFifo() const
363 {
364         BOOST_ASSERT(isOK());
365         return S_ISFIFO(buf_.st_mode);
366 }
367
368
369 bool FileInfo::isSocket() const
370 {
371         BOOST_ASSERT(isOK());
372 #ifdef S_ISSOCK
373         return S_ISSOCK(buf_.st_mode);
374 #else
375         return false;
376 #endif
377 }
378
379
380 // should not be in FileInfo
381 bool FileInfo::access(int p) const
382 {
383         // if we don't have a filename we fail
384         if (fname_.empty())
385                 return false;
386
387         // If we were really kind, we would also tell why
388         // the file access failed.
389         return ::access(fname_.c_str(), p) == 0;
390 }
391
392 } // namespace support
393 } // namespace lyx