blob: 770d6656e96152504a12c3856d86e1c4a45060c1 [file] [log] [blame]
/*
* Copyright (C) 2021 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. AND ITS CONTRIBUTORS ``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 ITS 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 "FileSystemDirectoryHandle.h"
#include "FileSystemHandleCloseScope.h"
#include "FileSystemStorageConnection.h"
#include "JSDOMPromiseDeferred.h"
#include "JSFileSystemDirectoryHandle.h"
#include "JSFileSystemFileHandle.h"
#include <wtf/IsoMallocInlines.h>
namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(FileSystemDirectoryHandle);
Ref<FileSystemDirectoryHandle> FileSystemDirectoryHandle::create(ScriptExecutionContext& context, String&& name, FileSystemHandleIdentifier identifier, Ref<FileSystemStorageConnection>&& connection)
{
auto result = adoptRef(*new FileSystemDirectoryHandle(context, WTFMove(name), identifier, WTFMove(connection)));
result->suspendIfNeeded();
return result;
}
FileSystemDirectoryHandle::FileSystemDirectoryHandle(ScriptExecutionContext& context, String&& name, FileSystemHandleIdentifier identifier, Ref<FileSystemStorageConnection>&& connection)
: FileSystemHandle(context, FileSystemHandle::Kind::Directory, WTFMove(name), identifier, WTFMove(connection))
{
}
void FileSystemDirectoryHandle::getFileHandle(const String& name, std::optional<FileSystemDirectoryHandle::GetFileOptions> options, DOMPromiseDeferred<IDLInterface<FileSystemFileHandle>>&& promise)
{
if (isClosed())
return promise.reject(Exception { InvalidStateError, "Handle is closed"_s });
bool createIfNecessary = options ? options->create : false;
connection().getFileHandle(identifier(), name, createIfNecessary, [weakThis = WeakPtr { *this }, connection = Ref { connection() }, name, promise = WTFMove(promise)](auto result) mutable {
if (result.hasException())
return promise.reject(result.releaseException());
auto* context = weakThis ? weakThis->scriptExecutionContext() : nullptr;
if (!context)
return promise.reject(Exception { InvalidStateError, "Context has stopped"_s });
auto [identifier, isDirectory] = result.returnValue()->release();
ASSERT(!isDirectory);
promise.resolve(FileSystemFileHandle::create(*context, String { name }, identifier, WTFMove(connection)));
});
}
void FileSystemDirectoryHandle::getDirectoryHandle(const String& name, std::optional<FileSystemDirectoryHandle::GetDirectoryOptions> options, DOMPromiseDeferred<IDLInterface<FileSystemDirectoryHandle>>&& promise)
{
if (isClosed())
return promise.reject(Exception { InvalidStateError, "Handle is closed"_s });
bool createIfNecessary = options ? options->create : false;
connection().getDirectoryHandle(identifier(), name, createIfNecessary, [weakThis = WeakPtr { *this }, connection = Ref { connection() }, name, promise = WTFMove(promise)](auto result) mutable {
if (result.hasException())
return promise.reject(result.releaseException());
auto* context = weakThis ? weakThis->scriptExecutionContext() : nullptr;
if (!context)
return promise.reject(Exception { InvalidStateError, "Context has stopped"_s });
auto [identifier, isDirectory] = result.returnValue()->release();
ASSERT(isDirectory);
promise.resolve(FileSystemDirectoryHandle::create(*context, String { name }, identifier, WTFMove(connection)));
});
}
void FileSystemDirectoryHandle::removeEntry(const String& name, std::optional<FileSystemDirectoryHandle::RemoveOptions> options, DOMPromiseDeferred<void>&& promise)
{
if (isClosed())
return promise.reject(Exception { InvalidStateError, "Handle is closed"_s });
bool deleteRecursively = options ? options->recursive : false;
connection().removeEntry(identifier(), name, deleteRecursively, [promise = WTFMove(promise)](auto result) mutable {
promise.settle(WTFMove(result));
});
}
void FileSystemDirectoryHandle::resolve(const FileSystemHandle& handle, DOMPromiseDeferred<IDLSequence<IDLUSVString>>&& promise)
{
if (isClosed())
return promise.reject(Exception { InvalidStateError, "Handle is closed"_s });
connection().resolve(identifier(), handle.identifier(), [promise = WTFMove(promise)](auto result) mutable {
promise.settle(WTFMove(result));
});
}
void FileSystemDirectoryHandle::getHandleNames(CompletionHandler<void(ExceptionOr<Vector<String>>&&)>&& completionHandler)
{
if (isClosed())
return completionHandler(Exception { InvalidStateError, "Handle is closed"_s });
connection().getHandleNames(identifier(), WTFMove(completionHandler));
}
void FileSystemDirectoryHandle::getHandle(const String& name, CompletionHandler<void(ExceptionOr<Ref<FileSystemHandle>>&&)>&& completionHandler)
{
if (isClosed())
return completionHandler(Exception { InvalidStateError, "Handle is closed"_s });
connection().getHandle(identifier(), name, [weakThis = WeakPtr { *this }, name, connection = Ref { connection() }, completionHandler = WTFMove(completionHandler)](auto result) mutable {
if (result.hasException())
return completionHandler(result.releaseException());
auto [identifier, isDirectory] = result.returnValue()->release();
auto* context = weakThis ? weakThis->scriptExecutionContext() : nullptr;
if (!context)
return completionHandler(Exception { InvalidStateError, "Context has stopped"_s });
if (isDirectory) {
Ref<FileSystemHandle> handle = FileSystemDirectoryHandle::create(*context, String { name }, identifier, WTFMove(connection));
return completionHandler(WTFMove(handle));
}
Ref<FileSystemHandle> handle = FileSystemFileHandle::create(*context, String { name }, identifier, WTFMove(connection));
completionHandler(WTFMove(handle));
});
}
using FileSystemDirectoryHandleIterator = FileSystemDirectoryHandle::Iterator;
Ref<FileSystemDirectoryHandleIterator> FileSystemDirectoryHandle::createIterator()
{
return Iterator::create(*this);
}
Ref<FileSystemDirectoryHandleIterator> FileSystemDirectoryHandleIterator::create(FileSystemDirectoryHandle& source)
{
return adoptRef(*new FileSystemDirectoryHandle::Iterator(source));
}
void FileSystemDirectoryHandleIterator::next(CompletionHandler<void(ExceptionOr<Result>&&)>&& completionHandler)
{
ASSERT(!m_isWaitingForResult);
m_isWaitingForResult = true;
auto wrappedCompletionHandler = [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler)](auto result) mutable {
m_isWaitingForResult = false;
completionHandler(WTFMove(result));
};
if (!m_isInitialized) {
m_source->getHandleNames([this, protectedThis = Ref { *this }, completionHandler = WTFMove(wrappedCompletionHandler)](auto result) mutable {
m_isInitialized = true;
if (result.hasException())
return completionHandler(result.releaseException());
m_keys = result.releaseReturnValue();
advance(WTFMove(completionHandler));
});
return;
}
advance(WTFMove(wrappedCompletionHandler));
}
void FileSystemDirectoryHandleIterator::advance(CompletionHandler<void(ExceptionOr<Result>&&)>&& completionHandler)
{
ASSERT(m_isInitialized);
if (m_index >= m_keys.size()) {
Result result = std::nullopt;
return completionHandler(Result { });
}
auto key = m_keys[m_index++];
m_source->getHandle(key, [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler), key](auto result) mutable {
if (result.hasException()) {
if (result.exception().code() == ExceptionCode::NotFoundError)
return advance(WTFMove(completionHandler));
return completionHandler(result.releaseException());
}
Result resultValue = KeyValuePair<String, Ref<FileSystemHandle>> { WTFMove(key), result.releaseReturnValue() };
completionHandler(WTFMove(resultValue));
});
}
} // namespace WebCore