Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "android-base/file.h"
     18 
     19 #include <errno.h>
     20 #include <fcntl.h>
     21 #include <sys/stat.h>
     22 #include <sys/types.h>
     23 
     24 #include <string>
     25 
     26 #include "android-base/macros.h"  // For TEMP_FAILURE_RETRY on Darwin.
     27 #include "android-base/utf8.h"
     28 #define LOG_TAG "base.file"
     29 #include "cutils/log.h"
     30 #include "utils/Compat.h"
     31 
     32 namespace android {
     33 namespace base {
     34 
     35 // Versions of standard library APIs that support UTF-8 strings.
     36 using namespace android::base::utf8;
     37 
     38 bool ReadFdToString(int fd, std::string* content) {
     39   content->clear();
     40 
     41   char buf[BUFSIZ];
     42   ssize_t n;
     43   while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
     44     content->append(buf, n);
     45   }
     46   return (n == 0) ? true : false;
     47 }
     48 
     49 bool ReadFileToString(const std::string& path, std::string* content) {
     50   content->clear();
     51 
     52   int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
     53   if (fd == -1) {
     54     return false;
     55   }
     56   bool result = ReadFdToString(fd, content);
     57   close(fd);
     58   return result;
     59 }
     60 
     61 bool WriteStringToFd(const std::string& content, int fd) {
     62   const char* p = content.data();
     63   size_t left = content.size();
     64   while (left > 0) {
     65     ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, left));
     66     if (n == -1) {
     67       return false;
     68     }
     69     p += n;
     70     left -= n;
     71   }
     72   return true;
     73 }
     74 
     75 static bool CleanUpAfterFailedWrite(const std::string& path) {
     76   // Something went wrong. Let's not leave a corrupt file lying around.
     77   int saved_errno = errno;
     78   unlink(path.c_str());
     79   errno = saved_errno;
     80   return false;
     81 }
     82 
     83 #if !defined(_WIN32)
     84 bool WriteStringToFile(const std::string& content, const std::string& path,
     85                        mode_t mode, uid_t owner, gid_t group) {
     86   int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
     87   int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
     88   if (fd == -1) {
     89     ALOGE("android::WriteStringToFile open failed: %s", strerror(errno));
     90     return false;
     91   }
     92 
     93   // We do an explicit fchmod here because we assume that the caller really
     94   // meant what they said and doesn't want the umask-influenced mode.
     95   if (fchmod(fd, mode) == -1) {
     96     ALOGE("android::WriteStringToFile fchmod failed: %s", strerror(errno));
     97     return CleanUpAfterFailedWrite(path);
     98   }
     99   if (fchown(fd, owner, group) == -1) {
    100     ALOGE("android::WriteStringToFile fchown failed: %s", strerror(errno));
    101     return CleanUpAfterFailedWrite(path);
    102   }
    103   if (!WriteStringToFd(content, fd)) {
    104     ALOGE("android::WriteStringToFile write failed: %s", strerror(errno));
    105     return CleanUpAfterFailedWrite(path);
    106   }
    107   close(fd);
    108   return true;
    109 }
    110 #endif
    111 
    112 bool WriteStringToFile(const std::string& content, const std::string& path) {
    113   int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
    114   int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, DEFFILEMODE));
    115   if (fd == -1) {
    116     return false;
    117   }
    118 
    119   bool result = WriteStringToFd(content, fd);
    120   close(fd);
    121   return result || CleanUpAfterFailedWrite(path);
    122 }
    123 
    124 bool ReadFully(int fd, void* data, size_t byte_count) {
    125   uint8_t* p = reinterpret_cast<uint8_t*>(data);
    126   size_t remaining = byte_count;
    127   while (remaining > 0) {
    128     ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining));
    129     if (n <= 0) return false;
    130     p += n;
    131     remaining -= n;
    132   }
    133   return true;
    134 }
    135 
    136 bool WriteFully(int fd, const void* data, size_t byte_count) {
    137   const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
    138   size_t remaining = byte_count;
    139   while (remaining > 0) {
    140     ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining));
    141     if (n == -1) return false;
    142     p += n;
    143     remaining -= n;
    144   }
    145   return true;
    146 }
    147 
    148 bool RemoveFileIfExists(const std::string& path, std::string* err) {
    149   struct stat st;
    150 #if defined(_WIN32)
    151   //TODO: Windows version can't handle symbol link correctly.
    152   int result = stat(path.c_str(), &st);
    153   bool file_type_removable = (result == 0 && S_ISREG(st.st_mode));
    154 #else
    155   int result = lstat(path.c_str(), &st);
    156   bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
    157 #endif
    158   if (result == 0) {
    159     if (!file_type_removable) {
    160       if (err != nullptr) {
    161         *err = "is not a regular or symbol link file";
    162       }
    163       return false;
    164     }
    165     if (unlink(path.c_str()) == -1) {
    166       if (err != nullptr) {
    167         *err = strerror(errno);
    168       }
    169       return false;
    170     }
    171   }
    172   return true;
    173 }
    174 
    175 }  // namespace base
    176 }  // namespace android
    177