08d711f3d41d1b1633ac52629eba3a54256ce4c3
[framework/web/webkit-efl.git] / Source / WebCore / platform / posix / FileSystemPOSIX.cpp
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 "FileMetadata.h"
33 #include "PlatformString.h"
34 #include <dirent.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <fnmatch.h>
38 #include <libgen.h>
39 #include <stdio.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <stdio.h>
43 #include <unistd.h>
44 #include <wtf/text/CString.h>
45
46 #if ENABLE(TIZEN_SOUP_COOKIE_CACHE_FOR_WEBKIT2)
47 #include <sys/statvfs.h>
48 #endif
49
50 namespace WebCore {
51
52 bool fileExists(const String& path)
53 {
54     if (path.isNull())
55         return false;
56
57     CString fsRep = fileSystemRepresentation(path);
58
59     if (!fsRep.data() || fsRep.data()[0] == '\0')
60         return false;
61
62     struct stat fileInfo;
63
64     // 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
65     return !stat(fsRep.data(), &fileInfo);
66 }
67
68 bool deleteFile(const String& path)
69 {
70     CString fsRep = fileSystemRepresentation(path);
71
72     if (!fsRep.data() || fsRep.data()[0] == '\0')
73         return false;
74
75     // unlink(...) returns 0 on successful deletion of the path and non-zero in any other case (including invalid permissions or non-existent file)
76     return !unlink(fsRep.data());
77 }
78
79 PlatformFileHandle openFile(const String& path, FileOpenMode mode)
80 {
81     CString fsRep = fileSystemRepresentation(path);
82
83     if (fsRep.isNull())
84         return invalidPlatformFileHandle;
85
86     int platformFlag = 0;
87     if (mode == OpenForRead)
88         platformFlag |= O_RDONLY;
89     else if (mode == OpenForWrite)
90         platformFlag |= (O_WRONLY | O_CREAT | O_TRUNC);
91     return open(fsRep.data(), platformFlag, 0666);
92 }
93
94 void closeFile(PlatformFileHandle& handle)
95 {
96     if (isHandleValid(handle)) {
97         close(handle);
98         handle = invalidPlatformFileHandle;
99     }
100 }
101
102 long long seekFile(PlatformFileHandle handle, long long offset, FileSeekOrigin origin)
103 {
104     int whence = SEEK_SET;
105     switch (origin) {
106     case SeekFromBeginning:
107         whence = SEEK_SET;
108         break;
109     case SeekFromCurrent:
110         whence = SEEK_CUR;
111         break;
112     case SeekFromEnd:
113         whence = SEEK_END;
114         break;
115     default:
116         ASSERT_NOT_REACHED();
117     }
118     return static_cast<long long>(lseek(handle, offset, whence));
119 }
120
121 bool truncateFile(PlatformFileHandle handle, long long offset)
122 {
123     // ftruncate returns 0 to indicate the success.
124     return !ftruncate(handle, offset);
125 }
126
127 int writeToFile(PlatformFileHandle handle, const char* data, int length)
128 {
129     do {
130         int bytesWritten = write(handle, data, static_cast<size_t>(length));
131         if (bytesWritten >= 0)
132             return bytesWritten;
133     } while (errno == EINTR);
134     return -1;
135 }
136
137 int readFromFile(PlatformFileHandle handle, char* data, int length)
138 {
139     do {
140         int bytesRead = read(handle, data, static_cast<size_t>(length));
141         if (bytesRead >= 0)
142             return bytesRead;
143     } while (errno == EINTR);
144     return -1;
145 }
146
147 bool deleteEmptyDirectory(const String& path)
148 {
149     CString fsRep = fileSystemRepresentation(path);
150
151     if (!fsRep.data() || fsRep.data()[0] == '\0')
152         return false;
153
154     // rmdir(...) returns 0 on successful deletion of the path and non-zero in any other case (including invalid permissions or non-existent file)
155     return !rmdir(fsRep.data());
156 }
157
158 bool getFileSize(const String& path, long long& result)
159 {
160     CString fsRep = fileSystemRepresentation(path);
161
162     if (!fsRep.data() || fsRep.data()[0] == '\0')
163         return false;
164
165     struct stat fileInfo;
166
167     if (stat(fsRep.data(), &fileInfo))
168         return false;
169
170     result = fileInfo.st_size;
171     return true;
172 }
173
174 bool getFileModificationTime(const String& path, time_t& result)
175 {
176     CString fsRep = fileSystemRepresentation(path);
177
178     if (!fsRep.data() || fsRep.data()[0] == '\0')
179         return false;
180
181     struct stat fileInfo;
182
183     if (stat(fsRep.data(), &fileInfo))
184         return false;
185
186     result = fileInfo.st_mtime;
187     return true;
188 }
189
190 #if !ENABLE(TIZEN_FILE_SYSTEM)
191 bool getFileMetadata(const String& path, FileMetadata& metadata)
192 {
193     CString fsRep = fileSystemRepresentation(path);
194
195     if (!fsRep.data() || fsRep.data()[0] == '\0')
196         return false;
197
198     struct stat fileInfo;
199     if (stat(fsRep.data(), &fileInfo))
200         return false;
201
202     metadata.modificationTime = fileInfo.st_mtime;
203     metadata.length = fileInfo.st_size;
204     metadata.type = S_ISDIR(fileInfo.st_mode) ? FileMetadata::TypeDirectory : FileMetadata::TypeFile;
205     return true;
206 }
207 #endif
208
209 String pathByAppendingComponent(const String& path, const String& component)
210 {
211     if (path.endsWith('/'))
212         return path + component;
213     return path + "/" + component;
214 }
215
216 bool makeAllDirectories(const String& path)
217 {
218     CString fullPath = fileSystemRepresentation(path);
219     if (!access(fullPath.data(), F_OK))
220         return true;
221
222     char* p = fullPath.mutableData() + 1;
223     int length = fullPath.length();
224
225     if(p[length - 1] == '/')
226         p[length - 1] = '\0';
227     for (; *p; ++p)
228         if (*p == '/') {
229             *p = '\0';
230             if (access(fullPath.data(), F_OK))
231                 if (mkdir(fullPath.data(), S_IRWXU))
232                     return false;
233             *p = '/';
234         }
235     if (access(fullPath.data(), F_OK))
236         if (mkdir(fullPath.data(), S_IRWXU))
237             return false;
238
239     return true;
240 }
241
242 String pathGetFileName(const String& path)
243 {
244     return path.substring(path.reverseFind('/') + 1);
245 }
246
247 String directoryName(const String& path)
248 {
249     CString fsRep = fileSystemRepresentation(path);
250
251     if (!fsRep.data() || fsRep.data()[0] == '\0')
252         return String();
253
254     return dirname(fsRep.mutableData());
255 }
256
257 #if !PLATFORM(EFL)
258 Vector<String> listDirectory(const String& path, const String& filter)
259 {
260     Vector<String> entries;
261     CString cpath = path.utf8();
262     CString cfilter = filter.utf8();
263     DIR* dir = opendir(cpath.data());
264     if (dir) {
265         struct dirent* dp;
266         while ((dp = readdir(dir))) {
267             const char* name = dp->d_name;
268             if (!strcmp(name, ".") || !strcmp(name, ".."))
269                 continue;
270             if (fnmatch(cfilter.data(), name, 0))
271                 continue;
272             char filePath[1024];
273             if (static_cast<int>(sizeof(filePath) - 1) < snprintf(filePath, sizeof(filePath), "%s/%s", cpath.data(), name))
274                 continue; // buffer overflow
275             entries.append(filePath);
276         }
277         closedir(dir);
278     }
279     return entries;
280 }
281 #endif
282
283 #if ENABLE(TIZEN_SOUP_COOKIE_CACHE_FOR_WEBKIT2)
284 uint64_t getVolumeFreeSizeForPath(const char* path)
285 {
286     struct statvfs buf;
287     if (!statvfs(path, &buf)) {
288         uint64_t freeSize = buf.f_bsize * buf.f_bfree;
289         return freeSize;
290     }
291     return 0;
292 }
293 #endif
294
295 #if ENABLE(TIZEN_FILE_SYSTEM)
296 bool copyFile(const String& sourcePath, const String& destinationPath)
297 {
298    if (!fileExists(sourcePath))
299         return false;
300
301     if (destinationPath.isEmpty())
302         return false;
303
304     PlatformFileHandle srcFile = openFile(sourcePath, OpenForRead);
305     if (srcFile == invalidPlatformFileHandle)
306         return false;
307
308     PlatformFileHandle dstFile = openFile(destinationPath, OpenForWrite);
309     if (dstFile == invalidPlatformFileHandle) {
310         closeFile(srcFile);
311         return false;
312     }
313
314     int readSize;
315     int writeSize;
316     char buffer[1024];
317     while ((readSize = read(srcFile, buffer, 1024)) > 0) {
318         if ((writeSize = write(dstFile, buffer, readSize)) == -1) {
319             closeFile(srcFile);
320             closeFile(dstFile);
321             return false;
322         }
323     }
324
325     closeFile(srcFile);
326     closeFile(dstFile);
327
328     return true;
329 }
330
331 bool removeDirectory(const String& path)
332 {
333     if(!fileExists(path))
334         return false;
335
336     DIR* directory = opendir(fileSystemRepresentation(path).data());
337     if(!directory)
338         return false;
339
340     struct dirent* directoryEntry;
341     struct stat buf;
342
343     while (directoryEntry = readdir(directory)) {
344         if (!strcmp(directoryEntry->d_name, ".") || !strcmp(directoryEntry->d_name, ".."))
345             continue;
346
347         String absolutePath = pathByAppendingComponent(path, String(directoryEntry->d_name));
348
349         if (lstat(absolutePath.utf8().data(), &buf) == -1) {
350             closedir(directory);
351             return false;
352         }
353
354         bool result;
355         if (S_ISDIR(buf.st_mode))
356             result = removeDirectory(absolutePath);
357         else
358             result = deleteFile(absolutePath);
359
360         if (!result) {
361             closedir(directory);
362             return false;
363         }
364     }
365     closedir(directory);
366
367     return deleteEmptyDirectory(path);
368 }
369 #endif // ENABLE(TIZEN_FILE_SYSTEM)
370
371 #if !PLATFORM(MAC)
372 String openTemporaryFile(const String& prefix, PlatformFileHandle& handle)
373 {
374     char buffer[PATH_MAX];
375     const char* tmpDir = getenv("TMPDIR");
376
377     if (!tmpDir)
378         tmpDir = "/tmp";
379
380     if (snprintf(buffer, PATH_MAX, "%s/%sXXXXXX", tmpDir, prefix.utf8().data()) >= PATH_MAX)
381         goto end;
382
383     handle = mkstemp(buffer);
384     if (handle < 0)
385         goto end;
386
387     return String::fromUTF8(buffer);
388
389 end:
390     handle = invalidPlatformFileHandle;
391     return String();
392 }
393 #endif
394
395 } // namespace WebCore