2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/machine/Disk.h"
4#include "pedigree/kernel/utilities/Pointers.h"
5#include "pedigree/kernel/utilities/utility.h"
7#include "Ext2Directory.h"
9#include "Ext2Filesystem.h"
10#include "Ext2Symlink.h"
15XattrStatus quotaAttributeStatus(QuotaStatus status) {
17 case QuotaStatus::Success:
18 return XattrStatus::Success;
19 case QuotaStatus::Limit:
20 return XattrStatus::Quota;
21 case QuotaStatus::Overflow:
22 return XattrStatus::Overflow;
23 case QuotaStatus::NoMemory:
24 return XattrStatus::NoMemory;
26 return XattrStatus::IoError;
31XattrStatus Ext2Node::changeXattr(
const StringView& name,
const void* value,
size_t length,
32 unsigned flags,
bool remove) {
35 return XattrStatus::NoMemory;
38 if (m_State->quotaFile)
39 return XattrStatus::Denied;
41 return XattrStatus::ReadOnly;
42 if (!m_State->allocationValid)
43 return XattrStatus::IoError;
44 const auto quotaStatus = m_pExt2Fs->prepareQuotaInodeLocked(m_InodeNumber);
45 if (quotaStatus != QuotaStatus::Success)
46 return quotaAttributeStatus(quotaStatus);
47 auto status = m_pExt2Fs->attributeFormatStatus();
48 if (status != XattrStatus::Success)
51 status = m_pExt2Fs->prepareAttributeRetirementLocked(m_pInode, old);
52 if (status != XattrStatus::Success)
55 status = Ext2Ea::rebuild(
reinterpret_cast<const void*
>(old.buffer), m_pExt2Fs->
m_BlockSize, name,
56 value, length, flags, remove, replacement.get(), empty);
57 if (status != XattrStatus::Success)
60 if (!encodeAllocation(m_State->allocatedDataBlocks, m_nMetadataBlocks, !empty,
62 return XattrStatus::NoSpace;
63 if (!m_pExt2Fs->prepareInodeWrite(m_InodeNumber))
64 return XattrStatus::IoError;
66 status = m_pExt2Fs->reserveAttributeWritesLocked(12);
67 if (status != XattrStatus::Success)
70 auto* destination = &old;
73 LITTLE_TO_HOST32(
reinterpret_cast<const Ext2Ea::Header*
>(old.buffer)->references) > 1)) {
74 status = m_pExt2Fs->allocateAttributeBlockLocked(m_InodeNumber, allocated);
75 if (status != XattrStatus::Success)
77 destination = &allocated;
79 const uint32_t newBlock = empty ? 0 : destination->block;
80 if (newBlock && !old.block) {
81 const auto charged = m_pExt2Fs->m_Quota.reserve(m_InodeNumber, m_pExt2Fs->
m_BlockSize);
82 if (charged != QuotaStatus::Success)
83 return quotaAttributeStatus(charged);
86 MemoryCopy(
reinterpret_cast<void*
>(destination->buffer), replacement.get(),
89 m_pExt2Fs->recordAttributeWriteLocked(
static_cast<uint64_t
>(newBlock) * m_pExt2Fs->
m_BlockSize,
90 Ext2Filesystem::AttributeWriteKind::Payload,
true);
91 destination->buffer = 0;
92 destination->provisional =
false;
93 if (destination == &allocated)
94 m_pExt2Fs->recordAttributeAllocationLocked(newBlock);
96 m_pInode->i_file_acl = HOST_TO_LITTLE32(newBlock);
97 m_pInode->i_blocks = HOST_TO_LITTLE32(sectors);
98 m_pInode->i_ctime = HOST_TO_LITTLE32(Time::getTime());
99 m_pExt2Fs->
m_pSuperblock->s_feature_compat |= HOST_TO_LITTLE32(EXT2_FEATURE_COMPAT_EXT_ATTR);
101 m_pExt2Fs->recordAttributeWriteLocked(1024, Ext2Filesystem::AttributeWriteKind::Allocation);
102 m_pExt2Fs->writeInode(m_InodeNumber);
103 m_pExt2Fs->recordAttributeInodeLocked(m_InodeNumber);
104 if (old.block && old.block != newBlock)
105 m_pExt2Fs->commitAttributeRetirementLocked(old);
106 if (old.block && !newBlock)
107 m_pExt2Fs->m_Quota.refund(m_InodeNumber, m_pExt2Fs->
m_BlockSize);
108 return XattrStatus::Success;
111XattrStatus Ext2Node::setXattr(
const StringView& name,
const void* value,
size_t length,
113 return changeXattr(name, value, length, flags,
false);
115XattrStatus Ext2Node::removeXattr(
const StringView& name) {
116 return changeXattr(name,
nullptr, 0, 0,
true);
121 return getXattr(name, output, capacity, required);
123XattrStatus Ext2File::listExtendedAttributes(
void* output,
size_t capacity,
size_t& required) {
124 return listXattrs(output, capacity, required);
126XattrStatus Ext2File::setExtendedAttribute(
const StringView& name,
const void* value,
size_t length,
128 const auto status = setXattr(name, value, length, flags);
129 if (status == XattrStatus::Success)
133XattrStatus Ext2File::removeExtendedAttribute(
const StringView& name) {
134 const auto status = removeXattr(name);
135 if (status == XattrStatus::Success)
140 size_t capacity,
size_t& required) {
141 return getXattr(name, output, capacity, required);
143XattrStatus Ext2Directory::listExtendedAttributes(
void* output,
size_t capacity,
size_t& required) {
144 return listXattrs(output, capacity, required);
146XattrStatus Ext2Directory::setExtendedAttribute(
const StringView& name,
const void* value,
147 size_t length,
unsigned flags) {
148 const auto status = setXattr(name, value, length, flags);
149 if (status == XattrStatus::Success)
153XattrStatus Ext2Directory::removeExtendedAttribute(
const StringView& name) {
154 const auto status = removeXattr(name);
155 if (status == XattrStatus::Success)
161 return getXattr(name, output, capacity, required);
163XattrStatus Ext2Symlink::listExtendedAttributes(
void* output,
size_t capacity,
size_t& required) {
164 return listXattrs(output, capacity, required);
166XattrStatus Ext2Symlink::setExtendedAttribute(
const StringView& name,
const void* value,
167 size_t length,
unsigned flags) {
168 const auto status = setXattr(name, value, length, flags);
169 if (status == XattrStatus::Success)
173XattrStatus Ext2Symlink::removeExtendedAttribute(
const StringView& name) {
174 const auto status = removeXattr(name);
175 if (status == XattrStatus::Success)
virtual void write(uint64_t location)
XattrStatus getExtendedAttribute(const StringView &, void *, size_t, size_t &) override
virtual XattrStatus getExtendedAttribute(const StringView &, void *, size_t, size_t &) override
void writeBlock(uint32_t block)
Superblock * m_pSuperblock
virtual XattrStatus getExtendedAttribute(const StringView &, void *, size_t, size_t &)
void publishEvent(FileEventMask mask, const StringView &name=StringView(), bool targetIsDirectory=false)