Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
4 : // Use of this source code is governed by a BSD-style license that can be
5 : // found in the LICENSE file.
6 :
7 : #include "base/file_util.h"
8 :
9 : #include <dirent.h>
10 : #include <errno.h>
11 : #include <fcntl.h>
12 : #include <fnmatch.h>
13 : #include <libgen.h>
14 : #include <stdio.h>
15 : #include <string.h>
16 : #include <errno.h>
17 : #include <sys/mman.h>
18 : #define _DARWIN_USE_64_BIT_INODE // Use 64-bit inode data structures
19 : #include <sys/stat.h>
20 : #include <sys/types.h>
21 : #include <time.h>
22 : #include <unistd.h>
23 :
24 : #include <fstream>
25 : #include <string>
26 : #include <vector>
27 :
28 : #include "base/basictypes.h"
29 : #include "base/eintr_wrapper.h"
30 : #include "base/file_path.h"
31 : #include "base/logging.h"
32 : #include "base/string_util.h"
33 : #include "base/time.h"
34 :
35 : namespace file_util {
36 :
37 : #if defined(GOOGLE_CHROME_BUILD)
38 : static const char* kTempFileName = "com.google.chrome.XXXXXX";
39 : #else
40 : static const char* kTempFileName = "org.chromium.XXXXXX";
41 : #endif
42 :
43 0 : bool AbsolutePath(FilePath* path) {
44 : char full_path[PATH_MAX];
45 0 : if (realpath(path->value().c_str(), full_path) == NULL)
46 0 : return false;
47 0 : *path = FilePath(full_path);
48 0 : return true;
49 : }
50 :
51 : // TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
52 : // which works both with and without the recursive flag. I'm not sure we need
53 : // that functionality. If not, remove from file_util_win.cc, otherwise add it
54 : // here.
55 13 : bool Delete(const FilePath& path) {
56 13 : const char* path_str = path.value().c_str();
57 : struct stat file_info;
58 13 : int test = stat(path_str, &file_info);
59 13 : if (test != 0) {
60 : // The Windows version defines this condition as success.
61 0 : bool ret = (errno == ENOENT || errno == ENOTDIR);
62 0 : return ret;
63 : }
64 13 : if (!S_ISDIR(file_info.st_mode))
65 13 : return (unlink(path_str) == 0);
66 :
67 0 : return (rmdir(path_str) == 0);
68 : }
69 :
70 0 : bool PathExists(const FilePath& path) {
71 : struct stat file_info;
72 0 : return (stat(path.value().c_str(), &file_info) == 0);
73 : }
74 :
75 0 : bool PathIsWritable(const FilePath& path) {
76 0 : FilePath test_path(path);
77 : struct stat file_info;
78 0 : if (stat(test_path.value().c_str(), &file_info) != 0) {
79 : // If the path doesn't exist, test the parent dir.
80 0 : test_path = test_path.DirName();
81 : // If the parent dir doesn't exist, then return false (the path is not
82 : // directly writable).
83 0 : if (stat(test_path.value().c_str(), &file_info) != 0)
84 0 : return false;
85 : }
86 0 : if (S_IWOTH & file_info.st_mode)
87 0 : return true;
88 0 : if (getegid() == file_info.st_gid && (S_IWGRP & file_info.st_mode))
89 0 : return true;
90 0 : if (geteuid() == file_info.st_uid && (S_IWUSR & file_info.st_mode))
91 0 : return true;
92 0 : return false;
93 : }
94 :
95 0 : bool DirectoryExists(const FilePath& path) {
96 : struct stat file_info;
97 0 : if (stat(path.value().c_str(), &file_info) == 0)
98 0 : return S_ISDIR(file_info.st_mode);
99 0 : return false;
100 : }
101 :
102 15 : bool ReadFromFD(int fd, char* buffer, size_t bytes) {
103 15 : size_t total_read = 0;
104 45 : while (total_read < bytes) {
105 : ssize_t bytes_read =
106 15 : HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read));
107 15 : if (bytes_read <= 0)
108 0 : break;
109 15 : total_read += bytes_read;
110 : }
111 15 : return total_read == bytes;
112 : }
113 :
114 : // Creates and opens a temporary file in |directory|, returning the
115 : // file descriptor. |path| is set to the temporary file path.
116 : // Note TODO(erikkay) comment in header for BlahFileName() calls; the
117 : // intent is to rename these files BlahFile() (since they create
118 : // files, not filenames). This function does NOT unlink() the file.
119 13 : int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
120 13 : *path = directory.Append(kTempFileName);
121 13 : const std::string& tmpdir_string = path->value();
122 : // this should be OK since mkstemp just replaces characters in place
123 13 : char* buffer = const_cast<char*>(tmpdir_string.c_str());
124 :
125 13 : return mkstemp(buffer);
126 : }
127 :
128 0 : bool CreateTemporaryFileName(FilePath* path) {
129 0 : FilePath directory;
130 0 : if (!GetTempDir(&directory))
131 0 : return false;
132 0 : int fd = CreateAndOpenFdForTemporaryFile(directory, path);
133 0 : if (fd < 0)
134 0 : return false;
135 0 : close(fd);
136 0 : return true;
137 : }
138 :
139 13 : FILE* CreateAndOpenTemporaryShmemFile(FilePath* path) {
140 26 : FilePath directory;
141 13 : if (!GetShmemTempDir(&directory))
142 0 : return NULL;
143 :
144 13 : return CreateAndOpenTemporaryFileInDir(directory, path);
145 : }
146 :
147 13 : FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
148 13 : int fd = CreateAndOpenFdForTemporaryFile(dir, path);
149 13 : if (fd < 0)
150 0 : return NULL;
151 :
152 13 : return fdopen(fd, "a+");
153 : }
154 :
155 0 : bool CreateTemporaryFileNameInDir(const std::wstring& dir,
156 : std::wstring* temp_file) {
157 : // Not implemented yet.
158 0 : NOTREACHED();
159 0 : return false;
160 : }
161 :
162 0 : bool CreateNewTempDirectory(const FilePath::StringType& prefix,
163 : FilePath* new_temp_path) {
164 0 : FilePath tmpdir;
165 0 : if (!GetTempDir(&tmpdir))
166 0 : return false;
167 0 : tmpdir = tmpdir.Append(kTempFileName);
168 0 : std::string tmpdir_string = tmpdir.value();
169 : #ifdef ANDROID
170 : char* dtemp = NULL;
171 : #else
172 : // this should be OK since mkdtemp just replaces characters in place
173 0 : char* buffer = const_cast<char*>(tmpdir_string.c_str());
174 0 : char* dtemp = mkdtemp(buffer);
175 : #endif
176 0 : if (!dtemp)
177 0 : return false;
178 0 : *new_temp_path = FilePath(dtemp);
179 0 : return true;
180 : }
181 :
182 0 : bool CreateDirectory(const FilePath& full_path) {
183 0 : std::vector<FilePath> subpaths;
184 :
185 : // Collect a list of all parent directories.
186 0 : FilePath last_path = full_path;
187 0 : subpaths.push_back(full_path);
188 0 : for (FilePath path = full_path.DirName();
189 0 : path.value() != last_path.value(); path = path.DirName()) {
190 0 : subpaths.push_back(path);
191 0 : last_path = path;
192 : }
193 :
194 : // Iterate through the parents and create the missing ones.
195 0 : for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin();
196 0 : i != subpaths.rend(); ++i) {
197 0 : if (!DirectoryExists(*i)) {
198 0 : if (mkdir(i->value().c_str(), 0777) != 0)
199 0 : return false;
200 : }
201 : }
202 0 : return true;
203 : }
204 :
205 0 : bool GetFileInfo(const FilePath& file_path, FileInfo* results) {
206 : struct stat file_info;
207 0 : if (stat(file_path.value().c_str(), &file_info) != 0)
208 0 : return false;
209 0 : results->is_directory = S_ISDIR(file_info.st_mode);
210 0 : results->size = file_info.st_size;
211 0 : return true;
212 : }
213 :
214 0 : FILE* OpenFile(const std::string& filename, const char* mode) {
215 0 : return OpenFile(FilePath(filename), mode);
216 : }
217 :
218 0 : FILE* OpenFile(const FilePath& filename, const char* mode) {
219 0 : return fopen(filename.value().c_str(), mode);
220 : }
221 :
222 0 : int ReadFile(const FilePath& filename, char* data, int size) {
223 0 : int fd = open(filename.value().c_str(), O_RDONLY);
224 0 : if (fd < 0)
225 0 : return -1;
226 :
227 0 : int ret_value = HANDLE_EINTR(read(fd, data, size));
228 0 : HANDLE_EINTR(close(fd));
229 0 : return ret_value;
230 : }
231 :
232 0 : int WriteFile(const FilePath& filename, const char* data, int size) {
233 0 : int fd = creat(filename.value().c_str(), 0666);
234 0 : if (fd < 0)
235 0 : return -1;
236 :
237 : // Allow for partial writes
238 0 : ssize_t bytes_written_total = 0;
239 0 : do {
240 : ssize_t bytes_written_partial =
241 0 : HANDLE_EINTR(write(fd, data + bytes_written_total,
242 : size - bytes_written_total));
243 0 : if (bytes_written_partial < 0) {
244 0 : HANDLE_EINTR(close(fd));
245 0 : return -1;
246 : }
247 0 : bytes_written_total += bytes_written_partial;
248 0 : } while (bytes_written_total < size);
249 :
250 0 : HANDLE_EINTR(close(fd));
251 0 : return bytes_written_total;
252 : }
253 :
254 : // Gets the current working directory for the process.
255 0 : bool GetCurrentDirectory(FilePath* dir) {
256 0 : char system_buffer[PATH_MAX] = "";
257 0 : if (!getcwd(system_buffer, sizeof(system_buffer))) {
258 0 : NOTREACHED();
259 0 : return false;
260 : }
261 0 : *dir = FilePath(system_buffer);
262 0 : return true;
263 : }
264 :
265 : // Sets the current working directory for the process.
266 0 : bool SetCurrentDirectory(const FilePath& path) {
267 0 : int ret = chdir(path.value().c_str());
268 0 : return !ret;
269 : }
270 :
271 : #if !defined(OS_MACOSX)
272 0 : bool GetTempDir(FilePath* path) {
273 0 : const char* tmp = getenv("TMPDIR");
274 0 : if (tmp)
275 0 : *path = FilePath(tmp);
276 : else
277 0 : *path = FilePath("/tmp");
278 0 : return true;
279 : }
280 :
281 13 : bool GetShmemTempDir(FilePath* path) {
282 : #if defined(OS_LINUX) && !defined(ANDROID)
283 13 : *path = FilePath("/dev/shm");
284 13 : return true;
285 : #else
286 : return GetTempDir(path);
287 : #endif
288 : }
289 :
290 0 : bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
291 0 : int infile = open(from_path.value().c_str(), O_RDONLY);
292 0 : if (infile < 0)
293 0 : return false;
294 :
295 0 : int outfile = creat(to_path.value().c_str(), 0666);
296 0 : if (outfile < 0) {
297 0 : close(infile);
298 0 : return false;
299 : }
300 :
301 0 : const size_t kBufferSize = 32768;
302 0 : std::vector<char> buffer(kBufferSize);
303 0 : bool result = true;
304 :
305 0 : while (result) {
306 0 : ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size()));
307 0 : if (bytes_read < 0) {
308 0 : result = false;
309 0 : break;
310 : }
311 0 : if (bytes_read == 0)
312 0 : break;
313 : // Allow for partial writes
314 0 : ssize_t bytes_written_per_read = 0;
315 0 : do {
316 0 : ssize_t bytes_written_partial = HANDLE_EINTR(write(
317 : outfile,
318 : &buffer[bytes_written_per_read],
319 : bytes_read - bytes_written_per_read));
320 0 : if (bytes_written_partial < 0) {
321 0 : result = false;
322 0 : break;
323 : }
324 0 : bytes_written_per_read += bytes_written_partial;
325 0 : } while (bytes_written_per_read < bytes_read);
326 : }
327 :
328 0 : if (HANDLE_EINTR(close(infile)) < 0)
329 0 : result = false;
330 0 : if (HANDLE_EINTR(close(outfile)) < 0)
331 0 : result = false;
332 :
333 0 : return result;
334 : }
335 : #endif // !defined(OS_MACOSX)
336 :
337 : } // namespace file_util
|