Add ugly cast for our siginfo_t forward declaration.
[libi2ncommon] / src / filefunc.cpp
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
e93545dd
GE
20/***************************************************************************
21 escape.cpp - escaping of strings
22 -------------------
23 begin : Sun Nov 14 1999
24 copyright : (C) 1999 by Intra2net AG
e93545dd
GE
25 ***************************************************************************/
26
6a93d84a 27#include <list>
e93545dd 28#include <string>
6a93d84a 29#include <fstream>
0a654ec0 30#include <sstream>
e93545dd 31#include <iostream>
0a654ec0 32#include <stdexcept>
e93545dd
GE
33
34#include <sys/types.h>
35#include <sys/stat.h>
0a654ec0 36#include <dirent.h>
e93545dd
GE
37#include <pwd.h>
38#include <grp.h>
39#include <unistd.h>
0a654ec0 40#include <errno.h>
5efd35b1 41#include <string.h>
e93545dd 42
6a93d84a
TJ
43#include <boost/scoped_array.hpp>
44#include "filefunc.hxx"
45#include "stringfunc.hxx"
46
a287a306 47namespace I2n
6a93d84a 48{
e93545dd
GE
49
50using namespace std;
51
6a93d84a
TJ
52/*
53** implementation of Stat
54*/
55
56Stat::Stat()
a287a306 57: Valid(false)
0107a75b 58{
a287a306 59 clear();
6a93d84a
TJ
60} // eo Stat::Stat()
61
62
63Stat::Stat(const std::string& path, bool follow_links)
64{
65 stat(path,follow_links);
66} // eo Stat::Stat(const std::string&,bool)
67
68
69Stat::~Stat()
70{
71} // eo Stat::~Stat()
72
73
74/**
75 * @brief updates the internal data.
76 *
77 * In other words: stat()'s the file again.
78 */
79void Stat::recheck()
80{
a287a306 81 if (! Path.empty())
6a93d84a 82 {
96fe2dc5
GE
83 // pass a copy of Path: otherwise clear() would leave an empty reference
84 stat(string(Path), FollowLinks);
6a93d84a
TJ
85 }
86} // eo Stat::recheck()
87
88
89/**
90 * @brief calls stat() or lstat() to get the information for the given path
91 * and stores that information.
92 * @param path the path which should be checked
93 * @param follow_links determine if (symbalic) links should be followed.
94 */
95void Stat::stat(const std::string& path, bool follow_links)
96{
97 clear();
a287a306
TJ
98 Path= path;
99 FollowLinks= follow_links;
6a93d84a
TJ
100 struct stat stat_info;
101 int res;
102 res = ( follow_links ? ::stat(path.c_str(), &stat_info) : ::lstat(path.c_str(), &stat_info) );
103 if ( 0 == res )
104 {
a287a306
TJ
105 Device = stat_info.st_dev;
106 Inode = stat_info.st_ino;
107 Mode = (stat_info.st_mode & ~(S_IFMT));
108 NumLinks = stat_info.st_nlink;
109 Uid = stat_info.st_uid;
110 Gid = stat_info.st_gid;
111 DeviceType = stat_info.st_rdev;
112 Size = stat_info.st_size;
113 Atime = stat_info.st_atime;
114 Mtime = stat_info.st_mtime;
115 Ctime = stat_info.st_atime;
116
117 IsLink= S_ISLNK( stat_info.st_mode );
118 IsRegular= S_ISREG( stat_info.st_mode );
119 IsDirectory= S_ISDIR( stat_info.st_mode );
120 IsCharacterDevice= S_ISCHR( stat_info.st_mode );
6ab3bc95 121 IsBlockDevice= S_ISBLK( stat_info.st_mode );
a287a306
TJ
122 IsFifo= S_ISFIFO( stat_info.st_mode );
123 IsSocket= S_ISSOCK( stat_info.st_mode );
6a93d84a 124 }
a287a306 125 Valid = (0 == res);
6a93d84a 126} // eo Stat::stat(const std::string&,bool)
0a654ec0 127
0107a75b 128
6a93d84a
TJ
129/**
130 * @brief clears the internal data.
131 */
132void Stat::clear()
133{
a287a306
TJ
134 Path.clear();
135 Valid= false;
136
137 Device = 0;
138 Inode = 0;
139 Mode = 0;
140 NumLinks = 0;
141 Uid = 0;
142 Gid = 0;
143 DeviceType = 0;
144 Size = 0;
145 Atime = 0;
146 Mtime = 0;
147 Ctime = 0;
148
149 IsLink= false;
150 IsRegular= false;
151 IsDirectory= false;
152 IsCharacterDevice= false;
153 IsBlockDevice= false;
154 IsFifo= false;
155 IsSocket= false;
6a93d84a
TJ
156} // eo Stat::clear()
157
158
159/**
160 * @brief checks if another instance describes the same file.
161 * @param rhs the other instance.
162 * @return @a true iff the other instance describes the same file.
163 * @note
164 * The "same file" means that the files are located on the same device and use the same inode.
165 * They might still have two different directory entries (different paths)!
166 */
a287a306 167bool Stat::is_same_as(const Stat& rhs)
6a93d84a 168{
a287a306
TJ
169 return Valid and rhs.Valid
170 and ( Device == rhs.Device)
171 and ( Inode == rhs.Inode);
172} // eo Stat::is_same_as(const Stat& rhs);
6a93d84a
TJ
173
174
175/**
176 * @brief checks if this and the other instance describe the same device.
177 * @param rhs the other instance.
178 * @return @a true if we and the other instance describe a device and the same device.
179 *
180 * "Same device" means that the devices have the same type and the same major and minor id.
181 */
a287a306 182bool Stat::is_same_device_as(const Stat& rhs)
6a93d84a 183{
a287a306
TJ
184 return is_device() and rhs.is_device()
185 and ( IsBlockDevice == rhs.IsBlockDevice )
186 and ( IsCharacterDevice == rhs.IsCharacterDevice )
187 and ( DeviceType == rhs.DeviceType);
188} // eo Stat::is_same_device_as(const Stat&)
6a93d84a
TJ
189
190/**
191 * @brief check existence of a path.
192 * @param path path which should be tested.
193 * @return @a true iff path exists.
194 */
195bool path_exists(const std::string& path)
196{
197 struct stat stat_info;
198 int res = ::stat(path.c_str(), &stat_info);
199 if (res) return false;
200 return true;
201} // eo path_exists(const std::string&)
202
203/**
204 * @brief check existence of a regular file.
205 * @param path path which should be tested.
206 * @return @a true if path exists and is a regular file (or a link pointing to a regular file).
207 * @note this checks for regular files; not for the pure exitsnace of a path; use pathExists() for that.
208 * @see pathExists
209 */
210bool file_exists(const std::string& path)
211{
212 struct stat stat_info;
213 int res = ::stat(path.c_str(), &stat_info);
214 if (res) return false;
215 return S_ISREG(stat_info.st_mode);
216} // eo file_exists(const std::string&)
217
218// TODO: Use Stat class
219/**
220 * Get size of file
221 * @param name filename to get size for
222 * @return file size or -1 if file does not exist
223 */
224long file_size (const string &name)
e93545dd
GE
225{
226 long iReturn = -1;
0a654ec0 227
e93545dd 228 struct stat statbuff;
0a654ec0 229
e93545dd
GE
230 if (lstat(name.c_str(), &statbuff) < 0)
231 return -1;
232
233 if (!S_ISREG(statbuff.st_mode))
234 return -1;
0a654ec0 235
e93545dd
GE
236 iReturn=statbuff.st_size;
237
238 return iReturn;
239}
240
6a93d84a
TJ
241/**
242 * @brief tests the last modification time stamp of a path.
243 * @param path path which should be tested.
244 * @return the last modification time or 0 if the path doen't exist.
245 */
a287a306 246time_t file_mtime(const std::string& path)
e93545dd 247{
6a93d84a
TJ
248 struct stat stat_info;
249 int res = ::stat(path.c_str(), &stat_info);
250 if (res) return 0;
251 return stat_info.st_mtime;
6ab3bc95 252} // eo file_mtime(const std::string&)
e93545dd 253
e93545dd 254
6a93d84a
TJ
255/**
256 * @brief reads the contents of a directory.
257 * @param path the path to the directory whose contents should be read.
258 * @param[out] result the resulting list of names.
259 * @param include_dot_names determines if dot-files should be included in the list.
260 * @return @a true if reading the directory was succesful, @a false on error.
261 */
a287a306 262bool get_dir(
6a93d84a
TJ
263 const std::string& path,
264 std::vector< std::string >& result,
265 bool include_dot_names )
266{
267 DIR* dir = ::opendir( path.c_str());
268 if (!dir)
269 {
270 return false;
271 }
10c3af2d
TJ
272 struct dirent store, *entry = NULL;
273 while (readdir_r(dir, &store, &entry) == 0 && entry != NULL)
e93545dd 274 {
6a93d84a
TJ
275 std::string name( entry->d_name );
276 if (! include_dot_names && (name[0] == '.') )
277 {
278 continue;
279 }
280 result.push_back( name );
e93545dd 281 }
6a93d84a
TJ
282 ::closedir(dir);
283 return true;
6ab3bc95 284} // eo get_dir(const std::string&,std::vector< std::string >&,bool)
6a93d84a
TJ
285
286
287/**
288 * @brief reads the contents of a directory
289 * @param path the path to the directory whose contents should be read.
290 * @param include_dot_names determines if dot-files should be included in the list.
291 * @return the list of names (empty on error).
292 */
a287a306 293std::vector< std::string > get_dir(const std::string& path, bool include_dot_names )
6a93d84a
TJ
294{
295 std::vector< std::string > result;
a287a306 296 get_dir(path,result,include_dot_names);
6a93d84a 297 return result;
6ab3bc95 298} // eo get_dir(const std::string&,bool)
e93545dd 299
e93545dd 300
e93545dd 301
6a93d84a
TJ
302/**
303 * @brief removes a file from a filesystem.
304 * @param path path to the file.
44725532 305 * @return @a true if the unlink was successful.
6a93d84a
TJ
306 */
307bool unlink( const std::string& path )
e93545dd 308{
6a93d84a
TJ
309 int res = ::unlink( path.c_str() );
310 return (res == 0);
311} // eo unlink(const std::string&)
312
e93545dd 313
e93545dd 314
6a93d84a
TJ
315/**
316 * @brief creates a symbolic link named @a link_name to @a target.
317 * @param target the target the link should point to.
318 * @param link_name the name of the link.
319 * @param force if @a true, the (file or link) @a link_name is removed if it exists.
320 * @return @a true iff the symlink was successfully created.
321 */
322bool symlink(const std::string& target, const std::string& link_name, bool force)
323{
324 int res= -1;
325 if (target.empty() or link_name.empty() or target == link_name)
326 {
327 // no, we don't do this!
e93545dd 328 return false;
6a93d84a
TJ
329 }
330 std::string n_target;
331 if (target[0] == '/') // absolute target?
332 {
333 n_target= target;
334 }
335 else // relative target
336 {
337 // for stat'ing: prepend dir of link_name:
338 n_target= dirname(link_name)+"/"+ target;
339 }
340 Stat target_stat(n_target, false);
341 Stat link_name_stat(link_name, false);
342 if (target_stat.exists() && link_name_stat.exists())
343 {
a287a306
TJ
344 if (link_name_stat.is_same_as(target_stat)
345 or link_name_stat.is_same_device_as(target_stat) )
6a93d84a
TJ
346 {
347 return false;
348 }
349 //TODO: more consistency checks?!
350 }
351 if (link_name_stat.exists())
352 {
353 // the link name already exists.
354 if (force)
355 {
356 // "force" as given, so try to remove the link_name:
357 unlink(link_name);
358 // update the stat:
359 link_name_stat.recheck();
360 }
361 }
362 if (link_name_stat.exists())
363 {
364 // well, if the link_name still exists; we cannot create that link:
365 errno = EEXIST;
366 return false;
367 }
368 res= ::symlink(target.c_str(), link_name.c_str());
369 return (0 == res);
370} // eo symlink(const std::string&,const std::string&,bool)
371
e93545dd 372
6a93d84a
TJ
373
374/**
375 * @brief reads the target of a symbolic link.
376 * @param path path to the symbolic link
377 * @return the target of the link or an empty string on error.
378 */
a287a306 379std::string read_link(const std::string& path)
6a93d84a
TJ
380{
381 errno= 0;
382 Stat stat(path,false);
a287a306 383 if (!stat || !stat.is_link())
6a93d84a
TJ
384 {
385 return std::string();
386 }
387 int buffer_size= PATH_MAX+1 + 128;
388 boost::scoped_array<char> buffer_ptr( new char[buffer_size] );
389 int res= ::readlink( path.c_str(), buffer_ptr.get(), buffer_size-1 );
390 if (res >= 0)
391 {
392 return std::string( buffer_ptr.get(), res );
393 }
394 return std::string();
6ab3bc95 395} // eo read_link(const std::string&)
6a93d84a
TJ
396
397
398
399/**
400 * @brief returns content of a file as string.
401 *
402 * A simple (q'n'd) function for retrieving content of a file as string.<br>
403 * Also able to read special (but regular) files which don't provide a size when stat'ed
404 * (like files in the /proc filesystem).
405 *
406 * @param path path to the file.
407 * @return the content of the file as string (empty if file could be opened).
408 */
a287a306 409std::string read_file(const std::string& path)
6a93d84a
TJ
410{
411 Stat stat(path);
a287a306 412 if (!stat.is_reg())
6a93d84a
TJ
413 {
414 return std::string();
415 }
416 std::ifstream f( path.c_str(), std::ios::in | std::ios::binary );
417 std::string result;
418 if (f.is_open())
419 {
420 // NOTE: there are cases where we don't know the correct size (/proc files...)
421 // therefore we only use the size for reserving space if we know it, but don't
422 // use it when reading the file!
423 if (stat.size() > 0)
424 {
425 // if we know the size, we reserve enough space.
426 result.reserve( stat.size() );
427 }
428 char buffer[2048];
429 while (f.good())
430 {
431 f.read(buffer, sizeof(buffer));
432 result.append(buffer, f.gcount());
433 }
434 }
435 return result;
6ab3bc95 436} // eo read_file(const std::string&)
6a93d84a
TJ
437
438
439/**
440 * @brief writes a string to a file.
441 * @param path path to the file
442 * @param data the data which should be written into the file
443 * @return @a true if the data was written to the file.
444 *
445 * A simple (q'n'd) function for writing a string to a file.
446 */
a287a306 447bool write_file(const std::string& path, const std::string& data)
6a93d84a
TJ
448{
449 std::ofstream f( path.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
450 if (f.good())
451 {
452 f.write( data.data(), data.size() );
453 return f.good();
454 }
e93545dd 455 else
6a93d84a 456 {
e93545dd 457 return false;
6a93d84a 458 }
6ab3bc95 459} // eo write_file(const std::string&,const std::string&)
6a93d84a
TJ
460
461
462/**
1a2fc4e8
TJ
463 * Copy file in 4k blocks from source to target.
464 * Overwrites the target if it already exists.
465 *
466 * On error the target file gets removed.
467 *
468 * @param src source file
469 * @param dest target file
470 * @return true if all is ok, false on error
471 */
472bool copy_file(const std::string& src, const std::string& dest)
473{
a1e7d2a7
GE
474 std::ifstream input( src.c_str(), std::ios::in | std::ios::binary );
475 if (!input)
476 return false;
477
478 std::ofstream output( dest.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
479 if (!output)
480 return false;
481
482 // Out of disc space?
483 if (!copy_stream(input,output))
484 {
485 output.close();
486 unlink(dest);
487 return false;
488 }
489
490 return true;
491}
492
493/**
494 * Copy streams in 4k blocks.
495 *
496 * @param is source stream
497 * @param os target stream
498 * @return true if all is ok, false on error
499 */
500bool copy_stream(std::istream& is, std::ostream& os)
501{
502 if (!is)
1a2fc4e8
TJ
503 return false;
504
a1e7d2a7 505 if (!os)
1a2fc4e8
TJ
506 return false;
507
508 char buffer[4096];
a1e7d2a7 509 while (is.good())
1a2fc4e8 510 {
a1e7d2a7
GE
511 is.read(buffer, sizeof(buffer));
512 os.write(buffer, is.gcount());
513
514 // Can't write?
515 if (!os.good())
1a2fc4e8 516 return false;
1a2fc4e8
TJ
517 }
518
519 return true;
520}
521
522/**
6a93d84a
TJ
523 * @brief returns the filename part of a path (last component)
524 * @param path the path.
525 * @return the last component of the path.
526 */
527std::string basename(const std::string& path)
528{
529 std::string::size_type pos= path.rfind('/');
530 if (pos != std::string::npos)
531 {
532 return path.substr(pos+1);
533 }
534 return path;
535} // eo basename(const std::string&)
536
537
538/**
539 * @brief returns the directory part of a path.
540 * @param path the path.
541 * @return the directory part of the path.
542 */
543std::string dirname(const std::string& path)
544{
545 std::string::size_type pos= path.rfind('/');
546 if (pos != std::string::npos)
547 {
548 std::string result(path,0,pos);
549 if (result.empty())
550 {
551 return ".";
552 }
553 return result;
554 }
555 return ".";
556} // eo dirname(const std::string&)
557
558
559/**
560 * @brief normalizes a path.
561 *
562 * This method removes empty and "." elements.
563 * It also resolves ".." parts by removing previous path elements if possible.
564 * Leading ".." elements are preserved when a relative path was given; else they are removed.
565 * Trailing slashes are removed.
566 *
567 * @param path the path which should be normalized.
568 * @return the normalized path.
569 */
570
a287a306 571std::string normalize_path(const std::string& path)
6a93d84a
TJ
572{
573 if (path.empty())
574 {
575 return std::string();
576 }
577 // remember if the given path was absolute since this information vanishes when
578 // we split the path (since we split with omitting empty parts...)
579 bool is_absolute= (path[0]=='/');
580 std::list< std::string > parts;
581 std::list< std::string > result_parts;
582
6ab3bc95 583 split_string(path,parts,"/",true);
6a93d84a
TJ
584
585 for(std::list< std::string >::const_iterator it_parts= parts.begin();
586 it_parts != parts.end();
587 ++it_parts)
588 {
589 std::string part(*it_parts); //convenience..
590 if (part == std::string(".") )
591 {
592 // single dot is "current path"; ignore!
593 continue;
594 }
595 if (part == std::string("..") )
596 {
597 // double dot is "one part back"
598 if (result_parts.empty())
599 {
600 if (is_absolute)
601 {
602 // ignore since we cannot move behind / on absolute paths...
603 }
604 else
605 {
606 // on relative path, we need to store the "..":
607 result_parts.push_back(part);
608 }
609 }
610 else if (result_parts.back() == std::string("..") )
611 {
612 // if last element was already "..", we need to store the new one again...
613 // (PS: no need for "absolute" check; this can only be the case on relative path)
614 result_parts.push_back(part);
615 }
616 else
617 {
618 // remove last element.
619 result_parts.pop_back();
620 }
621 continue;
622 }
623 result_parts.push_back(part);
624 }
625 std::string result;
626 if (is_absolute)
627 {
628 result= "/";
629 }
6ab3bc95 630 result+= join_string(result_parts,"/");
6a93d84a 631 return result;
6ab3bc95 632} // eo normalize_path(const std::string&)
6a93d84a
TJ
633
634
635/**
f002679a
GE
636 * @brief calls fsync on a given directory to sync all it's metadata
637 * @param path the path of the directory.
638 * @return true if successful
639 */
640bool dirsync(const std::string& path)
641{
642 // sync the directory the file is in
643 DIR* dir=opendir(path.c_str());
644 if (dir == NULL)
645 return false;
646
647 int ret=fsync(dirfd(dir));
648
649 closedir(dir);
650
651 return (ret==0);
652}
653
654/**
6a93d84a
TJ
655 * @brief changes the file(/path) mode.
656 * @param path the path to change the mode for.
657 * @param mode the new file mode.
658 * @return @a true iff the file mode was sucessfully changed.
659 */
660bool chmod(const std::string& path, int mode)
661{
662 int res= ::chmod(path.c_str(), mode);
663 return (res==0);
664} // eo chmod(const std::string&,int)
665
666
667/**
668 * @brief changed the owner of a file(/path)
669 * @param path the path to change the owner for.
670 * @param user the new file owner.
671 * @param group the new file group.
672 * @return @a true iff the file owner was succesfully changed.
673 *
674 * @note
675 * the validity of user and group within the system is not checked.
676 * This is intentional since this way we can use id's which are not assigned.
677 */
a287a306 678bool chown(const std::string& path, const I2n::User& user, const I2n::Group& group)
6a93d84a 679{
a287a306 680 uid_t uid= user.Uid;
6a93d84a 681 if (uid<0) return false;
a287a306
TJ
682 gid_t gid= group.Gid;
683 if (gid<0) gid= user.Gid;
6a93d84a
TJ
684 if (gid<0) return false;
685 int res= ::chown( path.c_str(), uid, gid);
686 return (res==0);
687} // eo chown(const std::string&,const User&,const Group&)
e93545dd 688
0a654ec0
TJ
689/**
690 * Recursive delete of files and directories
691 * @param path File or directory to delete
44725532 692 * @param error Will contain the error if the return value is false [optional]
0a654ec0
TJ
693 * @return true on success, false otherwise
694 */
695bool recursive_delete(const std::string &path, std::string *error)
696{
697 bool rtn = true;
698
699 try {
700 struct stat my_stat;
701 if (stat(path.c_str(), &my_stat) != 0) {
702 throw runtime_error("can't stat " + path);
703 }
704
705 if (S_ISDIR(my_stat.st_mode)) {
706 DIR *dir = opendir(path.c_str());
707 if (!dir) {
708 throw runtime_error("can't open directory " + path);
709 }
710
10c3af2d
TJ
711 struct dirent store, *entry = NULL;
712 while (readdir_r(dir, &store, &entry) == 0 && entry != NULL)
713 {
0a654ec0
TJ
714 string filename = entry->d_name;
715 if (filename == "." || filename == "..") {
716 continue;
717 }
718
719 // Delete subdir or file.
720 rtn = recursive_delete(path + "/" + filename, error);
721 if (rtn == false) {
722 break;
723 }
724 }
725
726 closedir(dir);
44725532 727 if (!rmdir(path)) {
0a654ec0
TJ
728 throw runtime_error("can't remove directory " + path);
729 }
730 } else {
44725532 731 if (!unlink(path)) {
0a654ec0
TJ
732 throw runtime_error("can't unlink " + path);
733 }
734 }
735 } catch (exception &e) {
736 if (error) {
737 ostringstream out;
738 out << e.what() << " (" << strerror(errno) << ")";
739 *error = out.str();
740 }
741 rtn = false;
742 } catch (...) {
743 if (error) {
744 ostringstream out;
745 out << "unknown error (" << strerror(errno) << ")";
746 *error = out.str();
747 }
748 rtn = false;
749 }
e93545dd 750
0a654ec0 751 return rtn;
6ab3bc95 752} // eo recursive_delete(const std::string&,std::string*)
6a93d84a 753
faf8475b
TJ
754/**
755 Create a unique temporary directory from path_template.
756 @param Path template. The last six characters must be XXXXXX.
44725532 757 @param error Will contain the error if the return value is false [optional]
faf8475b
TJ
758 @return Name of new directory or empty string on error.
759*/
44725532 760std::string mkdtemp(const std::string &path_template, std::string *error)
faf8475b
TJ
761{
762 boost::scoped_array<char> buf( new char[path_template.size()+1] );
763 path_template.copy(buf.get(), path_template.size());
764 buf[path_template.size()]=0;
765
766 char *unique_dir = ::mkdtemp(buf.get());
767 if (!unique_dir)
44725532
TJ
768 {
769 if (error)
770 *error = strerror(errno);
faf8475b 771 return "";
44725532 772 }
faf8475b
TJ
773
774 // Scoped pointer is still valid
775 return std::string(unique_dir);
776}
777
44725532
TJ
778/**
779 Create directory
780 @param path Path to create
781 @param error Will contain the error if the return value is false [optional]
782 @return True on success, false on error
783*/
784bool mkdir(const std::string &path, const mode_t &mode, std::string *error)
785{
786 if ( ::mkdir(path.c_str(), mode) == 0)
787 return true;
788
789 if (error)
790 *error = strerror(errno);
791 return false;
792}
793
794/**
795 Remove directory
796 @param path Path to removed
797 @param error Will contain the error if the return value is false [optional]
798 @return True on successs, false otherwise
799*/
800bool rmdir(const std::string &path, std::string *error)
801{
802 if ( ::rmdir(path.c_str() ) == 0)
803 return true;
804
805 if (error)
806 *error = strerror(errno);
807 return false;
808}
809
810/// Small helper class for scoped free
811class scoped_C_free
812{
813public:
814 scoped_C_free(void *ptr)
815 : pointer_to_free(ptr)
816 {
817 }
818
819 ~scoped_C_free()
820 {
821 free (pointer_to_free);
822 pointer_to_free = NULL;
823 }
824
825private:
826 void *pointer_to_free;
827};
828
829/**
830 Get current working directory
831 @return Current working directory. Empty string on error.
832*/
833std::string getcwd()
834{
835 char *cwd = ::getcwd(NULL, 0);
836 if (!cwd)
837 return "";
838
839 // Make deallocation of cwd exception safe
840 scoped_C_free holder(cwd);
841
842 string current_dir(cwd);
843 return current_dir;
844}
845
846/**
847 Change current working directory
848 @param path Path to change to
849 @param error Will contain the error if the return value is false [optional]
850 @return True on successs, false otherwise
851*/
852bool chdir(const std::string &path, std::string *error)
853{
854 if ( ::chdir(path.c_str() ) == 0)
855 return true;
856
857 if (error)
858 *error = strerror(errno);
859 return false;
860}
faf8475b 861
901e2943
TJ
862/**
863 Set file mode creation mask
864 @param mask Creation mask
865 @return Previous creation mask (function call always succeeds)
866*/
867mode_t umask(mode_t mask)
868{
869 return ::umask(mask);
870}
871
6ab3bc95 872} // eo namespace I2n