| // Copyright 2019 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "smbfs/request.h" | |
| #include <errno.h> | |
| #include <base/check.h> | |
| #include <base/check_op.h> | |
| #include <base/logging.h> | |
| #include <base/stl_util.h> | |
| namespace smbfs { | |
| namespace internal { | |
| BaseRequest::BaseRequest(fuse_req_t req) : req_(req) {} | |
| BaseRequest::~BaseRequest() { | |
| if (!replied_) { | |
| // If a reply was not sent, either because the request was interrupted or | |
| // the filesystem is being shut down, send an error reply so that the | |
| // request can be freed. | |
| fuse_reply_err(req_, EINTR); | |
| } | |
| } | |
| bool BaseRequest::IsInterrupted() const { | |
| return fuse_req_interrupted(req_); | |
| } | |
| void BaseRequest::ReplyError(int error) { | |
| DCHECK(!replied_); | |
| DCHECK_GT(error, 0); | |
| fuse_reply_err(req_, error); | |
| replied_ = true; | |
| } | |
| } // namespace internal | |
| void SimpleRequest::ReplyOk() { | |
| DCHECK(!replied_); | |
| fuse_reply_err(req_, 0); | |
| replied_ = true; | |
| } | |
| void StatFsRequest::ReplyStatFs(const struct statvfs& st) { | |
| DCHECK(!replied_); | |
| fuse_reply_statfs(req_, &st); | |
| replied_ = true; | |
| } | |
| void AttrRequest::ReplyAttr(const struct stat& attr, double attr_timeout) { | |
| DCHECK(!replied_); | |
| fuse_reply_attr(req_, &attr, attr_timeout); | |
| replied_ = true; | |
| } | |
| void EntryRequest::ReplyEntry(const fuse_entry_param& entry) { | |
| DCHECK(!replied_); | |
| fuse_reply_entry(req_, &entry); | |
| replied_ = true; | |
| } | |
| void OpenRequest::ReplyOpen(uint64_t file_handle) { | |
| DCHECK(!replied_); | |
| DCHECK_GT(file_handle, 0); | |
| fuse_file_info info = {0}; | |
| info.fh = file_handle; | |
| fuse_reply_open(req_, &info); | |
| replied_ = true; | |
| } | |
| void CreateRequest::ReplyCreate(const fuse_entry_param& entry, | |
| uint64_t file_handle) { | |
| DCHECK(!replied_); | |
| DCHECK_GT(file_handle, 0); | |
| fuse_file_info info = {0}; | |
| info.fh = file_handle; | |
| fuse_reply_create(req_, &entry, &info); | |
| replied_ = true; | |
| } | |
| void BufRequest::ReplyBuf(const char* buf, size_t size) { | |
| DCHECK(!replied_); | |
| DCHECK(buf); | |
| fuse_reply_buf(req_, buf, size); | |
| replied_ = true; | |
| } | |
| void WriteRequest::ReplyWrite(size_t written) { | |
| DCHECK(!replied_); | |
| fuse_reply_write(req_, written); | |
| replied_ = true; | |
| } | |
| DirentryRequest::DirentryRequest(fuse_req_t req, size_t size) | |
| : internal::BaseRequest(req), | |
| size_(size), | |
| buf_(std::make_unique<char[]>(size)) { | |
| DCHECK(size_); | |
| } | |
| bool DirentryRequest::AddEntry(std::string_view name, | |
| fuse_ino_t inode, | |
| mode_t mode, | |
| off_t next_offset) { | |
| CHECK(mode & S_IFREG || mode & S_IFDIR); | |
| CHECK_EQ(name.find('/'), std::string_view::npos); | |
| DCHECK_NE(name, "."); | |
| DCHECK_NE(name, ".."); | |
| struct stat stat = {0}; | |
| stat.st_ino = inode; | |
| stat.st_mode = mode; | |
| size_t remaining = size_ - off_; | |
| size_t used = fuse_add_direntry(req_, buf_.get() + off_, remaining, | |
| name.data(), &stat, next_offset); | |
| if (used > remaining) { | |
| return false; | |
| } | |
| off_ += used; | |
| return true; | |
| } | |
| void DirentryRequest::ReplyDone() { | |
| DCHECK(!replied_); | |
| fuse_reply_buf(req_, buf_.get(), off_); | |
| replied_ = true; | |
| } | |
| } // namespace smbfs |