"Fossies" - the Fresh Open Source Software Archive

Member "eucalyptus-4.4.2/util/euca_file.c" (4 Aug 2017, 33525 Bytes) of package /linux/misc/eucalyptus-4.4.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "euca_file.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.4.1_vs_4.4.2.

    1 // -*- mode: C; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-
    2 // vim: set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
    3 
    4 /*************************************************************************
    5  * Copyright 2009-2012 Eucalyptus Systems, Inc.
    6  *
    7  * This program is free software: you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; version 3 of the License.
   10  *
   11  * This program is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  * GNU General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU General Public License
   17  * along with this program.  If not, see http://www.gnu.org/licenses/.
   18  *
   19  * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
   20  * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
   21  * additional information or have any questions.
   22  *
   23  * This file may incorporate work covered under the following copyright
   24  * and permission notice:
   25  *
   26  *   Software License Agreement (BSD License)
   27  *
   28  *   Copyright (c) 2008, Regents of the University of California
   29  *   All rights reserved.
   30  *
   31  *   Redistribution and use of this software in source and binary forms,
   32  *   with or without modification, are permitted provided that the
   33  *   following conditions are met:
   34  *
   35  *     Redistributions of source code must retain the above copyright
   36  *     notice, this list of conditions and the following disclaimer.
   37  *
   38  *     Redistributions in binary form must reproduce the above copyright
   39  *     notice, this list of conditions and the following disclaimer
   40  *     in the documentation and/or other materials provided with the
   41  *     distribution.
   42  *
   43  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   44  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   45  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   46  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   47  *   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   48  *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   49  *   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   50  *   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   51  *   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   52  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   53  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   54  *   POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE
   55  *   THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL,
   56  *   COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE,
   57  *   AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
   58  *   IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA,
   59  *   SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY,
   60  *   WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION,
   61  *   REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO
   62  *   IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT
   63  *   NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS.
   64  ************************************************************************/
   65 
   66 //!
   67 //! @file util/euca_file.h
   68 //! This file implements the various file and directory utility functions
   69 //!
   70 
   71 /*----------------------------------------------------------------------------*\
   72  |                                                                            |
   73  |                                  INCLUDES                                  |
   74  |                                                                            |
   75 \*----------------------------------------------------------------------------*/
   76 
   77 #define _FILE_OFFSET_BITS 64           // so large-file support works on 32-bit systems
   78 #include <stdio.h>
   79 #include <stdlib.h>
   80 #define _GNU_SOURCE
   81 #include <string.h>                    // strlen, strcpy
   82 #include <ctype.h>                     // isspace
   83 #include <assert.h>
   84 #include <stdarg.h>
   85 #include <sys/types.h>
   86 #include <sys/stat.h>
   87 #include <sys/vfs.h>
   88 #include <unistd.h>
   89 #include <time.h>
   90 #include <math.h>                      // powf
   91 #include <fcntl.h>                     // open
   92 #include <utime.h>                     // utime
   93 #include <sys/wait.h>
   94 #include <pwd.h>
   95 #include <dirent.h>                    // opendir, etc
   96 #include <sys/errno.h>                 // errno
   97 #include <sys/time.h>                  // gettimeofday
   98 #include <limits.h>
   99 #include <sys/mman.h>                  // mmap
  100 #include <pthread.h>
  101 
  102 #include "eucalyptus.h"
  103 
  104 #include <diskutil.h>
  105 
  106 #include "misc.h"
  107 #include "euca_string.h"
  108 #include "euca_file.h"
  109 
  110 /*----------------------------------------------------------------------------*\
  111  |                                                                            |
  112  |                                  DEFINES                                   |
  113  |                                                                            |
  114 \*----------------------------------------------------------------------------*/
  115 
  116 #define BUFSIZE                                  1024
  117 
  118 /*----------------------------------------------------------------------------*\
  119  |                                                                            |
  120  |                                  TYPEDEFS                                  |
  121  |                                                                            |
  122 \*----------------------------------------------------------------------------*/
  123 
  124 /*----------------------------------------------------------------------------*\
  125  |                                                                            |
  126  |                                ENUMERATIONS                                |
  127  |                                                                            |
  128 \*----------------------------------------------------------------------------*/
  129 
  130 /*----------------------------------------------------------------------------*\
  131  |                                                                            |
  132  |                                 STRUCTURES                                 |
  133  |                                                                            |
  134 \*----------------------------------------------------------------------------*/
  135 
  136 /*----------------------------------------------------------------------------*\
  137  |                                                                            |
  138  |                             EXTERNAL VARIABLES                             |
  139  |                                                                            |
  140 \*----------------------------------------------------------------------------*/
  141 
  142 /* Should preferably be handled in header file */
  143 
  144 /*----------------------------------------------------------------------------*\
  145  |                                                                            |
  146  |                              GLOBAL VARIABLES                              |
  147  |                                                                            |
  148 \*----------------------------------------------------------------------------*/
  149 
  150 /*----------------------------------------------------------------------------*\
  151  |                                                                            |
  152  |                              STATIC VARIABLES                              |
  153  |                                                                            |
  154 \*----------------------------------------------------------------------------*/
  155 
  156 /*----------------------------------------------------------------------------*\
  157  |                                                                            |
  158  |                              STATIC PROTOTYPES                             |
  159  |                                                                            |
  160 \*----------------------------------------------------------------------------*/
  161 
  162 /*----------------------------------------------------------------------------*\
  163  |                                                                            |
  164  |                                   MACROS                                   |
  165  |                                                                            |
  166 \*----------------------------------------------------------------------------*/
  167 
  168 /*----------------------------------------------------------------------------*\
  169  |                                                                            |
  170  |                               IMPLEMENTATION                               |
  171  |                                                                            |
  172 \*----------------------------------------------------------------------------*/
  173 
  174 //!
  175 //! Remove a directory given by the psPath string pointer. If the 'force' parameter
  176 //! is set to TRUE, the directory will be emptied and deleted. If the 'force'
  177 //! parameter is set to FALSE then this is the equivalent of an 'rmdir()' system
  178 //! calls which will not delete a non-empty directory.
  179 //!
  180 //! @param[in] psPath a constant pointer to the string containing the path to the directory to remove.
  181 //! @param[in] force set to TRUE, will force remove a non-empty directory
  182 //!
  183 //! @return EUCA_OK on success or the following error code:
  184 //!         EUCA_INVALID_ERROR if any of our pre-conditions are not met
  185 //!         EUCA_SYSTEM_ERROR if the system fails to remove a file or directory in the process
  186 //!         EUCA_MEMORY_ERROR if we fail to allocate memory during the process
  187 //!
  188 //! @see
  189 //!
  190 //! @pre \li psPath must not be NULL
  191 //!      \li psPath must be a valid path to a directory
  192 //!      \li if force is set to FALSE, the directory should be empty
  193 //!
  194 //! @post \li on success, the directory will be removed
  195 //!       \li on failure, the directory may remain with some content
  196 //!
  197 //! @note
  198 //!
  199 int euca_rmdir(const char *psPath, boolean force)
  200 {
  201     int result = EUCA_OK;
  202     char *psBuf = NULL;
  203     DIR *pDir = NULL;
  204     size_t len = 0;
  205     size_t pathLen = 0;
  206     struct dirent *pDirEnt = NULL;
  207     struct stat statbuf = { 0 };
  208 
  209     // Make sure we have a path
  210     if (psPath == NULL) {
  211         return (EUCA_INVALID_ERROR);
  212     }
  213     // If force was set, read the directory and empty it
  214     if (force) {
  215         // Retrieve the length of our directory path
  216         pathLen = strlen(psPath);
  217 
  218         // Open the directory and start scanning for items
  219         if ((pDir = opendir(psPath)) != NULL) {
  220             while ((result == EUCA_OK) && ((pDirEnt = readdir(pDir)) != NULL)) {
  221                 // Skip the names "." and ".." as we don't want to recurse on them.
  222                 if (!strcmp(pDirEnt->d_name, ".") || !strcmp(pDirEnt->d_name, "..")) {
  223                     continue;
  224                 }
  225 
  226                 len = pathLen + strlen(pDirEnt->d_name) + 2;
  227                 if ((psBuf = EUCA_ALLOC(len, sizeof(char))) != NULL) {
  228 
  229                     snprintf(psBuf, len, "%s/%s", psPath, pDirEnt->d_name);
  230 
  231                     if (stat(psBuf, &statbuf) == 0) {
  232                         if (S_ISDIR(statbuf.st_mode)) {
  233                             result = euca_rmdir(psBuf, TRUE);
  234                         } else {
  235                             if (unlink(psBuf) != 0) {
  236                                 result = EUCA_SYSTEM_ERROR;
  237                             }
  238                         }
  239                     }
  240 
  241                     EUCA_FREE(psBuf);
  242                 } else {
  243                     // Memory failure
  244                     result = EUCA_MEMORY_ERROR;
  245                 }
  246             }
  247 
  248             closedir(pDir);
  249         } else {
  250             // return the proper error
  251             if (errno == ENOTDIR)
  252                 return (EUCA_INVALID_ERROR);
  253             return (EUCA_SYSTEM_ERROR);
  254         }
  255     }
  256     // If we were successful so far, remove the directory
  257     if (result == EUCA_OK) {
  258         if (rmdir(psPath) != 0) {
  259             // Set the proper return error
  260             if (errno == ENOTDIR)
  261                 return (EUCA_INVALID_ERROR);
  262             return (EUCA_SYSTEM_ERROR);
  263         }
  264     }
  265 
  266     return (result);
  267 }
  268 
  269 //!
  270 //! Sanitize a path string and make sure it does not contains any illegal characters
  271 //!
  272 //! @param[in] psPath a pointer to a string containing the path to sanitize
  273 //!
  274 //! @return EUCA_OK if the path is a valid string and EUCA_ERROR if its not. If NULL is passed
  275 //!         this function will return EUCA_INVALID_ERROR.
  276 //!
  277 //! @note a valid path should not contain any of the following characters: !@#$%^&*(...
  278 //!
  279 int euca_sanitize_path(const char *psPath)
  280 {
  281     static char sOkChar[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890/._-:";
  282 
  283     // Check if we have a path provided
  284     if (psPath) {
  285         // Does the path contains only legal characters?
  286         if (strlen(psPath) != strspn(psPath, sOkChar))
  287             return (EUCA_ERROR);
  288         return (EUCA_OK);
  289     }
  290     return (EUCA_INVALID_ERROR);
  291 }
  292 
  293 //!
  294 //! make sure 'dir' is a directory or a soft-link to one
  295 //! and that it is readable by the current user (1 on error)
  296 //!
  297 //! @param[in] dir the directory name to validate
  298 //!
  299 //! @return 0 if dir is a directory or 1 if not
  300 //!
  301 //! @pre The dir field must not be NULL
  302 //!
  303 int check_directory(const char *dir)
  304 {
  305     int rc = 0;
  306     DIR *d = NULL;
  307     char checked_dir[EUCA_MAX_PATH] = "";
  308     struct stat mystat = { 0 };
  309 
  310     if (!dir) {
  311         return (1);
  312     }
  313 
  314     snprintf(checked_dir, sizeof(checked_dir), "%s", dir);
  315 
  316     if ((rc = lstat(checked_dir, &mystat)) < 0)
  317         return (1);
  318 
  319     // if a soft link, append '/' and try lstat() again
  320     if (!S_ISDIR(mystat.st_mode) && S_ISLNK(mystat.st_mode)) {
  321         snprintf(checked_dir, sizeof(checked_dir), "%s/", dir);
  322         if ((rc = lstat(checked_dir, &mystat)) < 0)
  323             return (1);
  324     }
  325 
  326     if (!S_ISDIR(mystat.st_mode))
  327         return (1);
  328 
  329     if ((d = opendir(checked_dir)) == NULL)
  330         return (1);
  331 
  332     closedir(d);
  333     return (0);
  334 }
  335 
  336 //!
  337 //! Check if a file is newer than the given timestamp
  338 //!
  339 //! @param[in] file the file name string
  340 //! @param[in] mtime the timestamp to compare with
  341 //!
  342 //! @return 0 if the file is newer than timestamp or 1 if not
  343 //!
  344 int check_file_newer_than(const char *file, time_t mtime)
  345 {
  346     int rc = 0;
  347     struct stat mystat = { 0 };
  348 
  349     if (!file) {
  350         return (1);
  351     } else if (mtime <= 0) {
  352         return (0);
  353     }
  354 
  355     bzero(&mystat, sizeof(struct stat));
  356     if ((rc = stat(file, &mystat)) != 0) {
  357         return (1);
  358     }
  359 
  360     if (mystat.st_mtime > mtime) {
  361         return (0);
  362     }
  363 
  364     return (1);
  365 }
  366 
  367 //!
  368 //!
  369 //!
  370 //! @param[in] file
  371 //!
  372 //! @return 0 on success or 1 on failure
  373 //!
  374 int check_block(const char *file)
  375 {
  376     int rc = 0;
  377     char *rpath = NULL;
  378     struct stat mystat = { 0 };
  379 
  380     if (!file) {
  381         LOGERROR("Invalid file name");
  382         return (1);
  383     }
  384 
  385     if ((rpath = realpath(file, NULL)) == NULL) {
  386         LOGERROR("No canonical file found for %s", file);
  387         return (1);
  388     }
  389 
  390     rc = lstat(rpath, &mystat);
  391     EUCA_FREE(rpath);
  392     if ((rc < 0) || !S_ISBLK(mystat.st_mode)) {
  393         LOGERROR("No stat information found for %s", rpath);
  394         return (1);
  395     }
  396 
  397     return (0);
  398 }
  399 
  400 //!
  401 //! Checks if a file is a readable regular file.
  402 //!
  403 //! @param[in] file
  404 //!
  405 //! @return 0 if the file is readable, 1 otherwise
  406 //!
  407 //! @pre The file field must not be NULL.
  408 //!
  409 int check_file(const char *file)
  410 {
  411     int rc = 0;
  412     struct stat mystat = { 0 };
  413 
  414     if (!file) {
  415         return (1);
  416     }
  417 
  418     rc = lstat(file, &mystat);
  419     if ((rc < 0) || !S_ISREG(mystat.st_mode)) {
  420         return (1);
  421     }
  422 
  423     return (0);
  424 }
  425 
  426 //!
  427 //! Check if a path exists
  428 //!
  429 //! @param[in] path
  430 //!
  431 //! @return 0 if the path exists, othewise 1 is returned.
  432 //!
  433 int check_path(const char *path)
  434 {
  435     int rc = 0;
  436     struct stat mystat = { 0 };
  437 
  438     if (!path) {
  439         return (1);
  440     }
  441 
  442     if ((rc = lstat(path, &mystat)) < 0) {
  443         return (1);
  444     }
  445 
  446     return (0);
  447 }
  448 
  449 //!
  450 //! obtains size & available bytes of a file system that 'path' resides on
  451 //! path may be a symbolic link, which will get resolved.
  452 //!
  453 //! @param[in]  path
  454 //! @param[out] fs_bytes_size
  455 //! @param[out] fs_bytes_available
  456 //! @param[out] fs_id
  457 //!
  458 //! @return EUCA_OK on success or the following error code.
  459 //!         \li EUCA_INVALID_ERROR
  460 //!         \li EUCA_IO_ERROR
  461 //!
  462 //! @pre \li The path, fs_bytes_size, fs_bytes_available and fs_id fields must not be NULL.
  463 //!      \li The path field must be a valid path.
  464 //!
  465 //! @post The fs_id, fs_bytes_size and fs_bytes_available fields are set appropriately.
  466 //!
  467 int statfs_path(const char *path, unsigned long long *fs_bytes_size, unsigned long long *fs_bytes_available, int *fs_id)
  468 {
  469     char cpath[PATH_MAX] = { 0 };
  470     struct statfs fs = { 0 };
  471 
  472     if ((path == NULL) || (fs_bytes_size == NULL) || (fs_bytes_available == NULL) || (fs_id == NULL))
  473         return (EUCA_INVALID_ERROR);
  474 
  475     errno = 0;
  476 
  477     // will convert a path with symbolic links and '..' into canonical form
  478     if (realpath(path, cpath) == NULL) {
  479         LOGERROR("failed to resolve %s (%s)\n", path, strerror(errno));
  480         return (EUCA_IO_ERROR);
  481     }
  482     // obtain the size and ID info from the file system of the canonical path
  483     if (statfs(cpath, &fs) == -1) {
  484         LOGERROR("failed to stat %s (%s)\n", cpath, strerror(errno));
  485         return (EUCA_IO_ERROR);
  486     }
  487 
  488     *fs_id = hash_code_bin((char *)&fs.f_fsid, sizeof(fsid_t));
  489     *fs_bytes_size = (long long)fs.f_bsize * (long long)(fs.f_blocks);
  490     *fs_bytes_available = (long long)fs.f_bsize * (long long)(fs.f_bavail);
  491 
  492     LOGDEBUG("path '%s' resolved\n", path);
  493     LOGDEBUG("  to '%s' with ID %0x\n", cpath, *fs_id);
  494     LOGDEBUG("  of size %llu bytes with available %llu bytes\n", *fs_bytes_size, *fs_bytes_available);
  495 
  496     return (EUCA_OK);
  497 }
  498 
  499 //!
  500 //!
  501 //!
  502 //! @param[in] fp
  503 //!
  504 //! @return a pointer to the file output string
  505 //!
  506 //! @pre \li The fp field MUST not be NULL.
  507 //!      \li The file handles must have previously been opened.
  508 //!
  509 //! @post The file remains open regardless of the result.
  510 //!
  511 //! @note caller is responsible to free the returned memory
  512 //!
  513 char *fp2str(FILE * fp)
  514 {
  515 #define INCREMENT              512
  516 
  517     int buf_max = INCREMENT;
  518     int buf_current = 0;
  519     void *new_buf = NULL;
  520     char *last_read = NULL;
  521     char *buf = NULL;
  522 
  523     if (fp == NULL)
  524         return (NULL);
  525 
  526     do {
  527         // create/enlarge the buffer
  528         if ((new_buf = EUCA_REALLOC(buf, buf_max, sizeof(char))) == NULL) {
  529             // free partial buffer
  530             EUCA_FREE(buf);
  531             return (NULL);
  532         }
  533 
  534         memset((new_buf + buf_current), 0, (INCREMENT * sizeof(char)));
  535 
  536         buf = new_buf;
  537         LOGEXTREME("enlarged buf to %d\n", buf_max);
  538 
  539         do {                           // read in until EOF or buffer is full
  540             last_read = fgets(buf + buf_current, buf_max - buf_current, fp);
  541             if (last_read != NULL) {
  542                 buf_current = strlen(buf);
  543             } else if (!feof(fp)) {
  544                 LOGERROR("failed while reading from file handle\n");
  545                 EUCA_FREE(buf);
  546                 return (NULL);
  547             }
  548 
  549             LOGEXTREME("read %d characters so far (max=%d, last=%s)\n", buf_current, buf_max, last_read ? "no" : "yes");
  550         } while (last_read && (buf_max > (buf_current + 1)));   // +1 is needed for fgets() to put \0
  551 
  552         // in case it is full
  553         buf_max += INCREMENT;
  554     } while (last_read);
  555 
  556     return (buf);
  557 
  558 #undef INCREMENT
  559 }
  560 
  561 //!
  562 //! given a file path, prints it to stdout
  563 //!
  564 //! @param[in] file_name
  565 //!
  566 //! @return the number of bytes written to stdout
  567 //!
  568 int cat(const char *file_name)
  569 {
  570     int fd = 0;
  571     int got = 0;
  572     int put = 0;
  573     char buf[BUFSIZE] = "";
  574 
  575     if ((fd = open(file_name, O_RDONLY)) == -1) {
  576         // we should print some error
  577         return (put);
  578     }
  579 
  580     while ((got = read(fd, buf, BUFSIZE)) > 0) {
  581         put += write(1, buf, got);
  582     }
  583 
  584     close(fd);
  585     return (put);
  586 }
  587 
  588 //!
  589 //! "touch" a file, creating if necessary
  590 //!
  591 //! @param[in] path
  592 //!
  593 //! @return EUCA_OK on success or EUCA_IO_ERROR on failure
  594 //!
  595 int touch(const char *path)
  596 {
  597     int ret = EUCA_OK;
  598     int fd = -1;
  599 
  600     if ((fd = open(path, O_WRONLY | O_CREAT | O_NONBLOCK, 0644)) >= 0) {
  601         close(fd);
  602         if (utime(path, NULL) != 0) {
  603             LOGERROR("failed to adjust time for %s (%s)\n", path, strerror(errno));
  604             ret = EUCA_IO_ERROR;
  605         }
  606     } else {
  607         LOGERROR("failed to create/open file %s (%s)\n", path, strerror(errno));
  608         ret = EUCA_IO_ERROR;
  609     }
  610     return (ret);
  611 }
  612 
  613 //!
  614 //! diffs two files: 0=same, -N=different, N=error
  615 //!
  616 //! @param[in] path1
  617 //! @param[in] path2
  618 //!
  619 //! @return 0=same, -N=different, N=error
  620 //!
  621 int diff(const char *path1, const char *path2)
  622 {
  623     int fd1 = 0;
  624     int fd2 = 0;
  625     int read1 = 0;
  626     int read2 = 0;
  627     char buf1[BUFSIZE] = "";
  628     char buf2[BUFSIZE] = "";
  629 
  630     if ((fd1 = open(path1, O_RDONLY)) < 0) {
  631         LOGERROR("failed to open %s\n", path1);
  632     } else if ((fd2 = open(path2, O_RDONLY)) < 0) {
  633         LOGERROR("failed to open %s\n", path2);
  634         close(fd1);
  635     } else {
  636         do {
  637             read1 = read(fd1, buf1, BUFSIZE);
  638             read2 = read(fd2, buf2, BUFSIZE);
  639             if (read1 != read2)
  640                 break;
  641 
  642             if (read1 && memcmp(buf1, buf2, read1))
  643                 break;
  644         } while (read1);
  645 
  646         close(fd1);
  647         close(fd2);
  648         return (-(read1 + read2));     // both should be 0s if files are equal
  649     }
  650     return EUCA_ERROR;
  651 }
  652 
  653 //!
  654 //! sums up sizes of files in the directory, as well as the size of the
  655 //! directory itself; no subdirectories are allowed - if there are any, this
  656 //! returns -1
  657 //!
  658 //! @param[in] path
  659 //!
  660 //! @return the sommation of all file size in a directory
  661 //!
  662 long long dir_size(const char *path)
  663 {
  664     DIR *dir = NULL;
  665     char *name = NULL;
  666     char filepath[EUCA_MAX_PATH] = "";
  667     unsigned char type = '\0';
  668     long long size = 0;
  669     struct stat mystat = { 0 };
  670     struct dirent *dir_entry = NULL;
  671 
  672     if ((dir = opendir(path)) == NULL) {
  673         LOGWARN("unopeneable directory %s\n", path);
  674         return (-1);
  675     }
  676 
  677     if (stat(path, &mystat) < 0) {
  678         LOGWARN("could not stat %s\n", path);
  679         closedir(dir);
  680         return (-1);
  681     }
  682 
  683     size += ((long long)mystat.st_size);
  684 
  685     while ((dir_entry = readdir(dir)) != NULL) {
  686         name = dir_entry->d_name;
  687         type = dir_entry->d_type;
  688 
  689         if (!strcmp(".", name) || !strcmp("..", name))
  690             continue;
  691 
  692         if (DT_REG != type) {
  693             LOGWARN("non-regular (type=%d) file %s/%s\n", type, path, name);
  694             size = -1;
  695             break;
  696         }
  697 
  698         snprintf(filepath, EUCA_MAX_PATH, "%s/%s", path, name);
  699         if (stat(filepath, &mystat) < 0) {
  700             LOGWARN("could not stat file %s\n", filepath);
  701             size = -1;
  702             break;
  703         }
  704 
  705         size += ((long long)mystat.st_size);
  706     }
  707 
  708     closedir(dir);
  709     return (size);
  710 }
  711 
  712 //!
  713 //!
  714 //!
  715 //! @param[in] path
  716 //! @param[in] str
  717 //!
  718 //! @return EUCA_OK on success or EUCA_IO_ERROR on failure
  719 //!
  720 int write2file(const char *path, char *str)
  721 {
  722     FILE *FH = NULL;
  723 
  724     if ((FH = fopen(path, "w")) != NULL) {
  725         fprintf(FH, "%s", str);
  726         fclose(FH);
  727         return (EUCA_OK);
  728     }
  729 
  730     return (EUCA_IO_ERROR);
  731 }
  732 
  733 //!
  734 //!
  735 //!
  736 //! @param[in] path
  737 //! @param[in] limit
  738 //!
  739 //! @return the result of teh file2str() call
  740 //!
  741 //! @see file2str()
  742 //!
  743 //! @note the caller must free the memory when done.
  744 //!
  745 char *file2strn(const char *path, const ssize_t limit)
  746 {
  747     struct stat mystat = { 0 };
  748 
  749     if (stat(path, &mystat) < 0) {
  750         LOGERROR("could not stat file %s\n", path);
  751         return (NULL);
  752     }
  753 
  754     if (mystat.st_size > limit) {
  755         LOGERROR("file %s exceeds the limit (%lu) in file2strn()\n", path, limit);
  756         return (NULL);
  757     }
  758 
  759     return (file2str(path));
  760 }
  761 
  762 //!
  763 //! read file 'path' into a new string
  764 //!
  765 //! @param[in] path
  766 //!
  767 //! @return the string content of the given file
  768 //!
  769 //! @note the caller must free the memory when done.
  770 //!
  771 char *file2str(const char *path)
  772 {
  773     int fp = 0;
  774     int bytes = 0;
  775     int bytes_total = 0;
  776     int to_read = 0;
  777     char *p = NULL;
  778     char *content = NULL;
  779     off_t file_size = 0;
  780     struct stat mystat = { 0 };
  781 
  782     if (stat(path, &mystat) < 0) {
  783         LOGERROR("errno: %d could not stat file %s\n", errno, path);
  784         return (content);
  785     }
  786 
  787     file_size = mystat.st_size;
  788 
  789     if ((content = EUCA_ALLOC((file_size + 1), sizeof(char))) == NULL) {
  790         LOGERROR("out of memory reading file %s\n", path);
  791         return (content);
  792     }
  793 
  794     if ((fp = open(path, O_RDONLY)) < 0) {
  795         LOGERROR("errno: %d failed to open file %s\n", errno, path);
  796         EUCA_FREE(content);
  797         return (content);
  798     }
  799 
  800     p = content;
  801     to_read = (((SSIZE_MAX) < file_size) ? (SSIZE_MAX) : file_size);
  802     while ((bytes = read(fp, p, to_read)) > 0) {
  803         bytes_total += bytes;
  804         p += bytes;
  805         if (to_read > (file_size - bytes_total)) {
  806             to_read = file_size - bytes_total;
  807         }
  808     }
  809 
  810     close(fp);
  811 
  812     if (bytes < 0) {
  813         LOGERROR("failed to read file %s\n", path);
  814         EUCA_FREE(content);
  815         return (content);
  816     }
  817 
  818     *p = '\0';
  819     return (content);
  820 }
  821 
  822 //!
  823 //!
  824 //!
  825 //! @param[in] file
  826 //! @param[in] size
  827 //! @param[in] mode
  828 //!
  829 //! @return the newly allocated string or NULL if any error occured
  830 //!
  831 //! @note caller is responsible to free the allocated memory
  832 //!
  833 char *file2str_seek(char *file, size_t size, int mode)
  834 {
  835     int rc = 0;
  836     int fd = 0;
  837     char *ret = NULL;
  838     struct stat statbuf = { 0 };
  839 
  840     if (!file || size <= 0) {
  841         LOGERROR("bad input parameters\n");
  842         return (NULL);
  843     }
  844 
  845     if ((ret = EUCA_ZALLOC(size, sizeof(char))) == NULL) {
  846         LOGERROR("out of memory!\n");
  847         return (NULL);
  848     }
  849 
  850     if ((rc = stat(file, &statbuf)) >= 0) {
  851         if ((fd = open(file, O_RDONLY)) >= 0) {
  852             if (mode == 1) {
  853                 if ((rc = lseek(fd, (off_t) (-1 * size), SEEK_END)) < 0) {
  854                     if ((rc = lseek(fd, (off_t) 0, SEEK_SET)) < 0) {
  855                         LOGERROR("cannot seek\n");
  856                         EUCA_FREE(ret);
  857                         close(fd);
  858                         return (NULL);
  859                     }
  860                 }
  861             }
  862 
  863             rc = read(fd, ret, (size) - 1);
  864             close(fd);
  865         } else {
  866             LOGERROR("cannot open '%s' read-only\n", file);
  867             EUCA_FREE(ret);
  868             return (NULL);
  869         }
  870     } else {
  871         LOGERROR("cannot stat console_output file '%s'\n", file);
  872         EUCA_FREE(ret);
  873         return (NULL);
  874     }
  875 
  876     return (ret);
  877 }
  878 
  879 //!
  880 //! Write a NULL-terminated string to a file according to a file
  881 //! specification. If 'mktemp' is TRUE, 'path' is expected to be
  882 //! not a file path, but a template for a temporary file name,
  883 //! according to the mkstemp() specification, with six X's in it.
  884 //! Otherwise, 'path' is the path of the file to create and write
  885 //! the string to.
  886 //!
  887 //! @param[in] str String to write to a file.
  888 //! @param[in] path Path of the file to create or mktemp spec.
  889 //! @param[in] flags Same flags as accepted by open() call. Ignored when mktemp is TRUE.
  890 //! @param[in] mode Permissions of the file to create.
  891 //! @param[in] mktemp Flag requesting a temporary file.
  892 //!
  893 //! @return EUCA_OK on success and -1 on failure.
  894 //!
  895 int str2file(const char *str, char *path, int flags, mode_t mode, boolean mktemp)
  896 {
  897     if (path == NULL)
  898         return 1;
  899 
  900     int fd;
  901 
  902     // if temporary file was requested, assume that the path is actually
  903     // a template for mkstemp(), with 6 X's in it, and that it is to be
  904     // overwritten with the actual file path
  905     if (mktemp) {
  906         fd = safe_mkstemp(path);
  907         if (fd < 0) {
  908             LOGERROR("cannot create temporary file '%s': %s\n", path, strerror(errno));
  909             return (-1);
  910         }
  911         if (fchmod(fd, mode)) {
  912             LOGERROR("failed to change permissions on '%s': %s\n", path, strerror(errno));
  913             close(fd);
  914             return (-1);
  915         }
  916     } else {
  917         fd = open(path, flags, mode);
  918         if (fd == -1) {
  919             LOGERROR("failed to create file '%s': %s\n", path, strerror(errno));
  920             return (-1);
  921         }
  922     }
  923 
  924     if (str) {
  925         int to_write = strlen(str);
  926         int offset = 0;
  927         while (to_write > 0) {
  928             int wrote = write(fd, str + offset, to_write);
  929             if (wrote == -1) {
  930                 LOGERROR("failed to write to file '%s': %s\n", path, strerror(errno));
  931                 close(fd);
  932                 return (-1);
  933             }
  934             to_write -= wrote;
  935             offset += wrote;
  936         }
  937     }
  938     close(fd);
  939 
  940     return (EUCA_OK);
  941 }
  942 
  943 //!
  944 //! copies contents of src to dst, possibly overwriting whatever is in dst
  945 //!
  946 //! @param[in] src
  947 //! @param[in] dst
  948 //!
  949 //! @return EUCA_OK on success or EUCA_IO_ERROR on failure
  950 //!
  951 int copy_file(const char *src, const char *dst)
  952 {
  953 #define _BUFSIZE          16384
  954 
  955     int ret = EUCA_OK;
  956     int ifp = 0;
  957     int ofp = 0;
  958     char buf[_BUFSIZE] = "";
  959     ssize_t bytes = 0;
  960     struct stat mystat = { 0 };
  961 
  962     if (stat(src, &mystat) < 0) {
  963         LOGERROR("cannot stat '%s'\n", src);
  964         return (EUCA_IO_ERROR);
  965     }
  966 
  967     if ((ifp = open(src, O_RDONLY)) < 0) {
  968         LOGERROR("failed to open the input file '%s'\n", src);
  969         return (EUCA_IO_ERROR);
  970     }
  971 
  972     if ((ofp = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
  973         LOGERROR("failed to create the ouput file '%s'\n", dst);
  974         close(ifp);
  975         return (EUCA_IO_ERROR);
  976     }
  977 
  978     while ((bytes = read(ifp, buf, _BUFSIZE)) > 0) {
  979         if (write(ofp, buf, bytes) < 1) {
  980             LOGERROR("failed while writing to '%s'\n", dst);
  981             ret = EUCA_IO_ERROR;
  982             break;
  983         }
  984     }
  985 
  986     if (bytes < 0) {
  987         LOGERROR("failed while writing to '%s'\n", dst);
  988         ret = EUCA_IO_ERROR;
  989     }
  990 
  991     close(ifp);
  992     close(ofp);
  993 
  994     return (ret);
  995 
  996 #undef _BUFSIZE
  997 }
  998 
  999 //!
 1000 //!
 1001 //!
 1002 //! @param[in] file_path
 1003 //!
 1004 //! @return the size of the file
 1005 //!
 1006 long long file_size(const char *file_path)
 1007 {
 1008     int err = 0;
 1009     struct stat mystat = { 0 };
 1010 
 1011     if ((err = stat(file_path, &mystat)) < 0)
 1012         return ((long long)err);
 1013     return ((long long)mystat.st_size);
 1014 }
 1015 
 1016 //! Removes duplicate '/' in paths in-place.
 1017 //!
 1018 //! @param[in] path to modify in-place
 1019 //!
 1020 void dedup_path(char *path)
 1021 {
 1022     int i = 0;
 1023     int j = 0;
 1024     int src_len;
 1025     int duplicate_detected = 0;
 1026 
 1027     if (path == NULL) {
 1028         return;
 1029     }
 1030 
 1031     src_len = strlen(path);
 1032     if (src_len <= 1) {
 1033         return;
 1034     }
 1035     //Include copying the null terminator
 1036     for (i = 1, j = 0; i < src_len + 1; i++) {
 1037         if (duplicate_detected && path[i] != '/') {
 1038             duplicate_detected = 0;
 1039         } else if (path[j] == '/' && path[i] == '/') {
 1040             duplicate_detected = 1;
 1041         }
 1042 
 1043         if (!duplicate_detected) {
 1044             path[++j] = path[i];
 1045         }
 1046     }
 1047     return;
 1048 }
 1049 
 1050 //!
 1051 //! given path=A/B/C and only A existing, create A/B and, unless
 1052 //! is_file_path==1, also create A/B/C directory
 1053 //!
 1054 //! @param[in] path
 1055 //! @param[in] is_file_path
 1056 //! @param[in] user
 1057 //! @param[in] group
 1058 //! @param[in] mode
 1059 //!
 1060 //! @return 0 = path already existed, 1 = created OK, -1 = error
 1061 //!
 1062 int ensure_directories_exist(const char *path, int is_file_path, const char *user, const char *group, mode_t mode)
 1063 {
 1064     int ret = 0;
 1065     int i = 0;
 1066     int len = strlen(path);
 1067     int try_dir = 0;
 1068     char *path_copy = NULL;
 1069     struct stat buf = { 0 };
 1070 
 1071     if (len > 0)
 1072         path_copy = strdup(path);
 1073 
 1074     if (path_copy == NULL)
 1075         return (-1);
 1076 
 1077     for (i = 0; i < len; i++) {
 1078         try_dir = 0;
 1079 
 1080         if ((path[i] == '/') && (i > 0)) {
 1081             // dir path, not root
 1082             path_copy[i] = '\0';
 1083             try_dir = 1;
 1084 
 1085         } else if ((path[i] != '/') && ((i + 1) == len)) {
 1086             // last one
 1087             if (!is_file_path)
 1088                 try_dir = 1;
 1089         }
 1090 
 1091         if (try_dir) {
 1092             if (stat(path_copy, &buf) == -1) {
 1093                 LOGINFO("creating path %s\n", path_copy);
 1094 
 1095                 if (mkdir(path_copy, mode) == -1) {
 1096                     LOGERROR("failed to create path %s: %s\n", path_copy, strerror(errno));
 1097 
 1098                     EUCA_FREE(path_copy);
 1099                     return (-1);
 1100                 }
 1101 
 1102                 ret = 1;               // we created a directory
 1103 
 1104                 if (diskutil_ch(path_copy, user, group, mode) != EUCA_OK) {
 1105                     LOGERROR("failed to change perms on path %s\n", path_copy);
 1106                     EUCA_FREE(path_copy);
 1107                     return (-1);
 1108                 }
 1109             }
 1110 
 1111             path_copy[i] = '/';        // restore the slash
 1112         }
 1113     }
 1114 
 1115     EUCA_FREE(path_copy);
 1116     return (ret);
 1117 }
 1118 
 1119 //!
 1120 //! ensure the temp file is only readable by the user
 1121 //!
 1122 //! @param[in] template
 1123 //!
 1124 //! @return -1 on failure or the corresponding files descriptor for the temp file
 1125 //!
 1126 int safe_mkstemp(char *template)
 1127 {
 1128     int ret = 0;
 1129     ret = mkstemp(template);
 1130     return (ret);
 1131 }