Line data Source code
1 : /*
2 : Zipios++ - a small C++ library that provides easy access to .zip files.
3 :
4 : Copyright (C) 2000-2007 Thomas Sondergaard
5 : Copyright (C) 2015 Made to Order Software Corporation
6 :
7 : This library is free software; you can redistribute it and/or
8 : modify it under the terms of the GNU Lesser General Public
9 : License as published by the Free Software Foundation; either
10 : version 2 of the License, or (at your option) any later version.
11 :
12 : This library is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this library; if not, write to the Free Software
19 : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 : */
21 :
22 : /** \file
23 : * \brief Implementation of zipios::FilePath.
24 : *
25 : * This file includes the zipios::FilePath implementation which makes it
26 : * a little easier to handle the stat() system call on any file for any
27 : * system.
28 : */
29 :
30 : #include "zipios/filepath.hpp"
31 :
32 : #include "zipios_common.hpp"
33 :
34 : #include <memory.h>
35 :
36 :
37 : namespace zipios
38 : {
39 :
40 :
41 : namespace
42 : {
43 :
44 :
45 : /** \brief Prune the trailing separator if present.
46 : *
47 : * This function is used to ensure that the FilePath does NOT end
48 : * with a separator.
49 : *
50 : * \warning
51 : * At this time the path is not canonicalized properly. We expect \p path
52 : * to not include double separators one after another. However, passing
53 : * such a path to the FilePath will keep it as is.
54 : *
55 : * \param[in] path The path to prune of one trailing separator.
56 : *
57 : * \return The path as is or without the last '/'.
58 : */
59 634031 : std::string pruneTrailingSeparator(std::string path)
60 : {
61 634031 : if(path.size() > 0)
62 : {
63 396594 : if(path[path.size() - 1] == g_separator)
64 : {
65 16934 : path.erase(path.size() - 1);
66 : }
67 : }
68 :
69 634031 : return path;
70 : }
71 :
72 :
73 : } // no name namespace
74 :
75 :
76 :
77 : /** \class FilePath
78 : * \brief Handle a file path and name and its statistics.
79 : *
80 : * The FilePath class represents a path to a file or directory name.
81 : * FilePath has member functions to check if the file path is a valid
82 : * file system entity, and to check what kind of file system entity
83 : * it is, e.g. is it a file, a directory, a pipe, etc.
84 : *
85 : * It also knows of the last modification time and size of the file.
86 : *
87 : * \warning
88 : * The information about a file is cached so at the time it gets used
89 : * the file on disk may have changed, it may even have been deleted.
90 : */
91 :
92 :
93 : /** \brief Initialize a FilePath object.
94 : *
95 : * The constructor saves the path and if \p check_exists is true, read
96 : * the file statistics, especially the st_mode.
97 : *
98 : * \param[in] path A string representation of the path.
99 : *
100 : * \sa exists()
101 : * \sa pruneTrailingSeparator()
102 : */
103 633588 : FilePath::FilePath(std::string const& path)
104 633588 : : m_path(pruneTrailingSeparator(path))
105 : //, m_stat() -- see below
106 : //, m_checked(false) -- auto-init
107 : //, m_exists(false) -- auto-init
108 : {
109 633588 : memset(&m_stat, 0, sizeof(m_stat));
110 633588 : }
111 :
112 :
113 : /** \brief Read the file mode.
114 : *
115 : * This function sets m_checked to true, stat()'s the path, to see if
116 : * it exists and to determine what type of file it is. All the query
117 : * functions call check() before they test a flag to make sure it
118 : * is set appropriately.
119 : *
120 : * This means stat()'ing is deferred until it becomes necessary. But also
121 : * it is cached meaning that if the file changes in between we get the
122 : * old flags.
123 : */
124 1220957 : void FilePath::check() const
125 : {
126 1220957 : if(!m_checked)
127 : {
128 140837 : m_checked = true;
129 :
130 : /** \TODO
131 : * Under MS-Windows, we need to use _wstat() to make it work in
132 : * Unicode (i.e. UTF-8 to wchar_t then call _wstat()...) Also we
133 : * want to use the 64 bit variant to make sure that we get a
134 : * valid size. Any other reference to the stat() command should
135 : * be replace by using a FilePath().
136 : */
137 140837 : memset(&m_stat, 0, sizeof(m_stat));
138 140837 : m_exists = stat(m_path.c_str(), &m_stat) == 0;
139 : }
140 1220957 : }
141 :
142 :
143 : /** \brief Replace the path with a new path.
144 : *
145 : * This function replaces the internal path of this FilePath with
146 : * the new specified path.
147 : *
148 : * \param[in] path The new path to save in this object.
149 : *
150 : * \return A reference to this object.
151 : */
152 443 : FilePath& FilePath::operator = (std::string const& path)
153 : {
154 443 : m_path = pruneTrailingSeparator(path);
155 443 : return *this;
156 : }
157 :
158 :
159 : /** \brief Retrieve the path.
160 : *
161 : * This operator can be used to retrieve a copy of the path.
162 : *
163 : * \return The m_path string returned as is (i.e. the whole path).
164 : */
165 63761612 : FilePath::operator std::string () const
166 : {
167 63761612 : return m_path;
168 : }
169 :
170 :
171 : /** \brief Append the a child name to this path.
172 : *
173 : * This function concatenates two FilePath objects and returns
174 : * another FilePath.
175 : *
176 : * A file separator is inserted between both names if appropriate.
177 : *
178 : * \warning
179 : * Note that the function allows you to append two full paths,
180 : * or even a relative path (left) to a full path (right), which
181 : * may result in a new path that is not quite sensible.
182 : *
183 : * \param[in] rhs The right hand side.
184 : */
185 20226 : FilePath FilePath::operator + (FilePath const& rhs) const
186 : {
187 20226 : if(m_path.empty())
188 : {
189 132 : return rhs;
190 : }
191 :
192 20094 : if(rhs.m_path.empty())
193 : {
194 2109 : return *this;
195 : }
196 :
197 17985 : if(rhs.m_path[0] == g_separator)
198 : {
199 4 : return m_path + rhs.m_path;
200 : }
201 :
202 17981 : return m_path + g_separator + rhs.m_path;
203 : }
204 :
205 :
206 : /** \brief Check whether two FilePath represent the same file.
207 : *
208 : * This function compares a FilePath object (this) and a C-string
209 : * to know whether the two are the same.
210 : *
211 : * A null pointer as the C-string is viewed as an empty string.
212 : *
213 : * \param[in] rhs The right hand side to compare with.
214 : *
215 : * \sa operator == (FilePath const& rhs);
216 : */
217 6 : bool FilePath::operator == (char const *rhs) const
218 : {
219 6 : return m_path == rhs;
220 : }
221 :
222 :
223 : /** \brief Check whether two FilePath represent the same file.
224 : *
225 : * This function compares a FilePath object (this) and a C-string
226 : * to know whether the two are the same.
227 : *
228 : * A null pointer as the C-string is viewed as an empty string.
229 : *
230 : * \param[in] lhs The left hand side to compare with.
231 : * \param[in] rhs The right hand side to compare with.
232 : *
233 : * \sa operator == (FilePath const& rhs);
234 : */
235 6 : bool operator == (char const *lhs, FilePath const& rhs)
236 : {
237 6 : return lhs == rhs.m_path;
238 : }
239 :
240 :
241 : /** \brief Check whether two FilePath represent the same file.
242 : *
243 : * This function compares a FilePath object (this) against
244 : * a string representing a path to know whether the two are
245 : * the equal.
246 : *
247 : * \param[in] rhs The right hand side to compare with.
248 : *
249 : * \sa operator == (FilePath const& rhs);
250 : */
251 6 : bool FilePath::operator == (std::string const& rhs) const
252 : {
253 6 : return m_path == rhs;
254 : }
255 :
256 :
257 : /** \brief Check whether two FilePath represent the same file.
258 : *
259 : * This function compares a FilePath object (this) against
260 : * a string representing a path to know whether the two are
261 : * the equal.
262 : *
263 : * \param[in] lhs The left hand side to compare with.
264 : * \param[in] rhs The right hand side to compare with.
265 : *
266 : * \sa operator == (FilePath const& rhs);
267 : */
268 6 : bool operator == (std::string const& lhs, FilePath const& rhs)
269 : {
270 6 : return lhs == rhs.m_path;
271 : }
272 :
273 :
274 : /** \brief Check whether two FilePath represent the same file.
275 : *
276 : * This function compares two FilePath objects (this and rhs)
277 : * to know whether the two are the same.
278 : *
279 : * \note
280 : * It is important to know that the compare is rather primitive.
281 : * The two paths must be equal character by character instead
282 : * of actually representing exactly the same file. Also relative
283 : * paths will likely be equal and these may not represent the
284 : * same file at all.
285 : *
286 : * \param[in] rhs The right hand side to compare with.
287 : *
288 : * \sa operator == (char const *rhs);
289 : * \sa operator == (std::string const& rhs);
290 : */
291 82667 : bool FilePath::operator == (FilePath const& rhs) const
292 : {
293 82667 : return m_path == rhs.m_path;
294 : }
295 :
296 :
297 : /** \brief Retrieve the basename.
298 : *
299 : * This function returns the filename part of the FilePath
300 : * object by pruning the path off.
301 : *
302 : * \return Return the basename of this FilePath filename.
303 : */
304 3747615 : std::string FilePath::filename() const
305 : {
306 3747615 : std::string::size_type const pos(m_path.find_last_of(g_separator));
307 3747615 : if(pos != std::string::npos)
308 : {
309 3738843 : return m_path.substr(pos + 1);
310 : }
311 :
312 8772 : return m_path;
313 : }
314 :
315 :
316 : /** \brief Get the length of the string.
317 : *
318 : * This function returns the length of the string used to
319 : * represent this FilePath path and filename.
320 : *
321 : * \return The length of the string representing this file path.
322 : *
323 : * \sa size()
324 : */
325 726950 : size_t FilePath::length() const
326 : {
327 726950 : return m_path.length();
328 : }
329 :
330 :
331 : /** \brief Get the length of the string.
332 : *
333 : * This function returns the length of the string used to
334 : * represent this FilePath path and filename.
335 : *
336 : * \note
337 : * This is an overloaded function that calls the length() function.
338 : * It is defined because the string represents an array of bytes
339 : * and as such the size() function may be used.
340 : *
341 : * \return The length of the string representing this file path.
342 : *
343 : * \sa length()
344 : */
345 27 : size_t FilePath::size() const
346 : {
347 27 : return length();
348 : }
349 :
350 :
351 : /** \brief Check whether the file exists.
352 : *
353 : * This function calls check() and then returns true if the file
354 : * exists on disk.
355 : *
356 : * \return true If the path is a valid file system entity.
357 : */
358 27 : bool FilePath::exists() const
359 : {
360 27 : check();
361 27 : return m_exists;
362 : }
363 :
364 :
365 : /** \brief Check whether the file is a regular file.
366 : *
367 : * This function returns true if the file exists and is a
368 : * regular file.
369 : *
370 : * \return true if the path is a regular file.
371 : */
372 141084 : bool FilePath::isRegular() const
373 : {
374 141084 : check();
375 141084 : return m_exists && S_ISREG(m_stat.st_mode);
376 : }
377 :
378 :
379 : /** \brief Check whether the file is a directory.
380 : *
381 : * This function returns true if the file exists and is a
382 : * directory.
383 : *
384 : * \return true if the path is a directory.
385 : */
386 799359 : bool FilePath::isDirectory() const
387 : {
388 799359 : check();
389 799359 : return m_exists && S_ISDIR(m_stat.st_mode);
390 : }
391 :
392 :
393 : /** \brief Check whether the file is a character special file.
394 : *
395 : * This function returns true if the file exists and is a
396 : * character special file.
397 : *
398 : * \return true if the path is character special (a character device file).
399 : */
400 27 : bool FilePath::isCharSpecial() const
401 : {
402 27 : check();
403 27 : return m_exists && S_ISCHR(m_stat.st_mode);
404 : }
405 :
406 :
407 : /** \brief Check whether the file is a block special file.
408 : *
409 : * This function returns true if the file exists and is a
410 : * block special file.
411 : *
412 : * \return true if the path is block special (a block device file).
413 : */
414 27 : bool FilePath::isBlockSpecial() const
415 : {
416 27 : check();
417 27 : return m_exists && S_ISBLK(m_stat.st_mode);
418 : }
419 :
420 :
421 : /** \brief Check whether the file is a socket.
422 : *
423 : * This function returns true if the file exists and is a
424 : * socket file.
425 : *
426 : * \return true if the path is a socket.
427 : */
428 27 : bool FilePath::isSocket() const
429 : {
430 27 : check();
431 27 : return m_exists && S_ISSOCK(m_stat.st_mode);
432 : }
433 :
434 :
435 : /** \brief Check whether the file is a pipe.
436 : *
437 : * This function returns true if the file exists and is a
438 : * pipe file.
439 : *
440 : * \return true if the path is a FIFO.
441 : */
442 27 : bool FilePath::isFifo() const
443 : {
444 27 : check();
445 27 : return m_exists && S_ISFIFO(m_stat.st_mode);
446 : }
447 :
448 :
449 : /** \brief Get the size of the file.
450 : *
451 : * This function returns the size of the file. The size may be a 64 bit
452 : * size on 64 bit systems.
453 : *
454 : * \note
455 : * If the file represents a directory, the size will be zero.
456 : *
457 : * \note
458 : * If the file is not considered valid, the size returned is zero.
459 : *
460 : * \warning
461 : * There is also a function called size() which actually checks the
462 : * length of the path and not the size of the file.
463 : *
464 : * \return The last modification as a Unix time.
465 : *
466 : * \sa size()
467 : */
468 139675 : size_t FilePath::fileSize() const
469 : {
470 139675 : check();
471 139675 : return m_stat.st_size;
472 : }
473 :
474 :
475 : /** \brief Get the last modification time of the file.
476 : *
477 : * This function returns the last modification time of the specified
478 : * file.
479 : *
480 : * \note
481 : * If the file is not considered valid, the time returned is zero.
482 : *
483 : * \return The last modification as a Unix time.
484 : */
485 140704 : std::time_t FilePath::lastModificationTime() const
486 : {
487 140704 : check();
488 140704 : return m_stat.st_mtime;
489 : }
490 :
491 :
492 : /** \brief Print out a FilePath.
493 : *
494 : * This function prints out the name of the file that this FilePath
495 : * represents.
496 : *
497 : * \param[in,out] os The output stream.
498 : * \param[in] path The path to print out.
499 : *
500 : * \return A copy of the \p os stream reference.
501 : */
502 760 : std::ostream& operator << (std::ostream& os, FilePath const& path)
503 : {
504 760 : os << static_cast<std::string>(path);
505 760 : return os;
506 : }
507 :
508 3 : } // namespace
509 :
510 : // Local Variables:
511 : // mode: cpp
512 : // indent-tabs-mode: nil
513 : // c-basic-offset: 4
514 : // tab-width: 4
515 : // End:
516 :
517 : // vim: ts=4 sw=4 et
|