When we truncate or resize the file we need to trim the write_buffers. Otherwise

we waste space, but we also incorrectly fail to update the size for all writes
that do not go beyond the previous file size.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32825 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2009-08-30 02:41:31 +00:00
parent 39d6a07862
commit c1043ac95e
@@ -154,6 +154,8 @@ public:
overlay_dirent **entry);
private:
void _TrimBuffers();
status_t _PopulateDirents();
status_t _CreateCommon(const char *name, int type, int perms,
ino_t *newInodeNumber, OverlayInode **node);
@@ -388,8 +390,10 @@ OverlayInode::WriteStat(const struct stat *stat, uint32 statMask)
if (!fHasStat)
ReadStat(NULL);
if (statMask & B_STAT_SIZE)
if (statMask & B_STAT_SIZE) {
fStat.st_size = stat->st_size;
_TrimBuffers();
}
if (statMask & B_STAT_MODE)
fStat.st_mode = (fStat.st_mode & ~S_IUMSK) | (stat->st_mode & S_IUMSK);
@@ -445,8 +449,10 @@ OverlayInode::Open(int openMode, void **_cookie)
*_cookie = cookie;
if (fIsVirtual) {
if (openMode & O_TRUNC)
if (openMode & O_TRUNC) {
fStat.st_size = 0;
_TrimBuffers();
}
return B_OK;
}
@@ -466,6 +472,7 @@ OverlayInode::Open(int openMode, void **_cookie)
if (openMode & O_TRUNC) {
fStat.st_size = 0;
_TrimBuffers();
if (!fIsModified)
SetModified();
}
@@ -889,6 +896,57 @@ OverlayInode::RemoveEntry(const char *name, overlay_dirent **_entry)
}
void
OverlayInode::_TrimBuffers()
{
// the file size has been changed and we want to trim
// off everything that goes beyond the new size
write_buffer **link = &fWriteBuffers;
write_buffer *buffer = fWriteBuffers;
while (buffer != NULL) {
off_t bufferEnd = buffer->position + buffer->length;
if (bufferEnd > fStat.st_size)
break;
link = &buffer->next;
buffer = buffer->next;
}
if (buffer == NULL) {
// didn't find anything crossing or past the end
return;
}
if (buffer->position < fStat.st_size) {
// got a crossing buffer to resize
size_t newLength = fStat.st_size - buffer->position;
write_buffer *newBuffer = (write_buffer *)realloc(buffer,
sizeof(write_buffer) - 1 + newLength);
if (newBuffer != NULL) {
buffer = newBuffer;
*link = newBuffer;
} else {
// we don't really care if it worked, if it didn't we simply
// keep the old buffer and reset it's size
}
buffer->length = newLength;
link = &buffer->next;
buffer = buffer->next;
}
// everything else we can throw away
*link = NULL;
while (buffer != NULL) {
write_buffer *next = buffer->next;
free(buffer);
buffer = next;
}
}
status_t
OverlayInode::_PopulateDirents()
{