* added support for extra inode attributes in volumes with an inodesize of 256 or more:
this brings nanoseconds for access, change and modification times, and also brings creation time. * switched off some debug output * HTreeEntryIterator: fCount can equal fLimit. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38964 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -91,8 +91,9 @@ HTreeEntryIterator::Init()
|
||||
fCount = countLimit->Count();
|
||||
fLimit = countLimit->Limit();
|
||||
|
||||
if (fCount >= fLimit) {
|
||||
ERROR("HTreeEntryIterator::Init() bad fCount %lu\n", (uint32)fCount);
|
||||
if (fCount > fLimit) {
|
||||
ERROR("HTreeEntryIterator::Init() bad fCount %u (fLimit %u)\n",
|
||||
fCount, fLimit);
|
||||
fCount = fLimit = 0;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@ Inode::Inode(Volume* volume, ino_t id)
|
||||
|
||||
fInitStatus = UpdateNodeFromDisk();
|
||||
if (fInitStatus == B_OK) {
|
||||
fHasExtraAttributes = (fNodeSize == sizeof(ext2_inode)
|
||||
&& fNode.ExtraInodeSize() + EXT2_INODE_NORMAL_SIZE
|
||||
== sizeof(ext2_inode));
|
||||
|
||||
if (IsDirectory() || (IsSymLink() && Size() < 60)) {
|
||||
TRACE("Inode::Inode(): Not creating the file cache\n");
|
||||
fCached = false;
|
||||
@@ -342,7 +346,9 @@ Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer,
|
||||
WriteLocker writeLocker(fLock);
|
||||
|
||||
TRACE("Inode::WriteAt(): Updating modification time\n");
|
||||
fNode.SetModificationTime(real_time_clock());
|
||||
struct timespec timespec;
|
||||
_BigtimeToTimespec(real_time_clock_usecs(), ×pec);
|
||||
SetModificationTime(×pec);
|
||||
|
||||
// NOTE: Debugging info to find why sometimes resize doesn't happen
|
||||
size_t length = *_length;
|
||||
@@ -699,10 +705,14 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name,
|
||||
node.SetGroupID(parent != NULL ? parent->Node().GroupID() : getegid());
|
||||
node.SetNumLinks(inode->IsDirectory() ? 2 : 1);
|
||||
TRACE("Inode::Create(): Updating time\n");
|
||||
time_t creationTime = real_time_clock();
|
||||
node.SetAccessTime(creationTime);
|
||||
node.SetCreationTime(creationTime);
|
||||
node.SetModificationTime(creationTime);
|
||||
struct timespec timespec;
|
||||
_BigtimeToTimespec(real_time_clock_usecs(), ×pec);
|
||||
inode->SetAccessTime(×pec);
|
||||
inode->SetCreationTime(×pec);
|
||||
inode->SetModificationTime(×pec);
|
||||
|
||||
if (sizeof(ext2_inode) < volume->InodeSize())
|
||||
node.SetExtraInodeSize(sizeof(ext2_inode) - EXT2_INODE_NORMAL_SIZE);
|
||||
|
||||
TRACE("Inode::Create(): Updating ID\n");
|
||||
inode->fID = id;
|
||||
@@ -963,3 +973,4 @@ Inode::_SetNumBlocks(uint64 numBlocks)
|
||||
fNode.SetNumBlocks64(numBlocks);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,14 @@
|
||||
#include "Volume.h"
|
||||
|
||||
|
||||
//#define TRACE_EXT2
|
||||
#ifdef TRACE_EXT2
|
||||
# define TRACEI(x...) dprintf("\33[34mext2:\33[0m " x)
|
||||
#else
|
||||
# define TRACEI(x...) ;
|
||||
#endif
|
||||
|
||||
|
||||
class Inode : public TransactionListener {
|
||||
public:
|
||||
Inode(Volume* volume, ino_t id);
|
||||
@@ -38,17 +46,33 @@ public:
|
||||
status_t CheckPermissions(int accessMode) const;
|
||||
|
||||
bool IsDeleted() const { return fUnlinked; }
|
||||
bool HasExtraAttributes() const
|
||||
{ return fHasExtraAttributes; }
|
||||
|
||||
mode_t Mode() const { return fNode.Mode(); }
|
||||
int32 Flags() const { return fNode.Flags(); }
|
||||
|
||||
off_t Size() const { return fNode.Size(); }
|
||||
time_t ModificationTime() const
|
||||
{ return fNode.ModificationTime(); }
|
||||
time_t CreationTime() const
|
||||
{ return fNode.CreationTime(); }
|
||||
time_t AccessTime() const
|
||||
{ return fNode.AccessTime(); }
|
||||
void GetChangeTime(struct timespec *timespec) const
|
||||
{ fNode.GetChangeTime(timespec, fHasExtraAttributes); }
|
||||
void GetModificationTime(struct timespec *timespec) const
|
||||
{ fNode.GetModificationTime(timespec,
|
||||
fHasExtraAttributes); }
|
||||
void GetCreationTime(struct timespec *timespec) const
|
||||
{ fNode.GetCreationTime(timespec,
|
||||
fHasExtraAttributes); }
|
||||
void GetAccessTime(struct timespec *timespec) const
|
||||
{ fNode.GetAccessTime(timespec, fHasExtraAttributes); }
|
||||
void SetChangeTime(const struct timespec *timespec)
|
||||
{ fNode.SetChangeTime(timespec, fHasExtraAttributes); }
|
||||
void SetModificationTime(const struct timespec *timespec)
|
||||
{ fNode.SetModificationTime(timespec,
|
||||
fHasExtraAttributes); }
|
||||
void SetCreationTime(const struct timespec *timespec)
|
||||
{ fNode.SetCreationTime(timespec,
|
||||
fHasExtraAttributes); }
|
||||
void SetAccessTime(const struct timespec *timespec)
|
||||
{ fNode.SetAccessTime(timespec, fHasExtraAttributes); }
|
||||
|
||||
//::Volume* _Volume() const { return fVolume; }
|
||||
Volume* GetVolume() const { return fVolume; }
|
||||
@@ -76,7 +100,11 @@ public:
|
||||
ino_t* _id = NULL, Inode** _inode = NULL,
|
||||
fs_vnode_ops* vnodeOps = NULL,
|
||||
uint32 publishFlags = 0);
|
||||
|
||||
static void _BigtimeToTimespec(bigtime_t time,
|
||||
struct timespec *timespec)
|
||||
{ timespec->tv_sec = time / 1000000LL;
|
||||
timespec->tv_nsec = (time % 1000000LL) * 1000; }
|
||||
|
||||
void* FileCache() const { return fCache; }
|
||||
void* Map() const { return fMap; }
|
||||
status_t EnableFileCache();
|
||||
@@ -85,6 +113,8 @@ public:
|
||||
|
||||
status_t Sync();
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
virtual void TransactionDone(bool success);
|
||||
virtual void RemovedFromTransaction();
|
||||
@@ -98,8 +128,9 @@ private:
|
||||
|
||||
status_t _EnlargeDataStream(Transaction& transaction,
|
||||
off_t size);
|
||||
status_t _ShrinkDataStream(Transaction& transaction, off_t size);
|
||||
|
||||
status_t _ShrinkDataStream(Transaction& transaction,
|
||||
off_t size);
|
||||
|
||||
uint64 _NumBlocks();
|
||||
status_t _SetNumBlocks(uint64 numBlocks);
|
||||
|
||||
@@ -110,9 +141,10 @@ private:
|
||||
void* fMap;
|
||||
bool fCached;
|
||||
bool fUnlinked;
|
||||
bool fHasExtraAttributes;
|
||||
ext2_inode fNode;
|
||||
uint32 fNodeSize;
|
||||
// Inodes have a varible size, but the important
|
||||
// Inodes have a variable size, but the important
|
||||
// information is always the same size (except in ext4)
|
||||
ext2_xattr_header* fAttributesBlock;
|
||||
status_t fInitStatus;
|
||||
@@ -173,31 +205,31 @@ public:
|
||||
|
||||
void Keep()
|
||||
{
|
||||
dprintf("Vnode::Keep()\n");
|
||||
TRACEI("Vnode::Keep()\n");
|
||||
fInode = NULL;
|
||||
}
|
||||
|
||||
status_t Publish(Transaction& transaction, Inode* inode,
|
||||
fs_vnode_ops* vnodeOps, uint32 publishFlags)
|
||||
{
|
||||
dprintf("Vnode::Publish()\n");
|
||||
TRACEI("Vnode::Publish()\n");
|
||||
Volume* volume = transaction.GetVolume();
|
||||
|
||||
status_t status = B_OK;
|
||||
|
||||
if (!inode->IsSymLink() && volume->ID() >= 0) {
|
||||
dprintf("Vnode::Publish(): Publishing vnode: %d, %d, %p, %p, %x, "
|
||||
TRACEI("Vnode::Publish(): Publishing vnode: %d, %d, %p, %p, %x, "
|
||||
"%x\n", (int)volume->FSVolume(), (int)inode->ID(), inode,
|
||||
vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, (int)inode->Mode(),
|
||||
(int)publishFlags);
|
||||
status = publish_vnode(volume->FSVolume(), inode->ID(), inode,
|
||||
vnodeOps != NULL ? vnodeOps : &gExt2VnodeOps, inode->Mode(),
|
||||
publishFlags);
|
||||
dprintf("Vnode::Publish(): Result: %s\n", strerror(status));
|
||||
TRACEI("Vnode::Publish(): Result: %s\n", strerror(status));
|
||||
}
|
||||
|
||||
if (status == B_OK) {
|
||||
dprintf("Vnode::Publish(): Preparing internal data\n");
|
||||
TRACEI("Vnode::Publish(): Preparing internal data\n");
|
||||
fInode = inode;
|
||||
fStatus = B_OK;
|
||||
|
||||
|
||||
@@ -210,19 +210,21 @@ struct ext2_data_stream {
|
||||
uint32 triple_indirect;
|
||||
} _PACKED;
|
||||
|
||||
#define EXT2_INODE_NORMAL_SIZE 128
|
||||
|
||||
struct ext2_inode {
|
||||
uint16 mode;
|
||||
uint16 uid;
|
||||
uint32 size;
|
||||
uint32 access_time;
|
||||
uint32 creation_time;
|
||||
uint32 change_time;
|
||||
uint32 modification_time;
|
||||
uint32 deletion_time;
|
||||
uint16 gid;
|
||||
uint16 num_links;
|
||||
uint32 num_blocks;
|
||||
uint32 flags;
|
||||
uint32 _reserved1;
|
||||
uint32 version;
|
||||
union {
|
||||
ext2_data_stream stream;
|
||||
char symlink[EXT2_SHORT_SYMLINK_LENGTH];
|
||||
@@ -246,8 +248,16 @@ struct ext2_inode {
|
||||
uint16 uid_high;
|
||||
uint16 gid_high;
|
||||
uint32 _reserved2;
|
||||
|
||||
// extra attributes
|
||||
uint16 extra_inode_size;
|
||||
uint16 _padding2;
|
||||
uint32 change_time_extra;
|
||||
uint32 modification_time_extra;
|
||||
uint32 access_time_extra;
|
||||
uint32 creation_time;
|
||||
uint32 creation_time_extra;
|
||||
uint32 version_high;
|
||||
|
||||
uint16 Mode() const { return B_LENDIAN_TO_HOST_INT16(mode); }
|
||||
uint32 Flags() const { return B_LENDIAN_TO_HOST_INT32(flags); }
|
||||
@@ -256,12 +266,79 @@ struct ext2_inode {
|
||||
uint64 NumBlocks64() const { return B_LENDIAN_TO_HOST_INT32(num_blocks)
|
||||
| ((uint64)B_LENDIAN_TO_HOST_INT32(num_blocks_high) << 32); }
|
||||
|
||||
time_t AccessTime() const { return B_LENDIAN_TO_HOST_INT32(access_time); }
|
||||
time_t CreationTime() const { return B_LENDIAN_TO_HOST_INT32(creation_time); }
|
||||
time_t ModificationTime() const { return B_LENDIAN_TO_HOST_INT32(modification_time); }
|
||||
time_t DeletionTime() const { return B_LENDIAN_TO_HOST_INT32(deletion_time); }
|
||||
ino_t NextOrphan() const { return (ino_t)DeletionTime(); }
|
||||
static void _DecodeTime(struct timespec *timespec, uint32 time,
|
||||
uint32 time_extra, bool extra)
|
||||
{
|
||||
timespec->tv_sec = B_LENDIAN_TO_HOST_INT32(time);
|
||||
if (extra && sizeof(timespec->tv_sec) > 4)
|
||||
timespec->tv_sec |=
|
||||
(uint64)(B_LENDIAN_TO_HOST_INT32(time_extra) & 0x2) << 32;
|
||||
if (extra)
|
||||
timespec->tv_nsec = B_LENDIAN_TO_HOST_INT32(time_extra) >> 2;
|
||||
else
|
||||
timespec->tv_nsec = 0;
|
||||
}
|
||||
|
||||
void GetModificationTime(struct timespec *timespec, bool extra) const
|
||||
{ _DecodeTime(timespec, modification_time, modification_time_extra,
|
||||
extra); }
|
||||
void GetAccessTime(struct timespec *timespec, bool extra) const
|
||||
{ _DecodeTime(timespec, access_time, access_time_extra, extra); }
|
||||
void GetChangeTime(struct timespec *timespec, bool extra) const
|
||||
{ _DecodeTime(timespec, change_time, change_time_extra, extra); }
|
||||
void GetCreationTime(struct timespec *timespec, bool extra) const
|
||||
{
|
||||
if (extra)
|
||||
_DecodeTime(timespec, creation_time, creation_time_extra, extra);
|
||||
else {
|
||||
timespec->tv_sec = 0;
|
||||
timespec->tv_nsec = 0;
|
||||
}
|
||||
}
|
||||
time_t DeletionTime() const
|
||||
{ return B_LENDIAN_TO_HOST_INT32(deletion_time); }
|
||||
|
||||
static uint32 _EncodeTime(const struct timespec *timespec)
|
||||
{
|
||||
uint32 time = (timespec->tv_nsec << 2) & 0xfffffffc;
|
||||
if (sizeof(timespec->tv_sec) > 4)
|
||||
time |= (uint64)timespec->tv_sec >> 32;
|
||||
return B_HOST_TO_LENDIAN_INT32(time);
|
||||
}
|
||||
|
||||
void SetModificationTime(const struct timespec *timespec, bool extra)
|
||||
{
|
||||
modification_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
|
||||
if (extra)
|
||||
modification_time_extra = _EncodeTime(timespec);
|
||||
}
|
||||
void SetAccessTime(const struct timespec *timespec, bool extra)
|
||||
{
|
||||
access_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
|
||||
if (extra)
|
||||
access_time_extra = _EncodeTime(timespec);
|
||||
}
|
||||
void SetChangeTime(const struct timespec *timespec, bool extra)
|
||||
{
|
||||
change_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
|
||||
if (extra)
|
||||
change_time_extra = _EncodeTime(timespec);
|
||||
}
|
||||
void SetCreationTime(const struct timespec *timespec, bool extra)
|
||||
{
|
||||
if (extra) {
|
||||
creation_time = B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_sec);
|
||||
creation_time_extra =
|
||||
B_HOST_TO_LENDIAN_INT32((uint32)timespec->tv_nsec);
|
||||
}
|
||||
}
|
||||
void SetDeletionTime(time_t deletionTime)
|
||||
{
|
||||
deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime);
|
||||
}
|
||||
|
||||
ino_t NextOrphan() const { return (ino_t)DeletionTime(); }
|
||||
|
||||
off_t Size() const
|
||||
{
|
||||
if (S_ISREG(Mode())) {
|
||||
@@ -272,6 +349,9 @@ struct ext2_inode {
|
||||
return B_LENDIAN_TO_HOST_INT32(size);
|
||||
}
|
||||
|
||||
uint16 ExtraInodeSize() const
|
||||
{ return B_LENDIAN_TO_HOST_INT16(extra_inode_size); }
|
||||
|
||||
uint32 UserID() const
|
||||
{
|
||||
return B_LENDIAN_TO_HOST_INT16(uid)
|
||||
@@ -325,26 +405,6 @@ struct ext2_inode {
|
||||
num_blocks_high = B_HOST_TO_LENDIAN_INT32(numBlocks >> 32);
|
||||
}
|
||||
|
||||
void SetAccessTime(time_t accessTime)
|
||||
{
|
||||
access_time = B_HOST_TO_LENDIAN_INT32((uint32)accessTime);
|
||||
}
|
||||
|
||||
void SetCreationTime(time_t creationTime)
|
||||
{
|
||||
creation_time = B_HOST_TO_LENDIAN_INT32((uint32)creationTime);
|
||||
}
|
||||
|
||||
void SetModificationTime(time_t modificationTime)
|
||||
{
|
||||
modification_time = B_HOST_TO_LENDIAN_INT32((uint32)modificationTime);
|
||||
}
|
||||
|
||||
void SetDeletionTime(time_t deletionTime)
|
||||
{
|
||||
deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)deletionTime);
|
||||
}
|
||||
|
||||
void SetNextOrphan(ino_t id)
|
||||
{
|
||||
deletion_time = B_HOST_TO_LENDIAN_INT32((uint32)id);
|
||||
@@ -373,6 +433,11 @@ struct ext2_inode {
|
||||
{
|
||||
file_access_control = B_HOST_TO_LENDIAN_INT32(block);
|
||||
}
|
||||
|
||||
void SetExtraInodeSize(uint16 newSize)
|
||||
{
|
||||
extra_inode_size = B_HOST_TO_LENDIAN_INT16(newSize);
|
||||
}
|
||||
} _PACKED;
|
||||
|
||||
#define EXT2_SUPER_BLOCK_MAGIC 0xef53
|
||||
|
||||
@@ -550,10 +550,11 @@ ext2_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat)
|
||||
stat->st_mode = node.Mode();
|
||||
stat->st_type = 0;
|
||||
|
||||
stat->st_atime = node.AccessTime();
|
||||
stat->st_mtime = stat->st_ctime = node.ModificationTime();
|
||||
stat->st_crtime = node.CreationTime();
|
||||
|
||||
inode->GetAccessTime(&stat->st_atim);
|
||||
inode->GetModificationTime(&stat->st_mtim);
|
||||
inode->GetChangeTime(&stat->st_ctim);
|
||||
inode->GetCreationTime(&stat->st_crtim);
|
||||
|
||||
stat->st_size = inode->Size();
|
||||
stat->st_blocks = (inode->Size() + 511) / 512;
|
||||
|
||||
@@ -626,22 +627,22 @@ ext2_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat* stat,
|
||||
|
||||
if ((mask & B_STAT_MODIFICATION_TIME) != 0 || updateTime
|
||||
|| (mask & B_STAT_CHANGE_TIME) != 0) {
|
||||
time_t newTime = 0;
|
||||
struct timespec newTimespec = { 0, 0};
|
||||
|
||||
if ((mask & B_STAT_MODIFICATION_TIME) != 0)
|
||||
newTime = stat->st_mtim.tv_sec;
|
||||
newTimespec = stat->st_mtim;
|
||||
|
||||
if ((mask & B_STAT_CHANGE_TIME) != 0)
|
||||
newTime = newTime > stat->st_ctim.tv_sec ? newTime
|
||||
: stat->st_ctim.tv_sec;
|
||||
if ((mask & B_STAT_CHANGE_TIME) != 0
|
||||
&& stat->st_ctim.tv_sec > newTimespec.tv_sec)
|
||||
newTimespec = stat->st_ctim;
|
||||
|
||||
if (newTime == 0)
|
||||
newTime = real_time_clock();
|
||||
if (newTimespec.tv_sec == 0)
|
||||
Inode::_BigtimeToTimespec(real_time_clock_usecs(), &newTimespec);
|
||||
|
||||
node.SetModificationTime(newTime);
|
||||
inode->SetModificationTime(&newTimespec);
|
||||
}
|
||||
if ((mask & B_STAT_CREATION_TIME) != 0)
|
||||
node.SetCreationTime(stat->st_crtim.tv_sec);
|
||||
inode->SetCreationTime(&stat->st_crtim);
|
||||
|
||||
status = inode->WriteBack(transaction);
|
||||
if (status == B_OK)
|
||||
|
||||
Reference in New Issue
Block a user