blob: 9ab0a4104150a9665fc9883a354bae6bef86abc7 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <fs/dispatcher.h>
#include <fs/vfs.h>
#include <fs/watcher.h>
#include <zircon/types.h>
#include <zx/channel.h>
#include <fbl/array.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/ref_ptr.h>
namespace svcfs {
class ServiceProvider {
public:
virtual void Connect(const char* name, size_t len, zx::channel channel) = 0;
protected:
virtual ~ServiceProvider();
};
using Vnode = fs::Vnode;
class VnodeSvc : public Vnode {
public:
DISALLOW_COPY_ASSIGN_AND_MOVE(VnodeSvc);
using NodeState = fbl::DoublyLinkedListNodeState<fbl::RefPtr<VnodeSvc>>;
struct TypeChildTraits {
static NodeState& node_state(VnodeSvc& vn) {
return vn.type_child_state_;
}
};
VnodeSvc(uint64_t node_id,
fbl::Array<char> name,
ServiceProvider* provider);
~VnodeSvc() override;
zx_status_t Open(uint32_t flags) final;
zx_status_t Serve(fs::Vfs* vfs, zx::channel channel, uint32_t flags) final;
uint64_t node_id() const { return node_id_; }
const fbl::Array<char>& name() const { return name_; }
bool NameMatch(const char* name, size_t len) const;
void ClearProvider();
private:
NodeState type_child_state_;
// If non-zero, this vnode is a persistent child of a |VnodeDir|. Otherwise,
// if zero, this vnode is a temporary result of a |Lookup| and supports
// exactly one |Serve| operation.
uint64_t node_id_;
fbl::Array<char> name_;
ServiceProvider* provider_;
};
class VnodeDir : public Vnode {
public:
explicit VnodeDir();
~VnodeDir() override;
zx_status_t Open(uint32_t flags) final;
zx_status_t Lookup(fbl::RefPtr<fs::Vnode>* out, const char* name, size_t len) final;
zx_status_t Getattr(vnattr_t* a) final;
void Notify(const char* name, size_t len, unsigned event) final;
zx_status_t WatchDir(zx::channel* out) final;
zx_status_t WatchDirV2(fs::Vfs* vfs, const vfs_watch_dir_t* cmd) final;
zx_status_t Readdir(void* cookie, void* dirents, size_t len) final;
bool AddService(const char* name, size_t len, ServiceProvider* provider);
bool RemoveService(const char* name, size_t len);
void RemoveAllServices();
private:
using ServiceList = fbl::DoublyLinkedList<fbl::RefPtr<VnodeSvc>, VnodeSvc::TypeChildTraits>;
// Starts at 3 because . has ID one and .. has ID two.
uint64_t next_node_id_;
ServiceList services_;
fs::WatcherContainer watcher_;
};
// Similar to VnodeDir, but doesn't support enumeration or watching.
class VnodeProviderDir : public Vnode {
public:
explicit VnodeProviderDir();
~VnodeProviderDir() override;
zx_status_t Open(uint32_t flags) final;
zx_status_t Lookup(fbl::RefPtr<fs::Vnode>* out, const char* name, size_t len) final;
zx_status_t Getattr(vnattr_t* a) final;
// Set the service provider to null to prevent further requests.
void SetServiceProvider(ServiceProvider* provider);
private:
ServiceProvider* provider_;
};
} // namespace svcfs