Line data Source code
1 : /*
2 : * File.cxx
3 : * ers
4 : *
5 : * Created by Matthias Wiesmann on 04.01.05.
6 : * Copyright 2005 CERN. All rights reserved.
7 : *
8 : */
9 :
10 : #include <unistd.h>
11 : #include <stdio.h>
12 : #include <libgen.h>
13 : #include <unistd.h>
14 : #include <fcntl.h>
15 : #include <errno.h>
16 : #include <assert.h>
17 : #include <dirent.h>
18 : #include <sys/types.h>
19 : #include <sys/stat.h>
20 : #include <sys/param.h>
21 : #include <iostream>
22 : #include <sstream>
23 : #include <fstream>
24 : #include <pwd.h>
25 :
26 : #include "ers/ers.hpp"
27 :
28 : #include "okssystem/File.hpp"
29 : #include "okssystem/exceptions.hpp"
30 : #include "okssystem/Executable.hpp"
31 : #include "okssystem/User.hpp"
32 :
33 : #define SPACE_CHAR ' '
34 :
35 : const char * const OksSystem::File::HUMAN_SIZE_STR[] = { "B", "KB", "MB", "GB" };
36 : const char * const OksSystem::File::HUMAN_OPEN_STR[] = { "READ", "WRITE", "NOBLOCK", "APPEND", "CREATE", "TRUNCATE","EXCLUSIVE" };
37 : const char * const OksSystem::File::FILE_COMMAND_PATH = "/usr/bin/file";
38 : const char * const OksSystem::File::FILE_FLAG_STR = "-rwxS";
39 : const char * const OksSystem::File::FILE_PROTOCOL = "file";
40 :
41 :
42 : #define READ_CHAR_CODE (OksSystem::File::FILE_FLAG_STR[1])
43 : #define WRITE_CHAR_CODE (OksSystem::File::FILE_FLAG_STR[2])
44 : #define EXECUTE_CHAR_CODE (OksSystem::File::FILE_FLAG_STR[3])
45 : #define NOTHING_CHAR_CODE (OksSystem::File::FILE_FLAG_STR[0])
46 : #define SETUID_CHAR_CODE (OksSystem::File::FILE_FLAG_STR[4])
47 :
48 : #define SLASH_CHAR '/'
49 : #define COLON_CHAR ':'
50 : #define DOT_CHAR '.'
51 :
52 : const int OksSystem::File::KILOBYTE = 1024;
53 :
54 :
55 : // --------------------------------------
56 : // Static Methods
57 : // --------------------------------------
58 :
59 :
60 : /** Extracts the protocol part of an url.
61 : * The protocol part is everything until the colon (:)
62 : * \param url an url
63 : * \return the protocol part of an empty string
64 : */
65 :
66 0 : std::string OksSystem::File::protocol(const std::string &url) throw() {
67 0 : std::string::size_type colon = url.find(COLON_CHAR);
68 0 : if (colon==std::string::npos) return std::string();
69 0 : return url.substr(0,colon);
70 : } // protocol
71 :
72 : /** Extracts the extension of an url or path
73 : * \param url an url or file path
74 : * \return the extension (without the dot) or an empty string
75 : */
76 :
77 0 : std::string OksSystem::File::extension(const std::string &url) throw() {
78 0 : std::string::size_type dot = url.rfind(DOT_CHAR);
79 0 : if (dot==std::string::npos) return std::string();
80 0 : return url.substr(dot+1);
81 : } // extension
82 :
83 : /** Extracts the short file name of an url or path
84 : * \param url an url or file path
85 : * \return the short name or the full url if it cannot be found
86 : */
87 :
88 0 : std::string OksSystem::File::short_name(const std::string &url) throw() {
89 0 : std::string::size_type slash = url.rfind(SLASH_CHAR);
90 0 : if (slash==std::string::npos) return url;
91 0 : return url.substr(slash+1);
92 : } // extension
93 :
94 : /** Extacts the uri part of an url.
95 : * The uri of an url is everything except the protocol part
96 : * In the case of \c file or \c http urls, the uri is the local path
97 : * \param url an url
98 : * \return the uri or the full url if no colon in the string
99 : */
100 :
101 0 : std::string OksSystem::File::uri(const std::string &url) throw() {
102 0 : std::string::size_type colon = url.find(COLON_CHAR);
103 0 : if (colon==std::string::npos) return url;
104 0 : return url.substr(colon+1);
105 : } // uri
106 :
107 :
108 : /** Calculates the depth of a file.
109 : * This depth is the number of parent directories.
110 : * Files in the root directory have depht of 0,
111 : * other files have a depth of their parent's depth + 1
112 : * \param path to analyze
113 : * \return depth or -1 if the format of the path is not understood.
114 : */
115 :
116 0 : int OksSystem::File::depth(const std::string &path) throw() {
117 0 : if (path[0] == SLASH_CHAR) {
118 0 : int count = 0;
119 0 : std::string rest = path.substr(1);
120 0 : while(! rest.empty()) {
121 0 : std::string::size_type slash = rest.find(SLASH_CHAR);
122 0 : if (slash==std::string::npos) return count;
123 0 : count++;
124 0 : rest = rest.substr(slash+1);
125 : } // while
126 0 : return count;
127 0 : } // path with slash
128 0 : if (protocol(path) == FILE_PROTOCOL) {
129 0 : return depth(uri(path));
130 : } //
131 : return -1;
132 : } // depth
133 :
134 : /** Extracts the first line of a text
135 : * \param text the text to process
136 : * \return the first line of the text
137 : */
138 :
139 0 : std::string OksSystem::File::first_line(const std::string &text) {
140 0 : std::string::size_type nl = text.find('\n');
141 0 : if (nl>0) return text.substr(0,nl);
142 0 : return text;
143 : } // first_line
144 :
145 :
146 : /** Builds a \c File object ou of an url
147 : * \param url the url, it must start with the file protocol
148 : * \return a File object
149 : */
150 :
151 0 : OksSystem::File OksSystem::File::from_url(const std::string &url) {
152 0 : std::string prot = protocol(url);
153 0 : ERS_PRECONDITION(prot==FILE_PROTOCOL);
154 0 : const std::string path = uri(url);
155 0 : return File(path);
156 0 : } // from_url
157 :
158 : /** \return a string containing the working directory for the process */
159 :
160 0 : std::string OksSystem::File::working_directory() {
161 0 : char *wd_buffer = getcwd(0,MAXPATHLEN);
162 0 : if (wd_buffer) {
163 0 : std::string directory = std::string(wd_buffer);
164 0 : free(wd_buffer);
165 0 : return directory;
166 0 : }
167 0 : std::string message("getting the current working directory");
168 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "getcwd", message.c_str() );
169 0 : } // working_directory
170 :
171 0 : void OksSystem::File::working_directory(const File &dir) {
172 0 : const char * path = dir.c_full_name();
173 0 : const int status = ::chdir(path);
174 0 : if (status<0) {
175 0 : std::string message = "on directory " + dir.full_name();
176 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "chdir", message.c_str() );
177 0 : }
178 0 : } // working_directory
179 :
180 :
181 : /** Expands a file containing a home directory reference (~user).
182 : */
183 :
184 :
185 0 : std::string OksSystem::File::expand_home(const std::string path) {
186 0 : ERS_PRECONDITION(! path.empty());
187 0 : ERS_PRECONDITION(path[0] == '~');
188 0 : std::string::size_type slash = path.find('/');
189 0 : const std::string user_name = path.substr(1,slash-1);
190 0 : const std::string rest_path = path.substr(slash);
191 0 : OksSystem::User user;
192 0 : if (! user_name.empty()) {
193 0 : user = OksSystem::User(user_name);
194 : }
195 0 : return user.home() + rest_path;
196 0 : } // home_directory
197 :
198 :
199 : /** Builds a prettyfied version of permissions.
200 : * This should look similar to what \c ls returns with the -l flag
201 : * \param permissions the permission to beautify
202 : * \return a string containing the beautified permissions
203 : */
204 :
205 0 : std::string OksSystem::File::pretty_permissions(mode_t permissions) {
206 0 : char buffer[11];
207 0 : buffer[0] = (permissions & S_ISUID) ? SETUID_CHAR_CODE : NOTHING_CHAR_CODE;
208 0 : buffer[1] = (permissions & S_IRUSR) ? READ_CHAR_CODE : NOTHING_CHAR_CODE;
209 0 : buffer[2] = (permissions & S_IWUSR) ? WRITE_CHAR_CODE : NOTHING_CHAR_CODE;
210 0 : buffer[3] = (permissions & S_IXUSR) ? EXECUTE_CHAR_CODE : NOTHING_CHAR_CODE;
211 0 : buffer[4] = (permissions & S_IRGRP) ? READ_CHAR_CODE : NOTHING_CHAR_CODE;
212 0 : buffer[5] = (permissions & S_IWGRP) ? WRITE_CHAR_CODE : NOTHING_CHAR_CODE;
213 0 : buffer[6] = (permissions & S_IXGRP) ? EXECUTE_CHAR_CODE : NOTHING_CHAR_CODE;
214 0 : buffer[7] = (permissions & S_IROTH) ? READ_CHAR_CODE : NOTHING_CHAR_CODE;
215 0 : buffer[8] = (permissions & S_IWOTH) ? WRITE_CHAR_CODE : NOTHING_CHAR_CODE;
216 0 : buffer[9] = (permissions & S_IXOTH) ? EXECUTE_CHAR_CODE : NOTHING_CHAR_CODE;
217 0 : buffer[10] = '\0';
218 0 : return std::string(buffer);
219 : } // pretty_permissions
220 :
221 : /** Builds a prettyfied version of flags used by the \c open OksSystem call
222 : * \param flags as passed to \c open
223 : * \return a string containing the beautified flags
224 : * \note This method only handles flags available accross plateforms.
225 : */
226 :
227 0 : std::string OksSystem::File::pretty_open_flag(int flags) {
228 0 : std::ostringstream flag_str;
229 0 : if (flags & O_WRONLY) {
230 0 : flag_str << HUMAN_OPEN_STR[1];
231 0 : } else if (flags & O_RDWR) {
232 0 : flag_str << HUMAN_OPEN_STR[0] << "-" << HUMAN_OPEN_STR[1];
233 : } else {
234 0 : flag_str << HUMAN_OPEN_STR[0];
235 : }
236 0 : if (flags & O_NONBLOCK) {
237 0 : flag_str << "/" << HUMAN_OPEN_STR[2];
238 : }
239 0 : if (flags & O_APPEND) {
240 0 : flag_str << "/" << HUMAN_OPEN_STR[3];
241 : }
242 0 : if (flags & O_CREAT) {
243 0 : flag_str << "/" << HUMAN_OPEN_STR[4];
244 : }
245 0 : if (flags & O_TRUNC) {
246 0 : flag_str << "/" << HUMAN_OPEN_STR[5];
247 : }
248 0 : if (flags & O_EXCL) {
249 0 : flag_str << "/" << HUMAN_OPEN_STR[6];
250 : }
251 0 : flag_str << "(" << flags << ")";
252 0 : return flag_str.str();
253 0 : } // pretty_open_permission
254 :
255 :
256 0 : int OksSystem::File::unit(int u) {
257 0 : ERS_PRECONDITION(u >= 0);
258 0 : if (u==0) return 1;
259 0 : return KILOBYTE * unit(u-1);
260 : } // unit
261 :
262 : /** Builds a human readable textual description of a file size.
263 : * The file size is expressed in Gigabytes (GB), Megabytes (MB) and Kilobytes (KB) and Bytes (B).
264 : * \param size the size of the file
265 : * \param cut_small should the display only contain the highest quantity?
266 : * For example if a file is 1 gigabyte and 20 bytes, if \c cut_small is \c true, then
267 : * the 20 bytes are ignored.
268 : * \return a string containing the textual description
269 : */
270 :
271 0 : std::string OksSystem::File::pretty_size(size_t size, bool cut_small) {
272 0 : if (0==size) return "0";
273 0 : std::ostringstream size_str;
274 : bool writen_something = false;
275 0 : for(int i=3;i>=0;i--) {
276 0 : const unsigned int size_unit = unit(i);
277 0 : if (size > size_unit && ! (cut_small && writen_something)) {
278 0 : const int amount = size / size_unit;
279 0 : size = size % size_unit;
280 0 : size_str << amount << SPACE_CHAR << HUMAN_SIZE_STR[i];
281 : writen_something = true;
282 : } // if unit is present
283 : } // loop
284 0 : return size_str.str();
285 0 : } // pretty_size
286 :
287 : // --------------------------------------
288 : // Constructors
289 : // --------------------------------------
290 :
291 :
292 : /** Constructor
293 : * \note This method does not create a file, it simply builds an object describing a file
294 : */
295 :
296 0 : OksSystem::File::File(const std::string &name) {
297 0 : set_name(name);
298 0 : } // File
299 :
300 : /** Constructor
301 : * \overload
302 : */
303 :
304 0 : OksSystem::File::File(const char* c_name) {
305 0 : ERS_PRECONDITION(c_name);
306 0 : std::string name = std::string(c_name);
307 0 : set_name(name);
308 0 : } // File
309 :
310 : /** Constructor
311 : * \overload
312 : */
313 :
314 0 : OksSystem::File::File(const File& other) {
315 0 : set_name(other.m_full_name);
316 0 : } // File
317 :
318 : // --------------------------------------
319 : // Operators
320 : // --------------------------------------
321 :
322 :
323 :
324 0 : OksSystem::File::operator std::string() const throw() {
325 0 : return m_full_name;
326 : } // operator std::string
327 :
328 0 : OksSystem::File::operator const char*() const throw() {
329 0 : return m_full_name.c_str();
330 : } // operator const char*
331 :
332 : /** Cast to boolean, checks if the file exists
333 : * \return \c true if the file exists
334 : */
335 :
336 0 : OksSystem::File::operator bool() const throw() {
337 0 : return exists();
338 : } // operator bool
339 :
340 : /** Comparison operator
341 : * As path are canonicalized, we simply compare the full paths.
342 : * \param other file to compare this file to
343 : * \return true if both file are equal
344 : * \note This comparison method does not taken hard links into account
345 : */
346 :
347 0 : bool OksSystem::File::equals(const File &other) const throw() {
348 0 : return (m_full_name == other.m_full_name);
349 : } // operator==
350 :
351 : /** Cast to size type
352 : * \return the size of the file
353 : * \see size()
354 : */
355 :
356 0 : OksSystem::File::operator size_t() const {
357 0 : return size();
358 : } // operator size_t
359 :
360 :
361 :
362 :
363 : // --------------------------------------
364 : // Methods
365 : // --------------------------------------
366 :
367 :
368 : /** Sets the name for a file.
369 : * The path name is first expanded and the canonlicalized.
370 : * Expension means the following
371 : * \li If the path starts with / nothing is done
372 : * \li If the path starts with ~ the username is resolved and the path starts from there
373 : * \li If the path starts with any other character, the working directory is prepended.
374 : *
375 : * The path is then made canonical, this implies removing all ./ and ../ sequences,
376 : * and resolving all symbolic links.
377 : * \param name the name of the file
378 : */
379 :
380 0 : void OksSystem::File::set_name(const std::string &name) {
381 0 : ERS_PRECONDITION(! name.empty());
382 0 : const char c = name[0];
383 0 : std::string long_path;
384 0 : switch (c) {
385 0 : case '/' :
386 0 : long_path = name;
387 : break;
388 0 : case '~' :
389 0 : long_path = expand_home(name);
390 0 : break;
391 0 : default:
392 0 : long_path = working_directory() + "/" + name;
393 0 : break;
394 : } // switch
395 0 : char buffer[PATH_MAX];
396 0 : const char* result = realpath(long_path.c_str(),buffer);
397 0 : if (result==0) { // could not resolve path
398 0 : m_full_name = long_path;
399 : } else { // we could canonicalize the path
400 0 : m_full_name = buffer;
401 : } //
402 0 : } // set_name
403 :
404 : /** \return the full (absolute) path of the file */
405 :
406 0 : const std::string & OksSystem::File::full_name() const throw() {
407 0 : return m_full_name;
408 : } // full_name
409 :
410 : /** \return the full (absolute) path of the file */
411 :
412 0 : const char* OksSystem::File::c_full_name() const throw() {
413 0 : return m_full_name.c_str();
414 : } // c_full_name
415 :
416 :
417 : /** \return the short name of the file - that is the name of the file in its directory */
418 :
419 0 : std::string OksSystem::File::short_name() const throw() {
420 0 : return short_name(m_full_name);
421 : } // short_name
422 :
423 : /** Finds the name of the enclosing directory
424 : * \return the path of the directory containing the file
425 : */
426 :
427 0 : std::string OksSystem::File::parent_name() const throw() {
428 0 : std::string::size_type size = m_full_name.size();
429 0 : std::string::size_type slash = m_full_name.rfind(SLASH_CHAR,size-1);
430 0 : if (slash==std::string::npos || slash==0) return ("/");
431 0 : return m_full_name.substr(0,slash);
432 : } // directory
433 :
434 : /** \return the extension of the file */
435 :
436 0 : std::string OksSystem::File::extension() const throw() {
437 0 : return extension(m_full_name);
438 : } // extension
439 :
440 0 : int OksSystem::File::depth() const throw() {
441 0 : return depth(m_full_name);
442 : } // depth
443 :
444 : /** \return the parent directory */
445 :
446 0 : OksSystem::File OksSystem::File::parent() const {
447 0 : return File(parent_name());
448 : } // parent
449 :
450 0 : OksSystem::File OksSystem::File::child(const std::string &name) const {
451 0 : std::string child_name = m_full_name + "/" + name;
452 0 : return OksSystem::File(child_name);
453 0 : } // child
454 :
455 0 : OksSystem::File OksSystem::File::temporary(const std::string &prefix) const {
456 0 : char *tmp_name = tempnam(m_full_name.c_str(),prefix.c_str());
457 0 : if ( !tmp_name ) {
458 0 : std::string message = "while creating a valid filename in directory " + m_full_name;
459 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "tempnam", message.c_str() );
460 0 : }
461 0 : OksSystem::File tmp_file(tmp_name);
462 0 : free(tmp_name);
463 0 : return tmp_file;
464 : } // temporary
465 :
466 :
467 : /** Checks if the file exists in the fileOksSystem
468 : * \return \c true if the file exists, false otherwise
469 : * \exception ers::IOIssue if an error occurs
470 : */
471 :
472 0 : bool OksSystem::File::exists() const throw() {
473 0 : struct stat file_status;
474 0 : const int result = stat(m_full_name.c_str(),&file_status);
475 0 : if (0==result) return true;
476 : return false;
477 : } // exists
478 :
479 : /** Extracts the mode information of the file.
480 : * This is used to determine both the file type and the file permissions
481 : * \return the mode of the file
482 : * \exception OksSystem::FStatFail if fstat fails
483 : */
484 :
485 0 : mode_t OksSystem::File::get_mode() const {
486 0 : struct stat file_status;
487 0 : const int result = stat(m_full_name.c_str(),&file_status);
488 0 : if (0==result) {
489 0 : return file_status.st_mode;
490 : } // if
491 0 : std::string message = "on file/directory " + m_full_name;
492 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "stat", message.c_str() );
493 0 : } // mode
494 :
495 :
496 : /** \return the permissions for the file
497 : * \exception ers::IOIssue if an error occurs or the file does not exist
498 : */
499 :
500 0 : mode_t OksSystem::File::permissions() const {
501 0 : mode_t mode = get_mode();
502 0 : return (mode & 07777);
503 : } // permissions
504 :
505 : /** \return the prettfied permissions for the file
506 : * \exception ers::IOIssue if an error occurs or the file does not exist
507 : */
508 :
509 0 : std::string OksSystem::File::pretty_permissions() const {
510 0 : return pretty_permissions(permissions());
511 : } // pretty_permissions
512 :
513 : /** Converts permissions into a string
514 : * \param permissions the permissions
515 : * \return a string contaning the permissions in octal form
516 : */
517 :
518 0 : std::string OksSystem::File::to_string(mode_t permissions) throw() {
519 0 : std::ostringstream stream;
520 0 : stream.setf(std::ios::oct,std::ios::basefield);
521 0 : stream << permissions;
522 0 : return stream.str();
523 0 : } // to_string
524 :
525 :
526 : /** \return the size (in bytes) of the file
527 : * \exception OksSystem::IOIssue if an error occurs or the file does not exist
528 : */
529 :
530 0 : size_t OksSystem::File::size() const {
531 0 : struct stat file_status;
532 0 : const int result = stat(m_full_name.c_str(),&file_status);
533 0 : if (0==result) return file_status.st_size;
534 0 : std::string message = "on file/directory " + m_full_name;
535 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "stat", message.c_str() );
536 0 : } // size
537 :
538 : /** \return the user-id of the owner of the file
539 : * \exception OksSystem::IOIssue if an error occurs or the file does not exist
540 : */
541 :
542 0 : uid_t OksSystem::File::owner_id() const {
543 0 : struct stat file_status;
544 0 : const int result = stat(m_full_name.c_str(),&file_status);
545 0 : if (0==result) return file_status.st_uid;
546 0 : std::string message = "on file/directory " + m_full_name;
547 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "stat", message.c_str() );
548 0 : } // owner_id
549 :
550 0 : OksSystem::User OksSystem::File::owner() const {
551 0 : return User(owner_id());
552 : } // owner
553 :
554 :
555 : /** \return the group-id of the group of the file
556 : * \exception ers::IOIssue if an error occurs or the file does not exist
557 : */
558 :
559 0 : gid_t OksSystem::File::group() const {
560 0 : struct stat file_status;
561 0 : const int result = stat(m_full_name.c_str(),&file_status);
562 0 : if (0==result) return file_status.st_gid;
563 0 : std::string message = "on file/directory " + m_full_name;
564 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "stat", message.c_str() );
565 0 : } // owner
566 :
567 :
568 : /** Checks if the file a regular file (i.e not a directory, named pipe or anything else).
569 : * \return \c true if the file is regular
570 : * \exception ers::IOIssue if an error occurs or the file does not exist
571 : */
572 :
573 0 : bool OksSystem::File::is_regular() const {
574 0 : const mode_t mode = get_mode();
575 0 : return (mode & S_IFREG);
576 : } // is_regular
577 :
578 :
579 : /** Checks if the file a directory
580 : * \return \c true if the file is a directory
581 : * \exception ers::IOIssue if an error occurs or the file does not exist
582 : */
583 :
584 0 : bool OksSystem::File::is_directory() const {
585 0 : const mode_t mode = get_mode();
586 0 : return (mode & S_IFDIR);
587 : } // is_regular
588 :
589 : /** Checks if the file a named pipe (FIFO)
590 : * \return \c true if the file is named pipe (FIFO)
591 : * \exception ers::IOIssue if an error occurs or the file does not exist
592 : */
593 :
594 0 : bool OksSystem::File::is_fifo() const {
595 0 : const mode_t mode = get_mode();
596 0 : return (mode & S_IFIFO);
597 : } // is_pipe
598 :
599 :
600 0 : std::string OksSystem::File::file_type() const {
601 0 : OksSystem::Executable file_command(FILE_COMMAND_PATH);
602 0 : OksSystem::Executable::param_collection params;
603 0 : params.push_back("-b");
604 0 : params.push_back(full_name());
605 0 : return first_line(file_command.pipe_in(params));
606 0 : } // file_type
607 :
608 : /** Builds a vector containing all the files contained in a directory
609 : * \return a vector of files contained in the directory
610 : * \exception OksSystem::OpenFail if the directory could not be openend
611 : * \exception OksSystem::CloseFail if the directory cannot be closed
612 : */
613 :
614 0 : OksSystem::File::file_list_t OksSystem::File::directory() const {
615 0 : file_list_t file_vector;
616 0 : DIR* directory_ptr = opendir(m_full_name.c_str());
617 0 : if (! directory_ptr) {
618 0 : std::string message = "on directory " + m_full_name;
619 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "opendir", message.c_str() );
620 0 : }
621 0 : while(true) {
622 0 : struct dirent* directory_entry = readdir(directory_ptr);
623 0 : if (directory_entry) {
624 0 : const std::string name = directory_entry->d_name;
625 0 : if ((name!=".") && (name!="..")) {
626 0 : std::string path = m_full_name + "/" + name;
627 0 : OksSystem::File file(path);
628 0 : file_vector.push_back(file);
629 0 : } // if
630 0 : } else {
631 : break;
632 : } // if / else
633 0 : } // while
634 0 : int status = closedir(directory_ptr);
635 0 : if (status<0) {
636 0 : std::string message = "on directory " + m_full_name;
637 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "closedir", message.c_str() );
638 0 : }
639 0 : return file_vector;
640 0 : } // directory
641 :
642 : /** Unlinks (i.e deletes) a file.
643 : * \exception ers::IOIssue if an error occurs or the file does not exist
644 : */
645 :
646 0 : void OksSystem::File::unlink() const {
647 0 : const int result = ::unlink(m_full_name.c_str());
648 0 : if (0==result) return;
649 0 : throw OksSystem::RemoveFileIssue( ERS_HERE, errno, m_full_name.c_str() );
650 : } //unlink
651 :
652 0 : void OksSystem::File::rmdir() const {
653 0 : const int result = ::rmdir(m_full_name.c_str());
654 0 : if (0==result) return;
655 0 : std::string message = "on directory " + m_full_name;
656 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "rmdir", message.c_str() );
657 0 : } // rmdir
658 :
659 :
660 : /** Recursively delete files and directories.
661 : * If the file is a directory, all its child are deleted recursively.
662 : * \exception OksSystem::UnlinkFail if \c unlink fails
663 : */
664 :
665 0 : void OksSystem::File::remove() const {
666 0 : if (is_directory()) {
667 0 : file_list_t childs = directory();
668 0 : for (file_list_t::const_iterator p=childs.begin();p!=childs.end();p++) {
669 0 : const File f = *p;
670 0 : if(f.exists()) {
671 0 : f.remove();
672 : }
673 0 : } // for
674 0 : rmdir();
675 0 : } else {
676 0 : unlink();
677 : }
678 0 : } // remove
679 :
680 :
681 : /** Renames or moves a file.
682 : * \param new_name the new name of the file
683 : * \exception ers::IOIssue if an error occurs or the file does not exist
684 : */
685 :
686 0 : void OksSystem::File::rename(const File &other) const {
687 0 : const char *source = c_full_name() ;
688 0 : const char *dest = other.c_full_name();
689 0 : const int result = ::rename(source,dest);
690 0 : if (0==result) return;
691 0 : throw OksSystem::RenameFileIssue( ERS_HERE, errno, source, dest );
692 : } // rename
693 :
694 : /** Sets the permissions of the file
695 : * \param permissions the new permissions
696 : * \exception ers::IOIssue if an error occurs or the file does not exist
697 : */
698 :
699 0 : void OksSystem::File::permissions(mode_t perm) const {
700 0 : if(perm != permissions()) {
701 0 : const int result = ::chmod(m_full_name.c_str(),perm);
702 0 : if (0==result) {
703 0 : return;
704 : }
705 0 : std::string message = "on file/directory " + m_full_name;
706 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "chmod", message.c_str());
707 0 : }
708 : } // permissions
709 :
710 : /** Creates a directory
711 : * The current object is taken as the name of the directory to create.
712 : * \param perm the permissions to associate with the directory
713 : * \note if the directory exists, the method attempts to do a \c chmod
714 : * to match the permissions
715 : */
716 :
717 0 : void OksSystem::File::make_dir(mode_t perm) const {
718 :
719 0 : errno = 0;
720 0 : const int result = ::mkdir(m_full_name.c_str(),perm);
721 0 : int mkdir_error = errno;
722 :
723 0 : if (0==result) {
724 0 : try {
725 0 : permissions(perm);
726 : }
727 0 : catch (OksSystem::OksSystemCallIssue &e){
728 0 : std::string message = "on directory " + m_full_name;
729 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "mkdir -> chmod", message.c_str() );
730 0 : }
731 : return;
732 : } else {
733 0 : if (exists()) {
734 0 : if (is_directory()) { // already exists we attempt a chmod
735 0 : try {
736 0 : permissions(perm);
737 : }
738 0 : catch (OksSystem::OksSystemCallIssue &e){
739 : // ignore this case...
740 0 : }
741 0 : return;
742 : } // is directory
743 : } else { // exists
744 0 : std::string message = "on directory " + m_full_name;
745 0 : throw OksSystem::OksSystemCallIssue(ERS_HERE, mkdir_error, "mkdir", message.c_str());
746 0 : }
747 : }
748 :
749 : } // makedir
750 :
751 : /** Builds a full path.
752 : * The current object is taken as the name of a directory to create.
753 : * This method creates all the parent directories as needed
754 : * \param permissions the permissions to associate with the directory
755 : * \note If parent directories are created, their permissions will be those
756 : * defined in \c permissions ORed with 0700.
757 : * This is needed to ensure we can actually write into the directories
758 : * we create.
759 : */
760 :
761 0 : void OksSystem::File::make_path(mode_t perm) const {
762 0 : const File father = parent();
763 0 : if (! father.exists()) {
764 0 : mode_t father_permission = perm | S_IRWXU;// we need rights to write sons
765 0 : father.make_path(father_permission);
766 : } // if
767 0 : make_dir(perm);
768 0 : } // makepath
769 :
770 : /** Makes sure that the path for a file exists
771 : * This is done by calling \c make_path on the parent directory
772 : * \param permissions permissions used to create directories
773 : * \see OksSystem::File::make_path()
774 : */
775 :
776 0 : void OksSystem::File::ensure_path(mode_t perm) const {
777 0 : const File father = parent();
778 0 : father.make_path(perm);
779 0 : } // ensure_path
780 :
781 :
782 : /** Creates a named pipe (FIFO)
783 : * \param perm the permission to give the pipe
784 : */
785 :
786 0 : void OksSystem::File::make_fifo(mode_t perm) const {
787 0 : if (exists()) {
788 0 : if (is_fifo()) {
789 0 : if(perm != permissions()) {
790 0 : permissions(perm);
791 0 : return;
792 : } else {
793 : return;
794 : }
795 : } // is_fifo
796 : } // exists
797 0 : const int status = ::mkfifo(m_full_name.c_str(),perm);
798 0 : if (status==0) {
799 0 : permissions(perm);
800 0 : return;
801 : }
802 0 : std::string message = "while creating FIFO " + m_full_name;
803 0 : throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "mkfifo", message.c_str() );
804 0 : } // makefifo
805 :
806 :
807 :
808 :
809 : /** Conversion into a input stream pointer
810 : * This actually creates a new input stream that reads from the file.
811 : * \return a dynamically allocated input stream
812 : * \exception ers::IOIssue if an error occurs or the file does not exist
813 : */
814 :
815 0 : std::istream* OksSystem::File::input() const {
816 0 : try {
817 0 : std::ifstream *stream = new std::ifstream(m_full_name.c_str());
818 0 : stream->exceptions(std::ios::failbit | std::ios::badbit);
819 0 : return stream;
820 0 : } catch (std::ios_base::failure &ex) {
821 0 : throw OksSystem::OpenFileIssue( ERS_HERE, errno, m_full_name.c_str(), ex );
822 0 : } // catch
823 : } // std::istream*
824 :
825 : /** Conversion into an output stream pointer
826 : * This actually creates a new output stream that writes to the file.
827 : * \return a dynamically allocated output stream
828 : * \param append is the file opened in append mode
829 : * \exception ers::IOIssue if an error occurs
830 : */
831 :
832 0 : std::ostream* OksSystem::File::output(bool append) const {
833 0 : try {
834 0 : std::ios::openmode mode = std::ios::out;
835 0 : if (append) {
836 0 : mode |= std::ios::app;
837 : }
838 0 : std::ofstream *stream = new std::ofstream(m_full_name.c_str(),mode);
839 0 : stream->exceptions(std::ios::failbit | std::ios::badbit);
840 0 : return stream;
841 0 : } catch (std::ios_base::failure &ex) {
842 0 : throw OksSystem::OpenFileIssue( ERS_HERE, errno, m_full_name.c_str(), ex );
843 0 : } // catch
844 : } // std::ostream*
845 :
846 : /** Stream a file object into a STL stream.
847 : * \param stream destination stream.
848 : * \param file the file to write
849 : * \return the stream passed as parameter
850 : */
851 :
852 0 : std::ostream& operator<<(std::ostream& stream, const OksSystem::File& file) {
853 0 : stream << OksSystem::File::FILE_PROTOCOL << ":/" << file.full_name();
854 0 : return stream;
855 : } // operator<<
856 :
857 0 : bool operator ==(const OksSystem::File &a, const OksSystem::File &b) throw() {
858 0 : return a.equals(b);
859 : } // operator ==
860 :
861 0 : bool operator !=(const OksSystem::File &a, const OksSystem::File &b) throw() {
862 0 : return ! a.equals(b);
863 : } // operator !=
864 :
865 :
866 :
867 :
868 :
|