NTFS -usnjournal监控

usnjournal监控

概述三、图解1:判断元数据$usnjournal是否存在2:保存所有需要的信息3:定位到监控的位置

四、代码实现

首页

概述

1:百度百科 2:USN 日志( 更新序列号日志)或更改日志[ 1]是 Windows NT 文件系统 ( NTFS )的一项功能,它维护对卷所做更改的记录。不要将它与用于NTFS 文件系统日志的日志相混淆。

当Windows 2000发布时,Microsoft创建了NTFS版本 3.0,其中包括几个新功能和对旧版本文件系统的改进。其中之一是对某些类型的应用程序非常有用的新系统管理功能。在 Windows 2000 下,可以设置 NTFS 3.0分区来跟踪卷上文件和目录的更改,提供对各种对象执行的时间和操作的记录。启用后,系统会在 USN 日志中记录对卷所做的所有更改,该名称也用于描述功能本身。

为每个 NTFS 卷维护一个日志并存储在名为 $Extend$UsnJrnl的NTFS 元文件中。它以一个空文件开始。每当对卷进行更改时,都会将一条记录添加到文件中。每条记录由64 位更新序列号或 USN 标识(因此更改日志有时称为 USN 日志)。Change Journal 中的每条记录都包含 USN、文件的名称以及有关更改内容的信息。

更改日志使用位标志(例如 USN_REASON_DATA_OVERWRITE [2])描述发生的更改,因此它不包括与更改相关的所有数据或详细信息。因此,更改日志不能用于撤消对 NTFS 内文件的操作。维基百科 3:usnjournal结构 4:属性

三、图解

1:判断元数据$usnjournal是否存在

如果$ usnjournal不存在(一般刚刚初始化或者新建盘符),这个时候创建$usnjournal,否则就没办法监控usnjournal。

//%1 : 盘符

bool isOk = QProcess::startDetached("cmd", QStringList() << "/c" << QString("fsutil usn createjournal m=33554432 a=8388608 %1:").arg(m_partitionName.at(0)));

fsutil usn使用方法

2:保存所有需要的信息

后面还有两个$J,不在一一列出。

3:定位到监控的位置

四、代码实现

//获取usnJournal基本信息

bool CNtfsInfo::_getUsnJournalBasicInfo(S_MFT_USN_JOURNAL& usnJournalBasicInfo,QByteArray byteData)

