status_t Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size) { ASSERT(de != NULL); uint32 attempt = 0; do { RPC::Server* serv = fFileSystem->Server(); Request request(serv, fFileSystem); RequestBuilder& req = request.Builder(); req.PutFH(fInfo.fHandle); req.LookUpUp(); req.GetFH(); if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { Attribute attr[] = { FATTR4_FILEID }; req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); } status_t result = request.Send(); if (result != B_OK) return result; ReplyInterpreter& reply = request.Reply(); if (HandleErrors(attempt, reply.NFS4Error(), serv)) continue; reply.PutFH(); result = reply.LookUpUp(); if (result != B_OK) return result; FileHandle fh; reply.GetFH(&fh); uint64 fileId; if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { AttrValue* values; uint32 count; result = reply.GetAttr(&values, &count); if (result != B_OK) return result; fileId = values[0].fData.fValue64; delete[] values; } else fileId = fFileSystem->AllocFileId(); return FillDirEntry(de, FileIdToInoT(fileId), "..", pos, size); } while (true); }
int far pascal __loadds FS_FINDFIRST(struct cdfsi far * pcdfsi, /* pcdfsi */ struct cdfsd far * pcdfsd, /* pcdfsd */ char far * pName, /* pName */ unsigned short usCurDirEnd, /* iCurDirEnd */ unsigned short usAttr, /* attr */ struct fsfsi far * pfsfsi, /* pfsfsi */ struct fsfsd far * pfsfsd, /* pfsfsd */ char far * pData, /* pData */ unsigned short cbData, /* cbData */ unsigned short far * pcMatch, /* pcMatch */ unsigned short usLevel, /* level */ unsigned short usFlags) /* flags */ { PVOLINFO pVolInfo; PFINDINFO pFindInfo = (PFINDINFO)pfsfsd; USHORT rc; USHORT usIndex; USHORT usNeededLen; USHORT usNumClusters; ULONG ulCluster; ULONG ulDirCluster; PSZ pSearch; PFINFO pNext; ULONG ulNeededSpace; USHORT usEntriesWanted; EAOP EAOP; PROCINFO ProcInfo; if (f32Parms.fMessageActive & LOG_FS) Message("FS_FINDFIRST for %s attr %X, Level %d, cbData %u, MaxEntries %u", pName, usAttr, usLevel, cbData, *pcMatch); usEntriesWanted = *pcMatch; *pcMatch = 0; if (strlen(pName) > FAT32MAXPATH) { rc = ERROR_FILENAME_EXCED_RANGE; goto FS_FINDFIRSTEXIT; } memset(pfsfsd, 0, sizeof (struct fsfsd)); pVolInfo = GetVolInfo(pfsfsi->fsi_hVPB); if (IsDriveLocked(pVolInfo)) { rc = ERROR_DRIVE_LOCKED; goto FS_FINDFIRSTEXIT; } switch (usLevel) { case FIL_STANDARD : usNeededLen = sizeof (FILEFNDBUF) - CCHMAXPATHCOMP; break; case FIL_QUERYEASIZE : usNeededLen = sizeof (FILEFNDBUF2) - CCHMAXPATHCOMP; break; case FIL_QUERYEASFROMLIST : usNeededLen = sizeof (EAOP) + sizeof (FILEFNDBUF3) + sizeof (ULONG); break; default : rc = ERROR_NOT_SUPPORTED; goto FS_FINDFIRSTEXIT; } if (usFlags == FF_GETPOS) usNeededLen += sizeof (ULONG); if (cbData < usNeededLen) { rc = ERROR_BUFFER_OVERFLOW; goto FS_FINDFIRSTEXIT; } rc = MY_PROBEBUF(PB_OPWRITE, pData, cbData); if (rc) { Message("FAT32: Protection VIOLATION in FS_FINDFIRST! (SYS%d)", rc); return rc; } if (usLevel == FIL_QUERYEASFROMLIST) { memcpy(&EAOP, pData, sizeof (EAOP)); rc = MY_PROBEBUF(PB_OPREAD, (PBYTE)EAOP.fpGEAList, (USHORT)EAOP.fpGEAList->cbList); if (rc) goto FS_FINDFIRSTEXIT; } memset(pData, 0, cbData); usNumClusters = 0; ulDirCluster = FindDirCluster(pVolInfo, pcdfsi, pcdfsd, pName, usCurDirEnd, RETURN_PARENT_DIR, &pSearch); if (ulDirCluster == FAT_EOF) { rc = ERROR_PATH_NOT_FOUND; goto FS_FINDFIRSTEXIT; } ulCluster = ulDirCluster; while (ulCluster && ulCluster != FAT_EOF) { usNumClusters++; ulCluster = GetNextCluster( pVolInfo, ulCluster); } ulNeededSpace = sizeof (FINFO) + (usNumClusters - 1) * sizeof (ULONG); ulNeededSpace += pVolInfo->usClusterSize; GetProcInfo(&ProcInfo, sizeof ProcInfo); pFindInfo->pInfo = (PFINFO)malloc((size_t)ulNeededSpace); if (!pFindInfo->pInfo) { rc = ERROR_NOT_ENOUGH_MEMORY; goto FS_FINDFIRSTEXIT; } memset(pFindInfo->pInfo, 0, (size_t)ulNeededSpace); if (!pVolInfo->pFindInfo) pVolInfo->pFindInfo = pFindInfo->pInfo; else { pNext = (PFINFO)pVolInfo->pFindInfo; while (pNext->pNextEntry) pNext = (PFINFO)pNext->pNextEntry; pNext->pNextEntry = pFindInfo->pInfo; } memcpy(&pFindInfo->pInfo->EAOP, &EAOP, sizeof (EAOP)); pFindInfo->usEntriesPerCluster = pVolInfo->usClusterSize / sizeof (DIRENTRY); pFindInfo->usClusterIndex = 0; pFindInfo->pInfo->rgClusters[0] = ulDirCluster; pFindInfo->usTotalClusters = usNumClusters; pFindInfo->pInfo->pDirEntries = (PDIRENTRY)(&pFindInfo->pInfo->rgClusters[usNumClusters]); if (f32Parms.fMessageActive & LOG_FIND) Message("pInfo at %lX, pDirEntries at %lX", pFindInfo->pInfo, pFindInfo->pInfo->pDirEntries); pFindInfo->pInfo->pNextEntry = NULL; memcpy(&pFindInfo->pInfo->ProcInfo, &ProcInfo, sizeof (PROCINFO)); strcpy(pFindInfo->pInfo->szSearch, pSearch); FSH_UPPERCASE(pFindInfo->pInfo->szSearch, sizeof pFindInfo->pInfo->szSearch, pFindInfo->pInfo->szSearch); pFindInfo->ulMaxEntry = ((ULONG)pVolInfo->usClusterSize / sizeof (DIRENTRY)) * usNumClusters; if (!GetCluster(pVolInfo, pFindInfo, 0)) { rc = ERROR_SYS_INTERNAL; goto FS_FINDFIRSTEXIT; } pFindInfo->ulCurEntry = 0; if (usAttr & 0x0040) { pFindInfo->fLongNames = TRUE; usAttr &= ~0x0040; } else pFindInfo->fLongNames = FALSE; pFindInfo->bMustAttr = (BYTE)(usAttr >> 8); usAttr |= (FILE_READONLY | FILE_ARCHIVED); usAttr &= (FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED); pFindInfo->bAttr = (BYTE)~usAttr; if (usLevel == FIL_QUERYEASFROMLIST) { memcpy(pData, &pFindInfo->pInfo->EAOP, sizeof (EAOP)); pData += sizeof (EAOP); cbData -= sizeof (EAOP); } rc = 0; for (usIndex = 0; usIndex < usEntriesWanted; usIndex++) { PULONG pulOrdinal; if (usFlags == FF_GETPOS) { if (cbData < sizeof (ULONG)) { rc = ERROR_BUFFER_OVERFLOW; break; } pulOrdinal = (PULONG)pData; pData += sizeof (ULONG); cbData -= sizeof (ULONG); } rc = FillDirEntry(pVolInfo, &pData, &cbData, pFindInfo, usLevel); if (!rc || (rc == ERROR_EAS_DIDNT_FIT && usIndex == 0)) { if (usFlags == FF_GETPOS) *pulOrdinal = pFindInfo->ulCurEntry - 1; } if (rc) break; } if ((rc == ERROR_NO_MORE_FILES || rc == ERROR_BUFFER_OVERFLOW || rc == ERROR_EAS_DIDNT_FIT) && usIndex > 0) rc = 0; if (rc == ERROR_EAS_DIDNT_FIT && usIndex == 0) usIndex = 1; *pcMatch = usIndex; FS_FINDFIRSTEXIT: if (f32Parms.fMessageActive & LOG_FS) Message("FS_FINDFIRST returned %d (%d entries)", rc, *pcMatch); if (rc && rc != ERROR_EAS_DIDNT_FIT) { FS_FINDCLOSE(pfsfsi, pfsfsd); } return rc; }
int far pascal __loadds FS_FINDNEXT( struct fsfsi far * pfsfsi, /* pfsfsi */ struct fsfsd far * pfsfsd, /* pfsfsd */ char far * pData, /* pData */ unsigned short cbData, /* cbData */ unsigned short far * pcMatch, /* pcMatch */ unsigned short usLevel, /* level */ unsigned short usFlags /* flag */ ) { PVOLINFO pVolInfo; PFINDINFO pFindInfo = (PFINDINFO)pfsfsd; USHORT rc; USHORT usIndex; USHORT usNeededLen; USHORT usEntriesWanted; if (f32Parms.fMessageActive & LOG_FS) Message("FS_FINDNEXT, level %u, cbData %u, MaxEntries %u", usLevel, cbData, *pcMatch); usEntriesWanted = *pcMatch; *pcMatch = 0; pVolInfo = GetVolInfo(pfsfsi->fsi_hVPB); if (IsDriveLocked(pVolInfo)) { rc = ERROR_DRIVE_LOCKED; goto FS_FINDNEXTEXIT; } switch (usLevel) { case FIL_STANDARD : usNeededLen = sizeof (FILEFNDBUF) - CCHMAXPATHCOMP; break; case FIL_QUERYEASIZE : usNeededLen = sizeof (FILEFNDBUF2) - CCHMAXPATHCOMP; break; case FIL_QUERYEASFROMLIST : usNeededLen = sizeof (EAOP) + sizeof (FILEFNDBUF3) + sizeof (ULONG); break; default : rc = ERROR_NOT_SUPPORTED; goto FS_FINDNEXTEXIT; } if (usFlags == FF_GETPOS) usNeededLen += sizeof (ULONG); if (cbData < usNeededLen) { rc = ERROR_BUFFER_OVERFLOW; goto FS_FINDNEXTEXIT; } rc = MY_PROBEBUF(PB_OPWRITE, pData, cbData); if (rc) { Message("FAT32: Protection VIOLATION in FS_FINDNEXT!"); return rc; } if (usLevel == FIL_QUERYEASFROMLIST) { memcpy(&pFindInfo->pInfo->EAOP, pData, sizeof (EAOP)); rc = MY_PROBEBUF(PB_OPREAD, (PBYTE)pFindInfo->pInfo->EAOP.fpGEAList, (USHORT)pFindInfo->pInfo->EAOP.fpGEAList->cbList); if (rc) goto FS_FINDNEXTEXIT; } memset(pData, 0, cbData); if (usLevel == FIL_QUERYEASFROMLIST) { memcpy(pData, &pFindInfo->pInfo->EAOP, sizeof (EAOP)); pData += sizeof (EAOP); cbData -= sizeof (EAOP); } rc = 0; for (usIndex = 0; usIndex < usEntriesWanted; usIndex++) { PULONG pulOrdinal = NULL; if (usFlags == FF_GETPOS) { if (cbData < sizeof (ULONG)) { rc = ERROR_BUFFER_OVERFLOW; break; } pulOrdinal = (PULONG)pData; pData += sizeof (ULONG); cbData -= sizeof (ULONG); } rc = FillDirEntry(pVolInfo, &pData, &cbData, pFindInfo, usLevel); if (!rc || (rc == ERROR_EAS_DIDNT_FIT && usIndex == 0)) { if (usFlags == FF_GETPOS) *pulOrdinal = pFindInfo->ulCurEntry - 1; } if (rc) break; } if ((rc == ERROR_NO_MORE_FILES || rc == ERROR_BUFFER_OVERFLOW || rc == ERROR_EAS_DIDNT_FIT) && usIndex > 0) rc = 0; if (rc == ERROR_EAS_DIDNT_FIT && usIndex == 0) usIndex = 1; *pcMatch = usIndex; FS_FINDNEXTEXIT: if (f32Parms.fMessageActive & LOG_FS) Message("FS_FINDNEXT returned %d (%d entries)", rc, *pcMatch); return rc; }
status_t Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, OpenDirCookie* cookie) { ASSERT(_buffer != NULL); ASSERT(_count != NULL); ASSERT(cookie != NULL); if (cookie->fEOF) { *_count = 0; return B_OK; } status_t result; DirectoryCache* cache = cookie->fAttrDir ? fAttrCache : fCache; if (cookie->fSnapshot == NULL) { cache->Lock(); result = cache->Revalidate(); if (result != B_OK) { cache->Unlock(); return result; } DirectoryCacheSnapshot* snapshot; result = cache->GetSnapshot(&snapshot); if (result != B_OK) { cache->Unlock(); return result; } cookie->fSnapshot = new DirectoryCacheSnapshot(*snapshot); cache->Unlock(); if (cookie->fSnapshot == NULL) return B_NO_MEMORY; } char* buffer = reinterpret_cast<char*>(_buffer); uint32 pos = 0; uint32 i = 0; bool overflow = false; if (cookie->fSpecial == 0 && i < *_count && !cookie->fAttrDir) { struct dirent* de = reinterpret_cast<dirent*>(buffer + pos); status_t result; result = FillDirEntry(de, fInfo.fFileId, ".", pos, size); if (result == B_BUFFER_OVERFLOW) overflow = true; else if (result == B_OK) { pos += de->d_reclen; i++; cookie->fSpecial++; } else return result; } if (cookie->fSpecial == 1 && i < *_count && !cookie->fAttrDir) { struct dirent* de = reinterpret_cast<dirent*>(buffer + pos); status_t result; result = ReadDirUp(de, pos, size); if (result == B_ENTRY_NOT_FOUND) { result = FillDirEntry(de, FileIdToInoT(fInfo.fFileId), "..", pos, size); } if (result == B_BUFFER_OVERFLOW) overflow = true; else if (result == B_OK) { pos += de->d_reclen; i++; cookie->fSpecial++; } else return result; } MutexLocker _(cookie->fSnapshot->fLock); for (; !overflow && i < *_count; i++) { struct dirent* de = reinterpret_cast<dirent*>(buffer + pos); NameCacheEntry* temp = cookie->fCurrent; if (cookie->fCurrent == NULL) cookie->fCurrent = cookie->fSnapshot->fEntries.Head(); else { cookie->fCurrent = cookie->fSnapshot->fEntries.GetNext(cookie->fCurrent); } if (cookie->fCurrent == NULL) { cookie->fEOF = true; break; } if (FillDirEntry(de, cookie->fCurrent->fNode, cookie->fCurrent->fName, pos, size) == B_BUFFER_OVERFLOW) { cookie->fCurrent = temp; overflow = true; break; } pos += de->d_reclen; } if (i == 0 && overflow) return B_BUFFER_OVERFLOW; *_count = i; return B_OK; }