blob: cc7fe6b6cde10ed4ca456e46be28a04f6872474a [file] [log] [blame]
/*
* Copyright (C) 2017 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.
*/
#import "config.h"
#import "FileMonitor.h"
#import "Logging.h"
#import <wtf/BlockPtr.h>
#import <wtf/FileSystem.h>
namespace WebCore {
constexpr unsigned monitorMask = DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE;
constexpr unsigned fileUnavailableMask = DISPATCH_VNODE_DELETE | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE;
FileMonitor::FileMonitor(const String& path, Ref<WorkQueue>&& handlerQueue, WTF::Function<void(FileChangeType)>&& modificationHandler)
{
if (path.isEmpty())
return;
if (!modificationHandler)
return;
auto handle = FileSystem::openFile(path, FileSystem::FileOpenMode::EventsOnly);
if (handle == FileSystem::invalidPlatformFileHandle) {
RELEASE_LOG_ERROR(ResourceLoadStatistics, "Failed to open statistics file for monitoring: %s", path.utf8().data());
return;
}
// The source (platformMonitor) retains the dispatch queue.
m_platformMonitor = adoptOSObject(dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, handle, monitorMask, handlerQueue->dispatchQueue()));
LOG(ResourceLoadStatistics, "Creating monitor %p", m_platformMonitor.get());
dispatch_source_set_event_handler(m_platformMonitor.get(), makeBlockPtr([modificationHandler = WTFMove(modificationHandler), fileMonitor = m_platformMonitor] {
// If this is getting called after the monitor was cancelled, just drop the notification.
if (dispatch_source_testcancel(fileMonitor.get()))
return;
unsigned flag = dispatch_source_get_data(fileMonitor.get());
LOG(ResourceLoadStatistics, "File event %#X for monitor %p", flag, fileMonitor.get());
if (flag & fileUnavailableMask) {
modificationHandler(FileChangeType::Removal);
dispatch_source_cancel(fileMonitor.get());
} else {
ASSERT(flag & DISPATCH_VNODE_WRITE);
modificationHandler(FileChangeType::Modification);
}
}).get());
dispatch_source_set_cancel_handler(m_platformMonitor.get(), [handle] () mutable {
FileSystem::closeFile(handle);
});
dispatch_resume(m_platformMonitor.get());
}
FileMonitor::~FileMonitor()
{
if (!m_platformMonitor)
return;
LOG(ResourceLoadStatistics, "Stopping monitor %p", m_platformMonitor.get());
dispatch_source_cancel(m_platformMonitor.get());
}
} // namespace WebCore