/* * Copyright (C) 2008 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "File.h" #include "BlobURL.h" #include "MIMETypeRegistry.h" #include "ThreadableBlobRegistry.h" #include #include #include #include namespace WebCore { WTF_MAKE_ISO_ALLOCATED_IMPL(File); Ref File::createWithRelativePath(ScriptExecutionContext* context, const String& path, const String& relativePath) { auto file = File::create(context, path); file->setRelativePath(relativePath); return file; } Ref File::create(ScriptExecutionContext* context, const String& path, const String& replacementPath, const String& nameOverride) { String name; String type; String effectivePath = !replacementPath.isNull() ? replacementPath : path; computeNameAndContentType(effectivePath, nameOverride, name, type); auto internalURL = BlobURL::createInternalURL(); ThreadableBlobRegistry::registerFileBlobURL(internalURL, path, replacementPath, type); auto file = adoptRef(*new File(context, WTFMove(internalURL), WTFMove(type), WTFMove(effectivePath), WTFMove(name))); file->suspendIfNeeded(); return file; } File::File(ScriptExecutionContext* context, URL&& url, String&& type, String&& path, String&& name) : Blob(uninitializedContructor, context, WTFMove(url), WTFMove(type)) , m_path(WTFMove(path)) , m_name(WTFMove(name)) { } File::File(DeserializationContructor, ScriptExecutionContext* context, const String& path, const URL& url, const String& type, const String& name, const std::optional& lastModified) : Blob(deserializationContructor, context, url, type, { }, path) , m_path(path) , m_name(name) , m_lastModifiedDateOverride(lastModified) { } File::File(ScriptExecutionContext& context, Vector&& blobPartVariants, const String& filename, const PropertyBag& propertyBag) : Blob(context, WTFMove(blobPartVariants), propertyBag) , m_name(filename) , m_lastModifiedDateOverride(propertyBag.lastModified.value_or(WallTime::now().secondsSinceEpoch().milliseconds())) { } File::File(ScriptExecutionContext* context, const Blob& blob, const String& name) : Blob(referencingExistingBlobConstructor, context, blob) , m_name(name) { ASSERT(!blob.isFile()); } File::File(ScriptExecutionContext* context, const File& file, const String& name) : Blob(referencingExistingBlobConstructor, context, file) , m_path(file.path()) , m_relativePath(file.relativePath()) , m_name(!name.isNull() ? name : file.name()) , m_lastModifiedDateOverride(file.m_lastModifiedDateOverride) , m_isDirectory(file.isDirectory()) { } int64_t File::lastModified() const { if (m_lastModifiedDateOverride) return m_lastModifiedDateOverride.value(); int64_t result; // FIXME: This does sync-i/o on the main thread and also recalculates every time the method is called. // The i/o should be performed on a background thread, // and the result should be cached along with an asynchronous monitor for changes to the file. auto modificationTime = FileSystem::fileModificationTime(m_path); if (modificationTime) result = modificationTime->secondsSinceEpoch().millisecondsAs(); else result = WallTime::now().secondsSinceEpoch().millisecondsAs(); return WTF::timeClip(result); } void File::computeNameAndContentType(const String& path, const String& nameOverride, String& effectiveName, String& effectiveContentType) { #if ENABLE(FILE_REPLACEMENT) if (shouldReplaceFile(path)) { computeNameAndContentTypeForReplacedFile(path, nameOverride, effectiveName, effectiveContentType); return; } #endif effectiveName = nameOverride.isEmpty() ? FileSystem::pathFileName(path) : nameOverride; size_t index = effectiveName.reverseFind('.'); if (index != notFound) { callOnMainThreadAndWait([&effectiveContentType, &effectiveName, index] { effectiveContentType = MIMETypeRegistry::mimeTypeForExtension(effectiveName.substring(index + 1)).isolatedCopy(); }); } } String File::contentTypeForFile(const String& path) { String name; String type; computeNameAndContentType(path, String(), name, type); return type; } bool File::isDirectory() const { if (!m_isDirectory) m_isDirectory = FileSystem::fileTypeFollowingSymlinks(m_path) == FileSystem::FileType::Directory; return *m_isDirectory; } const char* File::activeDOMObjectName() const { return "File"; } } // namespace WebCore