1/*
2 * Copyright (C) 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 * 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "File.h"
28
29#include "BlobURL.h"
30#include "MIMETypeRegistry.h"
31#include "ThreadableBlobRegistry.h"
32#include <wtf/DateMath.h>
33#include <wtf/FileMetadata.h>
34#include <wtf/FileSystem.h>
35#include <wtf/IsoMallocInlines.h>
36#include <wtf/text/WTFString.h>
37
38namespace WebCore {
39
40WTF_MAKE_ISO_ALLOCATED_IMPL(File);
41
42Ref<File> File::createWithRelativePath(const String& path, const String& relativePath)
43{
44 auto file = File::create(path);
45 file->setRelativePath(relativePath);
46 return file;
47}
48
49File::File(const String& path)
50 : Blob(uninitializedContructor)
51 , m_path(path)
52{
53 m_internalURL = BlobURL::createInternalURL();
54 m_size = -1;
55 computeNameAndContentType(m_path, String(), m_name, m_type);
56 ThreadableBlobRegistry::registerFileBlobURL(m_internalURL, path, m_type);
57}
58
59File::File(const String& path, const String& nameOverride)
60 : Blob(uninitializedContructor)
61 , m_path(path)
62{
63 m_internalURL = BlobURL::createInternalURL();
64 m_size = -1;
65 computeNameAndContentType(m_path, nameOverride, m_name, m_type);
66 ThreadableBlobRegistry::registerFileBlobURL(m_internalURL, path, m_type);
67}
68
69File::File(DeserializationContructor, const String& path, const URL& url, const String& type, const String& name, const Optional<int64_t>& lastModified)
70 : Blob(deserializationContructor, url, type, -1, path)
71 , m_path(path)
72 , m_name(name)
73 , m_lastModifiedDateOverride(lastModified)
74{
75}
76
77static BlobPropertyBag convertPropertyBag(const File::PropertyBag& initialBag)
78{
79 BlobPropertyBag bag;
80 bag.type = initialBag.type;
81 return bag;
82}
83
84File::File(Vector<BlobPartVariant>&& blobPartVariants, const String& filename, const PropertyBag& propertyBag)
85 : Blob(WTFMove(blobPartVariants), convertPropertyBag(propertyBag))
86 , m_name(filename)
87 , m_lastModifiedDateOverride(propertyBag.lastModified.valueOr(WallTime::now().secondsSinceEpoch().milliseconds()))
88{
89}
90
91File::File(const Blob& blob, const String& name)
92 : Blob(referencingExistingBlobConstructor, blob)
93 , m_name(name)
94{
95 ASSERT(!blob.isFile());
96}
97
98File::File(const File& file, const String& name)
99 : Blob(referencingExistingBlobConstructor, file)
100 , m_path(file.path())
101 , m_relativePath(file.relativePath())
102 , m_name(!name.isNull() ? name : file.name())
103 , m_lastModifiedDateOverride(file.m_lastModifiedDateOverride)
104 , m_isDirectory(file.isDirectory())
105{
106}
107
108int64_t File::lastModified() const
109{
110 if (m_lastModifiedDateOverride)
111 return m_lastModifiedDateOverride.value();
112
113 int64_t result;
114
115 // FIXME: This does sync-i/o on the main thread and also recalculates every time the method is called.
116 // The i/o should be performed on a background thread,
117 // and the result should be cached along with an asynchronous monitor for changes to the file.
118 auto modificationTime = FileSystem::getFileModificationTime(m_path);
119 if (modificationTime)
120 result = modificationTime->secondsSinceEpoch().millisecondsAs<int64_t>();
121 else
122 result = WallTime::now().secondsSinceEpoch().millisecondsAs<int64_t>();
123
124 return WTF::timeClip(result);
125}
126
127void File::computeNameAndContentType(const String& path, const String& nameOverride, String& effectiveName, String& effectiveContentType)
128{
129#if ENABLE(FILE_REPLACEMENT)
130 if (shouldReplaceFile(path)) {
131 computeNameAndContentTypeForReplacedFile(path, nameOverride, effectiveName, effectiveContentType);
132 return;
133 }
134#endif
135 effectiveName = nameOverride.isNull() ? FileSystem::pathGetFileName(path) : nameOverride;
136 size_t index = effectiveName.reverseFind('.');
137 if (index != notFound)
138 effectiveContentType = MIMETypeRegistry::getMIMETypeForExtension(effectiveName.substring(index + 1));
139}
140
141String File::contentTypeForFile(const String& path)
142{
143 String name;
144 String type;
145 computeNameAndContentType(path, String(), name, type);
146
147 return type;
148}
149
150bool File::isDirectory() const
151{
152 if (!m_isDirectory)
153 m_isDirectory = FileSystem::fileIsDirectory(m_path, FileSystem::ShouldFollowSymbolicLinks::Yes);
154 return *m_isDirectory;
155}
156
157} // namespace WebCore
158