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