Home | History | Annotate | Download | only in wince
      1 /*
      2  * Copyright (C) 2007 Apple Inc. All rights reserved.
      3  * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
      4  * Copyright (C) 2007-2009 Torch Mobile, Inc.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  *
     10  * 1.  Redistributions of source code must retain the above copyright
     11  *     notice, this list of conditions and the following disclaimer.
     12  * 2.  Redistributions in binary form must reproduce the above copyright
     13  *     notice, this list of conditions and the following disclaimer in the
     14  *     documentation and/or other materials provided with the distribution.
     15  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     16  *     its contributors may be used to endorse or promote products derived
     17  *     from this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "FileSystem.h"
     33 
     34 #include "NotImplemented.h"
     35 #include "PlatformString.h"
     36 #include <wincrypt.h>
     37 #include <windows.h>
     38 #include <wtf/text/CString.h>
     39 
     40 namespace WebCore {
     41 
     42 static size_t reverseFindPathSeparator(const String& path, unsigned start = UINT_MAX)
     43 {
     44     size_t positionSlash = path.reverseFind('/', start);
     45     size_t positionBackslash = path.reverseFind('\\', start);
     46 
     47     if (positionSlash == notFound)
     48         return positionBackslash;
     49 
     50     if (positionBackslash == notFound)
     51         return positionSlash;
     52 
     53     return std::max(positionSlash, positionBackslash);
     54 }
     55 
     56 static bool getFileInfo(const String& path, BY_HANDLE_FILE_INFORMATION& fileInfo)
     57 {
     58     String filename = path;
     59     HANDLE hFile = CreateFile(filename.charactersWithNullTermination(), GENERIC_READ, FILE_SHARE_READ, 0
     60         , OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
     61 
     62     if (hFile == INVALID_HANDLE_VALUE)
     63         return false;
     64 
     65     bool rtn = GetFileInformationByHandle(hFile, &fileInfo) ? true : false;
     66 
     67     CloseHandle(hFile);
     68     return rtn;
     69 }
     70 
     71 bool getFileSize(const String& path, long long& result)
     72 {
     73     BY_HANDLE_FILE_INFORMATION fileInformation;
     74     if (!getFileInfo(path, fileInformation))
     75         return false;
     76 
     77     ULARGE_INTEGER fileSize;
     78     fileSize.LowPart = fileInformation.nFileSizeLow;
     79     fileSize.HighPart = fileInformation.nFileSizeHigh;
     80 
     81     result = fileSize.QuadPart;
     82 
     83     return true;
     84 }
     85 
     86 bool getFileModificationTime(const String& path, time_t& result)
     87 {
     88     BY_HANDLE_FILE_INFORMATION fileInformation;
     89     if (!getFileInfo(path, fileInformation))
     90         return false;
     91 
     92     ULARGE_INTEGER t;
     93     memcpy(&t, &fileInformation.ftLastWriteTime, sizeof(t));
     94 
     95     result = t.QuadPart * 0.0000001 - 11644473600.0;
     96 
     97     return true;
     98 }
     99 
    100 bool fileExists(const String& path)
    101 {
    102     String filename = path;
    103     HANDLE hFile = CreateFile(filename.charactersWithNullTermination(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE
    104         , 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
    105 
    106     CloseHandle(hFile);
    107 
    108     return hFile != INVALID_HANDLE_VALUE;
    109 }
    110 
    111 bool deleteFile(const String& path)
    112 {
    113     String filename = path;
    114     return !!DeleteFileW(filename.charactersWithNullTermination());
    115 }
    116 
    117 
    118 bool deleteEmptyDirectory(const String& path)
    119 {
    120     String filename = path;
    121     return !!RemoveDirectoryW(filename.charactersWithNullTermination());
    122 }
    123 
    124 String pathByAppendingComponent(const String& path, const String& component)
    125 {
    126     if (component.isEmpty())
    127         return path;
    128 
    129     Vector<UChar, MAX_PATH> buffer;
    130 
    131     buffer.append(path.characters(), path.length());
    132 
    133     if (buffer.last() != L'\\' && buffer.last() != L'/'
    134         && component[0] != L'\\' && component[0] != L'/')
    135         buffer.append(L'\\');
    136 
    137     buffer.append(component.characters(), component.length());
    138 
    139     return String(buffer.data(), buffer.size());
    140 }
    141 
    142 CString fileSystemRepresentation(const String&)
    143 {
    144     return "";
    145 }
    146 
    147 bool makeAllDirectories(const String& path)
    148 {
    149     size_t lastDivPos = reverseFindPathSeparator(path);
    150     unsigned endPos = path.length();
    151     if (lastDivPos == endPos - 1) {
    152         --endPos;
    153         lastDivPos = reverseFindPathSeparator(path, lastDivPos);
    154     }
    155 
    156     if (lastDivPos != notFound) {
    157         if (!makeAllDirectories(path.substring(0, lastDivPos)))
    158             return false;
    159     }
    160 
    161     String folder(path.substring(0, endPos));
    162     CreateDirectory(folder.charactersWithNullTermination(), 0);
    163 
    164     DWORD fileAttr = GetFileAttributes(folder.charactersWithNullTermination());
    165     return fileAttr != 0xFFFFFFFF && (fileAttr & FILE_ATTRIBUTE_DIRECTORY);
    166 }
    167 
    168 String homeDirectoryPath()
    169 {
    170     notImplemented();
    171     return "";
    172 }
    173 
    174 String pathGetFileName(const String& path)
    175 {
    176     size_t pos = reverseFindPathSeparator(path);
    177     if (pos == notFound)
    178         return path;
    179     return path.substring(pos + 1);
    180 }
    181 
    182 String directoryName(const String& path)
    183 {
    184     size_t pos = reverseFindPathSeparator(path);
    185     if (pos == notFound)
    186         return String();
    187     return path.left(pos);
    188 }
    189 
    190 String openTemporaryFile(const String&, PlatformFileHandle& handle)
    191 {
    192     handle = INVALID_HANDLE_VALUE;
    193 
    194     wchar_t tempPath[MAX_PATH];
    195     int tempPathLength = ::GetTempPath(WTF_ARRAY_LENGTH(tempPath), tempPath);
    196     if (tempPathLength <= 0 || tempPathLength > WTF_ARRAY_LENGTH(tempPath))
    197         return String();
    198 
    199     HCRYPTPROV hCryptProv = 0;
    200     if (!CryptAcquireContext(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
    201         return String();
    202 
    203     String proposedPath;
    204     while (1) {
    205 
    206         wchar_t tempFile[] = L"XXXXXXXX.tmp"; // Use 8.3 style name (more characters aren't helpful due to 8.3 short file names)
    207         const int randomPartLength = 8;
    208         if (!CryptGenRandom(hCryptProv, randomPartLength * 2, reinterpret_cast<BYTE*>(tempFile)))
    209             break;
    210 
    211         // Limit to valid filesystem characters, also excluding others that could be problematic, like punctuation.
    212         // don't include both upper and lowercase since Windows file systems are typically not case sensitive.
    213         const char validChars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
    214         for (int i = 0; i < randomPartLength; ++i)
    215             tempFile[i] = validChars[tempFile[i] % (sizeof(validChars) - 1)];
    216 
    217         ASSERT(wcslen(tempFile) * 2 == sizeof(tempFile) - 2);
    218 
    219         proposedPath = pathByAppendingComponent(String(tempPath), String(tempFile));
    220 
    221         // use CREATE_NEW to avoid overwriting an existing file with the same name
    222         handle = CreateFile(proposedPath.charactersWithNullTermination(), 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 String();
    233 
    234     return proposedPath;
    235 }
    236 
    237 PlatformFileHandle openFile(const String& path, FileOpenMode mode)
    238 {
    239     DWORD desiredAccess = 0;
    240     DWORD creationDisposition = 0;
    241     switch (mode) {
    242         case OpenForRead:
    243             desiredAccess = GENERIC_READ;
    244             creationDisposition = OPEN_EXISTING;
    245         case OpenForWrite:
    246             desiredAccess = GENERIC_WRITE;
    247             creationDisposition = CREATE_ALWAYS;
    248         default:
    249             ASSERT_NOT_REACHED();
    250     }
    251 
    252     String destination = path;
    253     return CreateFile(destination.charactersWithNullTermination(), desiredAccess, 0, 0, creationDisposition, FILE_ATTRIBUTE_NORMAL, 0);
    254 }
    255 
    256 void closeFile(PlatformFileHandle& handle)
    257 {
    258     if (isHandleValid(handle)) {
    259         ::CloseHandle(handle);
    260         handle = invalidPlatformFileHandle;
    261     }
    262 }
    263 
    264 int writeToFile(PlatformFileHandle handle, const char* data, int length)
    265 {
    266     if (!isHandleValid(handle))
    267         return -1;
    268 
    269     DWORD bytesWritten;
    270     bool success = WriteFile(handle, data, length, &bytesWritten, 0);
    271 
    272     if (!success)
    273         return -1;
    274     return static_cast<int>(bytesWritten);
    275 }
    276 
    277 bool unloadModule(PlatformModule module)
    278 {
    279     return ::FreeLibrary(module);
    280 }
    281 
    282 String localUserSpecificStorageDirectory()
    283 {
    284     return String(L"\\");
    285 }
    286 
    287 String roamingUserSpecificStorageDirectory()
    288 {
    289     return String(L"\\");
    290 }
    291 
    292 Vector<String> listDirectory(const String& path, const String& filter)
    293 {
    294     Vector<String> entries;
    295 
    296     Vector<UChar, 256> pattern;
    297     pattern.append(path.characters(), path.length());
    298     if (pattern.last() != L'/' && pattern.last() != L'\\')
    299         pattern.append(L'\\');
    300 
    301     String root(pattern.data(), pattern.size());
    302     pattern.append(filter.characters(), filter.length());
    303     pattern.append(0);
    304 
    305     WIN32_FIND_DATA findData;
    306     HANDLE hFind = FindFirstFile(pattern.data(), &findData);
    307     if (INVALID_HANDLE_VALUE != hFind) {
    308         do {
    309             // FIXEME: should we also add the folders? This function
    310             // is so far only called by PluginDatabase.cpp to list
    311             // all plugins in a folder, where it's not supposed to list sub-folders.
    312             if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
    313                 entries.append(root + findData.cFileName);
    314         } while (FindNextFile(hFind, &findData));
    315         FindClose(hFind);
    316     }
    317 
    318     return entries;
    319 }
    320 
    321 } // namespace WebCore
    322