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 <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 getFileModificationTime(const String& path, time_t& result) 187{ 188 CString fsRep = fileSystemRepresentation(path); 189 190 if (!fsRep.data() || fsRep.data()[0] == '\0') 191 return false; 192 193 struct stat fileInfo; 194 195 if (stat(fsRep.data(), &fileInfo)) 196 return false; 197 198 result = fileInfo.st_mtime; 199 return true; 200} 201 202bool getFileMetadata(const String& path, FileMetadata& metadata) 203{ 204 CString fsRep = fileSystemRepresentation(path); 205 206 if (!fsRep.data() || fsRep.data()[0] == '\0') 207 return false; 208 209 struct stat fileInfo; 210 if (stat(fsRep.data(), &fileInfo)) 211 return false; 212 213 metadata.modificationTime = fileInfo.st_mtime; 214 metadata.length = fileInfo.st_size; 215 metadata.type = S_ISDIR(fileInfo.st_mode) ? FileMetadata::TypeDirectory : FileMetadata::TypeFile; 216 return true; 217} 218 219String pathByAppendingComponent(const String& path, const String& component) 220{ 221 if (path.endsWith('/')) 222 return path + component; 223 return path + "/" + component; 224} 225 226bool makeAllDirectories(const String& path) 227{ 228 CString fullPath = fileSystemRepresentation(path); 229 if (!access(fullPath.data(), F_OK)) 230 return true; 231 232 char* p = fullPath.mutableData() + 1; 233 int length = fullPath.length(); 234 235 if(p[length - 1] == '/') 236 p[length - 1] = '\0'; 237 for (; *p; ++p) 238 if (*p == '/') { 239 *p = '\0'; 240 if (access(fullPath.data(), F_OK)) 241 if (mkdir(fullPath.data(), S_IRWXU)) 242 return false; 243 *p = '/'; 244 } 245 if (access(fullPath.data(), F_OK)) 246 if (mkdir(fullPath.data(), S_IRWXU)) 247 return false; 248 249 return true; 250} 251 252String pathGetFileName(const String& path) 253{ 254 return path.substring(path.reverseFind('/') + 1); 255} 256 257String directoryName(const String& path) 258{ 259 CString fsRep = fileSystemRepresentation(path); 260 261 if (!fsRep.data() || fsRep.data()[0] == '\0') 262 return String(); 263 264 return dirname(fsRep.mutableData()); 265} 266 267#if !PLATFORM(EFL) 268Vector<String> listDirectory(const String& path, const String& filter) 269{ 270 Vector<String> entries; 271 CString cpath = path.utf8(); 272 CString cfilter = filter.utf8(); 273 DIR* dir = opendir(cpath.data()); 274 if (dir) { 275 struct dirent* dp; 276 while ((dp = readdir(dir))) { 277 const char* name = dp->d_name; 278 if (!strcmp(name, ".") || !strcmp(name, "..")) 279 continue; 280 if (fnmatch(cfilter.data(), name, 0)) 281 continue; 282 char filePath[1024]; 283 if (static_cast<int>(sizeof(filePath) - 1) < snprintf(filePath, sizeof(filePath), "%s/%s", cpath.data(), name)) 284 continue; // buffer overflow 285 entries.append(filePath); 286 } 287 closedir(dir); 288 } 289 return entries; 290} 291#endif 292 293#if !PLATFORM(MAC) 294String openTemporaryFile(const String& prefix, PlatformFileHandle& handle) 295{ 296 char buffer[PATH_MAX]; 297 const char* tmpDir = getenv("TMPDIR"); 298 299 if (!tmpDir) 300 tmpDir = "/tmp"; 301 302 if (snprintf(buffer, PATH_MAX, "%s/%sXXXXXX", tmpDir, prefix.utf8().data()) >= PATH_MAX) 303 goto end; 304 305 handle = mkstemp(buffer); 306 if (handle < 0) 307 goto end; 308 309 return String::fromUTF8(buffer); 310 311end: 312 handle = invalidPlatformFileHandle; 313 return String(); 314} 315#endif 316 317} // namespace WebCore 318