99d41de204c912306fdd1f2b30f6ec95cc98486c
[WebKit-https.git] / Source / WebKit / NetworkProcess / cache / NetworkCacheFileSystem.cpp
1 /*
2  * Copyright (C) 2015 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "NetworkCacheFileSystem.h"
28
29 #include "Logging.h"
30 #include <wtf/Assertions.h>
31 #include <wtf/FileSystem.h>
32 #include <wtf/Function.h>
33 #include <wtf/text/CString.h>
34
35 #if !OS(WINDOWS)
36 #include <dirent.h>
37 #include <sys/stat.h>
38 #include <sys/time.h>
39 #endif
40
41 #if PLATFORM(IOS_FAMILY) && !PLATFORM(IOS_FAMILY_SIMULATOR)
42 #include <sys/attr.h>
43 #include <unistd.h>
44 #endif
45
46 #if USE(SOUP)
47 #include <gio/gio.h>
48 #include <wtf/glib/GRefPtr.h>
49 #endif
50
51 namespace WebKit {
52 namespace NetworkCache {
53
54 #if !OS(WINDOWS)
55 static DirectoryEntryType directoryEntryType(uint8_t dtype)
56 {
57     switch (dtype) {
58     case DT_DIR:
59         return DirectoryEntryType::Directory;
60     case DT_REG:
61         return DirectoryEntryType::File;
62     default:
63         ASSERT_NOT_REACHED();
64         return DirectoryEntryType::File;
65     }
66     return DirectoryEntryType::File;
67 }
68 #endif
69
70 void traverseDirectory(const String& path, const Function<void (const String&, DirectoryEntryType)>& function)
71 {
72 #if !OS(WINDOWS)
73     DIR* dir = opendir(FileSystem::fileSystemRepresentation(path).data());
74     if (!dir)
75         return;
76     dirent* dp;
77     while ((dp = readdir(dir))) {
78         if (dp->d_type != DT_DIR && dp->d_type != DT_REG)
79             continue;
80         const char* name = dp->d_name;
81         if (!strcmp(name, ".") || !strcmp(name, ".."))
82             continue;
83         auto nameString = String::fromUTF8(name);
84         if (nameString.isNull())
85             continue;
86         function(nameString, directoryEntryType(dp->d_type));
87     }
88     closedir(dir);
89 #else
90     auto entries = FileSystem::listDirectory(path);
91     for (auto& entry : entries) {
92         auto type = FileSystem::fileIsDirectory(entry, FileSystem::ShouldFollowSymbolicLinks::No) ? DirectoryEntryType::Directory : DirectoryEntryType::File;
93         function(entry, type);
94     }
95 #endif
96 }
97
98 void deleteDirectoryRecursively(const String& path)
99 {
100     traverseDirectory(path, [&path](const String& name, DirectoryEntryType type) {
101         String entryPath = FileSystem::pathByAppendingComponent(path, name);
102         switch (type) {
103         case DirectoryEntryType::File:
104             FileSystem::deleteFile(entryPath);
105             break;
106         case DirectoryEntryType::Directory:
107             deleteDirectoryRecursively(entryPath);
108             break;
109         // This doesn't follow symlinks.
110         }
111     });
112     FileSystem::deleteEmptyDirectory(path);
113 }
114
115 FileTimes fileTimes(const String& path)
116 {
117 #if HAVE(STAT_BIRTHTIME)
118     struct stat fileInfo;
119     if (stat(FileSystem::fileSystemRepresentation(path).data(), &fileInfo))
120         return { };
121     return { WallTime::fromRawSeconds(fileInfo.st_birthtime), WallTime::fromRawSeconds(fileInfo.st_mtime) };
122 #elif USE(SOUP)
123     // There's no st_birthtime in some operating systems like Linux, so we use xattrs to set/get the creation time.
124     GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(FileSystem::fileSystemRepresentation(path).data()));
125     GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_info(file.get(), "xattr::birthtime,time::modified", G_FILE_QUERY_INFO_NONE, nullptr, nullptr));
126     if (!fileInfo)
127         return { };
128     const char* birthtimeString = g_file_info_get_attribute_string(fileInfo.get(), "xattr::birthtime");
129     if (!birthtimeString)
130         return { };
131     return { WallTime::fromRawSeconds(g_ascii_strtoull(birthtimeString, nullptr, 10)),
132         WallTime::fromRawSeconds(g_file_info_get_attribute_uint64(fileInfo.get(), "time::modified")) };
133 #elif OS(WINDOWS)
134     auto createTime = FileSystem::getFileCreationTime(path);
135     auto modifyTime = FileSystem::getFileModificationTime(path);
136     return { createTime.valueOr(WallTime()), modifyTime.valueOr(WallTime()) };
137 #endif
138 }
139
140 void updateFileModificationTimeIfNeeded(const String& path)
141 {
142     auto times = fileTimes(path);
143     if (times.creation != times.modification) {
144         // Don't update more than once per hour.
145         if (WallTime::now() - times.modification < 1_h)
146             return;
147     }
148 #if !OS(WINDOWS)
149     // This really updates both the access time and the modification time.
150     utimes(FileSystem::fileSystemRepresentation(path).data(), nullptr);
151 #else
152     FILETIME time;
153     GetSystemTimeAsFileTime(&time);
154     auto file = CreateFile(path.wideCharacters().data(), GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
155     if (file == INVALID_HANDLE_VALUE)
156         return;
157     SetFileTime(file, &time, &time, &time);
158     CloseHandle(file);
159 #endif
160 }
161
162 }
163 }