Unreviewed restoration of non-unified build.
[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 #else
40 #include <windows.h>
41 #endif
42
43 #if PLATFORM(IOS_FAMILY) && !PLATFORM(IOS_FAMILY_SIMULATOR)
44 #include <sys/attr.h>
45 #include <unistd.h>
46 #endif
47
48 #if USE(SOUP)
49 #include <gio/gio.h>
50 #include <wtf/glib/GRefPtr.h>
51 #endif
52
53 namespace WebKit {
54 namespace NetworkCache {
55
56 #if !OS(WINDOWS)
57 static DirectoryEntryType directoryEntryType(uint8_t dtype)
58 {
59     switch (dtype) {
60     case DT_DIR:
61         return DirectoryEntryType::Directory;
62     case DT_REG:
63         return DirectoryEntryType::File;
64     default:
65         ASSERT_NOT_REACHED();
66         return DirectoryEntryType::File;
67     }
68     return DirectoryEntryType::File;
69 }
70 #endif
71
72 void traverseDirectory(const String& path, const Function<void (const String&, DirectoryEntryType)>& function)
73 {
74 #if !OS(WINDOWS)
75     DIR* dir = opendir(FileSystem::fileSystemRepresentation(path).data());
76     if (!dir)
77         return;
78     dirent* dp;
79     while ((dp = readdir(dir))) {
80         if (dp->d_type != DT_DIR && dp->d_type != DT_REG)
81             continue;
82         const char* name = dp->d_name;
83         if (!strcmp(name, ".") || !strcmp(name, ".."))
84             continue;
85         auto nameString = String::fromUTF8(name);
86         if (nameString.isNull())
87             continue;
88         function(nameString, directoryEntryType(dp->d_type));
89     }
90     closedir(dir);
91 #else
92     auto entries = FileSystem::listDirectory(path);
93     for (auto& entry : entries) {
94         auto type = FileSystem::fileIsDirectory(entry, FileSystem::ShouldFollowSymbolicLinks::No) ? DirectoryEntryType::Directory : DirectoryEntryType::File;
95         function(entry, type);
96     }
97 #endif
98 }
99
100 void deleteDirectoryRecursively(const String& path)
101 {
102     traverseDirectory(path, [&path](const String& name, DirectoryEntryType type) {
103         String entryPath = FileSystem::pathByAppendingComponent(path, name);
104         switch (type) {
105         case DirectoryEntryType::File:
106             FileSystem::deleteFile(entryPath);
107             break;
108         case DirectoryEntryType::Directory:
109             deleteDirectoryRecursively(entryPath);
110             break;
111         // This doesn't follow symlinks.
112         }
113     });
114     FileSystem::deleteEmptyDirectory(path);
115 }
116
117 FileTimes fileTimes(const String& path)
118 {
119 #if HAVE(STAT_BIRTHTIME)
120     struct stat fileInfo;
121     if (stat(FileSystem::fileSystemRepresentation(path).data(), &fileInfo))
122         return { };
123     return { WallTime::fromRawSeconds(fileInfo.st_birthtime), WallTime::fromRawSeconds(fileInfo.st_mtime) };
124 #elif USE(SOUP)
125     // There's no st_birthtime in some operating systems like Linux, so we use xattrs to set/get the creation time.
126     GRefPtr<GFile> file = adoptGRef(g_file_new_for_path(FileSystem::fileSystemRepresentation(path).data()));
127     GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_info(file.get(), "xattr::birthtime,time::modified", G_FILE_QUERY_INFO_NONE, nullptr, nullptr));
128     if (!fileInfo)
129         return { };
130     const char* birthtimeString = g_file_info_get_attribute_string(fileInfo.get(), "xattr::birthtime");
131     if (!birthtimeString)
132         return { };
133     return { WallTime::fromRawSeconds(g_ascii_strtoull(birthtimeString, nullptr, 10)),
134         WallTime::fromRawSeconds(g_file_info_get_attribute_uint64(fileInfo.get(), "time::modified")) };
135 #elif OS(WINDOWS)
136     auto createTime = FileSystem::getFileCreationTime(path);
137     auto modifyTime = FileSystem::getFileModificationTime(path);
138     return { createTime.valueOr(WallTime()), modifyTime.valueOr(WallTime()) };
139 #endif
140 }
141
142 void updateFileModificationTimeIfNeeded(const String& path)
143 {
144     auto times = fileTimes(path);
145     if (times.creation != times.modification) {
146         // Don't update more than once per hour.
147         if (WallTime::now() - times.modification < 1_h)
148             return;
149     }
150 #if !OS(WINDOWS)
151     // This really updates both the access time and the modification time.
152     utimes(FileSystem::fileSystemRepresentation(path).data(), nullptr);
153 #else
154     FILETIME time;
155     GetSystemTimeAsFileTime(&time);
156     auto file = CreateFile(path.wideCharacters().data(), GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
157     if (file == INVALID_HANDLE_VALUE)
158         return;
159     SetFileTime(file, &time, &time, &time);
160     CloseHandle(file);
161 #endif
162 }
163
164 }
165 }