*
* Reference: ntfsdoc.pdf
*/
-#define DEBUG 1
+#define DEBUG 0
#define VERBOSE 0
#include <acess.h>
#include <vfs.h>
.TypeName = "NTFS-Dir",
.ReadDir = NTFS_ReadDir,
.FindDir = NTFS_FindDir,
- .Close = NULL
+ .Close = NTFS_Close
};
tVFS_NodeType gNTFS_FileType = {
.TypeName = "NTFS-File",
- .Close = NULL
+ .Read = NTFS_ReadFile,
+ .Close = NTFS_Close
};
tNTFS_Disk gNTFS_Disks;
return NULL;
}
- Log_Debug("FS_NTFS", "&bs = %p", &bs);
VFS_ReadAt(disk->FD, 0, 512, &bs);
-
+
+#if 0
Log_Debug("FS_NTFS", "Jump = %02x%02x%02x",
bs.Jump[0],
bs.Jump[1],
Log_Debug("FS_NTFS", "ClustersPerMFTRecord = %i", bs.ClustersPerMFTRecord);
Log_Debug("FS_NTFS", "ClustersPerIndexRecord = %i", bs.ClustersPerIndexRecord);
Log_Debug("FS_NTFS", "SerialNumber = 0x%llx", bs.SerialNumber);
+#endif
disk->ClusterSize = bs.BytesPerSector * bs.SectorsPerCluster;
- Log_Debug("NTFS", "Cluster Size = %i KiB", disk->ClusterSize/1024);
disk->MFTBase = bs.MFTStart;
+ Log_Debug("NTFS", "Cluster Size = %i KiB", disk->ClusterSize/1024);
Log_Debug("NTFS", "MFT Base = %i", disk->MFTBase);
Log_Debug("NTFS", "TotalSectorCount = 0x%x", bs.TotalSectorCount);
//NTFS_DumpEntry(disk, 0); // $MFT
//NTFS_DumpEntry(disk, 3); // $VOLUME
- disk->InodeCache = Inode_GetHandle();
+ disk->InodeCache = Inode_GetHandle(NTFS_FreeNode);
disk->MFTDataAttr = NULL;
disk->MFTDataAttr = NTFS_GetAttrib(disk, 0, NTFS_FileAttrib_Data, "", 0);
- NTFS_DumpEntry(disk, 5); // .
+ //NTFS_DumpEntry(disk, 5); // .
disk->RootDir.I30Root = NTFS_GetAttrib(disk, 5, NTFS_FileAttrib_IndexRoot, "$I30", 0);
disk->RootDir.I30Allocation = NTFS_GetAttrib(disk, 5, NTFS_FileAttrib_IndexAllocation, "$I30", 0);
free(Disk);
}
+void NTFS_Close(tVFS_Node *Node)
+{
+ tNTFS_Disk *Disk = Node->ImplPtr;
+ Inode_UncacheNode(Disk->InodeCache, Node->Inode);
+}
+
+void NTFS_FreeNode(tVFS_Node *Node)
+{
+ if( Node->Type == &gNTFS_DirType ) {
+ tNTFS_Directory *Dir = (void*)Node;
+ NTFS_FreeAttrib(Dir->I30Root);
+ NTFS_FreeAttrib(Dir->I30Allocation);
+ }
+ else {
+ tNTFS_File *File = (void*)Node;
+ NTFS_FreeAttrib(File->Data);
+ }
+}
+
+int NTFS_int_ApplyUpdateSequence(void *Buffer, size_t BufLen, const Uint16 *Sequence, size_t NumEntries)
+{
+ Uint16 cksum = Sequence[0];
+ LOG("cksum = %04x", cksum);
+ Sequence ++;
+ Uint16 *buf16 = Buffer;
+ for( int i = 0; i < NumEntries-1; i ++ )
+ {
+ size_t ofs = (i+1)*512 - 2;
+ if( ofs + 2 > BufLen ) {
+ // Oops?
+ Log_Warning("NTFS", "%x > %x", ofs+2, BufLen);
+ }
+ Uint16 *cksum_word = &buf16[ofs/2];
+ LOG("[%i]: %04x => %04x", i, Sequence[i], *cksum_word);
+ if( *cksum_word != cksum ) {
+ Log_Warning("NTFS", "Disk corruption detected");
+ return 1;
+ }
+ *cksum_word = Sequence[i];
+ }
+ return 0;
+}
+
tNTFS_FILE_Header *NTFS_GetMFT(tNTFS_Disk *Disk, Uint32 MFTEntry)
{
- void *ret = malloc( Disk->MFTRecSize );
+ // TODO: Cache MFT allocation for short-term
+
+ //
+ tNTFS_FILE_Header *ret = malloc( Disk->MFTRecSize );
if(!ret) {
Log_Warning("FS_NTFS", "malloc() fail!");
return NULL;
else {
NTFS_ReadAttribData(Disk->MFTDataAttr, MFTEntry * Disk->MFTRecSize, Disk->MFTRecSize, ret);
}
-
+
+ NTFS_int_ApplyUpdateSequence(ret, Disk->MFTRecSize,
+ (void*)((char*)ret + ret->UpdateSequenceOfs), ret->UpdateSequenceSize
+ );
+
return ret;
}
if( attr->Type != Type )
continue;
if( Name ) {
- LOG("Name check = '%s'", Name);
+ if( attr->NameOffset + attr->NameLength*2 > attr->Size ) {
+ break;
+ }
const void *name16 = (char*)attr + attr->NameOffset;
+ LOG("Name check: '%s' == '%.*ls'",
+ Name, attr->NameLength, name16);
if( UTF16_CompareWithUTF8(attr->NameLength, name16, Name) != 0 )
continue ;
}
ASSERT(attr->NameOffset % 1 == 0);
Uint16 *name16 = (Uint16*)attr + attr->NameOffset/2;
size_t namelen = UTF16_ConvertToUTF8(0, NULL, attr->NameLength, name16);
- size_t edatalen = (attr->NonresidentFlag ? 0 : attr->Resident.AttribLen*4);
+ size_t edatalen = (attr->NonresidentFlag ? 0 : attr->Resident.AttribLen);
tNTFS_Attrib *ret = malloc( sizeof(tNTFS_Attrib) + namelen + 1 + edatalen );
if(!ret) {
- LEAVE('n');
- return NULL;
+ goto _error;
}
if( attr->NonresidentFlag )
ret->Name = (void*)(ret + 1);
}
else
{
+ ret->DataSize = edatalen;
memcpy(ret->ResidentData, (char*)attr + attr->Resident.AttribOfs, edatalen);
+ Debug_HexDump("GetAttrib Resident", ret->ResidentData, edatalen);
}
+ NTFS_ReleaseMFT(Disk, MFTEntry, hdr);
LEAVE('p', ret);
return ret;
}
+_error:
NTFS_ReleaseMFT(Disk, MFTEntry, hdr);
LEAVE('n');
return NULL;
}
+void NTFS_FreeAttrib(tNTFS_Attrib *Attrib)
+{
+ if( Attrib )
+ free(Attrib);
+}
+
size_t NTFS_ReadAttribData(tNTFS_Attrib *Attrib, Uint64 Offset, size_t Length, void *Buffer)
{
+ if( !Attrib )
+ return 0;
if( Offset >= Attrib->DataSize )
return 0;
if( Length > Attrib->DataSize )
tNTFS_FILE_Attrib *attr;
int i;
- tNTFS_FILE_Header *hdr = malloc( Disk->MFTRecSize );
+
+ tNTFS_FILE_Header *hdr = NTFS_GetMFT(Disk, Entry);
if(!hdr) {
Log_Warning("FS_NTFS", "malloc() fail!");
return ;
}
- VFS_ReadAt( Disk->FD,
- Disk->MFTBase * Disk->ClusterSize + Entry * Disk->MFTRecSize,
- Disk->MFTRecSize,
- hdr);
-
Log_Debug("FS_NTFS", "MFT Entry #%i", Entry);
Log_Debug("FS_NTFS", "- Magic = 0x%08x (%4C)", hdr->Magic, &hdr->Magic);
Log_Debug("FS_NTFS", "- UpdateSequenceOfs = 0x%x", hdr->UpdateSequenceOfs);
attr = (void*)( (tVAddr)attr + attr->Size );
}
- free(hdr);
+ NTFS_ReleaseMFT(Disk, Entry, hdr);
}