48,9 → 48,12 |
nameOffset = 10 |
attributeFlags = 12 |
attributeID = 14 |
sizeWithoutHeader = 16 |
; resident attribute header |
sizeWithoutHeader = 10h |
; attributeOffset = 14h |
indexedFlag = 16h |
; non resident attribute header |
firstVCN = 10h |
lastVCN = 18h |
dataRunsOffset = 20h |
attributeAllocatedSize = 28h |
439,6 → 442,9 |
mov eax, [ebp+NTFS.ntfs_cur_read] |
cmp eax, 4 |
jc .failFreeBitmapMFT |
mov ecx, [ebp+NTFS.ntfs_attr_offs] |
cmp byte [ecx+nonResidentFlag], 1 |
jnz .failFreeBitmapMFT |
mov [ebp+NTFS.mftBitmapSize], eax |
mov eax, [ebp+NTFS.ntfsLastRead] |
mov [ebp+NTFS.mftBitmapLocation], eax |
657,18 → 663,19 |
jc .errret |
; 2. Find required attribute. |
mov eax, [ebp+NTFS.frs_buffer] |
; a) For auxiliary records, read base record |
; N.B. If base record is present, |
; base iRecord may be 0 (for $Mft), but SequenceNumber is nonzero |
; a) For auxiliary records, read base record. |
; If base record is present, base iRecord may be 0 (for $Mft), |
; but SequenceNumber is nonzero. |
cmp dword [eax+24h], 0 |
jz @f |
mov eax, [eax+20h] |
; test eax, eax |
; jz @f |
.beginfindattr: |
mov [ebp+NTFS.ntfs_attr_iRecord], eax |
call ntfs_read_file_record |
jc .errret |
jmp @f |
.newAttribute: |
pushad |
@@: |
; b) Scan for required attribute and for $ATTR_LIST |
mov eax, [ebp+NTFS.frs_buffer] |
1070,7 → 1077,7 |
|
ntfs_read_file_record: |
; in: eax = iRecord |
; out: [ebp+NTFS.frs_buffer] = record data |
; out: [ebp+NTFS.frs_buffer] -> file record |
; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS |
; Read attr $DATA of $Mft, starting from eax*[ebp+NTFS.frs_size] |
push ecx edx |
1135,6 → 1142,9 |
ntfs_restore_usa_frs: |
mov eax, [ebp+NTFS.frs_size] |
ntfs_restore_usa: |
; in: |
; ebx -> record |
; eax = size in bytes |
pushad |
shr eax, 9 |
mov ecx, eax |
1163,13 → 1173,13 |
|
ntfs_decode_mcb_entry: |
; in: |
; esi -> mcb entry |
; esi -> MCB entry |
; esp -> buffer (16 bytes) |
; out: |
; esi -> next mcb entry |
; esi -> next MCB entry |
; esp -> data run size |
; esp+8 -> cluster (delta) |
; CF=0 -> mcb end |
; CF=0 -> MCB end |
push eax ecx edi |
lea edi, [esp+16] |
xor eax, eax |
1999,59 → 2009,79 |
@@: ; 1. Search file |
call ntfs_lock |
stdcall ntfs_find_lfn, [esp+4] |
jnc .found |
cmp [ebp+NTFS.ntfsFragmentCount], 1 |
jnz ntfsUnsupported ; record fragmented |
test eax, eax |
jz ntfsFail |
jmp .notFound |
|
.found: ; rewrite |
jc .notFound |
; found, rewrite |
cmp [ebp+NTFS.ntfs_cur_iRecord], 16 |
jc ntfsDenied |
cmp [ebp+NTFS.ntfsFolder], 1 |
jz ntfsDenied |
jz .folder |
cmp [ebp+NTFS.ntfsFragmentCount], 1 |
jnz ntfsUnsupported ; record fragmented |
; edit directory node |
mov edi, [ebp+NTFS.cur_index_buf] |
cmp dword [edi], 'INDX' |
jz @f |
mov esi, [ebp+NTFS.frs_buffer] |
mov ecx, [esi+recordRealSize] |
shr ecx, 2 |
rep movsd |
mov esi, [ebp+NTFS.ntfs_attr_offs] |
mov cl, [esi+attributeOffset] |
sub esi, [ebp+NTFS.frs_buffer] |
add eax, ecx |
add eax, esi |
@@: |
mov edx, [ebx+12] |
mov [eax+fileRealSize], edx |
mov dword [eax+fileRealSize+4], 0 |
mov eax, [ebp+NTFS.ntfsLastRead] |
mov [ebp+NTFS.nodeLastRead], eax |
mov [ebp+NTFS.ntfs_cur_attr], 0x80 |
mov [ebp+NTFS.ntfs_cur_offs], 0 |
mov [ebp+NTFS.ntfs_cur_size], 0 |
call ntfs_read_attr |
jc ntfsDenied |
mov eax, [ebp+NTFS.frs_buffer] |
cmp word [eax+baseRecordReuse], 0 |
jc ntfsFail |
mov ecx, [ebp+NTFS.frs_buffer] |
mov eax, edx |
xor edx, edx |
cmp word [ecx+baseRecordReuse], 0 |
jnz ntfsUnsupported ; auxiliary record |
cmp byte [eax+hardLinkCounter], 1 |
jnz ntfsUnsupported ; file copying required |
mov ecx, [ebp+NTFS.ntfs_attr_offs] |
cmp byte [ecx+nonResidentFlag], 1 |
jnz ntfsUnsupported ; resident $DATA |
mov eax, [ebx+4] |
mov edx, [ebx+8] |
add eax, [ebx+12] |
adc edx, 0 |
cmp edx, [ecx+attributeRealSize+4] |
cmp word [ecx+attributeFlags], 0 |
jnz ntfsUnsupported |
push ebx |
cmp byte [ecx+nonResidentFlag], 0 |
jz @f |
cmp [ecx+attributeRealSize+4], edx |
jnz @f |
cmp [ecx+attributeRealSize], eax |
jnz ntfsUnsupported |
jmp ntfs_WriteFile.write |
jz ntfs_WriteFile.writeNode |
@@: |
jmp ntfs_WriteFile.resizeAttribute |
|
.notFound: ; create; check path folders |
cmp dword [esp+4], 0 |
jnz ntfsNotFound |
cmp byte [esi], 0 |
jz ntfsNotFound |
.folder: |
bt dword [eax+fileFlags], 28 |
jnc ntfsDenied |
push 0 |
jmp ntfsOut |
|
.notFound: ; create |
test eax, eax |
jz ntfsFail |
cmp [ebp+NTFS.ntfsFragmentCount], 1 |
jnz ntfsUnsupported ; record fragmented |
; 2. Prepare directory record |
mov ecx, esi |
@@: ; count characters |
inc ecx |
cmp byte [ecx], '/' |
jz ntfsNotFound |
jz ntfsNotFound ; path folder not found |
cmp byte [ecx], 0 |
jnz @b |
sub ecx, esi |
push ecx |
lea ecx, [ecx*2+52h] ; precalculate index length |
add ecx, 7 ; align 8 |
and ecx, not 7 |
lea ecx, [ecx*2+52h+7] ; precalculate index length |
and ecx, not 7 ; align 8 |
mov edi, [ebp+NTFS.cur_index_buf] |
push esi |
push ecx |
2111,11 → 2141,12 |
rep stosd |
cld |
add edi, 4 |
pop eax |
pop ecx |
pop esi |
mov [edi+indexAllocatedSize], ax ; fill index with data |
mov [edi+indexAllocatedSize], cx ; fill index with data |
mov eax, [esp] |
lea eax, [eax*2+42h] |
shl eax, 1 |
add eax, 42h |
mov [edi+indexRawSize], ax |
mov eax, [ebp+NTFS.ntfs_attr_iRecord] |
mov [edi+directoryRecordReference], eax |
2123,8 → 2154,16 |
mov eax, [eax+reuseCounter] |
mov [edi+directoryReferenceReuse], ax |
mov eax, [ebx+12] |
add ecx, 30h+48h+8+18h+8 |
add ecx, eax |
mov [ebp+NTFS.fileRealSize], eax |
mov [edi+fileRealSize], eax |
cmp [ebp+NTFS.frs_size], ecx |
jc @f |
mov eax, [ebx+16] |
mov [ebp+NTFS.fileDataStart], eax |
xor eax, eax |
@@: |
mov ecx, [ebp+NTFS.sectors_per_cluster] |
shl ecx, 9 |
add eax, ecx |
2149,161 → 2188,15 |
cmp [ebp+NTFS.ntfsFolder], 0 |
jz @f |
mov edi, [ebp+NTFS.indexOffset] |
mov byte [edi+fileFlags+3], 16 |
bts dword [edi+fileFlags], 28 |
jmp .mftBitmap |
|
@@: ; 3. File data |
cmp [ebp+NTFS.fileRealSize], 0 |
cmp [ebp+NTFS.fileDataSize], 0 |
jz .mftBitmap |
; One piece free space bitmap search engine |
mov edi, [ebp+NTFS.BitmapBuffer] |
add edi, [ebp+NTFS.BitmapStart] |
mov eax, [ebp+NTFS.fileDataSize] |
shr eax, 5 |
jz .small |
push eax ; bitmap dwords |
add edi, 4 |
.start: |
mov ecx, [ebp+NTFS.BitmapSize] |
add ecx, [ebp+NTFS.BitmapBuffer] |
sub ecx, edi |
shr ecx, 2 |
@@: |
xor eax, eax |
repnz scasd ; search for empty dword |
jz @f |
call bitmapBuffering |
jmp @b |
@@: |
cmp ecx, [esp] |
jnc @f |
call bitmapBuffering |
jmp @b |
@@: |
sub edi, 4 |
mov ecx, [esp] |
mov esi, edi |
xor eax, eax |
repz scasd ; check following dwords |
jnz .start |
sub esi, 4 |
mov eax, [esi] |
xor edx, edx |
bsr edx, eax |
inc edx |
push edx ; starting bit |
push esi ; starting dword |
add esi, 4 |
neg edx |
add edx, 32 |
mov eax, [ebp+NTFS.fileDataSize] |
sub eax, edx |
mov edx, eax |
shr eax, 5 |
shl eax, 2 |
add esi, eax |
mov eax, [esi] |
bsf ecx, eax ; last dword |
jz .done |
and edx, 31 |
cmp ecx, edx |
jnc .done |
add esp, 8 |
jmp .start |
|
.small: ; less than 32 clusters |
mov ecx, [ebp+NTFS.BitmapSize] |
sub ecx, [ebp+NTFS.BitmapStart] |
shr ecx, 2 |
.smStart: |
mov eax, -1 |
repz scasd ; search for zero bits |
push ecx |
test ecx, ecx |
jnz @f |
call bitmapBuffering |
pop eax |
jmp .smStart |
@@: |
sub edi, 4 |
mov eax, [edi] |
not eax |
@@: |
bsf ecx, eax ; first 0 |
jz .again |
not eax |
shr eax, cl |
shl eax, cl |
bsf edx, eax ; next 1 |
jz @f |
sub edx, ecx |
cmp edx, [ebp+NTFS.fileDataSize] |
jnc .got ; fits inside |
bsf ecx, eax |
not eax |
shr eax, cl |
shl eax, cl |
jmp @b |
@@: ; next dword |
mov eax, [edi+4] |
bsf edx, eax |
jz .got ; empty |
add edx, 32 |
sub edx, ecx |
cmp edx, [ebp+NTFS.fileDataSize] |
jnc .got ; share between dwords |
.again: |
add edi, 4 |
pop ecx |
jmp .smStart |
|
.got: |
push ecx ; starting bit |
push edi ; starting dword |
.done: ; mark space |
mov ecx, [esp+4] |
cmp ecx, 32 |
jc @f |
xor ecx, ecx |
add dword [esp], 4 |
mov [esp+4], ecx |
@@: |
mov edi, [esp] |
xor eax, eax |
dec eax |
shr eax, cl |
shl eax, cl |
neg ecx |
add ecx, 32 |
sub ecx, [ebp+NTFS.fileDataSize] |
jc @f |
shl eax, cl ; fits inside dword |
shr eax, cl |
or [edi], eax |
jmp .writeData |
|
@@: |
or [edi], eax |
neg ecx |
push ecx |
shr ecx, 5 |
add edi, 4 |
xor eax, eax |
dec eax |
rep stosd |
pop ecx |
and ecx, 31 |
shr eax, cl |
shl eax, cl |
not eax |
or [edi], eax |
.writeData: |
pop edx |
sub edx, [ebp+NTFS.BitmapBuffer] |
shl edx, 3 |
pop eax |
add eax, edx |
pop edx |
mov edi, [ebp+NTFS.BitmapStart] |
call ntfsSpaceAlloc |
jc ntfsDiskFull |
mov [ebp+NTFS.fileDataStart], eax |
mul [ebp+NTFS.sectors_per_cluster] |
mov ecx, [ebp+NTFS.fileRealSize] |
2325,7 → 2218,7 |
movzx eax, byte [edi] |
not al |
bsf ecx, eax |
jz ntfsUnsupported ; no free records |
jz .extendBitmapMFT ; no free records |
bts [edi], ecx |
; get record location |
sub edi, [ebp+NTFS.mftBitmapBuffer] |
2343,89 → 2236,58 |
mov [ebp+NTFS.ntfs_cur_buf], eax |
call ntfs_read_attr |
cmp [ebp+NTFS.ntfs_cur_read], 0 |
jnz .mftRecord |
; extend MFT $DATA |
jz .extendMFT |
jmp .mftRecord |
|
.extendBitmapMFT: |
mov eax, [ebp+NTFS.sectors_per_cluster] |
shl eax, 9 |
cmp [ebp+NTFS.mftBitmapSize], eax |
jnc ntfsUnsupported |
mov [ebp+NTFS.ntfs_cur_iRecord], 0 |
mov [ebp+NTFS.ntfs_cur_attr], 0xB0 |
mov [ebp+NTFS.ntfs_cur_offs], 0 |
mov [ebp+NTFS.ntfs_cur_size], 0 |
call ntfs_read_attr |
jc ntfsFail |
mov eax, [ebp+NTFS.mft_cluster] |
mul [ebp+NTFS.sectors_per_cluster] |
cmp eax, [ebp+NTFS.ntfsLastRead] |
jnz ntfsUnsupported ; auxiliary record |
mov edi, [ebp+NTFS.ntfs_attr_offs] |
mov ebx, [ebp+NTFS.sectors_per_cluster] |
shl ebx, 9+3 |
add dword [edi+lastVCN], 8 |
add [edi+attributeAllocatedSize], ebx |
adc byte [edi+attributeAllocatedSize+4], 0 |
add [edi+attributeRealSize], ebx |
adc byte [edi+attributeRealSize+4], 0 |
add [edi+initialDataSize], ebx |
adc byte [edi+initialDataSize+4], 0 |
movzx eax, byte [edi+dataRunsOffset] |
add edi, eax |
mov al, [edi] |
inc edi |
shl eax, 4 |
shr al, 4 |
mov cl, 4 |
sub cl, al |
shl cl, 3 |
add ah, al |
shr eax, 8 |
cmp byte [edi+eax], 0 |
jnz ntfsUnsupported ; $MFT fragmented |
mov al, 8 |
mov edx, [edi] |
rol eax, cl |
rol edx, cl |
add eax, edx |
jc ntfsUnsupported |
ror eax, cl |
shr edx, cl |
mov [edi], eax |
add edx, [ebp+NTFS.mft_cluster] |
mov esi, edx |
mov ecx, edx |
and ecx, 7 |
shr edx, 3 |
add edx, [ebp+NTFS.BitmapBuffer] |
mov ax, [edx] |
shr ax, cl |
test al, al |
jnz ntfsUnsupported |
dec al |
xchg [edx], al |
mov [edx+1], al |
stdcall kernel_alloc, ebx |
test eax, eax |
jz ntfsNoMemory |
mov ecx, ebx |
shr ecx, 2 |
mov edi, eax |
push ebx |
mov ebx, eax |
xor eax, eax |
rep stosd |
mov eax, esi |
mov edi, [ebp+NTFS.mftBitmapBuffer] |
mov ecx, [ebp+NTFS.mftBitmapSize] |
add edi, ecx |
mov eax, ecx |
mov edx, [ebp+NTFS.ntfs_attr_offs] |
add ecx, 8 |
mov [edx+attributeRealSize], ecx |
mov [edx+initialDataSize], ecx |
shl eax, 3 |
mov [ebp+NTFS.newMftRecord], eax |
mov dword [edi], 1 |
mov dword [edi+4], 0 |
mov [ebp+NTFS.ntfs_cur_attr], 0x80 |
call ntfs_read_attr.newAttribute |
jc ntfsFail |
mov [ebp+NTFS.mftBitmapSize], ecx |
.extendMFT: |
mov eax, [ebp+NTFS.mft_cluster] |
mul [ebp+NTFS.sectors_per_cluster] |
pop ecx |
shr ecx, 9 |
call fs_write64_sys ; clear new records |
stdcall kernel_free, ebx |
mov eax, esi |
shr eax, 3+9 |
mov ebx, eax |
shl ebx, 9 |
add ebx, [ebp+NTFS.BitmapBuffer] |
add eax, [ebp+NTFS.BitmapLocation] |
mov ecx, 1 |
xor edx, edx |
call fs_write64_app ; partition bitmap |
test eax, eax |
jnz ntfsDevice |
cmp eax, [ebp+NTFS.ntfsLastRead] |
jnz ntfsUnsupported ; auxiliary record |
mov ecx, [ebp+NTFS.ntfs_attr_offs] |
mov eax, [ecx+attributeRealSize] |
mov edx, [ecx+attributeRealSize+4] |
xor ax, ax |
add eax, 10000h |
adc edx, 0 |
push [ebp+NTFS.fileDataStart] |
push [ebp+NTFS.fileDataSize] |
call resizeAttribute |
jc ntfsErrorPop2 |
mov eax, [ebp+NTFS.frs_buffer] |
mov [ebp+NTFS.ntfs_cur_buf], eax |
call writeRecord ; $MFT |
test eax, eax |
jnz ntfsDevice |
mov eax, [ebp+NTFS.mftmirr_cluster] |
mul [ebp+NTFS.sectors_per_cluster] |
mov ebx, [ebp+NTFS.frs_buffer] |
2432,28 → 2294,26 |
movzx ecx, word [ebx+updateSequenceSize] |
dec ecx |
call fs_write64_sys ; $MFTMirr |
test eax, eax |
jnz ntfsDevice |
mov eax, [ebp+NTFS.ntfs_cur_offs] |
add [ebp+NTFS.ntfsLastRead], eax |
call ntfsSpaceClean |
pop [ebp+NTFS.fileDataSize] |
pop [ebp+NTFS.fileDataStart] |
.mftRecord: |
mov esi, [ebp+NTFS.indexOffset] |
mov ecx, [ebp+NTFS.frs_size] |
shr ecx, 2 |
mov edi, [ebp+NTFS.frs_buffer] |
xor eax, eax |
movzx ecx, word [esi+indexAllocatedSize] |
add ecx, 8+30h+48h+50h+8 |
push ecx |
shr ecx, 2 |
rep stosd |
mov edi, [ebp+NTFS.frs_buffer] |
; record header |
mov eax, [ebp+NTFS.frs_size] |
mov [edi+recordAllocatedSize], eax |
shr eax, 9 |
inc eax |
mov [edi+updateSequenceSize], al |
mov dword[edi], 'FILE' |
mov byte [edi+updateSequenceOffset], 2ah |
mov byte [edi+updateSequenceSize], 3 |
mov byte [edi+hardLinkCounter], 1 |
mov byte [edi+attributeOffset], 30h |
pop dword[edi+recordRealSize] |
mov word [edi+recordAllocatedSize], 1024 |
mov byte [edi+newAttributeID], 3 |
rdtsc |
mov [edi+2ah], ax |
2465,27 → 2325,33 |
mov byte [edi+attributeOffset], 18h |
add edi, 48h |
; $FileName |
mov esi, [ebp+NTFS.indexOffset] |
mov byte [edi+attributeType], 30h |
mov byte [edi+attributeID], 1 |
mov byte [edi+attributeOffset], 18h |
mov byte [edi+indexedFlag], 1 |
mov cx, [esi+indexRawSize] |
mov [edi+sizeWithoutHeader], ecx |
mov cx, [esi+indexAllocatedSize] |
add ecx, 8 |
mov [edi+sizeWithHeader], ecx |
mov byte [edi+attributeOffset], 18h |
mov byte [edi+indexedFlag], 1 |
add edi, 18h |
add esi, 16 |
sub ecx, 18h |
shr ecx, 2 |
rep movsd |
cmp [ebp+NTFS.ntfsFolder], 0 |
jnz @f |
mov byte [edi+sizeWithHeader], 50h |
mov byte [edi+attributeID], 2 |
cmp [ebp+NTFS.ntfsFolder], 1 |
jz .indexRoot |
; $Data |
mov byte [edi+attributeType], 80h |
cmp [ebp+NTFS.fileRealSize], 0 |
jz .zeroSize |
mov eax, [ebp+NTFS.fileDataSize] |
test eax, eax |
jz .resident |
mov esi, [ebp+NTFS.indexOffset] |
dec eax |
mov [edi+lastVCN], eax |
mov byte [edi+nonResidentFlag], 1 |
mov byte [edi+dataRunsOffset], 40h |
mov eax, [esi+fileAllocatedSize] |
2493,22 → 2359,33 |
mov eax, [esi+fileRealSize] |
mov [edi+attributeRealSize], eax |
mov [edi+initialDataSize], eax |
mov byte [edi+40h], 44h |
mov eax, [ebp+NTFS.fileDataSize] |
mov [edi+41h], eax |
dec eax |
mov [edi+lastVCN], eax |
mov eax, [ebp+NTFS.fileDataStart] |
mov [edi+45h], eax |
mov al, 1 |
jmp .writeMftRecord |
push edi |
mov esi, edi |
add edi, 40h |
call createMcbEntry |
inc edi |
jmp @f |
|
.zeroSize: |
.resident: |
mov ecx, [ebp+NTFS.fileRealSize] |
mov [edi+sizeWithoutHeader], ecx |
mov byte [edi+attributeOffset], 18h |
push edi |
mov esi, [ebp+NTFS.fileDataStart] |
add edi, 18h |
rep movsb |
@@: |
mov eax, edi |
pop edi |
sub eax, edi |
add eax, 7 |
and eax, not 7 |
mov [edi+sizeWithHeader], eax |
add edi, eax |
mov al, 1 |
jmp .writeMftRecord |
jmp @f |
|
@@: ; $IndexRoot |
.indexRoot: |
mov byte [edi+attributeType], 90h |
mov byte [edi+nameLength], 4 |
mov byte [edi+nameOffset], 18h |
2527,19 → 2404,20 |
mov byte [edi+30h+nodeAllocatedSize], 32 |
mov byte [edi+40h+indexAllocatedSize], 16 |
mov byte [edi+40h+indexFlags], 2 |
add edi, 50h |
mov al, 3 |
.writeMftRecord: |
mov byte [edi+sizeWithHeader], 50h |
mov byte [edi+attributeID], 2 |
mov dword[edi+50h], -1 ; $End |
mov edi, [ebp+NTFS.frs_buffer] |
mov [edi+recordFlags], al |
mov [ebp+NTFS.ntfs_cur_buf], edi |
@@: |
mov esi, [ebp+NTFS.frs_buffer] |
mov dword [edi], -1 |
mov dword [edi+4], 0 |
add edi, 8 |
sub edi, esi |
mov [ebp+NTFS.ntfs_cur_buf], esi |
mov [esi+recordFlags], al |
mov [esi+recordRealSize], edi |
call writeRecord |
test eax, eax |
jnz ntfsDevice |
mov esi, [ebp+PARTITION.Disk] |
call disk_sync |
; write MFT bitmap |
mov eax, [ebp+NTFS.newMftRecord] |
shr eax, 3+9 |
2553,13 → 2431,13 |
test eax, eax |
jnz ntfsDevice |
; 5. Write partition bitmap |
cmp [ebp+NTFS.ntfsFolder], 0 |
jnz @f |
cmp [ebp+NTFS.fileRealSize], 0 |
cmp [ebp+NTFS.ntfsFolder], 1 |
jz @f |
mov ecx, [ebp+NTFS.fileDataStart] |
mov eax, ecx |
add ecx, [ebp+NTFS.fileDataSize] |
mov eax, [ebp+NTFS.fileDataStart] |
mov ecx, [ebp+NTFS.fileDataSize] |
test ecx, ecx |
jz @f |
add ecx, eax |
add ecx, 4095 |
shr ecx, 3+9 |
shr eax, 3+9 |
2573,8 → 2451,6 |
test eax, eax |
jnz ntfsDevice |
@@: |
mov esi, [ebp+PARTITION.Disk] |
call disk_sync |
mov edi, [ebp+NTFS.indexOffset] |
mov eax, [ebp+NTFS.newMftRecord] |
mov [edi+fileRecordReference], eax |
2584,8 → 2460,6 |
mov eax, [ebp+NTFS.cur_index_buf] |
mov [ebp+NTFS.ntfs_cur_buf], eax |
call writeRecord |
test eax, eax |
jnz ntfsDevice |
mov ebx, [ebp+NTFS.fileRealSize] |
ntfsDone: |
mov esi, [ebp+PARTITION.Disk] |
2595,16 → 2469,17 |
ret |
|
writeRecord: |
; make updateSequence and write to disk |
; in: |
; [ebp+NTFS.ntfs_cur_buf] = record |
; [ebp+NTFS.ntfs_cur_buf] -> record |
; [ebp+NTFS.ntfsLastRead] = partition sector |
; making updateSequence |
mov esi, [ebp+NTFS.ntfs_cur_buf] |
mov edi, esi |
movzx ecx, word [esi+updateSequenceOffset] |
add edi, ecx |
mov ax, [edi] |
add edi, 2 |
inc ax |
stosw |
mov cx, [esi+updateSequenceSize] |
dec ecx |
push ecx |
2614,7 → 2489,6 |
mov [esi-2], ax |
dec ecx |
jnz @b |
; writing to disk |
mov eax, [ebp+NTFS.ntfsLastRead] |
mov ebx, [ebp+NTFS.ntfs_cur_buf] |
pop ecx |
2621,11 → 2495,667 |
xor edx, edx |
jmp fs_write64_sys |
|
createMcbEntry: |
; in: |
; [ebp+NTFS.fileDataStart] = position value |
; [ebp+NTFS.fileDataSize] = size value |
; edi -> destination |
; esi -> attribute header |
mov eax, [ebp+NTFS.fileDataStart] |
xor edx, edx |
shl eax, 1 |
jnc @f |
not eax |
@@: |
inc edx |
shr eax, 8 |
jnz @b |
mov eax, [ebp+NTFS.fileDataSize] |
shl eax, 1 |
xor ecx, ecx |
@@: |
inc ecx |
shr eax, 8 |
jnz @b |
lea eax, [edi+edx+1] |
add eax, ecx |
sub eax, esi |
sub eax, [esi+sizeWithHeader] |
jc @f |
add word [esi+sizeWithHeader], 8 ; extend attribute |
mov esi, [ebp+NTFS.frs_buffer] |
mov eax, [esi+recordRealSize] |
add eax, 8 |
cmp [esi+recordAllocatedSize], eax |
jc .end ; no space in the record |
mov [esi+recordRealSize], eax |
push ecx edi |
add esi, eax |
mov ecx, esi |
sub ecx, edi |
sub ecx, 8 |
shr ecx, 2 |
mov edi, esi |
sub edi, 4 |
sub esi, 12 |
std |
rep movsd |
cld |
pop edi ecx |
@@: |
mov eax, edx |
shl eax, 4 |
add eax, ecx |
stosb |
lea esi, [ebp+NTFS.fileDataSize] |
rep movsb |
lea esi, [ebp+NTFS.fileDataStart] |
mov ecx, edx |
rep movsb |
mov [edi], cl |
.end: |
ret |
|
resizeAttribute: |
; in: |
; [ebp+NTFS.frs_buffer] -> file record |
; [ebp+NTFS.ntfs_attr_offs] -> attribute |
; edx:eax = new size |
; out: |
; [ebp+NTFS.fileDataSize] = clusters added (positive) |
; [ebp+NTFS.fileDataStart] = added block |
; CF=1 -> eax = error code |
mov esi, [ebp+NTFS.ntfs_attr_offs] |
mov dword [ebp+NTFS.ntfs_attr_size], eax |
mov dword [ebp+NTFS.ntfs_attr_size+4], edx |
cmp byte [esi+nonResidentFlag], 0 |
jz .resident |
mov ecx, [ebp+NTFS.sectors_per_cluster] |
shl ecx, 9 |
mov [esi+attributeRealSize], eax |
mov [esi+attributeRealSize+4], edx |
mov [esi+initialDataSize], eax |
mov [esi+initialDataSize+4], edx |
sub eax, 1 |
sbb edx, 0 |
jc .makeResident |
div ecx |
mov edi, eax |
inc eax |
mul ecx |
mov [esi+attributeAllocatedSize], eax |
mov [esi+attributeAllocatedSize+4], edx |
mov ecx, [esi+lastVCN] |
mov [esi+lastVCN], edi |
movzx eax, byte [esi+dataRunsOffset] |
sub edi, ecx |
mov [ebp+NTFS.fileDataSize], edi |
jz .done |
jc .shrinkAttribute |
; extend attribute |
xor edi, edi |
add esi, eax |
push edi edi edi edi |
@@: |
mov edx, eax |
mov eax, esi |
add edi, [esp+8] |
call ntfs_decode_mcb_entry |
jc @b |
mov [esp+4], edx |
mov [esp+12], edi |
add edi, [esp] |
push edi |
shr edi, 5 |
shl edi, 2 |
push eax |
cmp [ebp+NTFS.ntfs_cur_iRecord], 0 |
jz @f |
cmp edi, [ebp+NTFS.BitmapStart] |
jc .err1 |
@@: |
call ntfsSpaceAlloc |
jc .err1 |
pop edi |
pop edx |
cmp edx, eax |
jnz .newEntry |
pop edx |
pop edi |
pop [ebp+NTFS.fileDataStart] |
mov [esp], eax |
push [ebp+NTFS.fileDataSize] |
add [ebp+NTFS.fileDataSize], edx |
jmp @f |
|
.newEntry: |
add esp, 12 |
pop edx |
push eax |
push [ebp+NTFS.fileDataSize] |
sub eax, edx |
mov [ebp+NTFS.fileDataStart], eax |
@@: |
mov esi, [ebp+NTFS.ntfs_attr_offs] |
call createMcbEntry |
pop ecx |
pop eax |
jc .err2 |
mov [ebp+NTFS.fileDataSize], ecx |
mov [ebp+NTFS.fileDataStart], eax |
.writeBitmap: |
add ecx, eax |
add ecx, 4095 |
shr ecx, 3+9 |
shr eax, 3+9 |
sub ecx, eax |
mov ebx, eax |
shl ebx, 9 |
add eax, [ebp+NTFS.BitmapLocation] |
add ebx, [ebp+NTFS.BitmapBuffer] |
xor edx, edx |
call fs_write64_app |
test eax, eax |
jnz @f |
.done: |
ret |
|
.err4: |
pop eax |
@@: |
movi eax, ERROR_DEVICE |
stc |
ret |
|
.err1: |
add esp, 24 |
stc |
.err10: |
movi eax, ERROR_DISK_FULL |
ret |
|
.err2: |
movi eax, ERROR_UNSUPPORTED_FS |
ret |
|
.shrinkAttribute: |
add ecx, edi |
inc ecx |
add esi, eax |
xor edi, edi |
sub esp, 20 |
@@: |
mov [esp+16], esi |
call ntfs_decode_mcb_entry |
jnc .err3 |
add edi, [esp+8] |
sub ecx, [esp] |
jnc @b |
mov ebx, ecx |
add ecx, [esp] |
mov eax, [esp+8] |
mov [ebp+NTFS.fileDataSize], ecx |
mov [ebp+NTFS.fileDataStart], eax |
push edi |
add edi, ecx |
neg ebx |
call ntfsSpaceFree |
pop edi |
jc .end |
@@: |
call ntfs_decode_mcb_entry |
jnc .end |
cmp dword[esp+8], 0 |
jz @b |
add edi, [esp+8] |
mov ebx, [esp] |
call ntfsSpaceFree |
jnc @b |
.end: |
add esp, 16 |
pop edi |
cmp [ebp+NTFS.fileDataSize], 0 |
jz @f |
mov esi, [ebp+NTFS.ntfs_attr_offs] |
call createMcbEntry |
mov [ebp+NTFS.fileDataSize], 0 |
@@: |
ret |
|
.err3: |
movi eax, ERROR_FS_FAIL |
add esp, 20 |
stc |
ret |
|
.resident: |
test edx, edx |
jnz .nonResident |
cmp eax, 8000h |
jnc .nonResident |
add ax, [esi+attributeOffset] |
sub eax, [esi+sizeWithHeader] |
jc @f |
mov edi, [ebp+NTFS.frs_buffer] |
mov ecx, eax |
add ecx, [edi+recordRealSize] |
cmp [edi+recordAllocatedSize], ecx |
jc .nonResident |
add eax, 7 |
and eax, not 7 |
add [edi+recordRealSize], eax |
add edi, [edi+recordRealSize] |
add [esi+sizeWithHeader], eax |
add esi, [esi+sizeWithHeader] |
mov ecx, edi |
sub ecx, esi |
shr ecx, 2 |
sub edi, 4 |
mov esi, edi |
sub esi, eax |
std |
rep movsd |
mov ecx, eax |
shr ecx, 2 |
xor eax, eax |
rep stosd |
cld |
mov esi, [ebp+NTFS.ntfs_attr_offs] |
@@: |
mov eax, dword [ebp+NTFS.ntfs_attr_size] |
mov [esi+sizeWithoutHeader], eax |
mov [ebp+NTFS.fileDataSize], 0 |
clc |
ret |
|
.nonResident: ; convert resident to non-resident |
mov eax, dword [ebp+NTFS.ntfs_attr_size] |
sub eax, 1 |
sbb edx, 0 |
mov ecx, [ebp+NTFS.sectors_per_cluster] |
shl ecx, 9 |
div ecx |
inc eax |
mov [ebp+NTFS.fileDataSize], eax |
mov edi, [ebp+NTFS.BitmapStart] |
push ecx |
call ntfsSpaceAlloc |
pop ecx |
jc .err10 |
mov [ebp+NTFS.fileDataStart], eax |
mov esi, [ebp+NTFS.ntfs_attr_offs] |
xor eax, eax |
xor edx, edx |
@@: |
add eax, ecx |
inc edx |
cmp eax, [esi+sizeWithoutHeader] |
jc @b |
push edx |
push eax |
stdcall kernel_alloc, eax |
mov ecx, [esp] |
shr ecx, 2 |
mov edi, eax |
mov ebx, eax |
xor eax, eax |
rep stosd |
mov al, [esi+attributeOffset] |
mov ecx, [esi+sizeWithoutHeader] |
add esi, eax |
mov edi, ebx |
rep movsb |
mov eax, [ebp+NTFS.fileDataStart] |
mul [ebp+NTFS.sectors_per_cluster] |
pop ecx |
shr ecx, 9 |
call fs_write64_app |
push ebx |
mov ebx, eax |
call kernel_free |
test ebx, ebx |
jnz .err4 |
mov esi, [ebp+NTFS.ntfs_attr_offs] |
add esi, [esi+sizeWithHeader] |
mov ecx, [ebp+NTFS.frs_buffer] |
add ecx, [ecx+recordRealSize] |
sub ecx, esi |
shr ecx, 2 |
lea edi, [ebp+NTFS.ntfs_bitmap_buf] |
push ecx |
rep movsd |
mov edi, [ebp+NTFS.ntfs_attr_offs] |
add edi, 16 |
mov cl, 6 |
xor eax, eax |
rep stosd |
mov edi, [ebp+NTFS.ntfs_attr_offs] |
mov eax, [ebp+NTFS.fileDataSize] |
dec eax |
mov [edi+lastVCN], eax |
inc eax |
mov ecx, [ebp+NTFS.sectors_per_cluster] |
shl ecx, 9 |
mul ecx |
mov byte [edi+sizeWithHeader], 50h |
mov byte [edi+nonResidentFlag], 1 |
mov byte [edi+dataRunsOffset], 40h |
mov [edi+attributeAllocatedSize], eax |
mov [edi+attributeAllocatedSize+4], edx |
mov eax, dword [ebp+NTFS.ntfs_attr_size] |
mov edx, dword [ebp+NTFS.ntfs_attr_size+4] |
mov [edi+attributeRealSize], eax |
mov [edi+attributeRealSize+4], edx |
mov [edi+initialDataSize], eax |
mov [edi+initialDataSize+4], edx |
mov esi, edi |
add edi, 40h |
call createMcbEntry |
mov eax, edi |
mov edi, [ebp+NTFS.ntfs_attr_offs] |
sub eax, edi |
add eax, 8 |
and eax, not 7 |
mov [edi+sizeWithHeader], eax |
pop ecx |
lea esi, [ebp+NTFS.ntfs_bitmap_buf] |
add edi, eax |
rep movsd |
mov esi, [ebp+NTFS.frs_buffer] |
sub edi, esi |
mov [esi+recordRealSize], edi |
pop edx |
mov ecx, [ebp+NTFS.fileDataSize] |
sub [ebp+NTFS.fileDataSize], edx |
mov eax, [ebp+NTFS.fileDataStart] |
add [ebp+NTFS.fileDataStart], edx |
jmp .writeBitmap |
|
.makeResident: ; convert non-resident to empty resident |
movzx eax, byte [esi+dataRunsOffset] |
mov byte [esi+nonResidentFlag], 0 |
mov dword [esi+sizeWithoutHeader], 0 |
mov dword [esi+attributeOffset], 18h |
add esi, eax |
xor edi, edi |
sub esp, 16 |
@@: |
call ntfs_decode_mcb_entry |
jnc @f |
cmp dword[esp+8], 0 |
jz @b |
add edi, [esp+8] |
mov ebx, [esp] |
call ntfsSpaceFree |
jnc @b |
@@: |
add esp, 16 |
mov [ebp+NTFS.fileDataSize], 0 |
ret |
|
ntfsSpaceClean: |
; clean up to 16 Mb of disk space |
; in: |
; [ebp+NTFS.fileDataStart] = block to clean |
; [ebp+NTFS.fileDataSize] = block size |
mov eax, [ebp+NTFS.fileDataSize] |
test eax, eax |
jz @f |
mul [ebp+NTFS.sectors_per_cluster] |
cmp eax, 8001h |
jnc @f |
push eax |
shl eax, 9 |
stdcall kernel_alloc, eax |
pop ecx |
test eax, eax |
jz @f |
push ecx |
shl ecx, 7 |
mov edi, eax |
mov ebx, eax |
xor eax, eax |
rep stosd |
mov eax, [ebp+NTFS.fileDataStart] |
mul [ebp+NTFS.sectors_per_cluster] |
mov [ebp+NTFS.ntfsLastRead], eax |
pop ecx |
call fs_write64_app |
stdcall kernel_free, ebx |
@@: |
ret |
|
ntfsSpaceAlloc: |
; find and mark block of free space in bitmap buffer |
; in: |
; edi = offset in bitmap to start search from |
; [ebp+NTFS.fileDataSize] = block size in clusters |
; out: |
; eax = allocated block starting cluster |
; CF=1 -> disk full |
mov ecx, [ebp+NTFS.BitmapBuffer] |
add edi, ecx |
add ecx, [ebp+NTFS.BitmapSize] |
sub ecx, edi |
jnc @f |
call bitmapBuffering |
shl ecx, 2 |
@@: |
shr ecx, 2 |
mov eax, [ebp+NTFS.fileDataSize] |
shr eax, 5 |
jz .small |
push eax ; bitmap dwords |
.start: |
mov ecx, [ebp+NTFS.BitmapBuffer] |
add ecx, [ebp+NTFS.BitmapSize] |
sub ecx, edi |
shr ecx, 2 |
@@: |
xor eax, eax |
repnz scasd ; search for empty dword |
jz @f |
call bitmapBuffering |
jmp @b |
@@: |
cmp ecx, [esp] |
jnc @f |
call bitmapBuffering |
jmp @b |
@@: |
sub edi, 4 |
mov ecx, [esp] |
mov esi, edi |
xor eax, eax |
repz scasd ; check following dwords |
jnz .start |
sub esi, 4 |
mov eax, [esi] |
xor edx, edx |
bsr edx, eax |
inc edx |
push edx ; starting bit |
push esi ; starting dword |
add esi, 4 |
neg edx |
add edx, 32 |
mov eax, [ebp+NTFS.fileDataSize] |
sub eax, edx |
mov edx, eax |
shr eax, 5 |
shl eax, 2 |
add esi, eax |
mov eax, [esi] |
bsf ecx, eax ; check last dword |
jz .done |
and edx, 31 |
cmp ecx, edx |
jnc .done |
add esp, 8 |
jmp .start |
|
.small: ; less than 32 clusters |
mov eax, -1 |
repz scasd ; search for zero bits |
push ecx |
test ecx, ecx |
jnz @f |
call bitmapBuffering |
pop eax |
jmp .small |
@@: |
sub edi, 4 |
mov eax, [edi] |
not eax |
@@: |
bsf ecx, eax ; first 0 |
jz .again |
not eax |
shr eax, cl |
shl eax, cl |
bsf edx, eax ; next 1 |
jz @f |
sub edx, ecx |
cmp edx, [ebp+NTFS.fileDataSize] |
jnc .got ; fits inside |
bsf ecx, eax |
not eax |
shr eax, cl |
shl eax, cl |
jmp @b |
@@: ; next dword |
mov eax, [edi+4] |
bsf edx, eax |
jz .got ; empty |
add edx, 32 |
sub edx, ecx |
cmp edx, [ebp+NTFS.fileDataSize] |
jnc .got ; share between dwords |
.again: |
add edi, 4 |
pop ecx |
jmp .small |
|
.got: |
push ecx ; starting bit |
push edi ; starting dword |
.done: ; mark space |
mov ecx, [esp+4] |
cmp ecx, 32 |
jc @f |
xor ecx, ecx |
add dword [esp], 4 |
mov [esp+4], ecx |
@@: |
mov edi, [esp] |
xor eax, eax |
dec eax |
shr eax, cl |
shl eax, cl |
neg ecx |
add ecx, 32 |
sub ecx, [ebp+NTFS.fileDataSize] |
jc @f |
shl eax, cl ; fits inside dword |
shr eax, cl |
or [edi], eax |
jmp .end |
|
@@: |
or [edi], eax |
neg ecx |
push ecx |
shr ecx, 5 |
add edi, 4 |
xor eax, eax |
dec eax |
rep stosd |
pop ecx |
and ecx, 31 |
shr eax, cl |
shl eax, cl |
not eax |
or [edi], eax |
.end: |
pop eax |
sub eax, [ebp+NTFS.BitmapBuffer] |
shl eax, 3 |
pop edx |
add eax, edx |
pop edx |
ret |
|
ntfsSpaceFree: |
; free disk space |
; in: |
; edi = starting cluster |
; ebx = size in clusters |
mov eax, edi |
add eax, ebx |
shr eax, 3 |
inc eax |
cmp eax, [ebp+NTFS.BitmapSize] |
jc @f |
add eax, [ebp+NTFS.BitmapBuffer] |
push edi |
mov edi, eax |
call bitmapBuffering |
pop edi |
@@: |
push edi |
mov ecx, edi |
shr edi, 5 |
shl edi, 2 |
add edi, [ebp+NTFS.BitmapBuffer] |
and ecx, 31 |
xor eax, eax |
dec eax |
shr eax, cl |
shl eax, cl |
neg ecx |
add ecx, 32 |
sub ecx, ebx |
jc @f |
shl eax, cl ; fits inside dword |
shr eax, cl |
not eax |
and [edi], eax |
jmp .writeBitmap |
|
@@: |
not eax |
and [edi], eax |
neg ecx |
push ecx |
shr ecx, 5 |
add edi, 4 |
xor eax, eax |
rep stosd |
pop ecx |
and ecx, 31 |
dec eax |
shr eax, cl |
shl eax, cl |
and [edi], eax |
.writeBitmap: |
pop eax |
mov edi, eax |
lea ecx, [eax+ebx+4095] |
shr eax, 3+9 |
shr ecx, 3+9 |
sub ecx, eax |
mov ebx, eax |
shl ebx, 9 |
add eax, [ebp+NTFS.BitmapLocation] |
add ebx, [ebp+NTFS.BitmapBuffer] |
xor edx, edx |
jmp fs_write64_app |
|
bitmapBuffering: |
; Extend BitmapBuffer and read next 32kb of bitmap |
; Warning: $Bitmap fragmentation is not foreseen |
; if edi -> position in bitmap buffer, |
; then ecx = number of buffered dwords left |
; in: edi -> position in bitmap buffer |
; out: ecx = number of buffered dwords left |
push ebx |
mov eax, [ebp+NTFS.BitmapTotalSize] |
cmp eax, [ebp+NTFS.BitmapSize] |
2654,11 → 3184,12 |
jnc @f |
mov [ebp+NTFS.BitmapSize], eax |
@@: |
mov ecx, [ebp+NTFS.BitmapSize] |
add ecx, [ebp+NTFS.BitmapBuffer] |
pop ebx |
mov ecx, [ebp+NTFS.BitmapBuffer] |
add ecx, [ebp+NTFS.BitmapSize] |
sub ecx, edi |
jc bitmapBuffering |
shr ecx, 2 |
pop ebx |
ret |
|
.err: |
2667,9 → 3198,11 |
mov ecx, 8 |
call release_pages |
.end: |
add esp, 12 ; double ret |
push ERROR_DISK_FULL |
jmp ntfsOut |
pop ebx |
pop eax ; ret |
pop eax |
stc |
ret |
|
;---------------------------------------------------------------- |
ntfs_WriteFile: |
2684,34 → 3217,86 |
jc ntfsNotFound |
cmp [ebp+NTFS.ntfs_cur_iRecord], 16 |
jc ntfsDenied |
bt dword [eax+fileFlags], 28 |
jc ntfsDenied |
cmp [ebp+NTFS.ntfsFragmentCount], 1 |
jnz ntfsUnsupported ; record fragmented |
; edit directory node |
mov edi, [ebp+NTFS.cur_index_buf] |
cmp dword [edi], 'INDX' |
jz @f |
mov esi, [ebp+NTFS.frs_buffer] |
mov ecx, [esi+recordRealSize] |
shr ecx, 2 |
rep movsd |
mov esi, [ebp+NTFS.ntfs_attr_offs] |
mov cl, [esi+attributeOffset] |
sub esi, [ebp+NTFS.frs_buffer] |
add eax, ecx |
add eax, esi |
@@: |
mov ecx, [ebx+4] |
mov edx, [ebx+8] |
add ecx, [ebx+12] |
adc edx, 0 |
mov [eax+fileRealSize], ecx |
mov [eax+fileRealSize+4], edx |
mov eax, [ebp+NTFS.ntfsLastRead] |
mov [ebp+NTFS.nodeLastRead], eax |
mov [ebp+NTFS.ntfs_cur_attr], 0x80 |
mov [ebp+NTFS.ntfs_cur_offs], 0 |
mov [ebp+NTFS.ntfs_cur_size], 0 |
call ntfs_read_attr |
jc ntfsDenied |
mov eax, [ebp+NTFS.frs_buffer] |
cmp word [eax+baseRecordReuse], 0 |
jc ntfsFail |
mov eax, ecx |
mov ecx, [ebp+NTFS.frs_buffer] |
cmp word [ecx+baseRecordReuse], 0 |
jnz ntfsUnsupported ; auxiliary record |
cmp byte [eax+hardLinkCounter], 1 |
jnz ntfsUnsupported ; file copying required |
mov ecx, [ebp+NTFS.ntfs_attr_offs] |
cmp byte [ecx+nonResidentFlag], 1 |
jnz ntfsUnsupported ; resident $DATA |
cmp word [ecx+attributeFlags], 0 |
jnz ntfsUnsupported |
mov eax, [ebx+4] |
mov edx, [ebx+8] |
add eax, [ebx+12] |
adc edx, 0 |
push ebx |
cmp byte [ecx+nonResidentFlag], 0 |
jz .resizeAttribute |
cmp edx, [ecx+attributeRealSize+4] |
jc .write |
jnz ntfsUnsupported ; end of file |
jc .writeNode |
jnz .resizeAttribute |
cmp [ecx+attributeRealSize], eax |
jc ntfsUnsupported |
.write: |
jnc .writeNode |
.resizeAttribute: |
call resizeAttribute |
jc ntfsErrorPop |
mov ecx, [ebp+NTFS.ntfs_attr_offs] |
cmp byte [ecx+nonResidentFlag], 1 |
jz @f |
mov ebx, [esp] |
movzx edi, byte [ecx+attributeOffset] |
add edi, ecx |
add edi, [ebx+4] |
mov ecx, [ebx+12] |
mov esi, [ebx+16] |
rep movsb |
@@: |
mov eax, [ebp+NTFS.frs_buffer] |
mov [ebp+NTFS.ntfs_cur_buf], eax |
call writeRecord ; file |
mov ebx, [ebp+NTFS.frs_buffer] |
call ntfs_restore_usa_frs |
.writeNode: |
mov eax, [ebp+NTFS.nodeLastRead] |
mov [ebp+NTFS.ntfsLastRead], eax |
mov eax, [ebp+NTFS.cur_index_buf] |
mov [ebp+NTFS.ntfs_cur_buf], eax |
call writeRecord ; directory |
pop ebx |
mov ecx, [ebp+NTFS.ntfs_attr_offs] |
cmp byte [ecx+nonResidentFlag], 0 |
jz .done |
mov ecx, [ebx+12] |
test ecx, ecx |
jz .done |
mov eax, [ebx+4] |
mov edx, [ebx+8] |
mov ecx, [ebx+12] |
mov esi, [ebx+16] |
shrd eax, edx, 9 |
test dword[ebx+4], 1FFh |
2742,10 → 3327,8 |
call fs_write64_app |
pop ebx |
pop ecx |
test eax, eax |
jnz ntfsDevice |
test ecx, ecx |
jz @f |
jz .done |
mov eax, [ebx+4] |
mov edx, [ebx+8] |
shrd eax, edx, 9 |
2765,7 → 3348,7 |
pop ecx |
jc ntfsDevice |
and ecx, 1FFh |
jz @f |
jz .done |
add esi, [ebp+NTFS.ntfs_cur_read] |
mov [ebp+NTFS.ntfs_cur_size], 1 |
lea edi, [ebp+NTFS.ntfs_bitmap_buf] |
2780,9 → 3363,7 |
xor edx, edx |
call fs_write64_app |
pop ebx |
test eax, eax |
jnz ntfsDevice |
@@: |
.done: |
mov ebx, [ebx+12] |
jmp ntfsDone |
|
2809,6 → 3390,11 |
jnc ntfsUnsupported |
; delete index from the node |
movzx edx, word [eax+indexAllocatedSize] |
mov ecx, [eax+fileRecordReference] |
cmp [eax+edx+fileRecordReference], ecx |
jnz @f |
add dx, [eax+edx+indexAllocatedSize] |
@@: |
mov edi, [ebp+NTFS.cur_index_buf] |
cmp dword [edi], 'INDX' |
jz .indexRecord |
2855,8 → 3441,6 |
mov esi, [ebp+NTFS.frs_buffer] |
cmp word [esi+baseRecordReuse], 0 |
jnz ntfsUnsupported ; auxiliary record |
cmp byte [esi+hardLinkCounter], 2 |
jnc .writeFileRecord ; delete hard link |
mov esi, [ebp+NTFS.ntfs_attr_offs] |
cmp byte [esi+nonResidentFlag], 0 |
jz .writeBitmapMFT |
2864,83 → 3448,16 |
add esi, eax |
xor edi, edi |
sub esp, 16 |
.clearBitmap: ; "delete" file data |
@@: ; "delete" file data |
call ntfs_decode_mcb_entry |
jnc .mcbEnd |
jnc @f |
cmp dword[esp+8], 0 |
jz .clearBitmap |
jz @b |
add edi, [esp+8] |
mov ebx, [esp] |
mov eax, edi |
add eax, ebx |
shr eax, 3 |
inc eax |
cmp eax, [ebp+NTFS.BitmapSize] |
jc .buffered |
add eax, [ebp+NTFS.BitmapBuffer] |
add esp, 16 |
push edi |
mov edi, eax |
call ntfsSpaceFree |
jnc @b |
@@: |
call bitmapBuffering |
shl ecx, 2 |
js @b |
pop edi |
sub esp, 16 |
.buffered: |
push edi |
mov ecx, edi |
shr edi, 5 |
shl edi, 2 |
add edi, [ebp+NTFS.BitmapBuffer] |
and ecx, 31 |
xor eax, eax |
dec eax |
shr eax, cl |
shl eax, cl |
neg ecx |
add ecx, 32 |
sub ecx, ebx |
jc @f |
shl eax, cl ; fits inside dword |
shr eax, cl |
not eax |
and [edi], eax |
jmp .writeBitmap |
|
@@: |
not eax |
and [edi], eax |
neg ecx |
push ecx |
shr ecx, 5 |
add edi, 4 |
xor eax, eax |
rep stosd |
pop ecx |
and ecx, 31 |
dec eax |
shr eax, cl |
shl eax, cl |
and [edi], eax |
.writeBitmap: |
pop edi |
mov ecx, edi |
add ecx, ebx |
add ecx, 4095 |
shr ecx, 3+9 |
mov eax, edi |
shr eax, 3+9 |
sub ecx, eax |
mov ebx, eax |
shl ebx, 9 |
add eax, [ebp+NTFS.BitmapLocation] |
add ebx, [ebp+NTFS.BitmapBuffer] |
xor edx, edx |
call fs_write64_app |
jmp .clearBitmap |
|
.mcbEnd: |
add esp, 16 |
jmp .writeBitmapMFT |
|
2971,10 → 3488,8 |
xor edx, edx |
call fs_write64_sys |
mov esi, [ebp+NTFS.frs_buffer] |
mov [ebp+NTFS.ntfs_cur_buf], esi |
mov byte [esi+recordFlags], 0 |
.writeFileRecord: |
dec byte [esi+hardLinkCounter] |
mov [ebp+NTFS.ntfs_cur_buf], esi |
call writeRecord |
; write directory node |
mov eax, [ebp+NTFS.nodeLastRead] |
2982,12 → 3497,113 |
mov eax, [ebp+NTFS.cur_index_buf] |
mov [ebp+NTFS.ntfs_cur_buf], eax |
call writeRecord |
test eax, eax |
jz ntfsDone |
jmp ntfsDevice |
jmp ntfsDone |
|
;---------------------------------------------------------------- |
ntfs_SetFileEnd: |
cmp byte [esi], 0 |
jnz @f |
xor ebx, ebx |
movi eax, ERROR_ACCESS_DENIED |
ret |
@@: |
call ntfs_lock |
stdcall ntfs_find_lfn, [esp+4] |
jc ntfsNotFound |
cmp [ebp+NTFS.ntfs_cur_iRecord], 16 |
jc ntfsDenied |
bt dword [eax+fileFlags], 28 |
jc ntfsDenied |
cmp [ebp+NTFS.ntfsFragmentCount], 1 |
jnz ntfsUnsupported ; record fragmented |
; edit directory node |
mov edi, [ebp+NTFS.cur_index_buf] |
cmp dword [edi], 'INDX' |
jz @f |
mov esi, [ebp+NTFS.frs_buffer] |
mov ecx, [esi+recordRealSize] |
shr ecx, 2 |
rep movsd |
mov esi, [ebp+NTFS.ntfs_attr_offs] |
mov cl, [esi+attributeOffset] |
sub esi, [ebp+NTFS.frs_buffer] |
add eax, ecx |
add eax, esi |
@@: |
mov ecx, [ebx+4] |
mov edx, [ebx+8] |
mov [eax+fileRealSize], ecx |
mov [eax+fileRealSize+4], edx |
mov eax, [ebp+NTFS.ntfsLastRead] |
mov [ebp+NTFS.nodeLastRead], eax |
mov [ebp+NTFS.ntfs_cur_attr], 0x80 |
mov [ebp+NTFS.ntfs_cur_offs], 0 |
mov [ebp+NTFS.ntfs_cur_size], 0 |
call ntfs_read_attr |
jc ntfsFail |
mov eax, ecx |
mov ecx, [ebp+NTFS.frs_buffer] |
cmp word [ecx+baseRecordReuse], 0 |
jnz ntfsUnsupported ; auxiliary record |
mov ecx, [ebp+NTFS.ntfs_attr_offs] |
cmp word [ecx+attributeFlags], 0 |
jnz ntfsUnsupported |
cmp byte [ecx+nonResidentFlag], 0 |
jz .resizeAttribute |
cmp [ecx+attributeRealSize+4], edx |
jnz .resizeAttribute |
cmp [ecx+attributeRealSize], eax |
jnc .resizeAttribute |
mov eax, [ecx+attributeRealSize] |
mov ecx, [ebp+NTFS.sectors_per_cluster] |
mov [ebp+NTFS.ntfs_cur_size], ecx |
shl ecx, 9 |
div ecx |
test edx, edx |
jz .aligned |
push edx |
push ecx |
mul [ebp+NTFS.sectors_per_cluster] |
mov [ebp+NTFS.ntfs_cur_offs], eax |
stdcall kernel_alloc, ecx |
pop ecx |
pop edi |
sub ecx, edi |
add edi, eax |
mov [ebp+NTFS.ntfs_cur_buf], eax |
push [ebp+NTFS.ntfsLastRead] |
call ntfs_read_attr.continue |
jc @f |
xor eax, eax |
rep stosb |
push ebx |
mov eax, [ebp+NTFS.ntfsLastRead] |
mov ebx, [ebp+NTFS.ntfs_cur_buf] |
mov ecx, [ebp+NTFS.sectors_per_cluster] |
xor edx, edx |
call fs_write64_app |
pop ebx |
@@: |
pop [ebp+NTFS.ntfsLastRead] |
stdcall kernel_free, [ebp+NTFS.ntfs_cur_buf] |
.aligned: |
mov eax, [ebx+4] |
mov edx, [ebx+8] |
.resizeAttribute: |
call resizeAttribute |
jc ntfsError |
mov eax, [ebp+NTFS.frs_buffer] |
mov [ebp+NTFS.ntfs_cur_buf], eax |
call writeRecord ; file |
mov eax, [ebp+NTFS.nodeLastRead] |
mov [ebp+NTFS.ntfsLastRead], eax |
mov eax, [ebp+NTFS.cur_index_buf] |
mov [ebp+NTFS.ntfs_cur_buf], eax |
call writeRecord ; directory |
call ntfsSpaceClean |
jmp ntfsDone |
|
;---------------------------------------------------------------- |
ntfs_SetFileInfo: |
movi eax, ERROR_UNSUPPORTED_FS |
ret |
3018,11 → 3634,7 |
|
ntfsUnsupported: |
push ERROR_UNSUPPORTED_FS |
ntfsOut: |
call ntfs_unlock |
xor ebx, ebx |
pop eax |
ret |
jmp ntfsOut |
ntfsDevice: |
push ERROR_DEVICE |
jmp ntfsOut |
3035,6 → 3647,17 |
ntfsFail: |
push ERROR_FS_FAIL |
jmp ntfsOut |
ntfsNoMemory: |
push ERROR_OUT_OF_MEMORY |
ntfsDiskFull: |
push ERROR_DISK_FULL |
jmp ntfsOut |
ntfsErrorPop2: |
pop ebx |
ntfsErrorPop: |
pop ebx |
ntfsError: |
push eax |
ntfsOut: |
call ntfs_unlock |
xor ebx, ebx |
pop eax |
ret |