• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2016 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 "util.h"
18  
19  #include <sys/types.h>
20  #include <sys/stat.h>
21  #include <dirent.h>
22  #include <string.h>
23  #include <unistd.h>
24  
25  
FileInfo()26  FileInfo::FileInfo()
27  {
28      memset(this, 0, sizeof(FileInfo));
29  }
30  
FileInfo(const FileInfo & that)31  FileInfo::FileInfo(const FileInfo& that)
32  {
33      memcpy(this, &that, sizeof(FileInfo));
34  }
35  
FileInfo(const string & filename)36  FileInfo::FileInfo(const string& filename)
37  {
38      struct stat st;
39      int err = stat(filename.c_str(), &st);
40      if (err != 0) {
41          memset(this, 0, sizeof(FileInfo));
42      } else {
43          exists = true;
44          mtime = st.st_mtime;
45          ctime = st.st_ctime;
46          size = st.st_size;
47      }
48  }
49  
50  bool
operator ==(const FileInfo & that) const51  FileInfo::operator==(const FileInfo& that) const
52  {
53      return exists == that.exists
54              && mtime == that.mtime
55              && ctime == that.ctime
56              && size == that.size;
57  }
58  
59  bool
operator !=(const FileInfo & that) const60  FileInfo::operator!=(const FileInfo& that) const
61  {
62      return exists != that.exists
63              || mtime != that.mtime
64              || ctime != that.ctime
65              || size != that.size;
66  }
67  
~FileInfo()68  FileInfo::~FileInfo()
69  {
70  }
71  
TrackedFile()72  TrackedFile::TrackedFile()
73      :filename(),
74       fileInfo()
75  {
76  }
77  
TrackedFile(const TrackedFile & that)78  TrackedFile::TrackedFile(const TrackedFile& that)
79  {
80      filename = that.filename;
81      fileInfo = that.fileInfo;
82  }
83  
TrackedFile(const string & file)84  TrackedFile::TrackedFile(const string& file)
85      :filename(file),
86       fileInfo(file)
87  {
88  }
89  
~TrackedFile()90  TrackedFile::~TrackedFile()
91  {
92  }
93  
94  bool
HasChanged() const95  TrackedFile::HasChanged() const
96  {
97      FileInfo updated(filename);
98      return !updated.exists || fileInfo != updated;
99  }
100  
101  void
get_directory_contents(const string & name,map<string,FileInfo> * results)102  get_directory_contents(const string& name, map<string,FileInfo>* results)
103  {
104      DIR* dir = opendir(name.c_str());
105      if (dir == NULL) {
106          return;
107      }
108  
109      dirent* entry;
110      while ((entry = readdir(dir)) != NULL) {
111          if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
112              continue;
113          }
114          if (entry->d_type == DT_DIR) {
115              string subdir = name + "/" + entry->d_name;
116              get_directory_contents(subdir, results);
117          } else if (entry->d_type == DT_LNK || entry->d_type == DT_REG) {
118              string filename(name + "/" + entry->d_name);
119              (*results)[filename] = FileInfo(filename);
120          }
121      }
122  
123      closedir(dir);
124  }
125  
126  bool
directory_contents_differ(const map<string,FileInfo> & before,const map<string,FileInfo> & after)127  directory_contents_differ(const map<string,FileInfo>& before, const map<string,FileInfo>& after)
128  {
129      if (before.size() != after.size()) {
130          return true;
131      }
132      map<string,FileInfo>::const_iterator b = before.begin();
133      map<string,FileInfo>::const_iterator a = after.begin();
134      while (b != before.end() && a != after.end()) {
135          if (b->first != a->first) {
136              return true;
137          }
138          if (a->second != b->second) {
139              return true;
140          }
141          a++;
142          b++;
143      }
144      return false;
145  }
146  
147  string
escape_quotes(const char * str)148  escape_quotes(const char* str)
149  {
150      string result;
151      while (*str) {
152          if (*str == '"') {
153              result += '\\';
154              result += '"';
155          } else {
156              result += *str;
157          }
158      }
159      return result;
160  }
161  
162  string
escape_for_commandline(const char * str)163  escape_for_commandline(const char* str)
164  {
165      if (strchr(str, '"') != NULL || strchr(str, ' ') != NULL
166              || strchr(str, '\t') != NULL) {
167          return escape_quotes(str);
168      } else {
169          return str;
170      }
171  }
172  
173  static bool
spacechr(char c)174  spacechr(char c)
175  {
176      return c == ' ' || c == '\t' || c == '\n' || c == '\r';
177  }
178  
179  string
trim(const string & str)180  trim(const string& str)
181  {
182      const ssize_t N = (ssize_t)str.size();
183      ssize_t begin = 0;
184      while (begin < N && spacechr(str[begin])) {
185          begin++;
186      }
187      ssize_t end = N - 1;
188      while (end >= begin && spacechr(str[end])) {
189          end--;
190      }
191      return string(str, begin, end-begin+1);
192  }
193  
194  bool
starts_with(const string & str,const string & prefix)195  starts_with(const string& str, const string& prefix)
196  {
197      return str.compare(0, prefix.length(), prefix) == 0;
198  }
199  
200  bool
ends_with(const string & str,const string & suffix)201  ends_with(const string& str, const string& suffix)
202  {
203      if (str.length() < suffix.length()) {
204          return false;
205      } else {
206          return str.compare(str.length()-suffix.length(), suffix.length(), suffix) == 0;
207      }
208  }
209  
210  void
split_lines(vector<string> * result,const string & str)211  split_lines(vector<string>* result, const string& str)
212  {
213      const int N = str.length();
214      int begin = 0;
215      int end = 0;
216      for (; end < N; end++) {
217          const char c = str[end];
218          if (c == '\r' || c == '\n') {
219              if (begin != end) {
220                  result->push_back(string(str, begin, end-begin));
221              }
222              begin = end+1;
223          }
224      }
225      if (begin != end) {
226          result->push_back(string(str, begin, end-begin));
227      }
228  }
229  
230  string
read_file(const string & filename)231  read_file(const string& filename)
232  {
233      FILE* file = fopen(filename.c_str(), "r");
234      if (file == NULL) {
235          return string();
236      }
237  
238      fseek(file, 0, SEEK_END);
239      int size = ftell(file);
240      fseek(file, 0, SEEK_SET);
241  
242      char* buf = (char*)malloc(size);
243      if ((size_t) size != fread(buf, 1, size, file)) {
244          free(buf);
245          fclose(file);
246          return string();
247      }
248  
249      string result(buf, size);
250  
251      free(buf);
252      fclose(file);
253  
254      return result;
255  }
256  
257  bool
is_executable(const string & filename)258  is_executable(const string& filename)
259  {
260      int err;
261      struct stat st;
262  
263      err = stat(filename.c_str(), &st);
264      if (err != 0) {
265          return false;
266      }
267  
268      return (st.st_mode & S_IXUSR) != 0;
269  }
270  
271  string
dirname(const string & filename)272  dirname(const string& filename)
273  {
274      size_t slash = filename.rfind('/');
275      if (slash == string::npos) {
276          return "";
277      } else if (slash == 0) {
278          return "/";
279      } else {
280          return string(filename, 0, slash);
281      }
282  }
283  
284  string
leafname(const string & filename)285  leafname(const string& filename)
286  {
287      size_t slash = filename.rfind('/');
288      if (slash == string::npos) {
289          return filename;
290      } else if (slash == filename.length() - 1) {
291          return "";
292      } else {
293          return string(filename, slash + 1);
294      }
295  }
296