* Improved the status_change time check to actually filter out invalid times,

before, st_ctim was never updated; since you cannot change st_ctim via an API,
  '0' cannot ever be set, either.
* Inode::WriteAttribute(), and Attribute::Write() now return whether they
  created an attribute or not, and thus B_ATTR_CREATED is now correctly set.
* Moved status_change update from bfs_write_attr() into Inode::WriteAttribute()
  where it can be handled more efficiently.
* Likewise, Inode::RemoveAttribute() now updates the status_change time as well,
  I simply forgot this before.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33832 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-10-29 18:09:15 +00:00
parent 2350995e01
commit 1b944eec20
5 changed files with 52 additions and 32 deletions
@@ -205,13 +205,13 @@ Attribute::Read(attr_cookie* cookie, off_t pos, uint8* buffer, size_t* _length)
status_t
Attribute::Write(Transaction& transaction, attr_cookie* cookie, off_t pos,
const uint8* buffer, size_t* _length)
const uint8* buffer, size_t* _length, bool* _created)
{
if (!cookie->create && fSmall == NULL && fAttribute == NULL)
return B_NO_INIT;
return fInode->WriteAttribute(transaction, cookie->name, cookie->type,
pos, buffer, _length);
pos, buffer, _length, _created);
}
@@ -39,8 +39,8 @@ public:
status_t Read(attr_cookie* cookie, off_t pos, uint8* buffer,
size_t* _length);
status_t Write(Transaction& transaction, attr_cookie* cookie,
off_t pos, const uint8* buffer,
size_t* _length);
off_t pos, const uint8* buffer, size_t* _length,
bool* _created);
private:
status_t _Truncate();
+36 -4
View File
@@ -650,8 +650,12 @@ Inode::_RemoveSmallData(Transaction& transaction, NodeGetter& nodeGetter,
nodeGetter.MakeWritable(transaction);
status_t status = _RemoveSmallData(node, item, index);
if (status == B_OK)
if (status == B_OK) {
Node().status_change_time = HOST_ENDIAN_TO_BFS_INT64(
bfs_inode::ToInode(real_time_clock_usecs()));
status = WriteBack(transaction);
}
return status;
}
@@ -1033,7 +1037,7 @@ Inode::ReadAttribute(const char* name, int32 type, off_t pos, uint8* buffer,
*/
status_t
Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
off_t pos, const uint8* buffer, size_t* _length)
off_t pos, const uint8* buffer, size_t* _length, bool* _created)
{
if (pos < 0)
return B_BAD_VALUE;
@@ -1042,6 +1046,7 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
uint8 oldBuffer[BPLUSTREE_MAX_KEY_LENGTH];
uint8* oldData = NULL;
size_t oldLength = 0;
bool created = false;
// TODO: we actually depend on that the contents of "buffer" are constant.
// If they get changed during the write (hey, user programs), we may mess
@@ -1071,7 +1076,9 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
oldLength = BPLUSTREE_MAX_KEY_LENGTH;
memcpy(oldData = oldBuffer, smallData->Data(), oldLength);
}
}
} else
created = true;
recursive_lock_unlock(&fSmallDataLock);
// if the attribute doesn't exist yet (as a file), try to put it in the
@@ -1091,8 +1098,15 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
status = CreateAttribute(transaction, name, type, &attribute);
if (status != B_OK)
RETURN_ERROR(status);
} else if (status == B_OK)
created = true;
} else if (status == B_OK) {
// Update status time on attribute write
Node().status_change_time = HOST_ENDIAN_TO_BFS_INT64(
bfs_inode::ToInode(real_time_clock_usecs()));
status = WriteBack(transaction);
}
}
if (attribute != NULL) {
@@ -1127,6 +1141,14 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
_length);
}
}
if (status == B_OK) {
// Update status time on attribute write
Node().status_change_time = HOST_ENDIAN_TO_BFS_INT64(
bfs_inode::ToInode(real_time_clock_usecs()));
status = WriteBack(transaction);
}
} else
status = B_ERROR;
@@ -1149,6 +1171,10 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
length, this);
}
}
if (_created != NULL)
*_created = created;
return status;
}
@@ -1182,7 +1208,13 @@ Inode::RemoveAttribute(Transaction& transaction, const char* name)
if (status == B_ENTRY_NOT_FOUND && !Attributes().IsZero()) {
// remove the attribute file if it exists
status = _RemoveAttribute(transaction, name, hasIndex, &index);
if (status == B_OK) {
Node().status_change_time = HOST_ENDIAN_TO_BFS_INT64(
bfs_inode::ToInode(real_time_clock_usecs()));
WriteBack(transaction);
}
}
return status;
}
+2 -1
View File
@@ -107,7 +107,8 @@ public:
off_t pos, uint8* buffer, size_t* _length);
status_t WriteAttribute(Transaction& transaction,
const char* name, int32 type, off_t pos,
const uint8* buffer, size_t* _length);
const uint8* buffer, size_t* _length,
bool* _created);
status_t RemoveAttribute(Transaction& transaction,
const char* name);
@@ -43,15 +43,9 @@ fill_stat_time(const bfs_inode& node, struct stat& stat)
stat.st_crtim.tv_sec = bfs_inode::ToSecs(node.CreateTime());
stat.st_crtim.tv_nsec = bfs_inode::ToUsecs(node.CreateTime());
// if on-disk ctime is invalid (pointer value from previous [ab]use of
// the first 4 bytes) or 0, fall back to mtime:
// N.B.: This has the drawback that explicitly setting a ctime of 0
// will not work, but I suppose no one will do that, since ctime
// is usually just set to the current time whenever something happens
// to the inode.
// TODO: find out if this sanity check should be dropped!
// For BeOS compatibility, if on-disk ctime is invalid, fall back to mtime:
bigtime_t changeTime = node.StatusChangeTime();
if (((uint64)changeTime & 0xFFFF00000000FFFFULL) != 0 || changeTime == 0)
if (changeTime < node.LastModifiedTime())
stat.st_ctim = stat.st_mtim;
else {
stat.st_ctim.tv_sec = bfs_inode::ToSecs(changeTime);
@@ -1196,11 +1190,10 @@ bfs_rename(fs_volume* _volume, fs_vnode* _oldDir, const char* oldName,
}
}
if (newDirectory != oldDirectory) {
oldDirectory->ContainerContentsChanged(transaction);
newDirectory->ContainerContentsChanged(transaction);
} else
newDirectory->ContainerContentsChanged(transaction);
if (status == B_OK && newDirectory != oldDirectory)
status = oldDirectory->ContainerContentsChanged(transaction);
if (status == B_OK)
status = newDirectory->ContainerContentsChanged(transaction);
if (status == B_OK)
status = inode->WriteBack(transaction);
@@ -1808,20 +1801,14 @@ bfs_write_attr(fs_volume* _volume, fs_vnode* _file, void* _cookie,
Transaction transaction(volume, inode->BlockNumber());
Attribute attribute(inode, cookie);
bool created;
status_t status = attribute.Write(transaction, cookie, pos,
(const uint8*)buffer, _length);
(const uint8*)buffer, _length, &created);
if (status == B_OK) {
// Update status time on attribute write
inode->Node().status_change_time = HOST_ENDIAN_TO_BFS_INT64(
bfs_inode::ToInode(real_time_clock_usecs()));
inode->WriteBack(transaction);
status = transaction.Done();
if (status == B_OK) {
notify_attribute_changed(volume->ID(), inode->ID(), cookie->name,
B_ATTR_CHANGED);
// TODO: B_ATTR_CREATED is not yet taken into account
// (we don't know what Attribute::Write() does exactly)
created ? B_ATTR_CREATED : B_ATTR_CHANGED);
notify_stat_changed(volume->ID(), inode->ID(), B_STAT_CHANGE_TIME);
}
}
@@ -1877,7 +1864,7 @@ bfs_remove_attr(fs_volume* _volume, fs_vnode* _node, const char* name)
Inode* inode = (Inode*)_node->private_node;
status_t status = inode->CheckPermissions(W_OK);
if (status < B_OK)
if (status != B_OK)
return status;
Transaction transaction(volume, inode->BlockNumber());