{

S_FILE_RECORD fileRecordHead;//文件头

bool isOk = NTFS_MFTFileHeader(fileRecordHead,byteData);

if(!isOk)

return false;

quint32 allLength = fileRecordHead.BytesInUse-4;//所有属性的大小

quint32 byteOffset = fileRecordHead.AttributeOffset;

int whileCount = allLength ;

while(byteOffset

if((--whileCount) == 0){ //死循环异常

NTFS_setErrorType(CNTFS::WhileError);

return false;

}

if(!(byteData.mid(byteOffset,sizeof (quint32)).toHex()).compare("FFFFFFFF",Qt::CaseInsensitive))

return true;

S_USN_JOURNAL_ATTRIBUTE_HEADER attH;//属性头

qint8 NonResidentFlag = NTFS_MFTUsnAtt(attH,byteData.mid(byteOffset,sizeof(S_USN_JOURNAL_ATTRIBUTE_HEADER)));//获取属性 返回0常驻,1非常驻,-1:失败

if(NonResidentFlag == -1)

return false;

switch(attH.AttributeType) {

//0x20

case AttributeAttributeList:

{

byteOffset += attH.NonResidentFlag==0 ? attH.CCommon.CResident.StreamOffset : attH.CCommon.CNonResident.RunListOffset;

if(attH.NonResidentFlag==0 && (attH.AttributeLength - attH.CCommon.CResident.StreamOffset)>0) {

QList x20L = NTFS_0X20Att(byteData.mid(byteOffset,attH.AttributeLength - attH.CCommon.CResident.StreamOffset));

for(int i=0;i

QList _temp;

//只获取不同的mft 属性x80

if((x20L.at(i).AttributeType == AttributeData ) && x20L.at(i).Fdir.FileReferenceNumber != fileRecordHead.MFTRecordNumber){

if(!_temp.contains(x20L.at(i).Fdir.FileReferenceNumber)) { //以防多次执行,不同的mft只执行一次

_temp.append(x20L.at(i).Fdir.FileReferenceNumber);

quint64 offset = getMTFOffset(x20L.at(i).Fdir.FileReferenceNumber);

QByteArray data = getRawData(m_NTFSOffset + offset,BYTES_PER_MFT_FILE);

if(data.isNull())

return false;

bool isOk = _getUsnJournalBasicInfo( usnJournalBasicInfo,data);

if(!isOk)

return false;

}

}

}

byteOffset += (attH.AttributeLength-attH.CCommon.CResident.StreamOffset);

} else if(attH.NonResidentFlag==1 && (attH.AttributeLength - attH.CCommon.CNonResident.RunListOffset)>0) { //预防

QList DRunList;

DRunList = NTFS_DatasRun(byteData.mid(byteOffset,attH.AttributeLength - attH.CCommon.CNonResident.RunListOffset));

for(int i=0;i

QByteArray data = getRawData(m_NTFSOffset + DRunList[i].dataStartCluster * BYTES_PER_CLUSTER,attH.CCommon.CNonResident.StreamRealSize);

if(!data.isNull()) {

QList x20L = NTFS_0X20Att(data);

for(int i=0;i

QList _temp;

//只获取不同的mft 属性x10和x30和x80

if((x20L.at(i).AttributeType == AttributeData ) && x20L.at(i).Fdir.FileReferenceNumber != fileRecordHead.MFTRecordNumber) {

if(!_temp.contains(x20L.at(i).Fdir.FileReferenceNumber)){//以防多次执行,不同的mft只执行一次

_temp.append(x20L.at(i).Fdir.FileReferenceNumber);

quint64 offset = getMTFOffset(x20L.at(i).Fdir.FileReferenceNumber);

QByteArray data = getRawData(m_NTFSOffset + offset,BYTES_PER_MFT_FILE);

if(data.isNull())

return false;

bool isOk = _getUsnJournalBasicInfo( usnJournalBasicInfo,data);

if(!isOk)

return false;

}

}

}

}

}

byteOffset += (attH.AttributeLength - attH.CCommon.CNonResident.RunListOffset);

}

}

break;

//x30

case AttributeFileName:

{

byteOffset += attH.NonResidentFlag==0 ? attH.CCommon.CResident.StreamOffset : attH.CCommon.CNonResident.RunListOffset;

if(attH.NonResidentFlag==0 && (attH.AttributeLength - attH.CCommon.CResident.StreamOffset)>0) {

S_ATTRIBUTE_0X30 x30;

QByteArray dataName = NTFS_0X30AttName(x30,byteData.mid(byteOffset,attH.AttributeLength - attH.CCommon.CResident.StreamOffset));

if(!dataName.isNull()) {

if(dataName.compare("$UsnJrnl",Qt::CaseInsensitive)==0)

usnJournalBasicInfo.ISOK = true;

}

byteOffset += (attH.AttributeLength-attH.CCommon.CResident.StreamOffset);

} else if(attH.NonResidentFlag==1 && (attH.AttributeLength - attH.CCommon.CNonResident.RunListOffset)>0){//预防

byteOffset += (attH.AttributeLength - attH.CCommon.CNonResident.RunListOffset);

}

}

break;

//0x80

case AttributeData:

{

byteOffset += attH.NonResidentFlag==0 ? attH.CCommon.CResident.StreamOffset : attH.CCommon.CNonResident.RunListOffset;

if(attH.NonResidentFlag==0 && (attH.AttributeLength - attH.CCommon.CResident.StreamOffset)>0){

QString name = QString::fromWCharArray(attH.CCommon.CResident.CAttName,attH.AttributeNameLength);//QString ret2 = QString((QChar*)x30.Name, wcslen(x30.Name));

if(name=="$Max") {

errno_t err = memcpy_s(&usnJournalBasicInfo.MaxAtt,16,byteData.mid(byteOffset,16).data(),16);//返回值为0,拷贝成功

if(err) {

qDebug()<

return false;

}

}

byteOffset += (attH.AttributeLength-attH.CCommon.CResident.StreamOffset);

} else if(attH.NonResidentFlag==1 && (attH.AttributeLength - attH.CCommon.CNonResident.RunListOffset)>0) {

/*

* 获取属性名,可能存在偏移位置不同

*/

char dataTemp[100];

memset(dataTemp,0,sizeof(dataTemp));

errno_t err = memcpy_s(dataTemp,sizeof(dataTemp), &attH,sizeof (S_USN_JOURNAL_ATTRIBUTE_HEADER));//返回值为0,拷贝成功

if(err) {

qDebug()<

return false;

}

QString name = QString::fromWCharArray((wchar_t *)&dataTemp[attH.ContentOffset],attH.AttributeNameLength);

if(name=="$J"){

usnJournalBasicInfo.JAtt.append(attH);

QByteArray temp = byteData.mid(byteOffset,attH.AttributeLength - attH.CCommon.CNonResident.RunListOffset);

QList DRunList;

DRunList = NTFS_DatasRun(byteData.mid(byteOffset,attH.AttributeLength - attH.CCommon.CNonResident.RunListOffset));

if(!DRunList.isEmpty())

usnJournalBasicInfo.lDRun.append(DRunList);

byteOffset += (attH.AttributeLength - attH.CCommon.CNonResident.RunListOffset);

}

}

}

break;

case 0xFFFFFFFF:

return true;

default:

byteOffset += (attH.AttributeLength);

break;

}

}

return false;

}

