* This should mostly complete the write_overlay.

* Fix memory leaks here and there.
* Virtualize the dirent list.
* Handle "." and ".." ourselfs as at least iso9660 cannot really know them in
  the readdir call and therefore returns different values than on lookup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29458 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2009-03-09 01:26:45 +00:00
parent 42e53f97a2
commit f4041343e6
@@ -87,7 +87,7 @@ public:
OverlayInode(OverlayVolume *volume, OverlayInode(OverlayVolume *volume,
fs_vnode *superVnode, ino_t inodeNumber, fs_vnode *superVnode, ino_t inodeNumber,
OverlayInode *parentDir = NULL, OverlayInode *parentDir = NULL,
mode_t mode = 0); const char *name = NULL, mode_t mode = 0);
~OverlayInode(); ~OverlayInode();
status_t InitCheck(); status_t InitCheck();
@@ -99,7 +99,11 @@ public:
fs_vnode * SuperVnode() { return &fSuperVnode; } fs_vnode * SuperVnode() { return &fSuperVnode; }
ino_t InodeNumber() { return fInodeNumber; } ino_t InodeNumber() { return fInodeNumber; }
void SetParentDir(OverlayInode *parentDir);
OverlayInode * ParentDir() { return fParentDir; }
status_t Lookup(const char *name, ino_t *inodeNumber); status_t Lookup(const char *name, ino_t *inodeNumber);
status_t GetName(char *buffer, size_t bufferSize);
status_t ReadStat(struct stat *stat); status_t ReadStat(struct stat *stat);
status_t WriteStat(const struct stat *stat, uint32 statMask); status_t WriteStat(const struct stat *stat, uint32 statMask);
@@ -139,6 +143,7 @@ private:
OverlayVolume * fVolume; OverlayVolume * fVolume;
OverlayInode * fParentDir; OverlayInode * fParentDir;
const char * fName;
fs_vnode fSuperVnode; fs_vnode fSuperVnode;
ino_t fInodeNumber; ino_t fInodeNumber;
write_buffer * fWriteBuffers; write_buffer * fWriteBuffers;
@@ -157,7 +162,7 @@ private:
OverlayVolume::OverlayVolume(fs_volume *volume) OverlayVolume::OverlayVolume(fs_volume *volume)
: fVolume(volume), : fVolume(volume),
fCurrentInodeNumber((ino_t)1 << 32) fCurrentInodeNumber((ino_t)1 << 60)
{ {
} }
@@ -171,9 +176,10 @@ OverlayVolume::~OverlayVolume()
OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode, OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode,
ino_t inodeNumber, OverlayInode *parentDir, mode_t mode) ino_t inodeNumber, OverlayInode *parentDir, const char *name, mode_t mode)
: fVolume(volume), : fVolume(volume),
fParentDir(parentDir), fParentDir(parentDir),
fName(name),
fInodeNumber(inodeNumber), fInodeNumber(inodeNumber),
fWriteBuffers(NULL), fWriteBuffers(NULL),
fOriginalNodeLength(-1), fOriginalNodeLength(-1),
@@ -228,32 +234,52 @@ OverlayInode::InitCheck()
} }
void
OverlayInode::SetParentDir(OverlayInode *parentDir)
{
fParentDir = parentDir;
}
status_t status_t
OverlayInode::Lookup(const char *name, ino_t *inodeNumber) OverlayInode::Lookup(const char *name, ino_t *inodeNumber)
{ {
if (strcmp(name, ".") == 0) { if (!fHasDirents)
*inodeNumber = fInodeNumber; _PopulateDirents();
return get_vnode(SuperVolume(), *inodeNumber, NULL);
}
if (fIsVirtual && strcmp(name, "..") == 0) {
*inodeNumber = fParentDir->InodeNumber();
return get_vnode(Volume(), *inodeNumber, NULL);
}
for (uint32 i = 0; i < fDirentCount; i++) { for (uint32 i = 0; i < fDirentCount; i++) {
if (strcmp(fDirents[i]->name, name) == 0) { if (strcmp(fDirents[i]->name, name) == 0) {
*inodeNumber = fDirents[i]->inode_number; *inodeNumber = fDirents[i]->inode_number;
return get_vnode(SuperVolume(), *inodeNumber, NULL);
OverlayInode *node = NULL;
status_t result = get_vnode(Volume(), *inodeNumber,
(void **)&node);
if (result == B_OK && node != NULL)
node->SetParentDir(this);
return result;
} }
} }
if (!fHasDirents && !fIsVirtual && fSuperVnode.ops->lookup != NULL) { return B_ENTRY_NOT_FOUND;
return fSuperVnode.ops->lookup(SuperVolume(), &fSuperVnode, name, }
inodeNumber);
status_t
OverlayInode::GetName(char *buffer, size_t bufferSize)
{
if (fIsVirtual) {
if (fName == NULL)
return B_UNSUPPORTED;
strlcpy(buffer, fName, bufferSize);
return B_OK;
} }
return B_ENTRY_NOT_FOUND; if (fSuperVnode.ops->get_vnode_name == NULL)
return B_UNSUPPORTED;
return fSuperVnode.ops->get_vnode_name(SuperVolume(), &fSuperVnode, buffer,
bufferSize);
} }
@@ -617,10 +643,11 @@ OverlayInode::RewindDir(void *cookie)
status_t status_t
OverlayInode::CreateSymlink(const char *name, const char *path, int perms) OverlayInode::CreateSymlink(const char *name, const char *path, int mode)
{ {
OverlayInode *newNode = NULL; OverlayInode *newNode = NULL;
status_t result = _CreateCommon(name, S_IFLNK, perms, NULL, &newNode); // TODO: find out why mode is ignored
status_t result = _CreateCommon(name, S_IFLNK, 0777, NULL, &newNode);
if (result != B_OK) if (result != B_OK)
return result; return result;
@@ -653,9 +680,12 @@ OverlayInode::AddEntry(overlay_dirent *entry)
if (!fHasDirents) if (!fHasDirents)
_PopulateDirents(); _PopulateDirents();
for (uint32 i = 0; i < fDirentCount; i++) for (uint32 i = 0; i < fDirentCount; i++) {
if (strcmp(fDirents[i]->name, entry->name) == 0) if (strcmp(fDirents[i]->name, entry->name) == 0) {
TRACE("entry \"%s\" exists\n", entry->name);
return B_FILE_EXISTS; return B_FILE_EXISTS;
}
}
overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents, overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents,
sizeof(overlay_dirent *) * (fDirentCount + 1)); sizeof(overlay_dirent *) * (fDirentCount + 1));
@@ -709,47 +739,46 @@ OverlayInode::_PopulateDirents()
if (fHasDirents) if (fHasDirents)
return B_OK; return B_OK;
if (fIsVirtual || fSuperVnode.ops->open_dir == NULL fDirents = (overlay_dirent **)malloc(sizeof(overlay_dirent *) * 2);
|| fSuperVnode.ops->read_dir == NULL) { if (fDirents == NULL)
fDirents = (overlay_dirent **)malloc(sizeof(overlay_dirent *) * 2); return B_NO_MEMORY;
if (fDirents == NULL)
const char *names[] = { ".", ".." };
ino_t inodes[] = { fInodeNumber,
fParentDir != NULL ? fParentDir->InodeNumber() : 0 };
for (uint32 i = 0; i < 2; i++) {
fDirents[i] = (overlay_dirent *)malloc(sizeof(overlay_dirent));
if (fDirents[i] == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
const char *names[] = { ".", ".." }; fDirents[i]->inode_number = inodes[i];
ino_t inodes[] = { fInodeNumber, fDirents[i]->name = strdup(names[i]);
fParentDir != NULL ? fParentDir->InodeNumber() : 0 }; if (fDirents[i]->name == NULL) {
for (uint32 i = 0; i < 2; i++) { free(fDirents[i]);
fDirents[i] = (overlay_dirent *)malloc(sizeof(overlay_dirent)); return B_NO_MEMORY;
if (fDirents[i] == NULL)
return B_NO_MEMORY;
fDirents[i]->inode_number = inodes[i];
fDirents[i]->name = strdup(names[i]);
if (fDirents[i]->name == NULL) {
free(fDirents[i]);
return B_NO_MEMORY;
}
fDirentCount++;
} }
fHasDirents = true; fDirentCount++;
return B_OK;
} }
fHasDirents = true; fHasDirents = true;
if (fIsVirtual || fSuperVnode.ops->open_dir == NULL
|| fSuperVnode.ops->read_dir == NULL)
return B_OK;
// we don't really care about errors from here on
void *superCookie = NULL; void *superCookie = NULL;
status_t result = fSuperVnode.ops->open_dir(SuperVolume(), status_t result = fSuperVnode.ops->open_dir(SuperVolume(),
&fSuperVnode, &superCookie); &fSuperVnode, &superCookie);
if (result != B_OK) if (result != B_OK)
return result; return B_OK;
size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH; size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH;
struct dirent *buffer = (struct dirent *)malloc(bufferSize); struct dirent *buffer = (struct dirent *)malloc(bufferSize);
if (buffer == NULL) if (buffer == NULL)
return B_NO_MEMORY; goto close_dir;
while (result == B_OK) { while (true) {
uint32 num = 1; uint32 num = 1;
result = fSuperVnode.ops->read_dir(SuperVolume(), result = fSuperVnode.ops->read_dir(SuperVolume(),
&fSuperVnode, superCookie, buffer, bufferSize, &num); &fSuperVnode, superCookie, buffer, bufferSize, &num);
@@ -758,36 +787,49 @@ OverlayInode::_PopulateDirents()
overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents, overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents,
sizeof(overlay_dirent *) * (fDirentCount + num)); sizeof(overlay_dirent *) * (fDirentCount + num));
if (newDirents == NULL) if (newDirents == NULL) {
TRACE_ALWAYS("failed to allocate storage for dirents\n");
break; break;
}
fDirents = newDirents; fDirents = newDirents;
struct dirent *dirent = buffer; struct dirent *dirent = buffer;
for (uint32 i = 0; i < num; i++) { for (uint32 i = 0; i < num; i++) {
overlay_dirent *entry = (overlay_dirent *)malloc( if (strcmp(dirent->d_name, ".") != 0
sizeof(overlay_dirent)); && strcmp(dirent->d_name, "..") != 0) {
if (entry == NULL) overlay_dirent *entry = (overlay_dirent *)malloc(
break; sizeof(overlay_dirent));
if (entry == NULL) {
TRACE_ALWAYS("failed to allocate storage for dirent\n");
break;
}
entry->inode_number = dirent->d_ino; entry->inode_number = dirent->d_ino;
entry->name = strdup(dirent->d_name); entry->name = strdup(dirent->d_name);
if (entry->name == NULL) { if (entry->name == NULL) {
free(entry); TRACE_ALWAYS("failed to duplicate dirent entry name\n");
break; free(entry);
break;
}
fDirents[fDirentCount++] = entry;
} }
fDirents[fDirentCount++] = entry;
dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen); dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen);
} }
} }
free(buffer);
close_dir:
if (fSuperVnode.ops->close_dir != NULL) if (fSuperVnode.ops->close_dir != NULL)
fSuperVnode.ops->close_dir(SuperVolume(), &fSuperVnode, superCookie); fSuperVnode.ops->close_dir(SuperVolume(), &fSuperVnode, superCookie);
if (fSuperVnode.ops->free_dir_cookie != NULL) if (fSuperVnode.ops->free_dir_cookie != NULL) {
fSuperVnode.ops->free_dir_cookie(SuperVolume(), &fSuperVnode, superCookie); fSuperVnode.ops->free_dir_cookie(SuperVolume(), &fSuperVnode,
superCookie);
}
free(buffer);
return B_OK; return B_OK;
} }
@@ -815,7 +857,7 @@ OverlayInode::_CreateCommon(const char *name, int type, int perms,
entry->inode_number = fVolume->BuildInodeNumber(); entry->inode_number = fVolume->BuildInodeNumber();
OverlayInode *node = new(std::nothrow) OverlayInode(fVolume, NULL, OverlayInode *node = new(std::nothrow) OverlayInode(fVolume, NULL,
entry->inode_number, this, perms | type); entry->inode_number, this, entry->name, (perms & S_IUMSK) | type);
if (node == NULL) { if (node == NULL) {
free(entry->name); free(entry->name);
free(entry); free(entry);
@@ -827,6 +869,7 @@ OverlayInode::_CreateCommon(const char *name, int type, int perms,
free(entry->name); free(entry->name);
free(entry); free(entry);
delete node; delete node;
return result;
} }
result = publish_overlay_vnode(fVolume->Volume(), entry->inode_number, result = publish_overlay_vnode(fVolume->Volume(), entry->inode_number,
@@ -941,8 +984,7 @@ static status_t
overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer, overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer,
size_t bufferSize) size_t bufferSize)
{ {
OVERLAY_CALL(get_vnode_name, buffer, bufferSize) return ((OverlayInode *)vnode->private_node)->GetName(buffer, bufferSize);
return B_UNSUPPORTED;
} }
@@ -1511,6 +1553,11 @@ overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
return result; return result;
info->flags &= ~B_FS_IS_READONLY; info->flags &= ~B_FS_IS_READONLY;
// TODO: maybe calculate based on available ram
off_t available = 1024 * 1024 * 100 / info->block_size;
info->total_blocks += available;
info->free_blocks += available;
return B_OK; return B_OK;
} }