1 /*
2 * Copyright 2006-2008 The FLWOR Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #pragma once
17 #ifndef ZORBA_FS_UTIL_H
18 #define ZORBA_FS_UTIL_H
19
20 #include <zorba/config.h>
21
22 #include <iostream>
23 #include <stdexcept>
24 #ifdef WIN32
25 # include <windows.h>
26 #else
27 # include <dirent.h>
28 # include <sys/types.h> /* for off_t */
29 #endif /* WIN32 */
30
31 #include "ascii_util.h"
32 #include "cxx_util.h"
33 #include "error_util.h"
34 #include "string_util.h"
35 #include "zorbatypes/zstring.h"
36
37 #ifndef MAX_PATH
38 /**
39 * Maximum path length. This is defined under Windows to be 1024. There is no
40 * equivalent constant/macro for *nix systems, so simply borrow Windows' value.
41 */
42 #define MAX_PATH 1024
43 #endif /* MAX_PATH */
44
45 namespace zorba {
46 namespace fs {
47
48 ////////// constants //////////////////////////////////////////////////////////
49
50 #ifdef WIN32
51 char const dir_separator = '\\';
52 char const path_separator = ';';
53 #else
54 char const dir_separator = '/';
55 char const path_separator = ':';
56 #endif /* WIN32 */
57
58 ////////// types //////////////////////////////////////////////////////////////
59
60 /**
61 * File size type.
62 */
63 #ifdef WIN32
64 typedef __int64 size_type;
65 #else
66 typedef off_t size_type;
67 #endif /* WIN32 */
68
69 /**
70 * File type.
71 */
72 enum type {
73 non_existent,
74 directory,
75 file,
76 link,
77 volume,
78 other // named pipe, character/block special, socket, etc.
79 };
80 extern char const *const type_string[];
81
82 /**
83 * Emits the string representation of a file type to the given ostream.
84 *
85 * @param o The ostream to emit to.
86 * @param t The file type to emit.
87 * @return Returns \a o.
88 */
89 inline std::ostream& operator<<( std::ostream &o, type t ) {
90 return o << type_string[ t ];
91 }
92
93 ////////// Windows ////////////////////////////////////////////////////////////
94
95 #ifdef WIN32
96 namespace win32 {
97
98 // Do not use this function directly.
99 void make_absolute_impl( char const *path, char *abs_path );
100
101 } // namespace win32
102 #endif /* WIN32 */
103
104 ////////// Exceptions /////////////////////////////////////////////////////////
105
106 typedef os_error::exception exception;
107
108 ////////// Directory //////////////////////////////////////////////////////////
109
110 #ifdef ZORBA_WITH_FILE_ACCESS
111
112 /**
113 * Changes the current working directory.
114 *
115 * @param path The full path of the directory to change to.
116 */
117 void chdir( char const *path );
118
119 /**
120 * Changes the current working directory.
121 *
122 * @tparam PathStringType The \a path string type.
123 * @param path The full path of the directory to change to.
124 */
125 template<class PathStringType> inline
126 typename std::enable_if<ztd::has_c_str<PathStringType,
127 char const* (PathStringType::*)() const>::value,
128 void>::type
chdir(PathStringType const & path)129 chdir( PathStringType const &path ) {
130 chdir( path.c_str() );
131 }
132
133 #endif /* ZORBA_WITH_FILE_ACCESS */
134
135 /**
136 * Gets the current directory.
137 *
138 * @return Returns said directory.
139 * @throws fs::exception if it fails.
140 */
141 zstring curdir();
142
143 #ifdef ZORBA_WITH_FILE_ACCESS
144
145 /**
146 * Creates a directory.
147 *
148 * @param path The full path of the directory to create.
149 * @throws fs::exception if the creation fails.
150 */
151 void mkdir( char const *path );
152
153 /**
154 * Creates a directory.
155 *
156 * @tparam PathStringType The \a path string type.
157 * @param path The full path of the directory to create.
158 * @throws fs::exception if the creation fails.
159 */
160 template<class PathStringType> inline
161 typename std::enable_if<ztd::has_c_str<PathStringType,
162 char const* (PathStringType::*)() const>::value,
163 void>::type
mkdir(PathStringType const & path)164 mkdir( PathStringType const &path ) {
165 mkdir( path.c_str() );
166 }
167
168 ////////// Directory iteration ////////////////////////////////////////////////
169
170 /**
171 * An fs::iterator iterates over the entries in a directory.
172 */
173 class iterator {
174 public:
175 /**
176 * Constructs an %itertor.
177 *
178 * @throws fs::exception if the construction failed, e.g., path not found.
179 */
180 iterator( char const *path );
181
182 /**
183 * Destroys this %iterator.
184 */
185 ~iterator();
186
187 /**
188 * Attempts to get the next directory entry.
189 *
190 * @return Returns \c true only if there is a next directory.
191 */
192 bool next();
193
194 /**
195 * Gets the name of the curent directory entry.
196 *
197 * @return Returns said name.
198 */
entry_name()199 char const* entry_name() const {
200 # ifndef WIN32
201 return ent_->d_name;
202 # else
203 return ent_name_;
204 # endif /* WIN32 */
205 }
206
207 /**
208 * Gets the type of the current directory entry.
209 *
210 * @return Returns said type.
211 */
entry_type()212 type entry_type() const {
213 return ent_type_;
214 }
215
216 /**
217 * Gets the directory's path.
218 *
219 * @return Returns said path.
220 */
path()221 char const* path() const {
222 return dir_path_.c_str();
223 }
224
225 /**
226 * Resets this iterator to the beginning.
227 */
228 void reset();
229
230 private:
231 zstring dir_path_;
232 type ent_type_;
233 #ifndef WIN32
234 DIR *dir_;
235 struct dirent *ent_;
236 #else
237 HANDLE dir_;
238 bool dir_is_empty_;
239 WIN32_FIND_DATA ent_data_;
240 char ent_name_[ MAX_PATH ];
241 bool use_first_;
242
243 void win32_opendir( char const *path );
244 void win32_closedir();
245 #endif /* WIN32 */
246
247 // forbid
248 iterator( iterator const& );
249 iterator& operator=( iterator const& );
250 };
251
252 #endif /* ZORBA_WITH_FILE_ACCESS */
253
254 ////////// File creation //////////////////////////////////////////////////////
255
256 #ifdef ZORBA_WITH_FILE_ACCESS
257
258 /**
259 * Creates the given file.
260 *
261 * @param path The full path of the file to create.
262 * @throws fs::exception if the creation failed.
263 */
264 void create( char const *path );
265
266 /**
267 * Creates the given file.
268 *
269 * @tparam PathStringType The \a path string type.
270 * @param path The full path of the file to create.
271 * @throws fs::exception if the creation failed.
272 */
273 template<class PathStringType> inline
274 typename std::enable_if<ztd::has_c_str<PathStringType,
275 char const* (PathStringType::*)() const>::value,
276 void>::type
create(PathStringType const & path)277 create( PathStringType const &path ) {
278 create( path.c_str() );
279 }
280
281 #endif /* ZORBA_WITH_FILE_ACCESS */
282
283 ////////// File deletion //////////////////////////////////////////////////////
284
285 #ifdef ZORBA_WITH_FILE_ACCESS
286
287 /**
288 * Removes the given file or directory.
289 *
290 * @param path The full path of the file or directory to remove.
291 * @return Returns \c true only if the file or directory was removed.
292 */
293 bool remove( char const *path );
294
295 /**
296 * Removes the given file or directory.
297 *
298 * @tparam PathStringType The \a path string type.
299 * @param path The full path of the file or directory to remove.
300 * @return Returns \c true only if the file or directory was removed.
301 */
302 template<class PathStringType> inline
303 typename std::enable_if<ztd::has_c_str<PathStringType,
304 char const* (PathStringType::*)() const>::value,
305 bool>::type
remove(PathStringType const & path)306 remove( PathStringType const &path ) {
307 return remove( path.c_str() );
308 }
309
310 /**
311 * An %auto_remover is a simple class to guarantee that a file or directory
312 * referred to by a path is deleted upon the %auto_remover getting destroyed.
313 *
314 * @tparam PathStringType The type of string to store and return the path as.
315 */
316 template<class PathStringType>
317 class auto_remover {
318 public:
319 typedef PathStringType string_type;
320
321 /**
322 * Constructs an %auto_remover.
323 *
324 * @param The full path of the file or directory to delete automatically, if
325 * any.
326 */
path_(path)327 explicit auto_remover( char const *path = "" ) : path_( path ) {
328 }
329
330 /**
331 * Constructs an %auto_remover.
332 *
333 * @tparam PathStringType The path's string type.
334 * @param The full path of the file or directory to delete automatically, if
335 * any.
336 */
auto_remover(PathStringType const & path)337 explicit auto_remover( PathStringType const &path ) : path_( path ) {
338 }
339
340 /**
341 * Copy-constructs an %auto_remover from another. This is a destructive
342 * construction: the other %auto_remover's path will be reset to the empty
343 * string.
344 *
345 * @param a The %auto_remover to copy from.
346 */
auto_remover(auto_remover & a)347 auto_remover( auto_remover &a ) : path_( a.release() ) {
348 }
349
350 /**
351 * Copy-constructs an %auto_remover from another. This is a destructive
352 * construction: the other %auto_remover's path will be reset to the empty
353 * string.
354 *
355 * @tparam PathStringType2 The other %auto_remover's path string type.
356 * @param a The %auto_remover to copy from.
357 */
358 template<class PathStringType2>
auto_remover(auto_remover<PathStringType2> & a)359 auto_remover( auto_remover<PathStringType2> &a ) : path_( a.release() ) {
360 }
361
362 /**
363 * Destroys this %auto_remover. If its path is not empty, the referred to
364 * file or directory is deleted.
365 */
~auto_remover()366 ~auto_remover() {
367 delete_path();
368 }
369
370 /**
371 * Assigns the path of another %auto_remover to this %auto_remover. This is
372 * a destructive assignment: the other %auto_remover's path will be reset to
373 * the empty string.
374 *
375 * @param a The %auto_remover to assign from.
376 * @return Returns \c *this.
377 */
378 auto_remover& operator=( auto_remover &a ) {
379 reset( a.release() );
380 return *this;
381 }
382
383 /**
384 * Assigns the path of another %auto_remover to this %auto_remover. This is
385 * a destructive assignment: the other %auto_remover's path will be reset to
386 * the empty string.
387 *
388 * @tparam PathStringType2 The other %auto_remover's path string type.
389 * @param a The %auto_remover to assign from.
390 * @return Returns \c *this.
391 */
392 template<class PathStringType2>
393 auto_remover& operator=( auto_remover<PathStringType2> &a ) {
394 reset( a.release() );
395 return *this;
396 }
397
398 /**
399 * Gets the path of the file or directory this %auto_remover will delete upon
400 * destruction.
401 *
402 * @return Returns said path.
403 */
path()404 PathStringType const& path() const {
405 return path_;
406 }
407
408 /**
409 * Releases the current file or directory from being deleted automatically.
410 */
release()411 PathStringType release() {
412 PathStringType const temp( path_ );
413 path_.clear();
414 return temp;
415 }
416
417 /**
418 * Resets this %auto_remover to delete a different file or directory upon
419 * destruction. The previous file or directory is deleted immediately.
420 * (If you don't want it to be deleted, call release() first.)
421 *
422 * @param The full path of the file or directory to delete automatically.
423 */
reset(char const * path)424 void reset( char const *path ) {
425 if ( path != path_ ) {
426 delete_path();
427 path_ = path;
428 }
429 }
430
431 /**
432 * Resets this %auto_remover to delete a different file or directory upon
433 * destruction. The previous file or directory is deleted immediately.
434 * (If you don't want it to be deleted, call release() first.)
435 *
436 * @param The full path of the file or directory to delete automatically.
437 */
reset(PathStringType const & path)438 void reset( PathStringType const &path ) {
439 reset( path.c_str() );
440 }
441
442 /**
443 * Resets this %auto_remover to delete a different file or directory upon
444 * destruction. The previous file or directory is deleted immediately.
445 * (If you don't want it to be deleted, call release() first.)
446 *
447 * @tparam PathStringType2 The path's string type.
448 * @param The full path of the file or directory to delete automatically.
449 */
450 template<class PathStringType2>
reset(PathStringType2 const & path)451 void reset( PathStringType2 const &path ) {
452 reset( path.c_str() );
453 }
454
455 private:
delete_path()456 void delete_path() {
457 if ( !path_.empty() )
458 remove( path_ );
459 }
460
461 PathStringType path_;
462 };
463
464 #endif /* ZORBA_WITH_FILE_ACCESS */
465
466 ////////// File information ///////////////////////////////////////////////////
467
468 #ifdef ZORBA_WITH_FILE_ACCESS
469
470 /**
471 * Gets the type of the given file.
472 *
473 * @param path The full path to check.
474 * @param size A pointer to a receive the size of the file in bytes. The size
475 * is set only if it's not \c nullptr and the file's type is \c file.
476 * @return Returns said type.
477 */
478 type get_type( char const *path, size_type *size = nullptr );
479
480 /**
481 * Gets the type of the given file.
482 *
483 * @tparam PathStringType The \a path string type.
484 * @param path The full path to check.
485 * @param size A pointer to a receive the size of the file in bytes. The size
486 * is set only if it's not \c nullptr and the file's type is \c file.
487 * @return Returns said type.
488 */
489 template<class PathStringType> inline
490 typename std::enable_if<ztd::has_c_str<PathStringType,
491 char const* (PathStringType::*)() const>::value,
492 type>::type
493 get_type( PathStringType const &path, size_type *size = nullptr ) {
494 return get_type( path.c_str(), size );
495 }
496
497 #endif /* ZORBA_WITH_FILE_ACCESS */
498
499 /**
500 * Checks whether the given path is an absolute path.
501 *
502 * @param path The full path to check.
503 * @return Returns \c true only if the path is absolute.
504 */
is_absolute(char const * path)505 inline bool is_absolute( char const *path ) {
506 #ifndef WIN32
507 return path[0] == '/';
508 #else
509 //
510 // No, this should NOT also check for '/'. The path should have been
511 // normalized for Windows first, i.e., have '/' replaced by '\'.
512 //
513 return ascii::is_alpha( path[0] ) && path[1] == ':' && path[2] == '\\';
514 #endif /* WIN32 */
515 }
516
517 /**
518 * Checks whether the given path is an absolute path.
519 *
520 * @tparam PathStringType The \a path string type.
521 * @param path The full path to check.
522 * @return Returns \c true only if the path is absolute.
523 */
524 template<class PathStringType> inline
525 typename std::enable_if<ztd::has_c_str<PathStringType,
526 char const* (PathStringType::*)() const>::value,
527 bool>::type
is_absolute(PathStringType const & path)528 is_absolute( PathStringType const &path ) {
529 return is_absolute( path.c_str() );
530 }
531
532 ////////// File renaming //////////////////////////////////////////////////////
533
534 #ifdef ZORBA_WITH_FILE_ACCESS
535
536 /**
537 * Renames a file or directory.
538 *
539 * @param from The full path of the existing file or directory to rename.
540 * @param to The full path of the new name for the file or directory.
541 * @throws fs::exception if the rename fails.
542 */
543 void rename( char const *from, char const *to );
544
545 /**
546 * Renames a file or directory.
547 *
548 * @tparam FromStringType The \a from string type.
549 * @param from The full path of the existing file or directory to rename.
550 * @param to The full path of the new name for the file or directory.
551 * @throws fs::exception if the rename fails.
552 */
553 template<class FromStringType> inline
554 typename std::enable_if<ztd::has_c_str<FromStringType,
555 char const* (FromStringType::*)() const>::value,
556 void>::type
rename(FromStringType const & from,char const * to)557 rename( FromStringType const &from, char const *to ) {
558 rename( from.c_str(), to );
559 }
560
561 /**
562 * Renames a file or directory.
563 *
564 * @tparam ToStringType The \a to string type.
565 * @param from The full path of the existing file or directory to rename.
566 * @param to The full path of the new name for the file or directory.
567 * @throws fs::exception if the rename fails.
568 */
569 template<class ToStringType> inline
570 typename std::enable_if<ztd::has_c_str<ToStringType,
571 char const* (ToStringType::*)() const>::value,
572 void>::type
rename(char const * from,ToStringType const & to)573 rename( char const *from, ToStringType const &to ) {
574 rename( from, to.c_str() );
575 }
576
577 /**
578 * Renames a file or directory.
579 *
580 * @tparam FromStringType The \a from string type.
581 * @tparam ToStringType The \a to string type.
582 * @param from The full path of the existing file or directory to rename.
583 * @param to The full path of the new name for the file or directory.
584 * @throws fs::exception if the rename fails.
585 */
586 template<class FromStringType,class ToStringType> inline
587 typename std::enable_if<ztd::has_c_str<FromStringType,
588 char const* (FromStringType::*)() const>::value
589 && ztd::has_c_str<ToStringType,
590 char const* (ToStringType::*)() const>::value,
591 void>::type
rename(FromStringType const & from,ToStringType const & to)592 rename( FromStringType const &from, ToStringType const &to ) {
593 rename( from.c_str(), to.c_str() );
594 }
595
596 #endif /* ZORBA_WITH_FILE_ACCESS */
597
598 ////////// Path normalization /////////////////////////////////////////////////
599
600 /**
601 * Gets the normalized path of the given path.
602 *
603 * @param path The path to normalize.
604 * @param base The base path, if any.
605 * @return Returns the normalized path.
606 * @throws XQueryException err::XPTY0004 for malformed paths.
607 */
608 zstring get_normalized_path( char const *path, char const *base = nullptr );
609
610 /**
611 * Gets the normalized path of the given path.
612 *
613 * @tparam PathStringType The \a path string type.
614 * @param path The path to normalize.
615 * @param base The base path, if any.
616 * @return Returns the normalized path.
617 * @throws XQueryException err::XPTY0004 for malformed paths.
618 */
619 template<class PathStringType> inline
620 typename std::enable_if<ztd::has_c_str<PathStringType,
621 char const* (PathStringType::*)() const>::value,
622 zstring>::type
623 get_normalized_path( PathStringType const &path,
624 PathStringType const &base = "" ) {
625 return get_normalized_path( path.c_str(), base.c_str() );
626 }
627
628 /**
629 * Normalizes the given path.
630 *
631 * @tparam PathStringType The path string type.
632 * @param path The path to normalize.
633 * @param base The base path, if any.
634 * @return Returns the normalized path.
635 * @throws XQueryException err::XPTY0004 for malformed paths.
636 */
637 template<class PathStringType> inline
638 typename std::enable_if<ztd::has_c_str<PathStringType,
639 char const* (PathStringType::*)() const>::value,
640 void>::type
641 normalize_path( PathStringType &path, PathStringType const &base = "" ) {
642 path = get_normalized_path( path, base );
643 }
644
645 ////////// Path manipulation //////////////////////////////////////////////////
646
647 /**
648 * Appends a path component onto another path ensuring that exactly one
649 * separator is used.
650 *
651 * @tparam PathStringType1 The \a path1 string type.
652 * @param path1 The path to append to.
653 * @param path2 The path to append.
654 */
655 template<class PathStringType1> inline
656 typename std::enable_if<ztd::has_c_str<PathStringType1,
657 char const* (PathStringType1::*)() const>::value,
658 void>::type
append(PathStringType1 & path1,char const * path2)659 append( PathStringType1 &path1, char const *path2 ) {
660 if ( !ascii::ends_with( path1, dir_separator ) )
661 path1 += dir_separator;
662 path1 += path2;
663 }
664
665 /**
666 * Appends a path component onto another path.
667 *
668 * @tparam PathStringType1 The \a path1 string type.
669 * @tparam PathStringType2 The \a path2 string type.
670 * @param path1 The path to append to.
671 * @param path2 The path to append.
672 */
673 template<class PathStringType1,class PathStringType2> inline
674 typename std::enable_if<ztd::has_c_str<PathStringType1,
675 char const* (PathStringType1::*)() const>::value
676 && ztd::has_c_str<PathStringType2,
677 char const* (PathStringType2::*)() const>::value,
678 void>::type
append(PathStringType1 & path1,PathStringType2 const & path2)679 append( PathStringType1 &path1, PathStringType2 const &path2 ) {
680 append( path1, path2.c_str() );
681 }
682
683 /**
684 * Makes a relative path into an absolute path.
685 *
686 * @tparam PathStringType The \a path string type.
687 * @param path The path to make absolute.
688 */
689 template<class PathStringType> inline
690 typename std::enable_if<ztd::has_c_str<PathStringType,
691 char const* (PathStringType::*)() const>::value,
692 void>::type
make_absolute(PathStringType & path)693 make_absolute( PathStringType &path ) {
694 if ( !is_absolute( path ) ) {
695 #ifndef WIN32
696 typedef typename PathStringType::size_type size_type;
697 path.insert( static_cast<size_type>(0), static_cast<size_type>(1), '/' );
698 path.insert( 0, curdir().c_str() );
699 #else
700 char temp[ MAX_PATH ];
701 win32::make_absolute_impl( path.c_str(), temp );
702 path = temp;
703 #endif /* WIN32 */
704 }
705 }
706
707 ////////// Temporary files ////////////////////////////////////////////////////
708
709 #ifdef ZORBA_WITH_FILE_ACCESS
710
711 /**
712 * Gets a path for a temporary file.
713 *
714 * @param path_buf A buffer to receive the path. It must be at least
715 * \c MAX_PATH bytes long.
716 * @throws fs::exception if the operation fails.
717 */
718 void get_temp_file( char *path_buf );
719
720 /**
721 * Gets a path for a temporary file.
722 *
723 * @tparam PathStringType The \a path string type.
724 * @param path The string to receive the path.
725 * @throws fs::exception if the operation fails.
726 */
727 template<class PathStringType> inline
728 typename std::enable_if<ztd::has_c_str<PathStringType,
729 char const* (PathStringType::*)() const>::value,
730 void>::type
get_temp_file(PathStringType * path)731 get_temp_file( PathStringType *path ) {
732 char path_buf[ MAX_PATH ];
733 get_temp_file( path_buf );
734 *path = path_buf;
735 }
736
737 #endif /* ZORBA_WITH_FILE_ACCESS */
738
739 ///////////////////////////////////////////////////////////////////////////////
740
741 } // namespace fs
742 } // namespace zorba
743
744 #endif /* ZORBA_FS_UTIL_H */
745 /*
746 * Local variables:
747 * mode: c++
748 * End:
749 */
750 /* vim:set et sw=2 ts=2: */
751