Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
      3  * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1.  Redistributions of source code must retain the above copyright
     10  *     notice, this list of conditions and the following disclaimer.
     11  * 2.  Redistributions in binary form must reproduce the above copyright
     12  *     notice, this list of conditions and the following disclaimer in the
     13  *     documentation and/or other materials provided with the distribution.
     14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     15  *     its contributors may be used to endorse or promote products derived
     16  *     from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include "config.h"
     31 #include "FileSystem.h"
     32 
     33 #include "CString.h"
     34 #include "NotImplemented.h"
     35 #include "PlatformString.h"
     36 #include <wtf/HashMap.h>
     37 
     38 #include <windows.h>
     39 #include <winbase.h>
     40 #include <shlobj.h>
     41 #include <shlwapi.h>
     42 
     43 namespace WebCore {
     44 
     45 static bool statFile(String path, struct _stat64& st)
     46 {
     47     ASSERT_ARG(path, !path.isNull());
     48     return !_wstat64(path.charactersWithNullTermination(), &st) && (st.st_mode & _S_IFMT) == _S_IFREG;
     49 }
     50 
     51 bool getFileSize(const String& path, long long& result)
     52 {
     53     struct _stat64 sb;
     54     if (!statFile(path, sb))
     55         return false;
     56     result = sb.st_size;
     57     return true;
     58 }
     59 
     60 bool getFileModificationTime(const String& path, time_t& result)
     61 {
     62     struct _stat64 st;
     63     if (!statFile(path, st))
     64         return false;
     65     result = st.st_mtime;
     66     return true;
     67 }
     68 
     69 bool fileExists(const String& path)
     70 {
     71     struct _stat64 st;
     72     return statFile(path, st);
     73 }
     74 
     75 bool deleteFile(const String& path)
     76 {
     77     String filename = path;
     78     return !!DeleteFileW(filename.charactersWithNullTermination());
     79 }
     80 
     81 bool deleteEmptyDirectory(const String& path)
     82 {
     83     String filename = path;
     84     return !!RemoveDirectoryW(filename.charactersWithNullTermination());
     85 }
     86 
     87 String pathByAppendingComponent(const String& path, const String& component)
     88 {
     89     Vector<UChar> buffer(MAX_PATH);
     90 
     91     if (path.length() + 1 > buffer.size())
     92         return String();
     93 
     94     memcpy(buffer.data(), path.characters(), path.length() * sizeof(UChar));
     95     buffer[path.length()] = '\0';
     96 
     97     String componentCopy = component;
     98     if (!PathAppendW(buffer.data(), componentCopy.charactersWithNullTermination()))
     99         return String();
    100 
    101     buffer.resize(wcslen(buffer.data()));
    102 
    103     return String::adopt(buffer);
    104 }
    105 
    106 CString fileSystemRepresentation(const String&)
    107 {
    108     return "";
    109 }
    110 
    111 bool makeAllDirectories(const String& path)
    112 {
    113     String fullPath = path;
    114     if (SHCreateDirectoryEx(0, fullPath.charactersWithNullTermination(), 0) != ERROR_SUCCESS) {
    115         DWORD error = GetLastError();
    116         if (error != ERROR_FILE_EXISTS && error != ERROR_ALREADY_EXISTS) {
    117             LOG_ERROR("Failed to create path %s", path.ascii().data());
    118             return false;
    119         }
    120     }
    121     return true;
    122 }
    123 
    124 String homeDirectoryPath()
    125 {
    126     notImplemented();
    127     return "";
    128 }
    129 
    130 String pathGetFileName(const String& path)
    131 {
    132     return String(::PathFindFileName(String(path).charactersWithNullTermination()));
    133 }
    134 
    135 String directoryName(const String& path)
    136 {
    137     String fileName = pathGetFileName(path);
    138     String dirName = String(path);
    139     dirName.truncate(dirName.length() - pathGetFileName(path).length());
    140     return dirName;
    141 }
    142 
    143 static String bundleName()
    144 {
    145     static bool initialized;
    146     static String name = "WebKit";
    147 
    148     if (!initialized) {
    149         initialized = true;
    150 
    151         if (CFBundleRef bundle = CFBundleGetMainBundle())
    152             if (CFTypeRef bundleExecutable = CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleExecutableKey))
    153                 if (CFGetTypeID(bundleExecutable) == CFStringGetTypeID())
    154                     name = reinterpret_cast<CFStringRef>(bundleExecutable);
    155     }
    156 
    157     return name;
    158 }
    159 
    160 static String storageDirectory(DWORD pathIdentifier)
    161 {
    162     Vector<UChar> buffer(MAX_PATH);
    163     if (FAILED(SHGetFolderPathW(0, pathIdentifier | CSIDL_FLAG_CREATE, 0, 0, buffer.data())))
    164         return String();
    165     buffer.resize(wcslen(buffer.data()));
    166     String directory = String::adopt(buffer);
    167 
    168     static const String companyNameDirectory = "Apple Computer\\";
    169     directory = pathByAppendingComponent(directory, companyNameDirectory + bundleName());
    170     if (!makeAllDirectories(directory))
    171         return String();
    172 
    173     return directory;
    174 }
    175 
    176 static String cachedStorageDirectory(DWORD pathIdentifier)
    177 {
    178     static HashMap<DWORD, String> directories;
    179 
    180     HashMap<DWORD, String>::iterator it = directories.find(pathIdentifier);
    181     if (it != directories.end())
    182         return it->second;
    183 
    184     String directory = storageDirectory(pathIdentifier);
    185     directories.add(pathIdentifier, directory);
    186 
    187     return directory;
    188 }
    189 
    190 CString openTemporaryFile(const char*, PlatformFileHandle& handle)
    191 {
    192     handle = INVALID_HANDLE_VALUE;
    193 
    194     char tempPath[MAX_PATH];
    195     int tempPathLength = ::GetTempPathA(_countof(tempPath), tempPath);
    196     if (tempPathLength <= 0 || tempPathLength > _countof(tempPath))
    197         return CString();
    198 
    199     HCRYPTPROV hCryptProv = 0;
    200     if (!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
    201         return CString();
    202 
    203     char proposedPath[MAX_PATH];
    204     while (1) {
    205         char tempFile[] = "XXXXXXXX.tmp"; // Use 8.3 style name (more characters aren't helpful due to 8.3 short file names)
    206         const int randomPartLength = 8;
    207         if (!CryptGenRandom(hCryptProv, randomPartLength, reinterpret_cast<BYTE*>(tempFile)))
    208             break;
    209 
    210         // Limit to valid filesystem characters, also excluding others that could be problematic, like punctuation.
    211         // don't include both upper and lowercase since Windows file systems are typically not case sensitive.
    212         const char validChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
    213         for (int i = 0; i < randomPartLength; ++i)
    214             tempFile[i] = validChars[tempFile[i] % (sizeof(validChars) - 1)];
    215 
    216         ASSERT(strlen(tempFile) == sizeof(tempFile) - 1);
    217 
    218         if (!PathCombineA(proposedPath, tempPath, tempFile))
    219             break;
    220 
    221         // use CREATE_NEW to avoid overwriting an existing file with the same name
    222         handle = CreateFileA(proposedPath, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
    223         if (!isHandleValid(handle) && GetLastError() == ERROR_ALREADY_EXISTS)
    224             continue;
    225 
    226         break;
    227     }
    228 
    229     CryptReleaseContext(hCryptProv, 0);
    230 
    231     if (!isHandleValid(handle))
    232         return CString();
    233 
    234     return proposedPath;
    235 }
    236 
    237 void closeFile(PlatformFileHandle& handle)
    238 {
    239     if (isHandleValid(handle)) {
    240         ::CloseHandle(handle);
    241         handle = invalidPlatformFileHandle;
    242     }
    243 }
    244 
    245 int writeToFile(PlatformFileHandle handle, const char* data, int length)
    246 {
    247     if (!isHandleValid(handle))
    248         return -1;
    249 
    250     DWORD bytesWritten;
    251     bool success = WriteFile(handle, data, length, &bytesWritten, 0);
    252 
    253     if (!success)
    254         return -1;
    255     return static_cast<int>(bytesWritten);
    256 }
    257 
    258 bool unloadModule(PlatformModule module)
    259 {
    260     return ::FreeLibrary(module);
    261 }
    262 
    263 String localUserSpecificStorageDirectory()
    264 {
    265     return cachedStorageDirectory(CSIDL_LOCAL_APPDATA);
    266 }
    267 
    268 String roamingUserSpecificStorageDirectory()
    269 {
    270     return cachedStorageDirectory(CSIDL_APPDATA);
    271 }
    272 
    273 bool safeCreateFile(const String& path, CFDataRef data)
    274 {
    275     // Create a temporary file.
    276     WCHAR tempDirPath[MAX_PATH];
    277     if (!GetTempPathW(ARRAYSIZE(tempDirPath), tempDirPath))
    278         return false;
    279 
    280     WCHAR tempPath[MAX_PATH];
    281     if (!GetTempFileNameW(tempDirPath, L"WEBKIT", 0, tempPath))
    282         return false;
    283 
    284     HANDLE tempFileHandle = CreateFileW(tempPath, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    285     if (tempFileHandle == INVALID_HANDLE_VALUE)
    286         return false;
    287 
    288     // Write the data to this temp file.
    289     DWORD written;
    290     if (!WriteFile(tempFileHandle, CFDataGetBytePtr(data), static_cast<DWORD>(CFDataGetLength(data)), &written, 0))
    291         return false;
    292 
    293     CloseHandle(tempFileHandle);
    294 
    295     // Copy the temp file to the destination file.
    296     String destination = path;
    297     if (!MoveFileExW(tempPath, destination.charactersWithNullTermination(), MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
    298         return false;
    299 
    300     return true;
    301 }
    302 
    303 Vector<String> listDirectory(const String& path, const String& filter)
    304 {
    305     Vector<String> entries;
    306     notImplemented();
    307     return entries;
    308 }
    309 
    310 } // namespace WebCore
    311