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