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:
@@ -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, ¤tLength, _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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user