|
1 /**************************************************************************** |
|
2 ** |
|
3 ** |
|
4 ** Implementation of QFileInfo class |
|
5 ** |
|
6 ** Created : 950628 |
|
7 ** |
|
8 ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. |
|
9 ** |
|
10 ** This file is part of the tools module of the Qt GUI Toolkit. |
|
11 ** |
|
12 ** This file may be distributed under the terms of the Q Public License |
|
13 ** as defined by Trolltech AS of Norway and appearing in the file |
|
14 ** LICENSE.QPL included in the packaging of this file. |
|
15 ** |
|
16 ** This file may be distributed and/or modified under the terms of the |
|
17 ** GNU General Public License version 2 as published by the Free Software |
|
18 ** Foundation and appearing in the file LICENSE.GPL included in the |
|
19 ** packaging of this file. |
|
20 ** |
|
21 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition |
|
22 ** licenses for Unix/X11 or for Qt/Embedded may use this file in accordance |
|
23 ** with the Qt Commercial License Agreement provided with the Software. |
|
24 ** |
|
25 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE |
|
26 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
|
27 ** |
|
28 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for |
|
29 ** information about Qt Commercial License Agreements. |
|
30 ** See http://www.trolltech.com/qpl/ for QPL licensing information. |
|
31 ** See http://www.trolltech.com/gpl/ for GPL licensing information. |
|
32 ** |
|
33 ** Contact info@trolltech.com if any conditions of this licensing are |
|
34 ** not clear to you. |
|
35 ** |
|
36 **********************************************************************/ |
|
37 |
|
38 #include "qglobal.h" |
|
39 |
|
40 #if defined(_OS_SUN_) |
|
41 #define readlink _qt_hide_readlink |
|
42 #endif |
|
43 |
|
44 #include <pwd.h> |
|
45 #include <grp.h> |
|
46 |
|
47 #include "qfileinfo.h" |
|
48 #include "qfiledefs_p.h" |
|
49 #include "qdatetime.h" |
|
50 #include "qdir.h" |
|
51 |
|
52 #if defined(_OS_SUN_) |
|
53 #undef readlink |
|
54 extern "C" int readlink( const char *, void *, uint ); |
|
55 #endif |
|
56 |
|
57 |
|
58 void QFileInfo::slashify( QString& ) |
|
59 { |
|
60 return; |
|
61 } |
|
62 |
|
63 |
|
64 void QFileInfo::makeAbs( QString & ) |
|
65 { |
|
66 return; |
|
67 } |
|
68 |
|
69 extern bool qt_file_access( const QString& fn, int t ); |
|
70 |
|
71 /*! |
|
72 Returns TRUE if we are pointing to a real file. |
|
73 \sa isDir(), isSymLink() |
|
74 */ |
|
75 bool QFileInfo::isFile() const |
|
76 { |
|
77 if ( !fic || !cache ) |
|
78 doStat(); |
|
79 return fic ? (fic->st.st_mode & STAT_MASK) == STAT_REG : FALSE; |
|
80 } |
|
81 |
|
82 /*! |
|
83 Returns TRUE if we are pointing to a directory or a symbolic link to |
|
84 a directory. |
|
85 \sa isFile(), isSymLink() |
|
86 */ |
|
87 |
|
88 bool QFileInfo::isDir() const |
|
89 { |
|
90 if ( !fic || !cache ) |
|
91 doStat(); |
|
92 return fic ? (fic->st.st_mode & STAT_MASK) == STAT_DIR : FALSE; |
|
93 } |
|
94 |
|
95 /*! |
|
96 Returns TRUE if we are pointing to a symbolic link. |
|
97 \sa isFile(), isDir(), readLink() |
|
98 */ |
|
99 |
|
100 bool QFileInfo::isSymLink() const |
|
101 { |
|
102 if ( !fic || !cache ) |
|
103 doStat(); |
|
104 return fic ? fic->isSymLink : FALSE; |
|
105 } |
|
106 |
|
107 |
|
108 /*! |
|
109 Returns the name a symlink points to, or a null QString if the |
|
110 object does not refer to a symbolic link. |
|
111 |
|
112 This name may not represent an existing file; it is only a string. |
|
113 QFileInfo::exists() returns TRUE if the symlink points to an |
|
114 existing file. |
|
115 |
|
116 \sa exists(), isSymLink(), isDir(), isFile() |
|
117 */ |
|
118 |
|
119 QString QFileInfo::readLink() const |
|
120 { |
|
121 QString r; |
|
122 |
|
123 #if defined(_OS_UNIX_) && !defined(_OS_OS2EMX_) |
|
124 char s[PATH_MAX+1]; |
|
125 if ( !isSymLink() ) |
|
126 return QString(); |
|
127 int len = readlink( QFile::encodeName(fn).data(), s, PATH_MAX ); |
|
128 if ( len >= 0 ) { |
|
129 s[len] = '\0'; |
|
130 r = QFile::decodeName(s); |
|
131 } |
|
132 #endif |
|
133 |
|
134 return r; |
|
135 } |
|
136 |
|
137 static const uint nobodyID = (uint) -2; |
|
138 |
|
139 /*! |
|
140 Returns the owner of the file. |
|
141 |
|
142 On systems where files do not have owners this function returns 0. |
|
143 |
|
144 Note that this function can be time-consuming under UNIX. (in the order |
|
145 of milliseconds on a 486 DX2/66 running Linux). |
|
146 |
|
147 \sa ownerId(), group(), groupId() |
|
148 */ |
|
149 |
|
150 QString QFileInfo::owner() const |
|
151 { |
|
152 passwd *pw = getpwuid( ownerId() ); |
|
153 if ( pw ) |
|
154 return QFile::decodeName( pw->pw_name ); |
|
155 return QString::null; |
|
156 } |
|
157 |
|
158 /*! |
|
159 Returns the id of the owner of the file. |
|
160 |
|
161 On systems where files do not have owners this function returns ((uint) -2). |
|
162 |
|
163 \sa owner(), group(), groupId() |
|
164 */ |
|
165 |
|
166 uint QFileInfo::ownerId() const |
|
167 { |
|
168 if ( !fic || !cache ) |
|
169 doStat(); |
|
170 if ( fic ) |
|
171 return fic->st.st_uid; |
|
172 return nobodyID; |
|
173 } |
|
174 |
|
175 /*! |
|
176 Returns the group the file belongs to. |
|
177 |
|
178 On systems where files do not have groups this function always |
|
179 returns 0. |
|
180 |
|
181 Note that this function can be time-consuming under UNIX (in the order of |
|
182 milliseconds on a 486 DX2/66 running Linux). |
|
183 |
|
184 \sa groupId(), owner(), ownerId() |
|
185 */ |
|
186 |
|
187 QString QFileInfo::group() const |
|
188 { |
|
189 struct group *gr = getgrgid( groupId() ); |
|
190 if ( gr ) |
|
191 return QFile::decodeName( gr->gr_name ); |
|
192 return QString::null; |
|
193 } |
|
194 |
|
195 /*! |
|
196 Returns the id of the group the file belongs to. |
|
197 |
|
198 On systems where files do not have groups this function always |
|
199 returns ((uind) -2). |
|
200 |
|
201 \sa group(), owner(), ownerId() |
|
202 */ |
|
203 |
|
204 uint QFileInfo::groupId() const |
|
205 { |
|
206 if ( !fic || !cache ) |
|
207 doStat(); |
|
208 if ( fic ) |
|
209 return fic->st.st_gid; |
|
210 return nobodyID; |
|
211 } |
|
212 |
|
213 |
|
214 /*! |
|
215 \fn bool QFileInfo::permission( int permissionSpec ) const |
|
216 |
|
217 Tests for file permissions. The \e permissionSpec argument can be several |
|
218 flags of type PermissionSpec or'ed together to check for permission |
|
219 combinations. |
|
220 |
|
221 On systems where files do not have permissions this function always |
|
222 returns TRUE. |
|
223 |
|
224 Example: |
|
225 \code |
|
226 QFileInfo fi( "/tmp/tonsils" ); |
|
227 if ( fi.permission( QFileInfo::WriteUser | QFileInfo::ReadGroup ) ) |
|
228 qWarning( "Tonsils can be changed by me, and the group can read them."); |
|
229 if ( fi.permission( QFileInfo::WriteGroup | QFileInfo::WriteOther ) ) |
|
230 qWarning( "Danger! Tonsils can be changed by the group or others!" ); |
|
231 \endcode |
|
232 |
|
233 \sa isReadable(), isWritable(), isExecutable() |
|
234 */ |
|
235 |
|
236 bool QFileInfo::permission( int permissionSpec ) const |
|
237 { |
|
238 if ( !fic || !cache ) |
|
239 doStat(); |
|
240 if ( fic ) { |
|
241 uint mask = 0; |
|
242 if ( permissionSpec & ReadUser) |
|
243 mask |= S_IRUSR; |
|
244 if ( permissionSpec & WriteUser) |
|
245 mask |= S_IWUSR; |
|
246 if ( permissionSpec & ExeUser) |
|
247 mask |= S_IXUSR; |
|
248 if ( permissionSpec & ReadGroup) |
|
249 mask |= S_IRGRP; |
|
250 if ( permissionSpec & WriteGroup) |
|
251 mask |= S_IWGRP; |
|
252 if ( permissionSpec & ExeGroup) |
|
253 mask |= S_IXGRP; |
|
254 if ( permissionSpec & ReadOther) |
|
255 mask |= S_IROTH; |
|
256 if ( permissionSpec & WriteOther) |
|
257 mask |= S_IWOTH; |
|
258 if ( permissionSpec & ExeOther) |
|
259 mask |= S_IXOTH; |
|
260 if ( mask ) { |
|
261 return (fic->st.st_mode & mask) == mask; |
|
262 } else { |
|
263 #if defined(CHECK_NULL) |
|
264 qWarning( "QFileInfo::permission: permissionSpec is 0" ); |
|
265 #endif |
|
266 return TRUE; |
|
267 } |
|
268 } else { |
|
269 return FALSE; |
|
270 } |
|
271 } |
|
272 |
|
273 /*! |
|
274 Returns the file size in bytes, or 0 if the file does not exist if the size |
|
275 cannot be fetched. |
|
276 */ |
|
277 |
|
278 uint QFileInfo::size() const |
|
279 { |
|
280 if ( !fic || !cache ) |
|
281 doStat(); |
|
282 if ( fic ) |
|
283 return (uint)fic->st.st_size; |
|
284 else |
|
285 return 0; |
|
286 } |
|
287 |
|
288 |
|
289 /*! |
|
290 Returns the date and time when the file was last modified. |
|
291 \sa lastRead() |
|
292 */ |
|
293 |
|
294 QDateTime QFileInfo::lastModified() const |
|
295 { |
|
296 QDateTime dt; |
|
297 if ( !fic || !cache ) |
|
298 doStat(); |
|
299 if ( fic ) |
|
300 dt.setTime_t( fic->st.st_mtime ); |
|
301 return dt; |
|
302 } |
|
303 |
|
304 /*! |
|
305 Returns the date and time when the file was last read (accessed). |
|
306 |
|
307 On systems that do not support last read times, the modification time is |
|
308 returned. |
|
309 |
|
310 \sa lastModified() |
|
311 */ |
|
312 |
|
313 QDateTime QFileInfo::lastRead() const |
|
314 { |
|
315 QDateTime dt; |
|
316 if ( !fic || !cache ) |
|
317 doStat(); |
|
318 if ( fic ) |
|
319 dt.setTime_t( fic->st.st_atime ); |
|
320 return dt; |
|
321 } |
|
322 |
|
323 |
|
324 void QFileInfo::doStat() const |
|
325 { |
|
326 QFileInfo *that = ((QFileInfo*)this); // mutable function |
|
327 if ( !that->fic ) |
|
328 that->fic = new QFileInfoCache; |
|
329 STATBUF *b = &that->fic->st; |
|
330 that->fic->isSymLink = FALSE; |
|
331 |
|
332 #if defined(_OS_UNIX_) && defined(S_IFLNK) |
|
333 if ( ::lstat(QFile::encodeName(fn),b) == 0 ) { |
|
334 if ( S_ISLNK( b->st_mode ) ) |
|
335 that->fic->isSymLink = TRUE; |
|
336 else |
|
337 return; |
|
338 } |
|
339 #endif |
|
340 int r; |
|
341 |
|
342 r = STAT( QFile::encodeName(fn), b ); |
|
343 |
|
344 if ( r != 0 ) { |
|
345 delete that->fic; |
|
346 that->fic = 0; |
|
347 } |
|
348 } |
|
349 |
|
350 /*! |
|
351 Returns the directory path of the file. |
|
352 |
|
353 If \e absPath is TRUE an absolute path is always returned. |
|
354 |
|
355 \sa dir(), filePath(), fileName(), isRelative() |
|
356 */ |
|
357 #ifndef QT_NO_DIR |
|
358 QString QFileInfo::dirPath( bool absPath ) const |
|
359 { |
|
360 QString s; |
|
361 if ( absPath ) |
|
362 s = absFilePath(); |
|
363 else |
|
364 s = fn; |
|
365 int pos = s.findRev( '/' ); |
|
366 if ( pos == -1 ) { |
|
367 return QString::fromLatin1("."); |
|
368 } else { |
|
369 if ( pos == 0 ) |
|
370 return QString::fromLatin1( "/" ); |
|
371 return s.left( pos ); |
|
372 } |
|
373 } |
|
374 #endif |
|
375 /*! |
|
376 Returns the name of the file, the file path is not included. |
|
377 |
|
378 Example: |
|
379 \code |
|
380 QFileInfo fi( "/tmp/abdomen.lower" ); |
|
381 QString name = fi.fileName(); // name = "abdomen.lower" |
|
382 \endcode |
|
383 |
|
384 \sa isRelative(), filePath(), baseName(), extension() |
|
385 */ |
|
386 |
|
387 QString QFileInfo::fileName() const |
|
388 { |
|
389 int p = fn.findRev( '/' ); |
|
390 if ( p == -1 ) { |
|
391 return fn; |
|
392 } else { |
|
393 return fn.mid(p+1); |
|
394 } |
|
395 } |
|
396 |
|
397 /*! |
|
398 Returns the absolute path name. |
|
399 |
|
400 The absolute path name is the file name including the absolute path. If |
|
401 the QFileInfo is absolute (i.e. not relative) this function will return |
|
402 the same string as filePath(). |
|
403 |
|
404 Note that this function can be time-consuming under UNIX. (in the order |
|
405 of milliseconds on a 486 DX2/66 running Linux). |
|
406 |
|
407 \sa isRelative(), filePath() |
|
408 */ |
|
409 #ifndef QT_NO_DIR |
|
410 QString QFileInfo::absFilePath() const |
|
411 { |
|
412 if ( QDir::isRelativePath(fn) ) { |
|
413 QString tmp = QDir::currentDirPath(); |
|
414 tmp += '/'; |
|
415 tmp += fn; |
|
416 makeAbs( tmp ); |
|
417 return QDir::cleanDirPath( tmp ); |
|
418 } else { |
|
419 QString tmp = fn; |
|
420 makeAbs( tmp ); |
|
421 return QDir::cleanDirPath( tmp ); |
|
422 } |
|
423 |
|
424 } |
|
425 #endif |