blob: 97500d103ecc4cb17c651d1988cc94f660ef9171 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/util/file.h"
Brian Silverman61175fb2016-03-13 15:35:56 -04002
3#include <fcntl.h>
Austin Schuhe991fe22020-11-18 16:53:39 -08004#include <fts.h>
Austin Schuhfccb2d02020-01-26 16:11:19 -08005#include <sys/stat.h>
6#include <sys/types.h>
Brian Silverman61175fb2016-03-13 15:35:56 -04007#include <unistd.h>
8
James Kuszmaul3ae42262019-11-08 12:33:41 -08009#include <string_view>
10
John Park33858a32018-09-28 23:05:48 -070011#include "aos/scoped/scoped_fd.h"
Brian Silverman61175fb2016-03-13 15:35:56 -040012
13namespace aos {
14namespace util {
15
James Kuszmaul3ae42262019-11-08 12:33:41 -080016::std::string ReadFileToStringOrDie(const std::string_view filename) {
Brian Silverman61175fb2016-03-13 15:35:56 -040017 ::std::string r;
Austin Schuhcb108412019-10-13 16:09:54 -070018 ScopedFD fd(open(::std::string(filename).c_str(), O_RDONLY));
Alex Perrycb7da4b2019-08-28 19:35:56 -070019 PCHECK(fd.get() != -1) << ": opening " << filename;
Brian Silverman61175fb2016-03-13 15:35:56 -040020 while (true) {
21 char buffer[1024];
22 const ssize_t result = read(fd.get(), buffer, sizeof(buffer));
Alex Perrycb7da4b2019-08-28 19:35:56 -070023 PCHECK(result >= 0) << ": reading from " << filename;
24 if (result == 0) {
Brian Silverman61175fb2016-03-13 15:35:56 -040025 break;
26 }
27 r.append(buffer, result);
28 }
29 return r;
30}
31
James Kuszmaul3ae42262019-11-08 12:33:41 -080032void WriteStringToFileOrDie(const std::string_view filename,
33 const std::string_view contents) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 ::std::string r;
35 ScopedFD fd(open(::std::string(filename).c_str(),
36 O_CREAT | O_WRONLY | O_TRUNC, S_IRWXU));
37 PCHECK(fd.get() != -1) << ": opening " << filename;
38 size_t size_written = 0;
39 while (size_written != contents.size()) {
40 const ssize_t result = write(fd.get(), contents.data() + size_written,
41 contents.size() - size_written);
42 PCHECK(result >= 0) << ": reading from " << filename;
43 if (result == 0) {
44 break;
45 }
46
47 size_written += result;
48 }
49}
50
Brian Silvermana9f2ec92020-10-06 18:00:53 -070051bool MkdirPIfSpace(std::string_view path, mode_t mode) {
Austin Schuhfccb2d02020-01-26 16:11:19 -080052 auto last_slash_pos = path.find_last_of("/");
53
54 std::string folder(last_slash_pos == std::string_view::npos
55 ? std::string_view("")
56 : path.substr(0, last_slash_pos));
Brian Silvermana9f2ec92020-10-06 18:00:53 -070057 if (folder.empty()) {
58 return true;
59 }
60 if (!MkdirPIfSpace(folder, mode)) {
61 return false;
62 }
Austin Schuhfccb2d02020-01-26 16:11:19 -080063 const int result = mkdir(folder.c_str(), mode);
64 if (result == -1 && errno == EEXIST) {
65 VLOG(2) << folder << " already exists";
Brian Silvermana9f2ec92020-10-06 18:00:53 -070066 return true;
67 } else if (result == -1 && errno == ENOSPC) {
68 VLOG(2) << "Out of space";
69 return false;
Austin Schuhfccb2d02020-01-26 16:11:19 -080070 } else {
71 VLOG(1) << "Created " << folder;
72 }
73 PCHECK(result == 0) << ": Error creating " << folder;
Brian Silvermana9f2ec92020-10-06 18:00:53 -070074 return true;
Austin Schuhfccb2d02020-01-26 16:11:19 -080075}
76
James Kuszmaulf8178092020-05-10 18:46:45 -070077bool PathExists(std::string_view path) {
78 struct stat buffer;
79 return stat(path.data(), &buffer) == 0;
80}
81
Austin Schuhe991fe22020-11-18 16:53:39 -080082void UnlinkRecursive(std::string_view path) {
83 FTS *ftsp = NULL;
84 FTSENT *curr;
85
86 // Cast needed (in C) because fts_open() takes a "char * const *", instead
87 // of a "const char * const *", which is only allowed in C++. fts_open()
88 // does not modify the argument.
89 std::string p(path);
90 char *files[] = {const_cast<char *>(p.c_str()), NULL};
91
92 // FTS_NOCHDIR - Avoid changing cwd, which could cause unexpected behavior
93 // in multithreaded programs
94 // FTS_PHYSICAL - Don't follow symlinks. Prevents deletion of files outside
95 // of the specified directory
96 // FTS_XDEV - Don't cross filesystem boundaries
97 ftsp = fts_open(files, FTS_NOCHDIR | FTS_PHYSICAL | FTS_XDEV, NULL);
98 if (!ftsp) {
99 return;
100 }
101
102 while ((curr = fts_read(ftsp))) {
103 switch (curr->fts_info) {
104 case FTS_NS:
105 case FTS_DNR:
106 case FTS_ERR:
107 LOG(WARNING) << "Can't read " << curr->fts_accpath;
108 break;
109
110 case FTS_DC:
111 case FTS_DOT:
112 case FTS_NSOK:
113 // Not reached unless FTS_LOGICAL, FTS_SEEDOT, or FTS_NOSTAT were
114 // passed to fts_open()
115 break;
116
117 case FTS_D:
118 // Do nothing. Need depth-first search, so directories are deleted
119 // in FTS_DP
120 break;
121
122 case FTS_DP:
123 case FTS_F:
124 case FTS_SL:
125 case FTS_SLNONE:
126 case FTS_DEFAULT:
127 VLOG(1) << "Removing " << curr->fts_path;
128 if (remove(curr->fts_accpath) < 0) {
129 LOG(WARNING) << curr->fts_path
130 << ": Failed to remove: " << strerror(curr->fts_errno);
131 }
132 break;
133 }
134 }
135
136 if (ftsp) {
137 fts_close(ftsp);
138 }
139}
140
Brian Silverman61175fb2016-03-13 15:35:56 -0400141} // namespace util
142} // namespace aos