1 /*
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "config.h"
30 #include "FileSystem.h"
31
32 #include "PlatformString.h"
33 #include <dirent.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <fnmatch.h>
37 #include <libgen.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41 #include <wtf/text/CString.h>
42
43 namespace WebCore {
44
fileExists(const String & path)45 bool fileExists(const String& path)
46 {
47 if (path.isNull())
48 return false;
49
50 CString fsRep = fileSystemRepresentation(path);
51
52 if (!fsRep.data() || fsRep.data()[0] == '\0')
53 return false;
54
55 struct stat fileInfo;
56
57 // stat(...) returns 0 on successful stat'ing of the file, and non-zero in any case where the file doesn't exist or cannot be accessed
58 return !stat(fsRep.data(), &fileInfo);
59 }
60
deleteFile(const String & path)61 bool deleteFile(const String& path)
62 {
63 CString fsRep = fileSystemRepresentation(path);
64
65 if (!fsRep.data() || fsRep.data()[0] == '\0')
66 return false;
67
68 // unlink(...) returns 0 on successful deletion of the path and non-zero in any other case (including invalid permissions or non-existent file)
69 return !unlink(fsRep.data());
70 }
71
openFile(const String & path,FileOpenMode mode)72 PlatformFileHandle openFile(const String& path, FileOpenMode mode)
73 {
74 CString fsRep = fileSystemRepresentation(path);
75
76 if (fsRep.isNull())
77 return invalidPlatformFileHandle;
78
79 int platformFlag = 0;
80 if (mode == OpenForRead)
81 platformFlag |= O_RDONLY;
82 else if (mode == OpenForWrite)
83 platformFlag |= (O_WRONLY | O_CREAT | O_TRUNC);
84 return open(fsRep.data(), platformFlag, 0666);
85 }
86
closeFile(PlatformFileHandle & handle)87 void closeFile(PlatformFileHandle& handle)
88 {
89 if (isHandleValid(handle)) {
90 close(handle);
91 handle = invalidPlatformFileHandle;
92 }
93 }
94
seekFile(PlatformFileHandle handle,long long offset,FileSeekOrigin origin)95 long long seekFile(PlatformFileHandle handle, long long offset, FileSeekOrigin origin)
96 {
97 int whence = SEEK_SET;
98 switch (origin) {
99 case SeekFromBeginning:
100 whence = SEEK_SET;
101 break;
102 case SeekFromCurrent:
103 whence = SEEK_CUR;
104 break;
105 case SeekFromEnd:
106 whence = SEEK_END;
107 break;
108 default:
109 ASSERT_NOT_REACHED();
110 }
111 return static_cast<long long>(lseek(handle, offset, whence));
112 }
113
truncateFile(PlatformFileHandle handle,long long offset)114 bool truncateFile(PlatformFileHandle handle, long long offset)
115 {
116 // ftruncate returns 0 to indicate the success.
117 return !ftruncate(handle, offset);
118 }
119
writeToFile(PlatformFileHandle handle,const char * data,int length)120 int writeToFile(PlatformFileHandle handle, const char* data, int length)
121 {
122 do {
123 int bytesWritten = write(handle, data, static_cast<size_t>(length));
124 if (bytesWritten >= 0)
125 return bytesWritten;
126 } while (errno == EINTR);
127 return -1;
128 }
129
readFromFile(PlatformFileHandle handle,char * data,int length)130 int readFromFile(PlatformFileHandle handle, char* data, int length)
131 {
132 do {
133 int bytesRead = read(handle, data, static_cast<size_t>(length));
134 if (bytesRead >= 0)
135 return bytesRead;
136 } while (errno == EINTR);
137 return -1;
138 }
139
deleteEmptyDirectory(const String & path)140 bool deleteEmptyDirectory(const String& path)
141 {
142 CString fsRep = fileSystemRepresentation(path);
143
144 if (!fsRep.data() || fsRep.data()[0] == '\0')
145 return false;
146
147 // rmdir(...) returns 0 on successful deletion of the path and non-zero in any other case (including invalid permissions or non-existent file)
148 return !rmdir(fsRep.data());
149 }
150
getFileSize(const String & path,long long & result)151 bool getFileSize(const String& path, long long& result)
152 {
153 CString fsRep = fileSystemRepresentation(path);
154
155 if (!fsRep.data() || fsRep.data()[0] == '\0')
156 return false;
157
158 struct stat fileInfo;
159
160 if (stat(fsRep.data(), &fileInfo))
161 return false;
162
163 result = fileInfo.st_size;
164 return true;
165 }
166
getFileModificationTime(const String & path,time_t & result)167 bool getFileModificationTime(const String& path, time_t& result)
168 {
169 CString fsRep = fileSystemRepresentation(path);
170
171 if (!fsRep.data() || fsRep.data()[0] == '\0')
172 return false;
173
174 struct stat fileInfo;
175
176 if (stat(fsRep.data(), &fileInfo))
177 return false;
178
179 result = fileInfo.st_mtime;
180 return true;
181 }
182
pathByAppendingComponent(const String & path,const String & component)183 String pathByAppendingComponent(const String& path, const String& component)
184 {
185 if (path.endsWith("/"))
186 return path + component;
187 else
188 return path + "/" + component;
189 }
190
makeAllDirectories(const String & path)191 bool makeAllDirectories(const String& path)
192 {
193 CString fullPath = fileSystemRepresentation(path);
194 if (!access(fullPath.data(), F_OK))
195 return true;
196
197 char* p = fullPath.mutableData() + 1;
198 int length = fullPath.length();
199
200 if(p[length - 1] == '/')
201 p[length - 1] = '\0';
202 for (; *p; ++p)
203 if (*p == '/') {
204 *p = '\0';
205 if (access(fullPath.data(), F_OK))
206 if (mkdir(fullPath.data(), S_IRWXU))
207 return false;
208 *p = '/';
209 }
210 if (access(fullPath.data(), F_OK))
211 if (mkdir(fullPath.data(), S_IRWXU))
212 return false;
213
214 return true;
215 }
216
217 #if !PLATFORM(ANDROID)
pathGetFileName(const String & path)218 String pathGetFileName(const String& path)
219 {
220 return path.substring(path.reverseFind('/') + 1);
221 }
222 #endif
223
directoryName(const String & path)224 String directoryName(const String& path)
225 {
226 CString fsRep = fileSystemRepresentation(path);
227
228 if (!fsRep.data() || fsRep.data()[0] == '\0')
229 return String();
230
231 return dirname(fsRep.mutableData());
232 }
233
234 #if !PLATFORM(EFL)
listDirectory(const String & path,const String & filter)235 Vector<String> listDirectory(const String& path, const String& filter)
236 {
237 Vector<String> entries;
238 CString cpath = path.utf8();
239 CString cfilter = filter.utf8();
240 DIR* dir = opendir(cpath.data());
241 if (dir) {
242 struct dirent* dp;
243 while ((dp = readdir(dir))) {
244 const char* name = dp->d_name;
245 if (!strcmp(name, ".") || !strcmp(name, ".."))
246 continue;
247 if (fnmatch(cfilter.data(), name, 0))
248 continue;
249 char filePath[1024];
250 if (static_cast<int>(sizeof(filePath) - 1) < snprintf(filePath, sizeof(filePath), "%s/%s", cpath.data(), name))
251 continue; // buffer overflow
252 entries.append(filePath);
253 }
254 closedir(dir);
255 }
256 return entries;
257 }
258 #endif
259
260 } // namespace WebCore
261