// Copyright 2016 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.

#include <svcfs/svcfs.h>

#include <fcntl.h>
#include <string.h>

#include <fs/dispatcher.h>
#include <fs/watcher.h>
#include <fbl/alloc_checker.h>

namespace svcfs {

static void CopyToArray(const char* string, size_t len, fbl::Array<char>* result) {
    fbl::Array<char> array(new char[len + 1], len);
    memcpy(array.get(), string, len);
    array[len] = '\0';
    result->swap(array);
}

static bool IsDot(const char* name, size_t len) {
    return (len == 1) && (name[0] == '.');
}

static bool IsDotDot(const char* name, size_t len) {
    return (len == 2) && (name[0] == '.') && (name[1] == '.');
}

static bool IsValidServiceName(const char* name, size_t len) {
    return name && len >= 1 && !IsDot(name, len) && !IsDotDot(name, len) &&
        !memchr(name, '/', len) && !memchr(name, 0, len);
}

struct dircookie_t {
    uint64_t last_id;
};

static_assert(sizeof(dircookie_t) <= sizeof(vdircookie_t),
              "svcfs dircookie too large to fit in IO state");

// ServiceProvider -------------------------------------------------------------

ServiceProvider::~ServiceProvider() = default;

// VnodeSvc --------------------------------------------------------------------

VnodeSvc::VnodeSvc(uint64_t node_id,
                   fbl::Array<char> name,
                   ServiceProvider* provider)
    : node_id_(node_id), name_(fbl::move(name)), provider_(provider) {
}

VnodeSvc::~VnodeSvc() = default;

zx_status_t VnodeSvc::Open(uint32_t flags) {
    if (flags & O_DIRECTORY) {
        return ZX_ERR_NOT_DIR;
    }
    return ZX_OK;
}

zx_status_t VnodeSvc::Serve(fs::Vfs* vfs, zx::channel channel, uint32_t flags) {
    if (!provider_) {
        return ZX_ERR_UNAVAILABLE;
    }

    provider_->Connect(name_.get(), name_.size(), fbl::move(channel));

    // If node_id_ is zero, this vnode was created during |Lookup| and doesn't
    // have a parent. Without a parent, there isn't anyone to clean up the raw
    // |provider_| pointer, which means we need to clean it up here.
    if (!node_id_)
        provider_ = nullptr;

    return ZX_OK;
}

bool VnodeSvc::NameMatch(const char* name, size_t len) const {
    return (name_.size() == len) && (memcmp(name_.get(), name, len) == 0);
}

void VnodeSvc::ClearProvider() {
    provider_ = nullptr;
}

// VnodeDir --------------------------------------------------------------------

VnodeDir::VnodeDir()
    : next_node_id_(2) {}

VnodeDir::~VnodeDir() = default;

zx_status_t VnodeDir::Open(uint32_t flags) {
    return ZX_OK;
}

zx_status_t VnodeDir::Lookup(fbl::RefPtr<fs::Vnode>* out, const char* name, size_t len) {
    fbl::RefPtr<VnodeSvc> vn = nullptr;
    for (auto& child : services_) {
        if (child.NameMatch(name, len)) {
            *out = fbl::RefPtr<VnodeSvc>(&child);
            return ZX_OK;
        }
    }

    return ZX_ERR_NOT_FOUND;
}

zx_status_t VnodeDir::Getattr(vnattr_t* attr) {
    memset(attr, 0, sizeof(vnattr_t));
    attr->mode = V_TYPE_DIR | V_IRUSR;
    attr->nlink = 1;
    return ZX_OK;
}

void VnodeDir::Notify(const char* name, size_t len, unsigned event) { watcher_.Notify(name, len, event); }
zx_status_t VnodeDir::WatchDir(zx::channel* out) { return watcher_.WatchDir(out); }
zx_status_t VnodeDir::WatchDirV2(fs::Vfs* vfs, const vfs_watch_dir_t* cmd) {
    return watcher_.WatchDirV2(vfs, this, cmd);
}

zx_status_t VnodeDir::Readdir(void* cookie, void* data, size_t len) {
    dircookie_t* c = static_cast<dircookie_t*>(cookie);
    fs::DirentFiller df(data, len);

    zx_status_t r = 0;
    if (c->last_id < 1) {
        if ((r = df.Next(".", 1, VTYPE_TO_DTYPE(V_TYPE_DIR))) != ZX_OK) {
            return df.BytesFilled();
        }
        c->last_id = 1;
    }

    for (const VnodeSvc& vn : services_) {
        if (c->last_id >= vn.node_id()) {
            continue;
        }
        if ((r = df.Next(vn.name().get(), vn.name().size(),
                         VTYPE_TO_DTYPE(V_TYPE_FILE))) != ZX_OK) {
            return df.BytesFilled();
        }
        c->last_id = vn.node_id();
    }

    return df.BytesFilled();
}

bool VnodeDir::AddService(const char* name, size_t len, ServiceProvider* provider) {
    if (!IsValidServiceName(name, len)) {
        return false;
    }

    fbl::Array<char> array;
    CopyToArray(name, len, &array);

    fbl::RefPtr<VnodeSvc> vn = fbl::AdoptRef(new VnodeSvc(
        next_node_id_++, fbl::move(array), provider));

    services_.push_back(fbl::move(vn));
    Notify(name, len, VFS_WATCH_EVT_ADDED);
    return true;
}

bool VnodeDir::RemoveService(const char* name, size_t len) {
    for (auto& child : services_) {
        if (child.NameMatch(name, len)) {
            child.ClearProvider();
            services_.erase(child);
            return true;
        }
    }
    return false;
}

void VnodeDir::RemoveAllServices() {
    for (VnodeSvc& vn : services_) {
        vn.ClearProvider();
    }
    services_.clear();
}

// VnodeProviderDir --------------------------------------------------------------------

VnodeProviderDir::VnodeProviderDir()
    : provider_(nullptr) {}

VnodeProviderDir::~VnodeProviderDir() = default;

zx_status_t VnodeProviderDir::Open(uint32_t flags) {
    return ZX_OK;
}

zx_status_t VnodeProviderDir::Lookup(fbl::RefPtr<fs::Vnode>* out, const char* name, size_t len) {
    if (!IsValidServiceName(name, len)) {
        return ZX_ERR_NOT_FOUND;
    }

    fbl::Array<char> array;
    CopyToArray(name, len, &array);

    *out = fbl::AdoptRef(new VnodeSvc(0, fbl::move(array), provider_));
    return ZX_OK;
}

zx_status_t VnodeProviderDir::Getattr(vnattr_t* attr) {
    memset(attr, 0, sizeof(vnattr_t));
    attr->mode = V_TYPE_DIR | V_IRUSR;
    attr->nlink = 1;
    return ZX_OK;
}

void VnodeProviderDir::SetServiceProvider(ServiceProvider* provider) {
    provider_ = provider;
}

} // namespace svcfs
