| // Copyright 2019 The Chromium OS 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 "smbfs/request.h" |
| |
| #include <errno.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(base::StringPiece name, |
| fuse_ino_t inode, |
| mode_t mode, |
| off_t next_offset) { |
| CHECK(mode & S_IFREG || mode & S_IFDIR); |
| CHECK_EQ(name.find('/'), base::StringPiece::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 |