* 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:
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user