//获取usnJournal MFT信息

S_MFT_USN_JOURNAL CNtfsInfo::getUsnJournalBasicInfo()

{

S_MFT_USN_JOURNAL usnJournalBasicInfo;

usnJournalBasicInfo.ISOK = false;

quint64 mftOffset = getMTFOffset($Extend$UsnJrnl);

QByteArray mftByte_1 = getRawData(m_NTFSOffset + mftOffset,BYTES_PER_MFT_FILE);

if(mftByte_1.isNull())

return usnJournalBasicInfo;

S_MFT_INFO mftInfo_1;

bool mftInfo_1IsOk= NTFS_MFTFileInfo(mftInfo_1,mftByte_1);

if(!mftInfo_1IsOk)

return usnJournalBasicInfo;

if(mftInfo_1._x90.isEmpty())

return usnJournalBasicInfo;

if(mftInfo_1._x90.at(0).first.NonResidentFlag != 0)

return usnJournalBasicInfo;

QList> varData = mftInfo_1._x90.at(0).second._x90Body;

if (varData.isEmpty())

return usnJournalBasicInfo;

for(int i=0;i

if(!varData.at(i).second.compare(QString("$UsnJrnl"),Qt::CaseInsensitive)) {

quint64 mftOffset = getMTFOffset(varData.at(i).first.dir.MFTDirectoryFile);

QByteArray mftByte_1 = getRawData(m_NTFSOffset + mftOffset,BYTES_PER_MFT_FILE);

if(mftByte_1.isNull())

return usnJournalBasicInfo;

bool isOk = _getUsnJournalBasicInfo(usnJournalBasicInfo,mftByte_1);

if(isOk)

usnJournalBasicInfo.ISOK = true;

else{

qDebug()<

usnJournalBasicInfo.ISOK = false;

return usnJournalBasicInfo;

}

for(int i=0;i

if(QString::compare(QString::fromWCharArray(usnJournalBasicInfo.JAtt.at(i).CCommon.CNonResident.CNonAttName,usnJournalBasicInfo.JAtt.at(i).AttributeNameLength),"$J")){

usnJournalBasicInfo.JAtt.removeAt(i);

}else{

i++;

}

}

if(usnJournalBasicInfo.JAtt.isEmpty())

return usnJournalBasicInfo;

}

}

return usnJournalBasicInfo;

}

//更新数据库

void CNtfsInfo::updataDataBaseV2(PUSN_RECORD_UNION usnRecordUnion,quint64 usnRecordOffset /*=0*/)

