diff --git a/src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp b/src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp index 6b298b3c43..d47a2b2c27 100644 --- a/src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp +++ b/src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp @@ -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; } diff --git a/src/add-ons/kernel/file_systems/ext2/Inode.cpp b/src/add-ons/kernel/file_systems/ext2/Inode.cpp index 04d867ee05..1b9e334dc4 100644 --- a/src/add-ons/kernel/file_systems/ext2/Inode.cpp +++ b/src/add-ons/kernel/file_systems/ext2/Inode.cpp @@ -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; } + diff --git a/src/add-ons/kernel/file_systems/ext2/Inode.h b/src/add-ons/kernel/file_systems/ext2/Inode.h index 9a9b645523..36587b66b8 100644 --- a/src/add-ons/kernel/file_systems/ext2/Inode.h +++ b/src/add-ons/kernel/file_systems/ext2/Inode.h @@ -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; diff --git a/src/add-ons/kernel/file_systems/ext2/ext2.h b/src/add-ons/kernel/file_systems/ext2/ext2.h index 10c976ef70..57283004d3 100644 --- a/src/add-ons/kernel/file_systems/ext2/ext2.h +++ b/src/add-ons/kernel/file_systems/ext2/ext2.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp index a03e1e52e0..37770da5b0 100644 --- a/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/ext2/kernel_interface.cpp @@ -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)