// Copyright 2022 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 "src/storage/f2fs/f2fs.h"

namespace f2fs {
void NodePage::FillNodeFooter(nid_t nid, nid_t ino, uint32_t ofs, bool reset) {
  Node &rn = GetRawNode();
  if (reset)
    memset(&rn, 0, sizeof(rn));
  rn.footer.nid = CpuToLe(nid);
  rn.footer.ino = CpuToLe(ino);
  rn.footer.flag = CpuToLe(ofs << static_cast<int>(BitShift::kOffsetBitShift));
}

void NodePage::CopyNodeFooterFrom(NodePage &src) {
  memcpy(&GetRawNode().footer, &src.GetRawNode().footer, sizeof(NodeFooter));
}

void NodePage::FillNodeFooterBlkaddr(block_t blkaddr) {
  Checkpoint &ckpt = fs_->GetSuperblockInfo().GetCheckpoint();
  GetRawNode().footer.cp_ver = ckpt.checkpoint_ver;
  GetRawNode().footer.next_blkaddr = blkaddr;
}

nid_t NodePage::InoOfNode() { return LeToCpu(GetRawNode().footer.ino); }

nid_t NodePage::NidOfNode() { return LeToCpu(GetRawNode().footer.nid); }

uint32_t NodePage::OfsOfNode() {
  uint32_t flag = LeToCpu(GetRawNode().footer.flag);
  return flag >> static_cast<int>(BitShift::kOffsetBitShift);
}

uint64_t NodePage::CpverOfNode() { return LeToCpu(GetRawNode().footer.cp_ver); }

block_t NodePage::NextBlkaddrOfNode() { return LeToCpu(GetRawNode().footer.next_blkaddr); }

// f2fs assigns the following node offsets described as (num).
// N = kNidsPerBlock
//
//  Inode block (0)
//    |- direct node (1)
//    |- direct node (2)
//    |- indirect node (3)
//    |            `- direct node (4 => 4 + N - 1)
//    |- indirect node (4 + N)
//    |            `- direct node (5 + N => 5 + 2N - 1)
//    `- double indirect node (5 + 2N)
//                 `- indirect node (6 + 2N)
//                       `- direct node (x(N + 1))
bool NodePage::IsDnode() {
  uint32_t ofs = OfsOfNode();
  if (ofs == kOfsIndirectNode1 || ofs == kOfsIndirectNode2 || ofs == kOfsDoubleIndirectNode)
    return false;
  if (ofs >= kOfsDoubleIndirectNode + 1) {
    ofs -= kOfsDoubleIndirectNode + 1;
    if (static_cast<int64_t>(ofs) % (kNidsPerBlock + 1))
      return false;
  }
  return true;
}

void NodePage::SetNid(size_t off, nid_t nid, bool is_inode) {
  WaitOnWriteback();

  if (is_inode) {
    GetRawNode().i.i_nid[off - kNodeDir1Block] = CpuToLe(nid);
  } else {
    GetRawNode().in.nid[off] = CpuToLe(nid);
  }

  SetDirty();
}

nid_t NodePage::GetNid(size_t off, bool is_inode) {
  if (is_inode) {
    return LeToCpu(GetRawNode().i.i_nid[off - kNodeDir1Block]);
  }
  return LeToCpu(GetRawNode().in.nid[off]);
}

bool NodePage::IsColdNode() {
  uint32_t flag = LeToCpu(GetRawNode().footer.flag);
  return TestBit(static_cast<uint32_t>(BitShift::kColdBitShift), &flag);
}

bool NodePage::IsFsyncDnode() {
  uint32_t flag = LeToCpu(GetRawNode().footer.flag);
  return TestBit(static_cast<uint32_t>(BitShift::kFsyncBitShift), &flag);
}

bool NodePage::IsDentDnode() {
  uint32_t flag = LeToCpu(GetRawNode().footer.flag);
  return TestBit(static_cast<uint32_t>(BitShift::kDentBitShift), &flag);
}

void NodePage::SetColdNode(VnodeF2fs &vnode) {
  uint32_t flag = LeToCpu(GetRawNode().footer.flag);

  if (vnode.IsDir()) {
    ClearBit(static_cast<uint32_t>(BitShift::kColdBitShift), &flag);
  } else {
    SetBit(static_cast<uint32_t>(BitShift::kColdBitShift), &flag);
  }
  GetRawNode().footer.flag = CpuToLe(flag);
}

void NodePage::SetFsyncMark(bool mark) {
  uint32_t flag = LeToCpu(GetRawNode().footer.flag);
  if (mark) {
    SetBit(static_cast<uint32_t>(BitShift::kFsyncBitShift), &flag);
  } else {
    ClearBit(static_cast<uint32_t>(BitShift::kFsyncBitShift), &flag);
  }
  GetRawNode().footer.flag = CpuToLe(flag);
}

void NodePage::SetDentryMark(bool mark) {
  uint32_t flag = LeToCpu(GetRawNode().footer.flag);
  if (mark) {
    SetBit(static_cast<uint32_t>(BitShift::kDentBitShift), &flag);
  } else {
    ClearBit(static_cast<uint32_t>(BitShift::kDentBitShift), &flag);
  }
  GetRawNode().footer.flag = CpuToLe(flag);
}

block_t NodePage::StartBidxOfNode() {
  uint32_t node_ofs = OfsOfNode(), NumOfIndirectNodes = 0;

  if (node_ofs == kOfsInode) {
    return 0;
  } else if (node_ofs <= kOfsDirectNode2) {
    NumOfIndirectNodes = 0;
  } else if (node_ofs >= kOfsIndirectNode1 && node_ofs < kOfsIndirectNode2) {
    NumOfIndirectNodes = 1;
  } else if (node_ofs >= kOfsIndirectNode2 && node_ofs < kOfsDoubleIndirectNode) {
    NumOfIndirectNodes = 2;
  } else {
    NumOfIndirectNodes = (node_ofs - kOfsDoubleIndirectNode - 2) / (kNidsPerBlock + 1);
  }

  return kAddrsPerInode + (node_ofs - NumOfIndirectNodes - 1) * kAddrsPerBlock;
}
}  // namespace f2fs
