]> git.lyx.org Git - lyx.git/blob - src/support/FileInfo.C
Test for OS support for symbolic links and protect support library code
[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         if (S_ISREG(buf_.st_mode) && (buf_.st_mode & (S_IEXEC | S_IXGRP | S_IXOTH)))
243                 return '*';
244         return ' ';
245 }
246
247
248 mode_t FileInfo::getMode() const
249 {
250         BOOST_ASSERT(isOK());
251         return buf_.st_mode;
252 }
253
254
255 // should not be in FileInfo
256 string FileInfo::modeString() const
257 {
258         BOOST_ASSERT(isOK());
259         char str[11];
260         str[0] = typeLetter(buf_.st_mode);
261         flagRWX((buf_.st_mode & 0700) << 0, &str[1]);
262         flagRWX((buf_.st_mode & 0070) << 3, &str[4]);
263         flagRWX((buf_.st_mode & 0007) << 6, &str[7]);
264         setSticky(buf_.st_mode, str);
265         str[10] = 0;
266         return str;
267 }
268
269
270
271 time_t FileInfo::getModificationTime() const
272 {
273         BOOST_ASSERT(isOK());
274         return buf_.st_mtime;
275 }
276
277
278 time_t FileInfo::getAccessTime() const
279 {
280         BOOST_ASSERT(isOK());
281         return buf_.st_atime;
282 }
283
284
285 time_t FileInfo::getStatusChangeTime() const
286 {
287         BOOST_ASSERT(isOK());
288         return buf_.st_ctime;
289 }
290
291
292 uid_t FileInfo::getUid() const
293 {
294         BOOST_ASSERT(isOK());
295         return buf_.st_uid;
296 }
297
298
299 gid_t FileInfo::getGid() const
300 {
301         BOOST_ASSERT(isOK());
302         return buf_.st_gid;
303 }
304
305
306 off_t FileInfo::getSize() const
307 {
308         BOOST_ASSERT(isOK());
309         return buf_.st_size;
310 }
311
312
313 int FileInfo::getError() const
314 {
315         return err_;
316 }
317
318
319 bool FileInfo::isOK() const
320 {
321         return status_ == 0;
322 }
323
324
325 bool FileInfo::isLink() const
326 {
327         BOOST_ASSERT(isOK());
328 #ifdef S_ISLNK
329         return S_ISLNK(buf_.st_mode);
330 #else
331         return false;
332 #endif
333 }
334
335
336 bool FileInfo::isRegular() const
337 {
338         BOOST_ASSERT(isOK());
339         return S_ISREG(buf_.st_mode);
340 }
341
342
343 bool FileInfo::isDir() const
344 {
345         BOOST_ASSERT(isOK());
346         return S_ISDIR(buf_.st_mode);
347 }
348
349
350 bool FileInfo::isChar() const
351 {
352         BOOST_ASSERT(isOK());
353         return S_ISCHR(buf_.st_mode);
354 }
355
356
357 bool FileInfo::isBlock() const
358 {
359         BOOST_ASSERT(isOK());
360         return S_ISBLK(buf_.st_mode);
361 }
362
363
364 bool FileInfo::isFifo() const
365 {
366         BOOST_ASSERT(isOK());
367         return S_ISFIFO(buf_.st_mode);
368 }
369
370
371 bool FileInfo::isSocket() const
372 {
373         BOOST_ASSERT(isOK());
374 #ifdef S_ISSOCK
375         return S_ISSOCK(buf_.st_mode);
376 #else
377         return false;
378 #endif
379 }
380
381
382 // should not be in FileInfo
383 bool FileInfo::access(int p) const
384 {
385         // if we don't have a filename we fail
386         if (fname_.empty())
387                 return false;
388
389         // If we were really kind, we would also tell why
390         // the file access failed.
391         return ::access(fname_.c_str(), p) == 0;
392 }
393
394 } // namespace support
395 } // namespace lyx