{

//qDebug()<

QString fileName = QString::fromWCharArray(usnRecordUnion->V2.FileName,usnRecordUnion->V2.FileNameLength/2);

QScopedPointer dataBody(new S_DATA_BODY);

if(!dataBody)

return;

dataBody.data()->MFTNumber = usnRecordUnion->V2.FileReferenceNumber;

dataBody.data()->PMFTNumber = usnRecordUnion->V2.ParentFileReferenceNumber;

S_DATA_SUBSET aD;

aD.guid = m_initDatasInfo.info.uuid;

aD.reason = usnRecordUnion->V2.Reason;

aD.usnOffset = usnRecordOffset;

aD.mft = usnRecordUnion->V2.FileReferenceNumber;

/*//0x00000100:捕捉创建文件或文件夹;0x80000200:捕捉删除文件;0x8000200:捕捉重命名文件 或者本盘剪切

*

*

* 0x01 -> 0x80000001 文件中覆盖数据 (文件字节大小不变)

* 0x02 -> 0x80000002 文件中增加数据(从无到有)

* 0x03 -> 0x80000003 文件中增加数据 (在原来的存在数据中增加数据)

* 0x05 -> 0x80000005 文件中删除部分数据

* 0x04 -> 0x80000004 文件中删除全部数据

*

* 0x04 -> 0x8004 -> 0x80008004 粘贴一个空文件替换掉原来的文件

* 0x04 -> 0x6 -> 0x7 -> 0x8007 -> 0x80008007 粘贴一个非空文件替换掉原来的文件

*/

if(!(LOG_PATH_PMft == dataBody.data()->PMFTNumber || USN_RECORD_PATH_PMft == dataBody.data()->PMFTNumber ||

DATA_UPDATE_PATH_PMft == dataBody.data()->PMFTNumber || RUN_LOG_PATH_PMft == dataBody.data()->PMFTNumber)){//log文件夹下的所有文件发生改变不采集

S_USN_LOG array;

array.dataTime = DATETIMS;

array.partition = m_partitionName.toUtf8();

array.usnOffset = QByteArray::number(usnRecordOffset, 10);

array.mft = QByteArray::number((MFTNUM) usnRecordUnion->V2.FileReferenceNumber, 10);

array.pMft = QByteArray::number((MFTNUM) usnRecordUnion->V2.ParentFileReferenceNumber, 10);

array.usn = QByteArray::number(usnRecordUnion->V2.Usn, 10);

array.reasonDataTime = GlobalFunction::getInstance()->FILETIMEToDateTime(usnRecordUnion->V2.TimeStamp.QuadPart);

array.reason = QByteArray::number((quint32)usnRecordUnion->V2.Reason,10);

array.attributes = QByteArray::number((quint32)usnRecordUnion->V2.FileAttributes,10);

array.fileName = fileName.toUtf8();

emit SignalUsnRecordLog(UsnRecordLog,QVariant::fromValue(array));//记录usn日志

}

switch (usnRecordUnion->V2.Reason) {

case 0x00000100://捕捉创建 复制

case 0x80002000://重命名文件 本盘剪切也是0x00002000

case 0x80000200://捕捉删除文件

case 0x80000001://文件中覆盖数据 (文件字节大小不变)

case 0x80000002://文件中增加数据(从无到有)

// break;

case 0x80000003://文件中增加数据 (在原来的存在数据中增加数据)

// break;

case 0x80000004://文件中删除全部数据

// break;

case 0x80000005://文件中删除部分数据

// break;

case 0x80008004://粘贴一个空文件替换掉原来的文件

// break;

case 0x80008007://粘贴一个非空文件替换掉原来的文件

{

MFT_BASIC_INFO basicInfo;

quint64 mftOffset = getMTFOffset(dataBody.data()->MFTNumber);

QByteArray byteData = getRawData(m_NTFSOffset + mftOffset,BYTES_PER_MFT_FILE);

if(byteData.isNull())

return ;

if(!getMFTBasicInfo(basicInfo,byteData))

return;

for(int i=0;i

basicInfo.fileL.at(i)->bodyAtt = basicInfo.attBody;

aD.dataBodyL = basicInfo.fileL;

emit SignalDataBase(aD);//更新数据

}

return;

default:

break;

}

}

void CNtfsInfo::updataDataBaseV3(PUSN_RECORD_UNION usnRecordUnion)

{

qDebug()<

}

void CNtfsInfo::updataDataBaseV4(PUSN_RECORD_UNION usnRecordUnion)

{

qDebug()<

}

//监控usn记录

void CNtfsInfo::usnRecordMonitoring()

{

qDebug()<

while (!QThread::currentThread()->isInterruptionRequested()) {

if(m_mftUsnJournal.ISOK)

usnStartRun(m_mftUsnJournal);

while (!QThread::currentThread()->isInterruptionRequested() && MemoryPool::getInstance()->getSettingArgs().usnRecordNoMonitoring)

QThread::sleep(1);

QThread::sleep(1);

CNtfsInfo::Error type = anewInitDrive();

switch (type){

case NoError:

{

qDebug()<

while (!QThread::currentThread()->isInterruptionRequested()){

QThread::sleep(1);

m_mftUsnJournal = getUsnJournalBasicInfo();

if(!m_mftUsnJournal.ISOK)

break;

//判断后来的StreamAiiocSize和DataSize和类中的比较是否相等,相等表示,数据块未发生变化,继续采集

//不相等表示,数据块发生变化,覆盖类中的usnjournal MFT信息,重新采集usnjournal记录

if(m_mftUsnJournal.JAtt.isEmpty())

continue;

//必须大于lastUSNNumber 说明才有数据,不然一直循环获取usn,直到有数据。 等于说明,最后(0x228最大usnjournal日志大小)存在数据,需要重新获取最后

if(m_mftUsnJournal.JAtt[0].CCommon.CNonResident.StreamRealSize >= m_lastUsnNumber) {

m_firstAnew = false;

break;

}

}

}

break;

case InitError:

{

qDebug()<

return;

}

break;

case AnewInit:

{

qDebug()<

initData();

}

break;

}

}

}

//开启usn采集

void CNtfsInfo::usnStartRun(S_MFT_USN_JOURNAL usnJour)

{

qDebug()<

quint32 count_i = 0;

quint64 USNoffset=0;//实际偏移地址lcn

quint64 dataRunSize=0;//当前使用的数据块大小

quint64 dataRunOffset=0;//当前使用的数据块的偏移地址vcn (不能大于dataRunSize)

quint64 tempSize = 0;//记录数据块总共大小

//firstAnew为TRUE是第开启usn

if(m_firstAnew)

m_lastUsnNumber = usnJour.JAtt[0].CCommon.CNonResident.StreamRealSize;

//获取要读取usn记录的位置

for(int i=0;i

//累加数据块大小

tempSize += usnJour.lDRun[i].datalengthCluster * BYTES_PER_CLUSTER;

//数据块大小和最后一个usn相等,从下一个块读取

if(tempSize == m_lastUsnNumber){

//当相加的数据块大小等于usn号时,此时usn号时下一个块的开头,所以要验证下一个数据块是否存在

if((++i)>=usnJour.lDRun.count())

return ;

//要读取的数据块偏移vcn

dataRunOffset = 0;

//要读取的数据块大小vcn

dataRunSize = usnJour.lDRun[i].datalengthCluster * BYTES_PER_CLUSTER;

//要读取的物理偏移地址lcn

USNoffset = m_NTFSOffset + usnJour.lDRun[i].dataStartCluster * BYTES_PER_CLUSTER;

break;

} else if(tempSize > m_lastUsnNumber){ //数据块大小大于最后一个usn,从当前数据块读取

//要读取的数据块偏移vcn

dataRunOffset = usnJour.lDRun[i].datalengthCluster * BYTES_PER_CLUSTER + m_lastUsnNumber - tempSize;

//要读取的数据块大小vcn

dataRunSize = usnJour.lDRun[i].datalengthCluster * BYTES_PER_CLUSTER;

//要读取的物理偏移地址lcn 取扇区首地址才能正常读取数据

USNoffset = m_NTFSOffset + usnJour.lDRun[i].dataStartCluster * BYTES_PER_CLUSTER + dataRunOffset - (dataRunOffset % PAGE_USN_RECORD_SIZE);

break;

}

}

qDebug()<

while (dataRunOffsetisInterruptionRequested()){

//不监控usn

if(MemoryPool::getInstance()->getSettingArgs().usnRecordNoMonitoring)

return;

if(!m_fileHandle->seek(USNoffset))

return ;

QByteArray rawdata = m_fileHandle->read(PAGE_USN_RECORD_SIZE+1);//读取

if(rawdata.size()!=PAGE_USN_RECORD_SIZE+1)

return ;

quint32 readSize=0;

if((PAGE_USN_RECORD_SIZE - dataRunOffset % PAGE_USN_RECORD_SIZE) >= MAX_USN_REOCRD_SIZE)//判断要copy的字节大小

readSize = MAX_USN_REOCRD_SIZE;

else

readSize = (PAGE_USN_RECORD_SIZE - dataRunOffset % PAGE_USN_RECORD_SIZE);

//memcpy(m_usnRecordUnion,rawdata.mid(dataRunOffset % PAGE_USN_RECORD_SIZE,readSize).data(),readSize);

errno_t err = memcpy_s(m_usnRecordUnion,MAX_USN_REOCRD_SIZE,rawdata.mid(dataRunOffset % PAGE_USN_RECORD_SIZE,readSize).data(),readSize);//返回值为0,拷贝成功

if(err){

qDebug()<

return ;

}

if(m_usnRecordUnion->V2.Usn && !m_firstAnew && (quint64)m_usnRecordUnion->V2.Usn != m_lastUsnNumber)

return ;

if(!m_usnRecordUnion->Header.RecordLength){//当记录都为0的时候,表示没有数据,

count_i++;

if(count_i%50==0){ //连续n次数据为空给cpu腾出时间,进入休眠,给cpu腾出时间片,缓解cpu压力

//qDebug()<

CNtfsInfo::Error error = anewInitDrive();

if(error != NoError)

return ;

QThread::sleep(1);

count_i =0;

}

//QThread::msleep(500);//源码调用的也是Windows下Sleep();

//QThread::msleep(0);//给cpu腾出时间片,

}

/*//0x00000100:捕捉创建文件或文件夹;0x80000200:捕捉删除文件;0x8000200:捕捉重命名文件 或者本盘剪切

*

*

* 0x01 -> 0x80000001 文件中覆盖数据 (文件字节大小不变)

* 0x02 -> 0x80000002 文件中增加数据(从无到有)

* 0x03 -> 0x80000003 文件中增加数据 (在原来的存在数据中增加数据)

* 0x05 -> 0x80000005 文件中删除部分数据

* 0x04 -> 0x80000004 文件中删除全部数据

*

* 0x04 -> 0x8004 -> 0x80008004 粘贴一个空文件替换掉原来的文件

* 0x04 -> 0x6 -> 0x7 -> 0x8007 -> 0x80008007 粘贴一个非空文件替换掉原来的文件

*/

switch (m_usnRecordUnion->Header.MajorVersion) {

case 0x2:

{

if(m_usnRecordUnion->V2.Reason == 0)//等于0读取的数据不是完整的,重新读取

continue;

updataDataBaseV2(m_usnRecordUnion,USNoffset + dataRunOffset % PAGE_USN_RECORD_SIZE - m_NTFSOffset);

m_lastUsnNumber = m_usnRecordUnion->V2.Usn + m_usnRecordUnion->Header.RecordLength;//记录最后一个usn号

}

break;

case 0x3:

{

updataDataBaseV3(m_usnRecordUnion);

}

break;

case 0x4:

{

updataDataBaseV4(m_usnRecordUnion);

}

break;

default:

{

//continue;

}

break;

}

dataRunOffset += m_usnRecordUnion->Header.RecordLength;

quint32 temp = PAGE_USN_RECORD_SIZE - (dataRunOffset % PAGE_USN_RECORD_SIZE);

//剩余的数据小于0x40,丢弃//0x40 == sizeof(USN_RECORD_V2) + (8 - sizeof(USN_RECORD_V2)%8) //8字节是一个硬盘一块数据的最小占用

if(temp < 0x40) {

USNoffset += PAGE_USN_RECORD_SIZE;

dataRunOffset += temp;

m_lastUsnNumber += temp;//记录最后一个usn号

if(dataRunOffset == dataRunSize)//数据读到最后了,存在丢弃最后的小于0x228个字节

break;

else if(dataRunOffset > dataRunSize)//大于就抛出异常

return ;

}else if(!m_usnRecordUnion->Header.RecordLength && temp

if(dataRunOffset + temp == dataRunSize){ //数据读到最后了,存在丢弃最后的小于0x228个字节

S_MFT_USN_JOURNAL mftUsnJournal = getUsnJournalBasicInfo();//先获取usn记录管理 1

if(!mftUsnJournal.ISOK){ //usnjournal 错误: 卷更改日志处于非活动状态。

m_lastUsnNumber += temp;//记录最后一个usn号

break;

}

if(mftUsnJournal.JAtt[0].CCommon.CNonResident.StreamRealSize >= m_lastUsnNumber ){

m_firstAnew = false;

m_lastUsnNumber += temp;//记录最后一个usn号

break;

}

} else if(dataRunOffset + temp > dataRunSize){ //大于就抛出异常

return ;

}else if((quint8)rawdata.back()>0){

m_lastUsnNumber += temp;//记录最后一个usn号

dataRunOffset += temp;

USNoffset += PAGE_USN_RECORD_SIZE;

}

}else if(temp == PAGE_USN_RECORD_SIZE && m_usnRecordUnion->Header.RecordLength != 0){

USNoffset += PAGE_USN_RECORD_SIZE;

}

}

return ;

}

上面代码用到的结构体,可在这里查找

Back to top: