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,
|
DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id,
|
||||||
EntryVisitor* visitor)
|
EntryVisitor* visitor)
|
||||||
{
|
{
|
||||||
|
if (fCluster == EXFAT_CLUSTER_END)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
if (fOffset == -2) {
|
if (fOffset == -2) {
|
||||||
*_nameLength = 3;
|
if (*_nameLength < 3)
|
||||||
strlcpy(name, "..", *_nameLength);
|
return B_BUFFER_OVERFLOW;
|
||||||
|
*_nameLength = 2;
|
||||||
|
strlcpy(name, "..", *_nameLength + 1);
|
||||||
if (fInode->ID() == 1)
|
if (fInode->ID() == 1)
|
||||||
*_id = fInode->ID();
|
*_id = fInode->ID();
|
||||||
else
|
else
|
||||||
@@ -58,19 +62,22 @@ DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id,
|
|||||||
TRACE("DirectoryIterator::GetNext() found ..\n");
|
TRACE("DirectoryIterator::GetNext() found ..\n");
|
||||||
return B_OK;
|
return B_OK;
|
||||||
} else if (fOffset == -1) {
|
} else if (fOffset == -1) {
|
||||||
*_nameLength = 2;
|
if (*_nameLength < 2)
|
||||||
strlcpy(name, ".", *_nameLength);
|
return B_BUFFER_OVERFLOW;
|
||||||
|
*_nameLength = 1;
|
||||||
|
strlcpy(name, ".", *_nameLength + 1);
|
||||||
*_id = fInode->ID();
|
*_id = fInode->ID();
|
||||||
fOffset = 0;
|
fOffset = 0;
|
||||||
TRACE("DirectoryIterator::GetNext() found .\n");
|
TRACE("DirectoryIterator::GetNext() found .\n");
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
uchar unicodeName[EXFAT_FILENAME_MAX_LENGTH];
|
uchar unicodeName[EXFAT_FILENAME_MAX_LENGTH + 1];
|
||||||
size_t nameLength = EXFAT_FILENAME_MAX_LENGTH;
|
size_t nameLength = EXFAT_FILENAME_MAX_LENGTH;
|
||||||
status_t status = _GetNext(unicodeName, &nameLength, _id, visitor);
|
status_t status = _GetNext(unicodeName, &nameLength, _id, visitor);
|
||||||
if (status == B_OK && name != NULL) {
|
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",
|
TRACE("DirectoryIterator::GetNext() %ld %s, %" B_PRIdINO "\n",
|
||||||
fInode->Cluster(), name, *_id);
|
fInode->Cluster(), name, *_id);
|
||||||
}
|
}
|
||||||
@@ -96,7 +103,7 @@ DirectoryIterator::Lookup(const char* name, size_t nameLength, ino_t* _id)
|
|||||||
Rewind();
|
Rewind();
|
||||||
fOffset = 0;
|
fOffset = 0;
|
||||||
|
|
||||||
uchar currentName[EXFAT_FILENAME_MAX_LENGTH];
|
uchar currentName[EXFAT_FILENAME_MAX_LENGTH + 1];
|
||||||
size_t currentLength = EXFAT_FILENAME_MAX_LENGTH;
|
size_t currentLength = EXFAT_FILENAME_MAX_LENGTH;
|
||||||
while (_GetNext((uchar*)currentName, ¤tLength, _id) == B_OK) {
|
while (_GetNext((uchar*)currentName, ¤tLength, _id) == B_OK) {
|
||||||
char utfName[EXFAT_FILENAME_MAX_LENGTH];
|
char utfName[EXFAT_FILENAME_MAX_LENGTH];
|
||||||
@@ -122,7 +129,7 @@ DirectoryIterator::LookupEntry(EntryVisitor* visitor)
|
|||||||
fCluster = fInode->Cluster();
|
fCluster = fInode->Cluster();
|
||||||
fOffset = fInode->Offset();
|
fOffset = fInode->Offset();
|
||||||
|
|
||||||
uchar unicodeName[EXFAT_FILENAME_MAX_LENGTH];
|
uchar unicodeName[EXFAT_FILENAME_MAX_LENGTH + 1];
|
||||||
size_t nameLength = EXFAT_FILENAME_MAX_LENGTH;
|
size_t nameLength = EXFAT_FILENAME_MAX_LENGTH;
|
||||||
return _GetNext(unicodeName, &nameLength, NULL, visitor);
|
return _GetNext(unicodeName, &nameLength, NULL, visitor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ LabelVisitor::LabelVisitor(Volume* volume)
|
|||||||
bool
|
bool
|
||||||
LabelVisitor::VisitLabel(struct exfat_entry* entry)
|
LabelVisitor::VisitLabel(struct exfat_entry* entry)
|
||||||
{
|
{
|
||||||
dprintf("LabelVisitor::VisitLabel()\n");
|
TRACE("LabelVisitor::VisitLabel()\n");
|
||||||
char utfName[30];
|
char utfName[30];
|
||||||
size_t utfLength = 30;
|
size_t utfLength = 30;
|
||||||
unicode_to_utf8((const uchar*)entry->name_label.name,
|
unicode_to_utf8((const uchar*)entry->name_label.name,
|
||||||
@@ -418,6 +418,8 @@ Volume::LoadSuperBlock()
|
|||||||
status_t
|
status_t
|
||||||
Volume::ClusterToBlock(cluster_t cluster, fsblock_t &block)
|
Volume::ClusterToBlock(cluster_t cluster, fsblock_t &block)
|
||||||
{
|
{
|
||||||
|
if (cluster < 2)
|
||||||
|
return B_BAD_VALUE;
|
||||||
block = ((cluster - 2) << SuperBlock().BlocksPerClusterShift())
|
block = ((cluster - 2) << SuperBlock().BlocksPerClusterShift())
|
||||||
+ SuperBlock().FirstDataBlock();
|
+ SuperBlock().FirstDataBlock();
|
||||||
TRACE("Volume::ClusterToBlock() cluster %lu %u %lu: %llu, %lu\n", cluster,
|
TRACE("Volume::ClusterToBlock() cluster %lu %u %lu: %llu, %lu\n", cluster,
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ _lendian_unicode_to_utf8(
|
|||||||
int32 dstLimit = *dstLen;
|
int32 dstLimit = *dstLen;
|
||||||
int32 srcCount = 0;
|
int32 srcCount = 0;
|
||||||
int32 dstCount = 0;
|
int32 dstCount = 0;
|
||||||
|
status_t status = B_ERROR;
|
||||||
|
|
||||||
for (srcCount = 0; srcCount < srcLimit; srcCount += 2) {
|
for (srcCount = 0; srcCount < srcLimit; srcCount += 2) {
|
||||||
uint16 *UNICODE = (uint16 *)&src[srcCount];
|
uint16 *UNICODE = (uint16 *)&src[srcCount];
|
||||||
@@ -119,19 +120,22 @@ _lendian_unicode_to_utf8(
|
|||||||
u_lendian_to_utf8(UTF8, UNICODE);
|
u_lendian_to_utf8(UTF8, UNICODE);
|
||||||
|
|
||||||
utf8Len = UTF8 - utf8;
|
utf8Len = UTF8 - utf8;
|
||||||
if ((dstCount + utf8Len) > dstLimit)
|
if ((dstCount + utf8Len) > dstLimit) {
|
||||||
|
status = B_BUFFER_OVERFLOW;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (j = 0; j < utf8Len; j++)
|
for (j = 0; j < utf8Len; j++)
|
||||||
dst[dstCount + j] = utf8[j];
|
dst[dstCount + j] = utf8[j];
|
||||||
dstCount += utf8Len;
|
dstCount += utf8Len;
|
||||||
|
status = B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
*srcLen = srcCount;
|
*srcLen = srcCount;
|
||||||
*dstLen = dstCount;
|
*dstLen = dstCount;
|
||||||
dst[dstCount] = '\0';
|
dst[dstCount] = '\0';
|
||||||
|
|
||||||
return ((dstCount > 0) ? B_NO_ERROR : B_ERROR);
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// utf8 to LENDIAN unicode
|
// utf8 to LENDIAN unicode
|
||||||
@@ -146,6 +150,7 @@ _utf8_to_lendian_unicode(
|
|||||||
int32 dstLimit = *dstLen - 1;
|
int32 dstLimit = *dstLen - 1;
|
||||||
int32 srcCount = 0;
|
int32 srcCount = 0;
|
||||||
int32 dstCount = 0;
|
int32 dstCount = 0;
|
||||||
|
status_t status = B_ERROR;
|
||||||
|
|
||||||
while ((srcCount < srcLimit) && (dstCount < dstLimit)) {
|
while ((srcCount < srcLimit) && (dstCount < dstLimit)) {
|
||||||
uint16 unicode;
|
uint16 unicode;
|
||||||
@@ -157,20 +162,25 @@ _utf8_to_lendian_unicode(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
utf8_to_u_hostendian(UTF8, UNICODE, err_flag);
|
utf8_to_u_hostendian(UTF8, UNICODE, err_flag);
|
||||||
if(err_flag == 1)
|
if (err_flag == 1)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
unicode = B_HOST_TO_LENDIAN_INT16(unicode);
|
unicode = B_HOST_TO_LENDIAN_INT16(unicode);
|
||||||
|
if ((dstCount + 1) > dstLimit) {
|
||||||
|
status = B_BUFFER_OVERFLOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
dst[dstCount++] = unicode & 0xFF;
|
dst[dstCount++] = unicode & 0xFF;
|
||||||
dst[dstCount++] = unicode >> 8;
|
dst[dstCount++] = unicode >> 8;
|
||||||
|
|
||||||
srcCount += UTF8 - ((uchar *)(src + srcCount));
|
srcCount += UTF8 - ((uchar *)(src + srcCount));
|
||||||
|
status = B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
*srcLen = srcCount;
|
*srcLen = srcCount;
|
||||||
*dstLen = dstCount;
|
*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,
|
exfat_get_vnode(fs_volume* _volume, ino_t id, fs_vnode* _node, int* _type,
|
||||||
uint32* _flags, bool reenter)
|
uint32* _flags, bool reenter)
|
||||||
{
|
{
|
||||||
TRACE("get_vnode %lu\n", id);
|
TRACE("get_vnode %" B_PRIdINO "\n", id);
|
||||||
Volume* volume = (Volume*)_volume->private_volume;
|
Volume* volume = (Volume*)_volume->private_volume;
|
||||||
|
|
||||||
Inode* inode = new(std::nothrow) Inode(volume, id);
|
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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("exfat_lookup: ID %d\n", *_vnodeID);
|
TRACE("exfat_lookup: ID %" B_PRIdINO "\n", *_vnodeID);
|
||||||
|
|
||||||
return get_vnode(volume->FSVolume(), *_vnodeID, NULL);
|
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");
|
TRACE("exfat_read_dir\n");
|
||||||
DirectoryIterator* iterator = (DirectoryIterator*)_cookie;
|
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;
|
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");
|
TRACE("exfat_read_dir end\n");
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user