exfat: Return more than a single dirent at a time in exfat_read_dir().

* similar to what mmlr did in hrev45575 for bfs.
* DirectoryIterator could try to read past the end of the directory.
* replaced a dprintf with a TRACE() statement.
This commit is contained in:
Jerome Duval
2013-05-04 18:12:51 +02:00
parent 9f0006623c
commit ee668d24e3
4 changed files with 65 additions and 30 deletions
@@ -47,9 +47,13 @@ status_t
DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id,
EntryVisitor* visitor)
{
if (fCluster == EXFAT_CLUSTER_END)
return B_ENTRY_NOT_FOUND;
if (fOffset == -2) {
*_nameLength = 3;
strlcpy(name, "..", *_nameLength);
if (*_nameLength < 3)
return B_BUFFER_OVERFLOW;
*_nameLength = 2;
strlcpy(name, "..", *_nameLength + 1);
if (fInode->ID() == 1)
*_id = fInode->ID();
else
@@ -58,19 +62,22 @@ DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id,
TRACE("DirectoryIterator::GetNext() found ..\n");
return B_OK;
} else if (fOffset == -1) {
*_nameLength = 2;
strlcpy(name, ".", *_nameLength);
if (*_nameLength < 2)
return B_BUFFER_OVERFLOW;
*_nameLength = 1;
strlcpy(name, ".", *_nameLength + 1);
*_id = fInode->ID();
fOffset = 0;
TRACE("DirectoryIterator::GetNext() found .\n");
return B_OK;
}
uchar unicodeName[EXFAT_FILENAME_MAX_LENGTH];
uchar unicodeName[EXFAT_FILENAME_MAX_LENGTH + 1];
size_t nameLength = EXFAT_FILENAME_MAX_LENGTH;
status_t status = _GetNext(unicodeName, &nameLength, _id, visitor);
if (status == B_OK && name != NULL) {
unicode_to_utf8(unicodeName, nameLength, (uint8 *)name , _nameLength);
status = unicode_to_utf8(unicodeName, nameLength, (uint8 *)name,
_nameLength);
TRACE("DirectoryIterator::GetNext() %ld %s, %" B_PRIdINO "\n",
fInode->Cluster(), name, *_id);
}
@@ -96,7 +103,7 @@ DirectoryIterator::Lookup(const char* name, size_t nameLength, ino_t* _id)
Rewind();
fOffset = 0;
uchar currentName[EXFAT_FILENAME_MAX_LENGTH];
uchar currentName[EXFAT_FILENAME_MAX_LENGTH + 1];
size_t currentLength = EXFAT_FILENAME_MAX_LENGTH;
while (_GetNext((uchar*)currentName, &currentLength, _id) == B_OK) {
char utfName[EXFAT_FILENAME_MAX_LENGTH];
@@ -122,7 +129,7 @@ DirectoryIterator::LookupEntry(EntryVisitor* visitor)
fCluster = fInode->Cluster();
fOffset = fInode->Offset();
uchar unicodeName[EXFAT_FILENAME_MAX_LENGTH];
uchar unicodeName[EXFAT_FILENAME_MAX_LENGTH + 1];
size_t nameLength = EXFAT_FILENAME_MAX_LENGTH;
return _GetNext(unicodeName, &nameLength, NULL, visitor);
}
@@ -218,7 +218,7 @@ LabelVisitor::LabelVisitor(Volume* volume)
bool
LabelVisitor::VisitLabel(struct exfat_entry* entry)
{
dprintf("LabelVisitor::VisitLabel()\n");
TRACE("LabelVisitor::VisitLabel()\n");
char utfName[30];
size_t utfLength = 30;
unicode_to_utf8((const uchar*)entry->name_label.name,
@@ -418,6 +418,8 @@ Volume::LoadSuperBlock()
status_t
Volume::ClusterToBlock(cluster_t cluster, fsblock_t &block)
{
if (cluster < 2)
return B_BAD_VALUE;
block = ((cluster - 2) << SuperBlock().BlocksPerClusterShift())
+ SuperBlock().FirstDataBlock();
TRACE("Volume::ClusterToBlock() cluster %lu %u %lu: %llu, %lu\n", cluster,
@@ -106,6 +106,7 @@ _lendian_unicode_to_utf8(
int32 dstLimit = *dstLen;
int32 srcCount = 0;
int32 dstCount = 0;
status_t status = B_ERROR;
for (srcCount = 0; srcCount < srcLimit; srcCount += 2) {
uint16 *UNICODE = (uint16 *)&src[srcCount];
@@ -119,19 +120,22 @@ _lendian_unicode_to_utf8(
u_lendian_to_utf8(UTF8, UNICODE);
utf8Len = UTF8 - utf8;
if ((dstCount + utf8Len) > dstLimit)
if ((dstCount + utf8Len) > dstLimit) {
status = B_BUFFER_OVERFLOW;
break;
}
for (j = 0; j < utf8Len; j++)
dst[dstCount + j] = utf8[j];
dstCount += utf8Len;
status = B_OK;
}
*srcLen = srcCount;
*dstLen = dstCount;
dst[dstCount] = '\0';
return ((dstCount > 0) ? B_NO_ERROR : B_ERROR);
return status;
}
// utf8 to LENDIAN unicode
@@ -146,6 +150,7 @@ _utf8_to_lendian_unicode(
int32 dstLimit = *dstLen - 1;
int32 srcCount = 0;
int32 dstCount = 0;
status_t status = B_ERROR;
while ((srcCount < srcLimit) && (dstCount < dstLimit)) {
uint16 unicode;
@@ -157,20 +162,25 @@ _utf8_to_lendian_unicode(
break;
utf8_to_u_hostendian(UTF8, UNICODE, err_flag);
if(err_flag == 1)
if (err_flag == 1)
return EINVAL;
unicode = B_HOST_TO_LENDIAN_INT16(unicode);
if ((dstCount + 1) > dstLimit) {
status = B_BUFFER_OVERFLOW;
break;
}
dst[dstCount++] = unicode & 0xFF;
dst[dstCount++] = unicode >> 8;
srcCount += UTF8 - ((uchar *)(src + srcCount));
status = B_OK;
}
*srcLen = srcCount;
*dstLen = dstCount;
return ((dstCount > 0) ? B_NO_ERROR : B_ERROR);
return status;
}
@@ -179,7 +179,7 @@ static status_t
exfat_get_vnode(fs_volume* _volume, ino_t id, fs_vnode* _node, int* _type,
uint32* _flags, bool reenter)
{
TRACE("get_vnode %lu\n", id);
TRACE("get_vnode %" B_PRIdINO "\n", id);
Volume* volume = (Volume*)_volume->private_volume;
Inode* inode = new(std::nothrow) Inode(volume, id);
@@ -357,7 +357,7 @@ exfat_lookup(fs_volume* _volume, fs_vnode* _directory, const char* name,
return status;
}
TRACE("exfat_lookup: ID %d\n", *_vnodeID);
TRACE("exfat_lookup: ID %" B_PRIdINO "\n", *_vnodeID);
return get_vnode(volume->FSVolume(), *_vnodeID, NULL);
}
@@ -526,24 +526,40 @@ exfat_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie,
{
TRACE("exfat_read_dir\n");
DirectoryIterator* iterator = (DirectoryIterator*)_cookie;
size_t length = bufferSize;
ino_t id;
status_t status = iterator->GetNext(dirent->d_name, &length, &id);
if (status == B_ENTRY_NOT_FOUND) {
*_num = 0;
return B_OK;
} else if (status != B_OK)
return status;
Volume* volume = (Volume*)_volume->private_volume;
dirent->d_dev = volume->ID();
dirent->d_ino = id;
dirent->d_reclen = sizeof(struct dirent) + length;
*_num = 1;
uint32 maxCount = *_num;
uint32 count = 0;
while (count < maxCount && bufferSize > sizeof(struct dirent)) {
ino_t id;
size_t length = bufferSize - sizeof(struct dirent) + 1;
status_t status = iterator->GetNext(dirent->d_name, &length, &id);
if (status == B_ENTRY_NOT_FOUND)
break;
if (status == B_BUFFER_OVERFLOW) {
// the remaining name buffer length was too small
if (count == 0)
return B_BUFFER_OVERFLOW;
break;
}
if (status != B_OK)
return status;
dirent->d_dev = volume->ID();
dirent->d_ino = id;
dirent->d_reclen = sizeof(struct dirent) + length;
bufferSize -= dirent->d_reclen;
dirent = (struct dirent*)((uint8*)dirent + dirent->d_reclen);
count++;
}
*_num = count;
TRACE("exfat_read_dir end\n");
return B_OK;
}