Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 4272 → Rev 4273

/data/eng/Makefile
290,7 → 290,6
OTHER_FILES:=settings/autorun.dat:SETTINGS/AUTORUN.DAT \
default.skn:DEFAULT.SKN \
graph:GRAPH \
../common/hdread:HDREAD \
settings/icon.ini:SETTINGS/ICON.INI \
../common/iconstrp.png:ICONSTRP.PNG index_htm:INDEX.HTM \
kernel.mnt:KERNEL.MNT \
/data/eng/settings/menu.dat
112,7 → 112,6
Ghost Monitor /sys/gmon
K. Bus disconnected /sys/kbd
HDD informer /sys/hdd_info
Read HDD /sys/hdread
#13 **** WORK WITH FILES ****
KFAR /sys/File Managers/kfar
KFM /sys/File Managers/kfm
/data/et/Makefile
290,7 → 290,6
OTHER_FILES:=settings/autorun.dat:SETTINGS/AUTORUN.DAT \
default.skn:DEFAULT.SKN \
graph:GRAPH \
../common/hdread:HDREAD \
settings/icon.ini:SETTINGS/ICON.INI \
../common/iconstrp.png:ICONSTRP.PNG index_htm:INDEX.HTM \
kernel.mnt:KERNEL.MNT \
/data/et/settings/menu.dat
112,7 → 112,6
Ghost Monitor /sys/gmon
K. Bus disconnected /sys/kbd
HDD info /sys/hdd_info
Read HDD /sys/hdread
#13 **** WORK WITH FILES ****
KFAR /sys/File Managers/kfar
KFM /sys/File Managers/kfm
/data/it/Makefile
289,7 → 289,6
OTHER_FILES:=settings/autorun.dat:SETTINGS/AUTORUN.DAT \
default.skn:DEFAULT.SKN \
graph:GRAPH \
../common/hdread:HDREAD \
settings/icon.ini:SETTINGS/ICON.INI \
../common/iconstrp.png:ICONSTRP.PNG index_htm:INDEX.HTM \
kernel.mnt:KERNEL.MNT \
/data/it/settings/menu.dat
111,7 → 111,6
Ghost Monitor /sys/gmon
K. Bus disconnected /sys/kbd
HDD informer /sys/hdd_info
Read HDD /sys/hdread
#13 **** WORK WITH FILES ****
KFAR /sys/File Managers/kfar
KFM /sys/File Managers/kfm
/data/rus/Makefile
283,7 → 283,6
OTHER_FILES:=settings/autorun.dat:SETTINGS/AUTORUN.DAT \
default.skn:DEFAULT.SKN \
graph:GRAPH \
../common/hdread:HDREAD \
settings/icon.ini:SETTINGS/ICON.INI \
../common/iconstrp.png:ICONSTRP.PNG index_htm:INDEX.HTM \
kernel.mnt:KERNEL.MNT \
/data/rus/settings/menu.dat
116,7 → 116,6
GHOST Monitor /sys/gmon
K. Bus disconnected /sys/kbd
HDD ¨­ä®à¬¥à /sys/hdd_info
—⥭¨¥ HDD /sys/hdread
#13 **** ‘¨á⥬  ->  ¡®â  á ä ©« ¬¨ ****
KFM /sys/File Managers/kfm
KFAR /sys/File Managers/kfar
/data/sp/Makefile
289,7 → 289,6
OTHER_FILES:=settings/autorun.dat:SETTINGS/AUTORUN.DAT \
default.skn:DEFAULT.SKN \
graph:GRAPH \
../common/hdread:HDREAD \
settings/icon.ini:SETTINGS/ICON.INI \
../common/iconstrp.png:ICONSTRP.PNG index_htm:INDEX.HTM \
kernel.mnt:KERNEL.MNT \
/data/sp/settings/menu.dat
112,7 → 112,6
Ghost Monitor /sys/gmon
K. Bus desconectado /sys/kbd
Informaci¢n de HDD /sys/hdd_info
Leer HDD /sys/hdread
#13 **** ARCHIVOS ****
KFAR /sys/File Managers/kfar
KFM /sys/File Managers/kfm
/kernel/trunk/blkdev/disk.inc
1213,8 → 1213,40
; ecx = partition number, esi+ebp = ASCIIZ name
fs_dyndisk:
dec ecx ; convert to zero-based partition index
pop edx edx edx eax ; edx = pointer to DISK, eax = NULL or edx
pop edx edx edx ; edx = pointer to DISK, dword [esp] = NULL or edx
; If the driver does not support insert notifications and we are the only fs
; operation with this disk, ask the driver whether the media
; was inserted/removed/changed. Otherwise, assume that media status is valid.
test byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION
jz .media_accurate
push ecx esi
mov esi, edx
cmp dword [esp+8], 0
jz .test_no_media
cmp [esi+DISK.MediaRefCount], 2
jnz .media_accurate_pop
lea edx, [esi+DISK.MediaInfo]
and [edx+DISKMEDIAINFO.Flags], 0
mov al, DISKFUNC.querymedia
stdcall disk_call_driver, edx
test eax, eax
jz .media_accurate_pop
stdcall disk_media_dereference ; drop our reference so that disk_media_changed could close the media
stdcall disk_media_changed, esi, 0
and dword [esp+8], 0 ; no media
.test_no_media:
stdcall disk_media_changed, esi, 1 ; issue fake notification
; if querymedia() inside disk_media_changed returns error, the notification is ignored
cmp [esi+DISK.MediaInserted], 0
jz .media_accurate_pop
lock inc [esi+DISK.MediaRefCount]
mov dword [esp+8], esi
.media_accurate_pop:
mov edx, esi
pop esi ecx
.media_accurate:
pop eax
test eax, eax
jz .nomedia
.main:
cmp ecx, [edx+DISK.NumPartitions]
1252,30 → 1284,6
.nomedia:
test ecx, ecx
jnz .notfound
test byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION
jz .deverror
; if the driver does not support insert notifications and we are the only fs
; operation with this disk, issue the fake insert notification; if media is
; still not inserted, 'disk_media_changed' will detect this and do nothing
lea ecx, [edx+DISK.MediaLock]
call mutex_lock
cmp [edx+DISK.MediaRefCount], 1
jnz .noluck
call mutex_unlock
push edx
stdcall disk_media_changed, edx, 1
pop edx
lea ecx, [edx+DISK.MediaLock]
call mutex_lock
cmp [edx+DISK.MediaInserted], 0
jz .noluck
lock inc [edx+DISK.MediaRefCount]
call mutex_unlock
xor ecx, ecx
jmp .main
.noluck:
call mutex_unlock
.deverror:
mov dword [esp+32], ERROR_DEVICE
mov esi, edx
call disk_dereference
/kernel/trunk/blkdev/fdc.inc
21,40 → 21,48
ret
 
save_image:
call reserve_flp
call restorefatchain
cmp [ramdisk_actual_size], FLOPPY_CAPACITY
jnz .fail
pusha
call check_label
mov ecx, floppy_mutex
call mutex_lock
mov [flp_number], bl
call floppy_read_bootsector
cmp [FDC_Status], 0
jne unnecessary_save_image
jne .unnecessary_save_image
mov [FDD_Track], 0; Цилиндр
mov [FDD_Head], 0; Сторона
mov [FDD_Sector], 1; Сектор
mov esi, RAMDISK
call SeekTrack
save_image_1:
push esi
.save_image_1:
call take_data_from_application_1
pop esi
add esi, 512
call WriteSectWithRetr
; call WriteSector
cmp [FDC_Status], 0
jne unnecessary_save_image
jne .unnecessary_save_image
inc [FDD_Sector]
cmp [FDD_Sector], 19
jne save_image_1
jne .save_image_1
mov [FDD_Sector], 1
inc [FDD_Head]
cmp [FDD_Head], 2
jne save_image_1
jne .save_image_1
mov [FDD_Head], 0
inc [FDD_Track]
call SeekTrack
cmp [FDD_Track], 80
jne save_image_1
unnecessary_save_image:
jne .save_image_1
.unnecessary_save_image:
cmp [FDC_Status], 0
pushf
mov ecx, floppy_mutex
call mutex_unlock
popf
popa
mov [flp_status], 0
jnz .fail
xor eax, eax
ret
 
.fail:
movi eax, 1
ret
/kernel/trunk/blkdev/flp_drv.inc
1,6 → 1,6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
20,8 → 20,7
; add edi,ecx
give_back_application_data_1:
mov esi, FDD_BUFF;FDD_DataBuffer ;0x40000
xor ecx, ecx
mov cx, 128
mov ecx, 128
cld
rep movsd
ret
32,8 → 31,7
; add esi,ecx
take_data_from_application_1:
mov edi, FDD_BUFF;FDD_DataBuffer ;0x40000
xor ecx, ecx
mov cx, 128
mov ecx, 128
cld
rep movsd
ret
122,6 → 120,7
;* AL - выводимый байт. *
;***********************************
FDCDataOutput:
; DEBUGF 1,'K : FDCDataOutput(%x)',al
; pusha
push eax ecx edx
mov AH, AL ;запомнить байт в AH
137,6 → 136,7
je @@OutByteToFDC
loop @@TestRS
; Ошибка тайм-аута
; DEBUGF 1,' timeout\n'
mov [FDC_Status], FDC_TimeOut
jmp @@End_5
; Вывести байт в порт данных
144,6 → 144,7
inc DX
mov AL, AH
out DX, AL
; DEBUGF 1,' ok\n'
@@End_5:
; popa
pop edx ecx eax
170,6 → 171,7
je @@GetByteFromFDC
loop @@TestRS_1
; Ошибка тайм-аута
; DEBUGF 1,'K : FDCDataInput: timeout\n'
mov [FDC_Status], FDC_TimeOut
jmp @@End_6
; Ввести байт из порта данных
176,6 → 178,7
@@GetByteFromFDC:
inc DX
in AL, DX
; DEBUGF 1,'K : FDCDataInput: %x\n',al
@@End_6:
pop DX
pop ECX
185,6 → 188,7
;* ОБРАБОТЧИК ПРЕРЫВАНИЯ ОТ КОНТРОЛЛЕРА НГМД *
;*********************************************
FDCInterrupt:
; dbgstr 'FDCInterrupt'
; Установить флаг прерывания
mov [FDD_IntFlag], 1
mov al, 1
207,12 → 211,12
jnz @@End_7 ;прерывание произошло
mov eax, [timer_ticks]
sub eax, [TickCounter]
cmp eax, 50 ;25 ;5 ;ожидать 5 тиков
cmp eax, 200;50 ;25 ;5 ;ожидать 5 тиков
jb @@TestRS_2
; jl @@TestRS_2
; Ошибка тайм-аута
; dbgstr 'WaitFDCInterrupt: timeout'
mov [FDC_Status], FDC_TimeOut
; mov [flp_status],0
@@End_7:
popa
ret
221,6 → 225,7
;* ВКЛЮЧИТЬ МОТОР ДИСКОВОДА "A:" *
;*********************************
FDDMotorON:
; dbgstr 'FDDMotorON'
pusha
; cmp [fdd_motor_status],1
; je fdd_motor_on
252,6 → 257,20
sub eax, [TickCounter]
cmp eax, 50 ;10
jb @@dT
; Read results of RESET command
push 4
; DEBUGF 1,'K : floppy reset results:'
@@:
mov al, 8
call FDCDataOutput
call FDCDataInput
; DEBUGF 1,' %x',al
call FDCDataInput
; DEBUGF 1,' %x',al
dec dword [esp]
jnz @b
; DEBUGF 1,'\n'
pop eax
cmp [flp_number], 1
jne fdd_motor_on_B
mov [fdd_motor_status], 1
275,8 → 294,6
;* ПРОВЕРКА ЗАДЕРЖКИ ВЫКЛЮЧЕНИЯ МОТОРА *
;*****************************************
proc check_fdd_motor_status_has_work?
cmp [flp_status], 0
jnz .yes
cmp [fdd_motor_status], 0
jz .no
mov eax, [timer_ticks]
303,7 → 320,6
call FDDMotorOFF
mov [fdd_motor_status], 0
end_check_fdd_motor_status_1:
mov [flp_status], 0
end_check_fdd_motor_status:
ret
 
311,6 → 327,7
;* ВЫКЛЮЧИТЬ МОТОР ДИСКОВОДА *
;**********************************
FDDMotorOFF:
; dbgstr 'FDDMotorOFF'
push AX
push DX
cmp [flp_number], 1
323,8 → 340,8
pop DX
pop AX
; сброс флагов кеширования в связи с устареванием информации
mov [root_read], 0
mov [flp_fat], 0
or [floppy_media_flags+0], FLOPPY_MEDIA_NEED_RESCAN
or [floppy_media_flags+1], FLOPPY_MEDIA_NEED_RESCAN
ret
 
FDDMotorOFF_A:
343,8 → 360,11
;* РЕКАЛИБРОВКА ДИСКОВОДА "A:" *
;*******************************
RecalibrateFDD:
; dbgstr 'RecalibrateFDD'
pusha
call save_timer_fdd_motor
; Сбросить флаг прерывания
mov [FDD_IntFlag], 0
; Подать команду "Рекалибровка"
mov AL, 07h
call FDCDataOutput
352,10 → 372,18
call FDCDataOutput
; Ожидать завершения операции
call WaitFDCInterrupt
; cmp [FDC_Status],0
; je no_fdc_status_error
; mov [flp_status],0
;no_fdc_status_error:
cmp [FDC_Status], 0
jne .fail
; Read results of RECALIBRATE command
; DEBUGF 1,'K : floppy recalibrate results:'
mov al, 8
call FDCDataOutput
call FDCDataInput
; DEBUGF 1,' %x',al
call FDCDataInput
; DEBUGF 1,' %x',al
; DEBUGF 1,'\n'
.fail:
call save_timer_fdd_motor
popa
ret
368,6 → 396,7
;* Результат операции заносится в FDC_Status. *
;*****************************************************
SeekTrack:
; dbgstr 'SeekTrack'
pusha
call save_timer_fdd_motor
; Сбросить флаг прерывания
402,17 → 431,20
cmp AL, [FDD_Track]
jne @@Err
; Номер головки совпадает с заданным?
mov AL, [FDC_ST0]
and AL, 100b
shr AL, 2
cmp AL, [FDD_Head]
jne @@Err
; The H bit (Head Address) in ST0 will always return a "0" (c) 82077AA datasheet,
; description of SEEK command. So we can not verify the proper head.
; mov AL, [FDC_ST0]
; and AL, 100b
; shr AL, 2
; cmp AL, [FDD_Head]
; jne @@Err
; Операция завершена успешно
; dbgstr 'SeekTrack: FDC_Normal'
mov [FDC_Status], FDC_Normal
jmp @@Exit
@@Err: ; Трек не найден
; dbgstr 'SeekTrack: FDC_TrackNotFound'
mov [FDC_Status], FDC_TrackNotFound
; mov [flp_status],0
@@Exit:
call save_timer_fdd_motor
popa
429,6 → 461,7
;* содержимое сектора будет занесено в FDD_DataBuffer. *
;*******************************************************
ReadSector:
; dbgstr 'ReadSector'
pushad
call save_timer_fdd_motor
; Сбросить флаг прерывания
468,11 → 501,12
call GetStatusInfo
test [FDC_ST0], 11011000b
jnz @@Err_1
; dbgstr 'ReadSector: FDC_Normal'
mov [FDC_Status], FDC_Normal
jmp @@Exit_1
@@Err_1:
; dbgstr 'ReadSector: FDC_SectorNotFound'
mov [FDC_Status], FDC_SectorNotFound
; mov [flp_status],0
@@Exit_1:
call save_timer_fdd_motor
popad
511,12 → 545,10
inc [RecalRepCounter]
cmp [RecalRepCounter], 3
jb @@TryAgain
; mov [flp_status],0
@@Exit_2:
popa
ret
@@Err_3:
mov [flp_status], 0
popa
ret
 
531,6 → 563,7
;* содержимое FDD_DataBuffer будет занесено в сектор. *
;*******************************************************
WriteSector:
; dbgstr 'WriteSector'
pushad
call save_timer_fdd_motor
; Сбросить флаг прерывания
616,7 → 649,6
popa
ret
@@Err_4:
mov [flp_status], 0
popa
ret
 
642,3 → 674,276
pop AX
ret
 
; Interface for disk subsystem.
; Assume fixed capacity for 1.44M.
FLOPPY_CAPACITY = 2880 ; in sectors
 
iglobal
align 4
floppy_functions:
dd .size
dd 0 ; no close() function
dd 0 ; no closemedia() function
dd floppy_querymedia
dd floppy_read
dd floppy_write
dd 0 ; no flush() function
dd 0 ; no adjust_cache_size() function
.size = $ - floppy_functions
endg
 
uglobal
floppy_media_flags rb 2
n_sector dd 0 ; temporary save for sector value
flp_number db 0 ; 1- Floppy A, 2-Floppy B
old_track db 0 ; old value track
flp_label rb 15*2 ; Label and ID of inserted floppy disk
align 4
; Hardware does not allow to work with two floppies in parallel,
; so there is one mutex guarding access to any floppy.
floppy_mutex MUTEX
endg
; Meaning of bits in floppy_media_flags
FLOPPY_MEDIA_PRESENT = 1 ; media was present when last asked
FLOPPY_MEDIA_NEED_RESCAN = 2 ; media was possibly changed, need to rescan
FLOPPY_MEDIA_LABEL_CHANGED = 4 ; temporary state
 
iglobal
floppy1_name db 'fd',0
floppy2_name db 'fd2',0
endg
 
; This function is called in boot process.
; It creates filesystems /fd and/or /fd2, if the system has one/two floppy drives.
proc floppy_init
mov ecx, floppy_mutex
call mutex_init
; First floppy is present if [DRIVE_DATA] and 0xF0 is nonzero.
test byte [DRIVE_DATA], 0xF0
jz .no1
stdcall disk_add, floppy_functions, floppy1_name, 1, DISK_NO_INSERT_NOTIFICATION
.no1:
; Second floppy is present if [DRIVE_DATA] and 0x0F is nonzero.
test byte [DRIVE_DATA], 0x0F
jz .no2
stdcall disk_add, floppy_functions, floppy2_name, 2, DISK_NO_INSERT_NOTIFICATION
.no2:
ret
endp
 
; Returns information about disk media.
; Floppy drives do not support insert notifications,
; DISK_NO_INSERT_NOTIFICATION is set,
; the disk subsystem calls this function before each filesystem operation.
; If the media has changed, return error for the first call as signal
; to finalize work with old media and the true geometry for the second call.
; Assume that media is (possibly) changed anytime when motor is off.
proc floppy_querymedia
virtual at esp+4
.userdata dd ?
.info dd ?
end virtual
; 1. Acquire the global lock.
mov ecx, floppy_mutex
call mutex_lock
mov edx, [.userdata] ; 1 for /fd, 2 for /fd2
; 2. If the media was reported and has been changed, forget it and report an error.
mov al, [floppy_media_flags+edx-1]
and al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN
cmp al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN
jnz .not_reported
.no_media:
mov [floppy_media_flags+edx-1], 0
.return_no_media:
mov ecx, floppy_mutex
call mutex_unlock
mov eax, DISK_STATUS_NO_MEDIA
retn 8
.not_reported:
; 3. If we are in the temporary state LABEL_CHANGED, this is the second call
; after intermediate DISK_STATUS_NO_MEDIA due to media change;
; clear the flag and return the current geometry without rereading the bootsector.
cmp [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED
jz .report_geometry
; 4. Try to read the bootsector.
mov [flp_number], dl
mov [FDC_Status], 0
call floppy_read_bootsector
; 5. If reading bootsector failed, assume that media is not present.
mov edx, [.userdata]
cmp [FDC_Status], 0
jnz .no_media
; 6. Check whether the previous status is "present". If not, go to 10.
push esi edi
imul edi, edx, 15
add edi, flp_label-15
mov esi, FDD_BUFF+39
mov ecx, 15
test [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT
jz .set_label
; 7. Compare the old label with the current one.
rep cmpsb
; 8. If the label has not changed, go to 11.
jz .ok
; 9. If the label has changed, store it, enter temporary state LABEL_CHANGED
; and report DISK_STATUS_NO_MEDIA.
; dbgstr 'floppy label changed'
add esi, ecx
add edi, ecx
mov ecx, 15
sub esi, ecx
sub edi, ecx
rep movsb
mov [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED
pop edi esi
jmp .return_no_media
.set_label:
; 10. The previous state was "not present". Copy the label.
rep movsb
.ok:
pop edi esi
.report_geometry:
; 11. Fill DISKMEDIAINFO structure.
mov ecx, [.info]
and [ecx+DISKMEDIAINFO.Flags], 0
mov [ecx+DISKMEDIAINFO.SectorSize], 512
mov dword [ecx+DISKMEDIAINFO.Capacity], FLOPPY_CAPACITY
and dword [ecx+DISKMEDIAINFO.Capacity+4], 0
; 12. Update state: media is present, data are actual.
mov [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT
; 13. Release the global lock and return successful status.
mov ecx, floppy_mutex
call mutex_unlock
xor eax, eax
retn 8
endp
 
proc floppy_read_bootsector
pushad
mov [FDD_Track], 0; Цилиндр
mov [FDD_Head], 0; Сторона
mov [FDD_Sector], 1; Сектор
call FDDMotorON
call RecalibrateFDD
cmp [FDC_Status], 0
jne .nothing
call SeekTrack
cmp [FDC_Status], 0
jne .nothing
call ReadSectWithRetr
.nothing:
popad
ret
endp
 
read_chs_sector:
call calculate_chs
call ReadSectWithRetr
ret
 
save_chs_sector:
call calculate_chs
call WriteSectWithRetr
ret
 
calculate_chs:
mov bl, [FDD_Track]
mov [old_track], bl
mov ebx, 18
xor edx, edx
div ebx
inc edx
mov [FDD_Sector], dl
mov edx, eax
shr eax, 1
and edx, 1
mov [FDD_Track], al
mov [FDD_Head], dl
mov dl, [old_track]
cmp dl, [FDD_Track]
je no_seek_track_1
call SeekTrack
no_seek_track_1:
ret
 
; Writes one or more sectors to the device.
proc floppy_write
mov dl, 1
jmp floppy_read_write
endp
 
; Reads one or more sectors from the device.
proc floppy_read
mov dl, 0
endp
 
; Common part of floppy_read and floppy_write.
proc floppy_read_write userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword
virtual at ebp-8
.sectors_todo dd ?
.operation db ?
end virtual
push edx ; save operation code to [.operation]
; 1. Get number of sectors to read/write
; and zero number of sectors that were actually read/written.
mov eax, [numsectors_ptr]
push dword [eax] ; initialize [.sectors_todo]
and dword [eax], 0
push ebx esi edi ; save used registers to be stdcall
; 2. Acquire the global lock.
mov ecx, floppy_mutex
call mutex_lock
; 3. Set floppy number for this operation.
mov edx, [userdata]
mov [flp_number], dl
; 4. Read/write sector-by-sector.
.operation_loop:
; 4a. Check that the sector is inside the media.
cmp dword [start_sector+4], 0
jnz .end_of_media
mov eax, dword [start_sector]
cmp eax, FLOPPY_CAPACITY
jae .end_of_media
; 4b. For read operation, call read_chs_sector and then move data from FDD_BUFF to [buffer].
; For write operation, move data from [buffer] to FDD_BUFF and then call save_chs_sector.
cmp [.operation], 0
jz .read
mov esi, [buffer]
mov edi, FDD_BUFF
mov ecx, 512/4
rep movsd
mov [buffer], esi
call save_chs_sector
jmp @f
.read:
call read_chs_sector
mov esi, FDD_BUFF
mov edi, [buffer]
mov ecx, 512/4
rep movsd
mov [buffer], edi
@@:
; 4c. If there was an error, propagate it to the caller.
cmp [FDC_Status], 0
jnz .fail
; 4d. Otherwise, increment number of sectors processed and continue the loop.
mov eax, [numsectors_ptr]
inc dword [eax]
inc dword [start_sector]
dec [.sectors_todo]
jnz .operation_loop
; 5. Release the global lock and return with the correct status.
push 0
.return:
mov ecx, floppy_mutex
call mutex_unlock
pop eax
pop edi esi ebx ; restore used registers to be stdcall
ret ; this translates to leave/retn N and purges local variables
.fail:
push -1
jmp .return
.end_of_media:
push DISK_STATUS_END_OF_MEDIA
jmp .return
endp
/kernel/trunk/blkdev/hd_drv.inc
47,6 → 47,10
hd1_data HD_DATA ?, 0x10, 2
hd2_data HD_DATA ?, 0, 3
hd3_data HD_DATA ?, 0x10, 4
 
hd_address_table:
dd 0x1f0, 0x00, 0x1f0, 0x10
dd 0x170, 0x00, 0x170, 0x10
endg
 
uglobal
645,14 → 649,6
end if
ret
;-----------------------------------------------------------------------------
hd_lba_error:
if lang eq sp
DEBUGF 1,"K : FS - HD error en LBA\n"
else
DEBUGF 1,"K : FS - HD LBA error\n"
end if
jmp LBA_read_ret
;-----------------------------------------------------------------------------
align 4
wait_for_hd_idle:
push eax edx
/kernel/trunk/blkdev/rd.inc
1,2296 → 1,195
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
;; Copyright (C) KolibriOS team 2013. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; RAMDISK functions ;;
;; (C) 2004 Ville Turjanmaa, License: GPL ;;
;; Addings by M.Lisovin ;;
;; LFN support by diamond ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
iglobal
align 4
ramdisk_functions:
dd .size
dd 0 ; no close() function
dd 0 ; no closemedia() function
dd ramdisk_querymedia
dd ramdisk_read
dd ramdisk_write
dd 0 ; no flush() function
dd ramdisk_adjust_cache_size
.size = $ - ramdisk_functions
endg
 
; calculate fat chain
; See memmap.inc.
; Currently size of memory allocated for the ramdisk is fixed.
; This should be revisited when/if memory map would become more dynamic.
RAMDISK_CAPACITY = 2880 ; in sectors
 
calculatefatchain:
 
pushad
 
mov esi, RAMDISK+512
mov edi, RAMDISK_FAT
 
fcnew:
mov eax, dword [esi]
mov ebx, dword [esi+4]
mov ecx, dword [esi+8]
mov edx, ecx
shr edx, 4;8 ok
shr dx, 4;7 ok
xor ch, ch
shld ecx, ebx, 20;6 ok
shr cx, 4;5 ok
shld ebx, eax, 12
and ebx, 0x0fffffff;4 ok
shr bx, 4;3 ok
shl eax, 4
and eax, 0x0fffffff;2 ok
shr ax, 4;1 ok
mov dword [edi], eax
mov dword [edi+4], ebx
mov dword [edi+8], ecx
mov dword [edi+12], edx
add edi, 16
add esi, 12
 
cmp edi, RAMDISK_FAT+2856*2;2849 clusters
jnz fcnew
 
popad
ret
 
 
restorefatchain: ; restore fat chain
 
pushad
 
mov esi, RAMDISK_FAT
mov edi, RAMDISK+512
 
fcnew2:
mov eax, dword [esi]
mov ebx, dword [esi+4]
shl ax, 4
shl eax, 4
shl bx, 4
shr ebx, 4
shrd eax, ebx, 8
shr ebx, 8
mov dword [edi], eax
mov word [edi+4], bx
add edi, 6
add esi, 8
 
cmp edi, RAMDISK+512+4278;4274 bytes - all used FAT
jb fcnew2
 
mov esi, RAMDISK+512 ; duplicate fat chain
mov edi, RAMDISK+512+0x1200
mov ecx, 1069;4274/4
cld
rep movsd
 
popad
ret
 
 
ramdisk_free_space:
;---------------------------------------------
;
; returns free space in edi
; rewr.by Mihasik
;---------------------------------------------
 
push eax ebx ecx
 
mov edi, RAMDISK_FAT;start of FAT
xor ax, ax;Free cluster=0x0000 in FAT
xor ebx, ebx;counter
mov ecx, 2849;2849 clusters
cld
rdfs1:
repne scasw
jnz rdfs2 ;if last cluster not 0
inc ebx
test ecx, ecx
jnz rdfs1
rdfs2:
shl ebx, 9;free clusters*512
mov edi, ebx
 
pop ecx ebx eax
ret
 
 
expand_filename:
;---------------------------------------------
;
; exapand filename with '.' to 11 character
; eax - pointer to filename
;---------------------------------------------
 
push esi edi ebx
 
mov edi, esp ; check for '.' in the name
add edi, 12+8
 
mov esi, eax
 
mov eax, edi
mov [eax+0], dword ' '
mov [eax+4], dword ' '
mov [eax+8], dword ' '
 
flr1:
 
cmp [esi], byte '.'
jne flr2
mov edi, eax
add edi, 7
jmp flr3
 
flr2:
 
mov bl, [esi]
mov [edi], bl
 
flr3:
 
inc esi
inc edi
 
mov ebx, eax
add ebx, 11
 
cmp edi, ebx
jbe flr1
 
pop ebx edi esi
ret
 
fileread:
;----------------------------------------------------------------
;
; fileread - sys floppy
;
; eax points to filename 11 chars
; ebx first wanted block ; 1+ ; if 0 then set to 1
; ecx number of blocks to read ; 1+ ; if 0 then set to 1
; edx mem location to return data
; esi length of filename 12*X 0=root
;
; ret ebx = size or 0xffffffff file not found
; eax = 0 ok read or other = errormsg
;
;--------------------------------------------------------------
test ebx, ebx;if ebx=0 - set to 1
jnz frfl5
inc ebx
frfl5:
test ecx, ecx;if ecx=0 - set to 1
jnz frfl6
inc ecx
frfl6:
test esi, esi ; return ramdisk root
jnz fr_noroot ;if not root
cmp ebx, 14 ;14 clusters=root dir
ja oorr
cmp ecx, 14
ja oorr
jmp fr_do
oorr:
mov eax, 5 ;out of root range (fnf)
xor ebx, ebx
dec ebx ;0xffffffff
ret
 
fr_do: ;reading rootdir
mov edi, edx
dec ebx
push edx
mov edx, ecx
add edx, ebx
cmp edx, 15 ;ebx+ecx=14+1
pushf
jbe fr_do1
sub edx, 14
sub ecx, edx
fr_do1:
shl ebx, 9
mov esi, RAMDISK+512*19
add esi, ebx
shl ecx, 7
cld
rep movsd
popf
pop edx
jae fr_do2
xor eax, eax; ok read
xor ebx, ebx
ret
fr_do2: ;if last cluster
mov eax, 6;end of file
xor ebx, ebx
ret
 
fr_noroot:
 
sub esp, 32
call expand_filename
 
dec ebx
 
push eax
 
push eax ebx ecx edx esi edi
call rd_findfile
je fifound
add esp, 32+28 ;if file not found
ret
 
fifound:
 
mov ebx, [edi-11+28] ;file size
mov [esp+20], ebx
mov [esp+24], ebx
add edi, 0xf
movzx eax, word [edi]
mov edi, eax ;edi=cluster
 
frnew:
 
add eax, 31 ;bootsector+2*fat+filenames
shl eax, 9 ;*512
add eax, RAMDISK ;image base
mov ebx, [esp+8]
mov ecx, 512 ;[esp+4]
 
cmp [esp+16], dword 0 ; wanted cluster ?
jne frfl7
call memmove
add [esp+8], dword 512
dec dword [esp+12] ; last wanted cluster ?
je frnoread
jmp frfl8
frfl7:
dec dword [esp+16]
frfl8:
movzx eax, word [edi*2+RAMDISK_FAT] ; find next cluster from FAT
mov edi, eax
cmp edi, 4095 ;eof - cluster
jz frnoread2
 
cmp [esp+24], dword 512 ;eof - size
jb frnoread
sub [esp+24], dword 512
 
jmp frnew
 
frnoread2:
 
cmp [esp+16], dword 0 ; eof without read ?
je frnoread
 
pop edi esi edx ecx
add esp, 4
pop ebx ; ebx <- eax : size of file
add esp, 36
mov eax, 6 ; end of file
ret
 
frnoread:
 
pop edi esi edx ecx
add esp, 4
pop ebx ; ebx <- eax : size of file
add esp, 36
xor eax, eax;read ok
ret
 
 
 
rd_findfile:
;by Mihasik
;IN: eax - pointer to filename OUT: filestring+11 in edi or notZero in flags and fnf in eax,ebx
 
mov edi, RAMDISK+512*18+512;Point at directory
cld
rd_newsearch:
mov esi, eax
mov ecx, 11
rep cmpsb
je rd_ff
add cl, 21
add edi, ecx
cmp edi, RAMDISK+512*33
jb rd_newsearch
mov eax, 5 ;if file not found - eax=5
xor ebx, ebx
dec ebx ;ebx=0xffffffff and zf=0
rd_ff:
ret
 
; \begin{diamond}
 
uni2ansi_str:
; convert UNICODE zero-terminated string to ASCII-string (codepage 866)
; in: esi->source, edi->buffer (may be esi=edi)
; destroys: eax,esi,edi
lodsw
test ax, ax
jz .done
cmp ax, 0x80
jb .ascii
cmp ax, 0x401
jz .yo1
cmp ax, 0x451
jz .yo2
cmp ax, 0x410
jb .unk
cmp ax, 0x440
jb .rus1
cmp ax, 0x450
jb .rus2
.unk:
mov al, '_'
jmp .doit
.yo1:
mov al, 0xF0 ; 'Ё'
jmp .doit
.yo2:
mov al, 0xF1 ; 'ё'
jmp .doit
.rus1:
; 0x410-0x43F -> 0x80-0xAF
add al, 0x70
jmp .doit
.rus2:
; 0x440-0x44F -> 0xE0-0xEF
add al, 0xA0
.ascii:
.doit:
stosb
jmp uni2ansi_str
.done:
mov byte [edi], 0
ret
 
ansi2uni_char:
; convert ANSI character in al to UNICODE character in ax, using cp866 encoding
mov ah, 0
; 0x00-0x7F - trivial map
cmp al, 0x80
jb .ret
; 0x80-0xAF -> 0x410-0x43F
cmp al, 0xB0
jae @f
add ax, 0x410-0x80
.ret:
ret
@@:
; 0xE0-0xEF -> 0x440-0x44F
cmp al, 0xE0
jb .unk
cmp al, 0xF0
jae @f
add ax, 0x440-0xE0
ret
; 0xF0 -> 0x401
; 0xF1 -> 0x451
@@:
cmp al, 0xF0 ; 'Ё'
jz .yo1
cmp al, 0xF1 ; 'ё'
jz .yo2
.unk:
mov al, '_' ; ah=0
ret
.yo1:
mov ax, 0x401
ret
.yo2:
mov ax, 0x451
ret
 
char_toupper:
; convert character to uppercase, using cp866 encoding
; in: al=symbol
; out: al=converted symbol
cmp al, 'a'
jb .ret
cmp al, 'z'
jbe .az
cmp al, 0xF1 ; 'ё'
jz .yo1
cmp al, 0xA0 ; 'а'
jb .ret
cmp al, 0xE0 ; 'р'
jb .rus1
cmp al, 0xEF ; 'я'
ja .ret
; 0xE0-0xEF -> 0x90-0x9F
sub al, 0xE0-0x90
.ret:
ret
.rus1:
; 0xA0-0xAF -> 0x80-0x8F
.az:
and al, not 0x20
ret
.yo1:
; 0xF1 -> 0xF0
dec ax
ret
 
fat_get_name:
; in: edi->FAT entry
; out: CF=1 - no valid entry
; else CF=0 and ebp->ASCIIZ-name
; (maximum length of filename is 255 (wide) symbols without trailing 0,
; but implementation requires buffer 261 words)
; destroys eax
cmp byte [edi], 0
jz .no
cmp byte [edi], 0xE5
jnz @f
.no:
stc
ret
@@:
cmp byte [edi+11], 0xF
jz .longname
test byte [edi+11], 8
jnz .no
push ecx
push edi ebp
test byte [ebp-4], 1
jnz .unicode_short
 
mov eax, [edi]
mov ecx, [edi+4]
mov [ebp], eax
mov [ebp+4], ecx
 
mov ecx, 8
@@:
cmp byte [ebp+ecx-1], ' '
loope @b
 
mov eax, [edi+8]
cmp al, ' '
je .done
shl eax, 8
mov al, '.'
 
lea ebp, [ebp+ecx+1]
mov [ebp], eax
mov ecx, 3
@@:
rol eax, 8
cmp al, ' '
jne .done
loop @b
dec ebp
.done:
and byte [ebp+ecx+1], 0 ; CF=0
pop ebp edi ecx
ret
.unicode_short:
mov ecx, 8
push ecx
@@:
mov al, [edi]
inc edi
call ansi2uni_char
mov [ebp], ax
inc ebp
inc ebp
loop @b
pop ecx
@@:
cmp word [ebp-2], ' '
jnz @f
dec ebp
dec ebp
loop @b
@@:
mov word [ebp], '.'
inc ebp
inc ebp
mov ecx, 3
push ecx
@@:
mov al, [edi]
inc edi
call ansi2uni_char
mov [ebp], ax
inc ebp
inc ebp
loop @b
pop ecx
@@:
cmp word [ebp-2], ' '
jnz @f
dec ebp
dec ebp
loop @b
dec ebp
dec ebp
@@:
and word [ebp], 0 ; CF=0
pop ebp edi ecx
ret
.longname:
; LFN
mov al, byte [edi]
and eax, 0x3F
dec eax
cmp al, 20
jae .no ; ignore invalid entries
mov word [ebp+260*2], 0 ; force null-terminating for orphans
imul eax, 13*2
add ebp, eax
test byte [edi], 0x40
jz @f
mov word [ebp+13*2], 0
@@:
push eax
; now copy name from edi to ebp ...
mov eax, [edi+1]
mov [ebp], eax ; symbols 1,2
mov eax, [edi+5]
mov [ebp+4], eax ; 3,4
mov eax, [edi+9]
mov [ebp+8], ax ; 5
mov eax, [edi+14]
mov [ebp+10], eax ; 6,7
mov eax, [edi+18]
mov [ebp+14], eax ; 8,9
mov eax, [edi+22]
mov [ebp+18], eax ; 10,11
mov eax, [edi+28]
mov [ebp+22], eax ; 12,13
; ... done
pop eax
sub ebp, eax
test eax, eax
jz @f
; if this is not first entry, more processing required
stc
ret
@@:
; if this is first entry:
test byte [ebp-4], 1
jnz .ret
; buffer at ebp contains UNICODE name, convert it to ANSI
push esi edi
mov esi, ebp
mov edi, ebp
call uni2ansi_str
pop edi esi
.ret:
clc
ret
 
fat_compare_name:
; compares ASCIIZ-names, case-insensitive (cp866 encoding)
; in: esi->name, ebp->name
; out: if names match: ZF=1 and esi->next component of name
; else: ZF=0, esi is not changed
; destroys eax
push ebp esi
.loop:
mov al, [ebp]
inc ebp
call char_toupper
push eax
lodsb
call char_toupper
cmp al, [esp]
jnz .done
pop eax
test al, al
jnz .loop
dec esi
pop eax
pop ebp
xor eax, eax ; set ZF flag
ret
.done:
cmp al, '/'
jnz @f
cmp byte [esp], 0
jnz @f
mov [esp+4], esi
@@:
pop eax
pop esi ebp
ret
 
fat_time_to_bdfe:
; in: eax=FAT time
; out: eax=BDFE time
push ecx edx
mov ecx, eax
mov edx, eax
shr eax, 11
shl eax, 16 ; hours
and edx, 0x1F
add edx, edx
mov al, dl ; seconds
shr ecx, 5
and ecx, 0x3F
mov ah, cl ; minutes
pop edx ecx
ret
 
fat_date_to_bdfe:
push ecx edx
mov ecx, eax
mov edx, eax
shr eax, 9
add ax, 1980
shl eax, 16 ; year
and edx, 0x1F
mov al, dl ; day
shr ecx, 5
and ecx, 0xF
mov ah, cl ; month
pop edx ecx
ret
 
bdfe_to_fat_time:
push edx
mov edx, eax
shr eax, 16
and dh, 0x3F
shl eax, 6
or al, dh
shr dl, 1
and dl, 0x1F
shl eax, 5
or al, dl
pop edx
ret
 
bdfe_to_fat_date:
push edx
mov edx, eax
shr eax, 16
sub ax, 1980
and dh, 0xF
shl eax, 4
or al, dh
and dl, 0x1F
shl eax, 5
or al, dl
pop edx
ret
 
fat_entry_to_bdfe:
; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi
; destroys eax
mov eax, [ebp-4]
mov [esi+4], eax ; ASCII/UNICODE name
fat_entry_to_bdfe2:
movzx eax, byte [edi+11]
mov [esi], eax ; attributes
movzx eax, word [edi+14]
call fat_time_to_bdfe
mov [esi+8], eax ; creation time
movzx eax, word [edi+16]
call fat_date_to_bdfe
mov [esi+12], eax ; creation date
and dword [esi+16], 0 ; last access time is not supported on FAT
movzx eax, word [edi+18]
call fat_date_to_bdfe
mov [esi+20], eax ; last access date
movzx eax, word [edi+22]
call fat_time_to_bdfe
mov [esi+24], eax ; last write time
movzx eax, word [edi+24]
call fat_date_to_bdfe
mov [esi+28], eax ; last write date
mov eax, [edi+28]
mov [esi+32], eax ; file size (low dword)
xor eax, eax
mov [esi+36], eax ; file size (high dword)
test ebp, ebp
jz .ret
push ecx edi
lea edi, [esi+40]
mov esi, ebp
test byte [esi-4], 1
jz .ansi
mov ecx, 260/2
rep movsd
mov [edi-2], ax
@@:
mov esi, edi
pop edi ecx
.ret:
ret
.ansi:
mov ecx, 264/4
rep movsd
mov [edi-1], al
jmp @b
 
bdfe_to_fat_entry:
; convert BDFE at edx to FAT entry at edi
; destroys eax
; attributes byte
test byte [edi+11], 8 ; volume label?
jnz @f
mov al, [edx]
and al, 0x27
and byte [edi+11], 0x10
or byte [edi+11], al
@@:
mov eax, [edx+8]
call bdfe_to_fat_time
mov [edi+14], ax ; creation time
mov eax, [edx+12]
call bdfe_to_fat_date
mov [edi+16], ax ; creation date
mov eax, [edx+20]
call bdfe_to_fat_date
mov [edi+18], ax ; last access date
mov eax, [edx+24]
call bdfe_to_fat_time
mov [edi+22], ax ; last write time
mov eax, [edx+28]
call bdfe_to_fat_date
mov [edi+24], ax ; last write date
ret
 
ramdisk_root_first:
mov edi, RAMDISK+512*19
clc
ret
ramdisk_root_next:
add edi, 0x20
cmp edi, RAMDISK+512*33
cmc
ret
 
ramdisk_root_extend_dir:
stc
ret
 
uglobal
; this is for delete support
rd_prev_sector dd ?
rd_prev_prev_sector dd ?
iglobal
align 4
ramdisk_actual_size dd RAMDISK_CAPACITY
endg
 
ramdisk_notroot_next:
add edi, 0x20
test edi, 0x1FF
jz ramdisk_notroot_next_sector
ret ; CF=0
ramdisk_notroot_next_sector:
push ecx
mov ecx, [eax]
push [rd_prev_sector]
pop [rd_prev_prev_sector]
mov [rd_prev_sector], ecx
mov ecx, [ecx*2+RAMDISK_FAT]
and ecx, 0xFFF
cmp ecx, 2849
jae ramdisk_notroot_first.err2
mov [eax], ecx
pop ecx
ramdisk_notroot_first:
mov eax, [eax]
cmp eax, 2
jb .err
cmp eax, 2849
jae .err
shl eax, 9
lea edi, [eax+(31 shl 9)+RAMDISK]
clc
ret
.err2:
pop ecx
.err:
stc
ret
ramdisk_notroot_next_write:
test edi, 0x1FF
jz ramdisk_notroot_next_sector
ramdisk_root_next_write:
ret
 
ramdisk_notroot_extend_dir:
pusha
xor eax, eax
mov edi, RAMDISK_FAT
mov ecx, 2849
repnz scasw
jnz .notfound
mov word [edi-2], 0xFFF
sub edi, RAMDISK_FAT
shr edi, 1
dec edi
mov eax, [esp+28]
mov ecx, [eax]
mov [RAMDISK_FAT+ecx*2], di
mov [eax], edi
shl edi, 9
add edi, (31 shl 9)+RAMDISK
mov [esp], edi
xor eax, eax
mov ecx, 128
rep stosd
popa
clc
ret
.notfound:
popa
stc
ret
 
rd_find_lfn:
; in: esi+ebp -> name
; out: CF=1 - file not found
; else CF=0 and edi->direntry
push esi edi
push 0
push ramdisk_root_first
push ramdisk_root_next
.loop:
call fat_find_lfn
jc .notfound
cmp byte [esi], 0
jz .found
.continue:
test byte [edi+11], 10h
jz .notfound
movzx eax, word [edi+26]
mov [esp+8], eax
mov dword [esp+4], ramdisk_notroot_first
mov dword [esp], ramdisk_notroot_next
test eax, eax
jnz .loop
mov dword [esp+4], ramdisk_root_first
mov dword [esp], ramdisk_notroot_next
jmp .loop
.notfound:
add esp, 12
pop edi esi
stc
ret
.found:
test ebp, ebp
jz @f
mov esi, ebp
xor ebp, ebp
jmp .continue
@@:
mov eax, [esp+8]
add esp, 16 ; CF=0
pop esi
ret
 
;----------------------------------------------------------------
;
; fs_RamdiskRead - LFN variant for reading sys floppy
;
; esi points to filename
; ebx pointer to 64-bit number = first wanted byte, 0+
; may be ebx=0 - start from first byte
; ecx number of bytes to read, 0+
; edx mem location to return data
;
; ret ebx = bytes read or 0xffffffff file not found
; eax = 0 ok read or other = errormsg
;
;--------------------------------------------------------------
fs_RamdiskRead:
cmp byte [esi], 0
jnz @f
or ebx, -1
mov eax, 10 ; access denied
ret
@@:
push edi
call rd_find_lfn
jnc .found
pop edi
or ebx, -1
mov eax, 5 ; file not found
ret
.found:
test ebx, ebx
jz .l1
cmp dword [ebx+4], 0
jz @f
xor ebx, ebx
.reteof:
mov eax, 6 ; EOF
pop edi
ret
@@:
mov ebx, [ebx]
.l1:
push ecx edx
push 0
mov eax, [edi+28]
sub eax, ebx
jb .eof
cmp eax, ecx
jae @f
mov ecx, eax
mov byte [esp], 6 ; EOF
@@:
movzx edi, word [edi+26] ; cluster
.new:
jecxz .done
test edi, edi
jz .eof
cmp edi, 0xFF8
jae .eof
lea eax, [edi+31] ; bootsector+2*fat+filenames
shl eax, 9 ; *512
add eax, RAMDISK ; image base
; now eax points to data of cluster
sub ebx, 512
jae .skip
lea eax, [eax+ebx+512]
neg ebx
push ecx
cmp ecx, ebx
jbe @f
mov ecx, ebx
@@:
mov ebx, edx
call memmove
add edx, ecx
sub [esp], ecx
pop ecx
xor ebx, ebx
.skip:
movzx edi, word [edi*2+RAMDISK_FAT] ; find next cluster from FAT
jmp .new
.eof:
mov ebx, edx
pop eax edx ecx
sub ebx, edx
jmp .reteof
.done:
mov ebx, edx
pop eax edx ecx edi
sub ebx, edx
ret
 
;----------------------------------------------------------------
;
; fs_RamdiskReadFolder - LFN variant for reading sys floppy folder
;
; esi points to filename; only root is folder on ramdisk
; ebx pointer to structure 32-bit number = first wanted block
; & flags (bitfields)
; flags: bit 0: 0=ANSI names, 1=UNICODE names
; ecx number of blocks to read, 0+
; edx mem location to return data
;
; ret ebx = size or 0xffffffff file not found
; eax = 0 ok read or other = errormsg
;
;--------------------------------------------------------------
fs_RamdiskReadFolder:
push edi
cmp byte [esi], 0
jz .root
call rd_find_lfn
jnc .found
pop edi
or ebx, -1
mov eax, ERROR_FILE_NOT_FOUND
ret
.found:
test byte [edi+11], 0x10
jnz .found_dir
pop edi
or ebx, -1
mov eax, ERROR_ACCESS_DENIED
ret
.found_dir:
movzx eax, word [edi+26]
add eax, 31
push 0
jmp .doit
.root:
mov eax, 19
push 14
.doit:
push esi ecx ebp
sub esp, 262*2 ; reserve space for LFN
mov ebp, esp
push dword [ebx+4] ; for fat_get_name: read ANSI/UNICODE names
mov ebx, [ebx]
; init header
push eax ecx
mov edi, edx
mov ecx, 32/4
xor eax, eax
rep stosd
mov byte [edx], 1 ; version
pop ecx eax
mov esi, edi ; esi points to block of data of folder entry (BDFE)
.main_loop:
mov edi, eax
shl edi, 9
add edi, RAMDISK
push eax
.l1:
call fat_get_name
jc .l2
cmp byte [edi+11], 0xF
jnz .do_bdfe
add edi, 0x20
test edi, 0x1FF
jnz .do_bdfe
pop eax
inc eax
dec byte [esp+262*2+16]
jz .done
jns @f
; read next sector from FAT
mov eax, [(eax-31-1)*2+RAMDISK_FAT]
and eax, 0xFFF
cmp eax, 0xFF8
jae .done
add eax, 31
mov byte [esp+262*2+16], 0
@@:
mov edi, eax
shl edi, 9
add edi, RAMDISK
push eax
.do_bdfe:
inc dword [edx+8] ; new file found
dec ebx
jns .l2
dec ecx
js .l2
inc dword [edx+4] ; new file block copied
call fat_entry_to_bdfe
.l2:
add edi, 0x20
test edi, 0x1FF
jnz .l1
pop eax
inc eax
dec byte [esp+262*2+16]
jz .done
jns @f
; read next sector from FAT
mov eax, [(eax-31-1)*2+RAMDISK_FAT]
and eax, 0xFFF
cmp eax, 0xFF8
jae .done
add eax, 31
mov byte [esp+262*2+16], 0
@@:
jmp .main_loop
.done:
add esp, 262*2+4
pop ebp
mov ebx, [edx+4]
xor eax, eax
dec ecx
js @f
mov al, ERROR_END_OF_FILE
@@:
pop ecx esi edi edi
ret
 
; This function is called early in boot process.
; It creates filesystem /rd/1 based on raw image data loaded by somebody before
; to memory named as RAMDISK with max size RAMDISK_CAPACITY, may be less.
proc ramdisk_init
iglobal
label fat_legal_chars byte
; 0 = not allowed
; 1 = allowed only in long names
; 3 = allowed
times 32 db 0
; ! " # $ % & ' ( ) * + , - . /
db 1,3,0,3,3,3,3,3,3,3,0,1,1,3,3,0
; 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
db 3,3,3,3,3,3,3,3,3,3,0,1,0,1,0,0
; @ A B C D E F G H I J K L M N O
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
; P Q R S T U V W X Y Z [ \ ] ^ _
db 3,3,3,3,3,3,3,3,3,3,3,1,0,1,3,3
; ` a b c d e f g h i j k l m n o
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
; p q r s t u v w x y z { | } ~
db 3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,0
ramdisk_name db 'rd',0
endg
 
fat_name_is_legal:
; in: esi->(long) name
; out: CF set <=> legal
; destroys eax
push esi
xor eax, eax
@@:
lodsb
test al, al
jz .done
cmp al, 80h
jae .big
test [fat_legal_chars+eax], 1
jnz @b
.err:
pop esi
clc
ret
.big:
; 0x80-0xAF, 0xE0-0xEF
cmp al, 0xB0
jb @b
cmp al, 0xE0
jb .err
cmp al, 0xF0
jb @b
jmp .err
.done:
sub esi, [esp]
cmp esi, 257
pop esi
ret
 
fat_next_short_name:
; in: edi->8+3 name
; out: name corrected
; CF=1 <=> error
pushad
mov ecx, 8
mov al, '~'
std
push edi
add edi, 7
repnz scasb
pop edi
cld
jz .tilde
; tilde is not found, insert "~1" at end
add edi, 6
cmp word [edi], ' '
jnz .insert_tilde
@@:
dec edi
cmp byte [edi], ' '
jz @b
inc edi
.insert_tilde:
mov word [edi], '~1'
popad
clc
ret
.tilde:
push edi
add edi, 7
push ebx esi ; save used registers to be stdcall
; 1. Register the device and the (always inserted) media in the disk subsystem.
stdcall disk_add, ramdisk_functions, ramdisk_name, 0, 0
test eax, eax
jz .fail
mov ebx, eax
stdcall disk_media_changed, eax, 1
; 2. We don't know actual size of loaded image,
; so try to calculate it using partition structure,
; assuming that file systems fill the real size based on contents of the partition.
; 2a. Prepare for loop over partitions.
xor ecx, ecx
xor edx, edx
; 2b. Check that at least one partition was recognized.
cmp [ebx+DISK.NumPartitions], ecx
jz .fail
; 2c. Loop over partitions.
.partitions:
; For every partition, set edx to maximum between edx and end of partition.
mov esi, [ebx+DISK.Partitions]
mov esi, [esi+ecx*4]
mov eax, dword [esi+PARTITION.FirstSector]
add eax, dword [esi+PARTITION.Length]
cmp eax, edx
jb @f
mov edx, eax
@@:
; after tilde may be only digits and trailing spaces
cmp byte [edi], '~'
jz .break
cmp byte [edi], ' '
jz .space
cmp byte [edi], '9'
jnz .found
dec edi
jmp @b
.space:
dec edi
inc ecx
jmp @b
.found:
inc byte [edi]
add dword [esp], 8
jmp .zerorest
.break:
jecxz .noplace
inc edi
mov al, '1'
cmp ecx, [ebx+DISK.NumPartitions]
jb .partitions
; 3. Reclaim unused memory, if any.
mov [ramdisk_actual_size], edx
add edx, 7 ; aligning up
shr edx, 3 ; 512-byte sectors -> 4096-byte pages
mov esi, RAMDISK_CAPACITY / 8 ; aligning down
sub esi, edx
jbe .no_reclaim
shl edx, 12
add edx, RAMDISK - OS_BASE
@@:
xchg al, [edi]
inc edi
cmp al, ' '
mov al, '0'
mov eax, edx
call free_page
add edx, 0x1000
dec esi
jnz @b
.succ:
pop edi
popad
clc
.no_reclaim:
pop esi ebx ; restore used registers to be stdcall
ret
.noplace:
dec edi
cmp edi, [esp]
jz .err
add dword [esp], 8
mov word [edi], '~1'
inc edi
inc edi
@@:
mov byte [edi], '0'
.zerorest:
inc edi
cmp edi, [esp]
jb @b
pop edi
popad
;clc ; automatically
.fail:
dbgstr 'Failed to initialize ramdisk'
pop esi ebx ; restore used registers to be stdcall
ret
.err:
pop edi
popad
stc
ret
endp
 
fat_gen_short_name:
; in: esi->long name
; edi->buffer (8+3=11 chars)
; out: buffer filled
pushad
mov eax, ' '
push edi
stosd
stosd
stosd
pop edi
; Returns information about disk media.
proc ramdisk_querymedia
virtual at esp+4
.userdata dd ?
.info dd ?
end virtual
; Media is always present, sector size is always 512 bytes.
mov edx, [.userdata]
mov ecx, [.info]
mov [ecx+DISKMEDIAINFO.Flags], 0
mov [ecx+DISKMEDIAINFO.SectorSize], 512
mov eax, [ramdisk_actual_size]
mov dword [ecx+DISKMEDIAINFO.Capacity], eax
mov dword [ecx+DISKMEDIAINFO.Capacity+4], 0
; Return zero as an indicator of success.
xor eax, eax
movi ebx, 8
lea ecx, [edi+8]
.loop:
lodsb
test al, al
jz .done
call char_toupper
cmp al, ' '
jz .space
cmp al, 80h
ja .big
test [fat_legal_chars+eax], 2
jnz .symbol
.inv_symbol:
mov al, '_'
or bh, 1
.symbol:
cmp al, '.'
jz .dot
.normal_symbol:
dec bl
jns .store
mov bl, 0
.space:
or bh, 1
jmp .loop
.store:
stosb
jmp .loop
.big:
cmp al, 0xB0
jb .normal_symbol
cmp al, 0xE0
jb .inv_symbol
cmp al, 0xF0
jb .normal_symbol
jmp .inv_symbol
.dot:
test bh, 2
jz .firstdot
pop ebx
add ebx, edi
sub ebx, ecx
push ebx
cmp ebx, ecx
jb @f
pop ebx
push ecx
@@:
cmp edi, ecx
jbe .skip
@@:
dec edi
mov al, [edi]
dec ebx
mov [ebx], al
mov byte [edi], ' '
cmp edi, ecx
ja @b
.skip:
mov bh, 3
jmp @f
.firstdot:
cmp bl, 8
jz .space
push edi
or bh, 2
@@:
mov edi, ecx
mov bl, 3
jmp .loop
.done:
test bh, 2
jz @f
pop edi
@@:
lea edi, [ecx-8]
test bh, 1
jz @f
call fat_next_short_name
@@:
popad
ret
retn 8
endp
 
;----------------------------------------------------------------
;
; fs_RamdiskRewrite - LFN variant for writing ramdisk
; fs_RamdiskCreateFolder - create folder on ramdisk
;
; esi points to file/folder name
; ebx ignored (reserved)
; ecx number of bytes to write, 0+ (ignored for folders)
; edx mem location to data (ignored for folders)
;
; ret ebx = number of written bytes
; eax = 0 ok read or other = errormsg
;
;--------------------------------------------------------------
@@:
mov eax, ERROR_ACCESS_DENIED
xor ebx, ebx
ret
 
fs_RamdiskCreateFolder:
mov al, 1 ; create folder
jmp fs_RamdiskRewrite.common
 
fs_RamdiskRewrite:
xor eax, eax ; create file
.common:
cmp byte [esi], 0
jz @b
pushad
xor edi, edi
push esi
test ebp, ebp
jz @f
mov esi, ebp
@@:
lodsb
test al, al
jz @f
cmp al, '/'
jnz @b
lea edi, [esi-1]
jmp @b
@@:
pop esi
test edi, edi
jnz .noroot
test ebp, ebp
jnz .hasebp
push ramdisk_root_extend_dir
push ramdisk_root_next_write
push edi
push ramdisk_root_first
push ramdisk_root_next
jmp .common1
.hasebp:
mov eax, ERROR_ACCESS_DENIED
cmp byte [ebp], 0
jz .ret1
push ebp
xor ebp, ebp
call rd_find_lfn
pop esi
jc .notfound0
jmp .common0
.noroot:
mov eax, ERROR_ACCESS_DENIED
cmp byte [edi+1], 0
jz .ret1
; check existence
mov byte [edi], 0
push edi
call rd_find_lfn
pop esi
mov byte [esi], '/'
jnc @f
.notfound0:
mov eax, ERROR_FILE_NOT_FOUND
.ret1:
mov [esp+28], eax
popad
xor ebx, ebx
ret
@@:
inc esi
.common0:
test byte [edi+11], 0x10 ; must be directory
mov eax, ERROR_ACCESS_DENIED
jz .ret1
movzx ebp, word [edi+26] ; ebp=cluster
mov eax, ERROR_FAT_TABLE
cmp ebp, 2
jb .ret1
cmp ebp, 2849
jae .ret1
push ramdisk_notroot_extend_dir
push ramdisk_notroot_next_write
push ebp
push ramdisk_notroot_first
push ramdisk_notroot_next
.common1:
call fat_find_lfn
jc .notfound
; found
test byte [edi+11], 10h
jz .exists_file
; found directory; if we are creating directory, return OK,
; if we are creating file, say "access denied"
add esp, 20
popad
test al, al
mov eax, ERROR_ACCESS_DENIED
jz @f
mov al, 0
@@:
xor ebx, ebx
ret
.exists_file:
; found file; if we are creating directory, return "access denied",
; if we are creating file, delete existing file and continue
cmp byte [esp+20+28], 0
jz @f
add esp, 20
popad
mov eax, ERROR_ACCESS_DENIED
xor ebx, ebx
ret
@@:
; delete FAT chain
push edi
xor eax, eax
mov dword [edi+28], eax ; zero size
xchg ax, word [edi+26] ; start cluster
test eax, eax
jz .done1
@@:
cmp eax, 0xFF8
jae .done1
lea edi, [RAMDISK_FAT + eax*2] ; position in FAT
xor eax, eax
xchg ax, [edi]
jmp @b
.done1:
pop edi
call get_time_for_file
mov [edi+22], ax
call get_date_for_file
mov [edi+24], ax
mov [edi+18], ax
or byte [edi+11], 20h ; set 'archive' attribute
jmp .doit
.notfound:
; file is not found; generate short name
call fat_name_is_legal
jc @f
add esp, 20
popad
mov eax, ERROR_FILE_NOT_FOUND
xor ebx, ebx
ret
@@:
sub esp, 12
mov edi, esp
call fat_gen_short_name
.test_short_name_loop:
push esi edi ecx
mov esi, edi
lea eax, [esp+12+12+8]
mov [eax], ebp
call dword [eax-4]
jc .found
.test_short_name_entry:
cmp byte [edi+11], 0xF
jz .test_short_name_cont
mov ecx, 11
push esi edi
repz cmpsb
pop edi esi
jz .short_name_found
.test_short_name_cont:
lea eax, [esp+12+12+8]
call dword [eax-8]
jnc .test_short_name_entry
jmp .found
.short_name_found:
pop ecx edi esi
call fat_next_short_name
jnc .test_short_name_loop
.disk_full:
add esp, 12+20
popad
mov eax, ERROR_DISK_FULL
xor ebx, ebx
ret
.found:
pop ecx edi esi
; now find space in directory
; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~'
mov al, '~'
push ecx edi
mov ecx, 8
repnz scasb
movi eax, 1 ; 1 entry
jnz .notilde
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total
xor eax, eax
@@:
cmp byte [esi], 0
jz @f
inc esi
inc eax
jmp @b
@@:
sub esi, eax
add eax, 12+13
mov ecx, 13
push edx
cdq
div ecx
pop edx
.notilde:
push -1
push -1
; find <eax> successive entries in directory
; Common procedure for reading and writing.
; operation = 0 for reading, operation = 1 for writing.
; Arguments of ramdisk_read and ramdisk_write are the same.
macro ramdisk_read_write operation
{
push esi edi ; save used registers to be stdcall
mov esi, [userdata]
mov edi, [numsectors_ptr]
; 1. Determine number of sectors to be transferred.
; This is either the requested number of sectors or number of sectors
; up to the disk boundary, depending of what is less.
xor ecx, ecx
push eax
lea eax, [esp+12+8+12+8]
mov [eax], ebp
call dword [eax-4]
pop eax
.scan_dir:
cmp byte [edi], 0
jz .free
cmp byte [edi], 0xE5
jz .free
xor ecx, ecx
.scan_cont:
push eax
lea eax, [esp+12+8+12+8]
call dword [eax-8]
pop eax
jnc .scan_dir
push eax
lea eax, [esp+12+8+12+8]
call dword [eax+8] ; extend directory
pop eax
jnc .scan_dir
add esp, 8+8+12+20
popad
mov eax, ERROR_DISK_FULL
xor ebx, ebx
ret
.free:
test ecx, ecx
jnz @f
mov [esp], edi
mov ecx, [esp+8+8+12+8]
mov [esp+4], ecx
xor ecx, ecx
@@:
inc ecx
; 1a. Test whether [start_sector] is less than RAMDISK_CAPACITY.
; If so, calculate number of sectors between [start_sector] and RAMDISK_CAPACITY.
; Otherwise, the actual number of sectors is zero.
cmp dword [start_sector+4], ecx
jnz .got_number
mov eax, [ramdisk_actual_size]
sub eax, dword [start_sector]
jbe .got_number
; 1b. Get the requested number of sectors.
mov ecx, [edi]
; 1c. If it is greater than number of sectors calculated in 1a, use the value
; from 1a.
cmp ecx, eax
jb .scan_cont
; found!
; If creating a directory, allocate one data cluster now and fail immediately
; if this is impossible. This prevents from creating an invalid directory entry
; on a full disk.
; yup, the argument is quite non-intuitive... but what should I do if
; the entire function uses such arguments? BTW, it refers to al from pushad,
; which in turn is filled with 0 in fs_RamdiskRewrite and 1 in fs_RamdiskCreateFolder.
push esi ecx
cmp byte [esp+24+12+20+28], 0
jz .no.preallocate.folder.data
mov ecx, 2849
mov edi, RAMDISK_FAT
jb .got_number
mov ecx, eax
.got_number:
; 2. Compare the actual number of sectors with requested. If they are
; equal, set eax (it will be the returned value) to zero. Otherwise,
; use DISK_STATUS_END_OF_MEDIA.
xor eax, eax
repnz scasw
cmp ecx, [edi]
jz @f
add esp, 24
jmp .disk_full
mov al, DISK_STATUS_END_OF_MEDIA
@@:
mov [esp+24+12+20+20], edi ; store the cluster somewhere
.no.preallocate.folder.data:
; calculate name checksum
mov esi, [esp+8+8]
mov ecx, 11
xor eax, eax
@@:
ror al, 1
add al, [esi]
inc esi
loop @b
pop ecx esi
pop edi
pop dword [esp+8+12+8]
; edi points to last entry in free chunk
dec ecx
jz .nolfn
push esi
push eax
mov al, 40h
.writelfn:
or al, cl
mov esi, [esp+4]
push ecx
dec ecx
imul ecx, 13
add esi, ecx
stosb
mov cl, 5
call .read_symbols
mov ax, 0xF
stosw
mov al, [esp+4]
stosb
mov cl, 6
call .read_symbols
xor eax, eax
stosw
mov cl, 2
call .read_symbols
pop ecx
lea eax, [esp+8+8+12+8]
call dword [eax+4] ; next write
xor eax, eax
loop .writelfn
pop eax
pop esi
.nolfn:
xchg esi, [esp]
mov ecx, 11
rep movsb
mov word [edi], 20h ; attributes
sub edi, 11
pop esi ecx
add esp, 12
mov byte [edi+13], 0 ; tenths of a second at file creation time
call get_time_for_file
mov [edi+14], ax ; creation time
mov [edi+22], ax ; last write time
call get_date_for_file
mov [edi+16], ax ; creation date
mov [edi+24], ax ; last write date
mov [edi+18], ax ; last access date
and word [edi+20], 0 ; high word of cluster
and word [edi+26], 0 ; low word of cluster - to be filled
and dword [edi+28], 0 ; file size - to be filled
cmp byte [esp+20+28], 0
jz .doit
; create directory
mov byte [edi+11], 10h ; attributes: folder
mov ecx, 32*2
mov edx, edi
push edx
push ecx
push edi
add edi, 26 ; edi points to low word of cluster
push edi
mov edi, [esp+16+20+20]
jmp .doit2
.doit:
push edx
push ecx
push edi
add edi, 26 ; edi points to low word of cluster
push edi
jecxz .done
mov ecx, 2849
mov edi, RAMDISK_FAT
.write_loop:
; allocate new cluster
xor eax, eax
repnz scasw
jnz .disk_full2
.doit2:
dec edi
dec edi
 
; lea eax, [edi-(RAMDISK_FAT)]
 
mov eax, edi
sub eax, RAMDISK_FAT
 
shr eax, 1 ; eax = cluster
mov word [edi], 0xFFF ; mark as last cluster
xchg edi, [esp]
stosw
pop edi
push edi
inc ecx
; write data
cmp byte [esp+16+20+28], 0
jnz .writedir
shl eax, 9
add eax, RAMDISK+31*512
.writefile:
mov ebx, edx
xchg eax, ebx
push ecx
mov ecx, 512
cmp dword [esp+12], ecx
jae @f
mov ecx, [esp+12]
@@:
call memmove
add edx, ecx
sub [esp+12], ecx
pop ecx
jnz .write_loop
.done:
mov ebx, edx
pop edi edi ecx edx
sub ebx, edx
mov [edi+28], ebx
add esp, 20
mov [esp+16], ebx
popad
xor eax, eax
ret
.disk_full2:
mov ebx, edx
pop edi edi ecx edx
sub ebx, edx
mov [edi+28], ebx
add esp, 20
mov [esp+16], ebx
popad
movi eax, ERROR_DISK_FULL
ret
.writedir:
mov edi, eax
; 3. Store the actual number of sectors.
mov [edi], ecx
; 4. Calculate source and destination addresses.
if operation = 0 ; reading?
mov esi, dword [start_sector]
shl esi, 9
add esi, RAMDISK
mov edi, [buffer]
else ; writing?
mov edi, dword [start_sector]
shl edi, 9
add edi, RAMDISK+31*512
mov esi, edx
mov ecx, 32/4
push ecx
add edi, RAMDISK
mov esi, [buffer]
end if
; 5. Calculate number of dwords to be transferred.
shl ecx, 9-2
; 6. Copy data.
rep movsd
mov dword [edi-32], '. '
mov dword [edi-32+4], ' '
mov dword [edi-32+8], ' '
mov byte [edi-32+11], 10h
mov word [edi-32+26], ax
mov esi, edx
pop ecx
rep movsd
mov dword [edi-32], '.. '
mov dword [edi-32+4], ' '
mov dword [edi-32+8], ' '
mov byte [edi-32+11], 10h
mov eax, [esp+16+8]
mov word [edi-32+26], ax
xor eax, eax
mov ecx, (512-32*2)/4
rep stosd
pop edi edi ecx edx
add esp, 20
popad
xor eax, eax
xor ebx, ebx
ret
; 7. Return. The value in eax was calculated in step 2.
pop edi esi ; restore used registers to be stdcall
}
 
.read_symbol:
or ax, -1
test esi, esi
jz .retFFFF
lodsb
test al, al
jnz ansi2uni_char
xor eax, eax
xor esi, esi
.retFFFF:
; Reads one or more sectors from the device.
proc ramdisk_read userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword
ramdisk_read_write 0
ret
endp
 
.read_symbols:
call .read_symbol
stosw
loop .read_symbols
; Writes one or more sectors to the device.
proc ramdisk_write userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword
ramdisk_read_write 1
ret
endp
 
;----------------------------------------------------------------
;
; fs_RamdiskWrite - LFN variant for writing to sys floppy
;
; esi points to filename
; ebx pointer to 64-bit number = first wanted byte, 0+
; may be ebx=0 - start from first byte
; ecx number of bytes to write, 0+
; edx mem location to data
;
; ret ebx = bytes written (maybe 0)
; eax = 0 ok write or other = errormsg
;
;--------------------------------------------------------------
@@:
push ERROR_ACCESS_DENIED
fs_RamdiskWrite.ret0:
pop eax
xor ebx, ebx
ret
 
fs_RamdiskWrite:
cmp byte [esi], 0
jz @b
pushad
call rd_find_lfn
jnc .found
popad
push ERROR_FILE_NOT_FOUND
jmp .ret0
.found:
; must not be directory
test byte [edi+11], 10h
jz @f
popad
push ERROR_ACCESS_DENIED
jmp .ret0
@@:
; FAT does not support files larger than 4GB
test ebx, ebx
jz .l1
cmp dword [ebx+4], 0
jz @f
.eof:
popad
push ERROR_END_OF_FILE
jmp .ret0
@@:
mov ebx, [ebx]
.l1:
; now edi points to direntry, ebx=start byte to write,
; ecx=number of bytes to write, edx=data pointer
call fat_update_datetime
 
; extend file if needed
add ecx, ebx
jc .eof ; FAT does not support files larger than 4GB
push 0 ; return value=0
cmp ecx, [edi+28]
jbe .length_ok
cmp ecx, ebx
jz .length_ok
call ramdisk_extend_file
jnc .length_ok
; ramdisk_extend_file can return two error codes: FAT table error or disk full.
; First case is fatal error, in second case we may write some data
mov [esp], eax
cmp al, ERROR_DISK_FULL
jz .disk_full
pop eax
mov [esp+28], eax
popad
xor ebx, ebx
ret
.disk_full:
; correct number of bytes to write
mov ecx, [edi+28]
cmp ecx, ebx
ja .length_ok
.ret:
pop eax
mov [esp+28], eax ; eax=return value
sub edx, [esp+20]
mov [esp+16], edx ; ebx=number of written bytes
popad
ret
.length_ok:
; now ebx=start pos, ecx=end pos, both lie inside file
sub ecx, ebx
jz .ret
movzx edi, word [edi+26] ; starting cluster
.write_loop:
sub ebx, 0x200
jae .next_cluster
push ecx
neg ebx
cmp ecx, ebx
jbe @f
mov ecx, ebx
@@:
mov eax, edi
shl eax, 9
add eax, RAMDISK+31*512+0x200
sub eax, ebx
mov ebx, eax
mov eax, edx
call memmove
xor ebx, ebx
add edx, ecx
sub [esp], ecx
pop ecx
jz .ret
.next_cluster:
movzx edi, word [edi*2+RAMDISK_FAT]
jmp .write_loop
 
ramdisk_extend_file.zero_size:
; The kernel calls this function when initializing cache subsystem for
; the media. This call allows the driver to adjust the cache size.
proc ramdisk_adjust_cache_size
virtual at esp+4
.userdata dd ?
.suggested_size dd ?
end virtual
; Since ramdisk does not need cache, just return 0.
xor eax, eax
jmp ramdisk_extend_file.start_extend
 
; extends file on ramdisk to given size, new data area is filled by 0
; in: edi->direntry, ecx=new size
; out: CF=0 => OK, eax=0
; CF=1 => error, eax=code (ERROR_FAT_TABLE or ERROR_DISK_FULL)
ramdisk_extend_file:
push ecx
; find the last cluster of file
movzx eax, word [edi+26] ; first cluster
mov ecx, [edi+28]
jecxz .zero_size
@@:
sub ecx, 0x200
jbe @f
mov eax, [eax*2+RAMDISK_FAT]
and eax, 0xFFF
jz .fat_err
cmp eax, 0xFF8
jb @b
.fat_err:
pop ecx
movi eax, ERROR_FAT_TABLE
stc
ret
@@:
push eax
mov eax, [eax*2+RAMDISK_FAT]
and eax, 0xFFF
cmp eax, 0xFF8
pop eax
jb .fat_err
; set length to full number of sectors and make sure that last sector is zero-padded
sub [edi+28], ecx
push eax edi
mov edi, eax
shl edi, 9
lea edi, [edi+RAMDISK+31*512+0x200+ecx]
neg ecx
xor eax, eax
rep stosb
pop edi eax
.start_extend:
pop ecx
; now do extend
push edx esi
mov esi, RAMDISK_FAT+2*2 ; start scan from cluster 2
mov edx, 2847 ; number of clusters to scan
.extend_loop:
cmp [edi+28], ecx
jae .extend_done
; add new sector
push ecx
mov ecx, edx
push edi
mov edi, esi
jecxz .disk_full
push eax
xor eax, eax
repnz scasw
pop eax
jnz .disk_full
mov word [edi-2], 0xFFF
mov esi, edi
mov edx, ecx
sub edi, RAMDISK_FAT
shr edi, 1
dec edi ; now edi=new cluster
test eax, eax
jz .first_cluster
mov [RAMDISK_FAT+eax*2], di
jmp @f
.first_cluster:
pop eax ; eax->direntry
push eax
mov [eax+26], di
@@:
push edi
shl edi, 9
add edi, RAMDISK+31*512
xor eax, eax
mov ecx, 512/4
rep stosd
pop eax ; eax=new cluster
pop edi ; edi->direntry
pop ecx ; ecx=required size
add dword [edi+28], 0x200
jmp .extend_loop
.extend_done:
mov [edi+28], ecx
pop esi edx
xor eax, eax ; CF=0
ret
.disk_full:
pop edi ecx
pop esi edx
stc
movi eax, ERROR_DISK_FULL
ret
 
fat_update_datetime:
call get_time_for_file
mov [edi+22], ax ; last write time
call get_date_for_file
mov [edi+24], ax ; last write date
mov [edi+18], ax ; last access date
ret
 
;----------------------------------------------------------------
;
; fs_RamdiskSetFileEnd - set end of file on ramdisk
;
; esi points to filename
; ebx points to 64-bit number = new file size
; ecx ignored (reserved)
; edx ignored (reserved)
;
; ret eax = 0 ok or other = errormsg
;
;--------------------------------------------------------------
fs_RamdiskSetFileEnd:
cmp byte [esi], 0
jnz @f
.access_denied:
push ERROR_ACCESS_DENIED
jmp .ret
@@:
push edi
call rd_find_lfn
jnc @f
pop edi
push ERROR_FILE_NOT_FOUND
.ret:
pop eax
ret
@@:
; must not be directory
test byte [edi+11], 10h
jz @f
pop edi
jmp .access_denied
@@:
; file size must not exceed 4Gb
cmp dword [ebx+4], 0
jz @f
pop edi
push ERROR_END_OF_FILE
jmp .ret
@@:
; set file modification date/time to current
call fat_update_datetime
mov eax, [ebx]
cmp eax, [edi+28]
jb .truncate
ja .expand
pop edi
xor eax, eax
ret
.expand:
push ecx
mov ecx, eax
call ramdisk_extend_file
pop ecx
pop edi
ret
.truncate:
mov [edi+28], eax
push ecx
movzx ecx, word [edi+26]
test eax, eax
jz .zero_size
; find new last sector
@@:
sub eax, 0x200
jbe @f
movzx ecx, word [RAMDISK_FAT+ecx*2]
jmp @b
@@:
; zero data at the end of last sector
push ecx
mov edi, ecx
shl edi, 9
lea edi, [edi+RAMDISK+31*512+eax+0x200]
mov ecx, eax
neg ecx
xor eax, eax
rep stosb
pop ecx
; terminate FAT chain
lea ecx, [RAMDISK_FAT+ecx+ecx]
push dword [ecx]
mov word [ecx], 0xFFF
pop ecx
and ecx, 0xFFF
jmp .delete
.zero_size:
and word [edi+26], 0
.delete:
; delete FAT chain starting with ecx
; mark all clusters as free
cmp ecx, 0xFF8
jae .deleted
lea ecx, [RAMDISK_FAT+ecx+ecx]
push dword [ecx]
and word [ecx], 0
pop ecx
and ecx, 0xFFF
jmp .delete
.deleted:
pop ecx
pop edi
xor eax, eax
ret
 
fs_RamdiskGetFileInfo:
cmp byte [esi], 0
jnz @f
mov eax, 2 ; unsupported
ret
@@:
push edi
call rd_find_lfn
fs_GetFileInfo_finish:
jnc @f
pop edi
mov eax, ERROR_FILE_NOT_FOUND
ret
@@:
push esi ebp
xor ebp, ebp
mov esi, edx
and dword [esi+4], 0
call fat_entry_to_bdfe2
pop ebp esi
pop edi
xor eax, eax
ret
 
fs_RamdiskSetFileInfo:
cmp byte [esi], 0
jnz @f
mov eax, 2 ; unsupported
ret
@@:
push edi
call rd_find_lfn
jnc @f
pop edi
mov eax, ERROR_FILE_NOT_FOUND
ret
@@:
call bdfe_to_fat_entry
pop edi
xor eax, eax
ret
 
;----------------------------------------------------------------
;
; fs_RamdiskDelete - delete file or empty folder from ramdisk
;
; esi points to filename
;
; ret eax = 0 ok or other = errormsg
;
;--------------------------------------------------------------
fs_RamdiskDelete:
cmp byte [esi], 0
jnz @f
; cannot delete root!
.access_denied:
push ERROR_ACCESS_DENIED
.pop_ret:
pop eax
ret
@@:
and [rd_prev_sector], 0
and [rd_prev_prev_sector], 0
push edi
call rd_find_lfn
jnc .found
pop edi
push ERROR_FILE_NOT_FOUND
jmp .pop_ret
.found:
cmp dword [edi], '. '
jz .access_denied2
cmp dword [edi], '.. '
jz .access_denied2
test byte [edi+11], 10h
jz .dodel
; we can delete only empty folders!
movzx eax, word [edi+26]
push ebx
mov ebx, eax
shl ebx, 9
add ebx, RAMDISK + 31*0x200 + 2*0x20
.checkempty:
cmp byte [ebx], 0
jz .empty
cmp byte [ebx], 0xE5
jnz .notempty
add ebx, 0x20
test ebx, 0x1FF
jnz .checkempty
movzx eax, word [RAMDISK_FAT + eax*2]
test eax, eax
jz .empty
mov ebx, eax
shl ebx, 9
add ebx, RAMDISK + 31*0x200
jmp .checkempty
.notempty:
pop ebx
.access_denied2:
pop edi
jmp .access_denied
.empty:
pop ebx
.dodel:
movzx eax, word [edi+26]
; delete folder entry
mov byte [edi], 0xE5
; delete LFN (if present)
.lfndel:
test edi, 0x1FF
jnz @f
cmp [rd_prev_sector], 0
jz @f
cmp [rd_prev_sector], -1
jz .lfndone
mov edi, [rd_prev_sector]
push [rd_prev_prev_sector]
pop [rd_prev_sector]
or [rd_prev_prev_sector], -1
shl edi, 9
add edi, RAMDISK + 31*0x200 + 0x200
@@:
sub edi, 0x20
cmp byte [edi], 0xE5
jz .lfndone
cmp byte [edi+11], 0xF
jnz .lfndone
mov byte [edi], 0xE5
jmp .lfndel
.lfndone:
; delete FAT chain
cmp eax, 2
jb .done
cmp eax, 0xFF8
jae .done
lea eax, [RAMDISK_FAT + eax*2]
push dword [eax]
and word [eax], 0
pop eax
and eax, 0xFFF
jmp .lfndone
.done:
pop edi
xor eax, eax
ret
 
; \end{diamond}
retn 8
endp
/kernel/trunk/blkdev/rdsave.inc
13,7 → 13,8
dd 2 ; subfunction: write
dd 0 ; (reserved)
dd 0 ; (reserved)
dd 1440*1024 ; size 1440 Kb
.size:
dd 0
dd RAMDISK
db 0
.name:
20,9 → 21,11
dd ?
endg
sysfn_saveramdisk: ; 18.6 = SAVE FLOPPY IMAGE (HD version only)
call restorefatchain
mov ebx, saverd_fileinfo
mov [saverd_fileinfo.name], ecx
mov [ebx+21], ecx
mov eax, [ramdisk_actual_size]
shl eax, 9
mov [ebx+12], eax
pushad
call file_system_lfn_protected ;in ebx
popad
/kernel/trunk/core/sys32.inc
660,10 → 660,6
call free_cd_channel
and [cd_status], 0
@@:
cmp [flp_status], esi
jnz @f
and [flp_status], 0
@@:
pop esi
cmp [bgrlockpid], esi
jnz @f
/kernel/trunk/core/syscall.inc
7,20 → 7,6
 
$Revision$
 
; Old style system call converter
align 16
cross_order:
; load all registers in crossed order
mov eax, ebx
mov ebx, ecx
mov ecx, edx
mov edx, esi
mov esi, edi
movzx edi, byte[esp+28 + 4]
sub edi, 53
call dword [servetable+edi*4]
ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; SYSENTER ENTRY ;;
109,25 → 95,7
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SYSTEM FUNCTIONS TABLE ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
align 4
servetable:
dd 0
dd 0
dd 0
dd 0
dd 0
dd file_system ; 58-Common file system interface
dd 0
dd 0
dd 0
dd 0
dd 0
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; NEW SYSTEM FUNCTIONS TABLE ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 4
servetable2:
 
dd syscall_draw_window ; 0-DrawWindow
136,7 → 104,7
dd sys_clock ; 3-GetTime
dd syscall_writetext ; 4-WriteText
dd delay_hs_unprotected ; 5-DelayHs
dd syscall_openramdiskfile ; 6-OpenRamdiskFile
dd undefined_syscall ; 6-deprecated OpenRamdiskFile
dd syscall_putimage ; 7-PutImage
dd syscall_button ; 8-DefineButton
dd sys_cpuusage ; 9-GetProcessInfo
188,7 → 156,7
dd sound_interface ; 55-Sound interface
dd undefined_syscall ; 56-reserved
dd sys_pcibios ; 57-PCI BIOS32
dd cross_order ; 58-Common file system interface
dd undefined_syscall ; 58-deprecated Common file system interface
dd undefined_syscall ; 59-reserved
dd sys_IPC ; 60-Inter Process Communication
dd sys_gs ; 61-Direct graphics access
/kernel/trunk/data32.inc
51,7 → 51,7
if lang eq ru
boot_initirq cp866 'Инициализация IRQ',0
boot_picinit cp866 'Инициализация PIC',0
boot_v86machine cp866 'Инициализация системы V86 машины',0
boot_v86machine cp866 'Инициализация системной V86 машины',0
boot_inittimer cp866 'Инициализация системного таймера (IRQ0)',0
boot_initapic cp866 'Попытка инициализации APIC',0
boot_enableirq cp866 'Включить прерывания 2, 13',0
69,6 → 69,7
boot_cpuid cp866 'Чтение CPUIDs',0
; boot_devices cp866 'Поиск устройств',0
boot_timer cp866 'Установка таймера',0
boot_initramdisk cp866 'Инициализация рамдиска',0
boot_irqs cp866 'Переопределение IRQ',0
boot_setmouse cp866 'Установка мыши',0
boot_windefs cp866 'Установка настроек окон по умолчанию',0
98,6 → 99,7
boot_picinit db 'Initialize PIC',0
boot_v86machine db 'Initialize system V86 machine',0
boot_inittimer db 'Initialize system timer (IRQ0)',0
boot_initramdisk db 'Initialize ramdisk',0
boot_initapic db 'Try to initialize APIC',0
boot_enableirq db 'Enable interrupts 2, 13',0
boot_disabling_ide db 'Disable interrupts in IDE controller',0
172,7 → 174,13
 
vmode db '/sys/drivers/VMODE.MDR',0
;vrr_m db 'VRR_M',0
kernel_file db 'KERNEL MNT'
kernel_file_load:
; load kernel.mnt to 0x7000:0
dd 0 ; subfunction
dq 0 ; offset in file
dd 0x30000 ; number of bytes to read
dd 0x70000 ; buffer for data
db '/RD/1/KERNEL.MNT',0
 
dev_data_path db '/RD/1/DRIVERS/DEVICES.DAT',0
 
570,8 → 578,7
org (OS_BASE+0x0100000)
 
RAMDISK: rb 2880*512
RAMDISK_FAT: rb 2856*2
FLOPPY_FAT: rb 2856*2
rb 2856*4 ; not used
 
_CLEAN_ZONE:
 
/kernel/trunk/data32et.inc
2,6 → 2,7
boot_picinit latin1 'Algväärtustan PIC',0
boot_v86machine latin1 'Algväärtustan süsteemi V86 masinat',0
boot_inittimer latin1 'Algväärtustan süsteemi taimerit (IRQ0)',0
boot_initramdisk latin1 'Initialize ramdisk',0
boot_initapic latin1 'Proovin Algväärtustada APIC',0
boot_enableirq latin1 'Luban katkestused 2, 13',0
boot_disabling_ide latin1 'Keelan IDE kontrolleri katkestused',0
/kernel/trunk/data32sp.inc
2,6 → 2,7
boot_picinit: cp850 'Inicializar PIC',0
boot_v86machine: cp850 'Inicializar sistema V86',0
boot_inittimer: cp850 'Inicializar reloj del sistema (IRQ0)',0
boot_initramdisk cp850 'Initialize ramdisk',0
boot_initapic: cp850 'Prueba inicializar APIC',0
boot_enableirq: cp850 'Habilitar interrupciones 2, 13',0
boot_disabling_ide:cp850 'Habiliar interrupciones en controladores IDE',0
/kernel/trunk/detect/dev_fd.inc
33,5 → 33,6
 
stdcall attach_int_handler, 6, FDCInterrupt, 0
DEBUGF 1, "K : Set IDE IRQ6 return code %x\n", eax
call floppy_init
@@:
 
/kernel/trunk/fs/fs-sp.inc
File deleted
Property changes:
Deleted: svn:eol-style
-native
\ No newline at end of property
/kernel/trunk/fs/fs-et.inc
File deleted
\ No newline at end of file
Property changes:
Deleted: svn:eol-style
-native
\ No newline at end of property
/kernel/trunk/fs/fat12.inc
File deleted
Property changes:
Deleted: svn:eol-style
-native
\ No newline at end of property
Deleted: svn:keywords
-Rev
\ No newline at end of property
/kernel/trunk/fs/fat32.inc
File deleted
Property changes:
Deleted: svn:eol-style
-native
\ No newline at end of property
Deleted: svn:keywords
-Rev
\ No newline at end of property
/kernel/trunk/fs/fs.inc
File deleted
Property changes:
Deleted: svn:eol-style
-native
\ No newline at end of property
Deleted: svn:keywords
-Rev
\ No newline at end of property
/kernel/trunk/fs/fat.inc
0,0 → 1,3705
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; FAT32.INC ;;
;; ;;
;; FAT functions for KolibriOS ;;
;; ;;
;; Copyright 2002 Paolo Minazzi, paolo.minazzi@inwind.it ;;
;; ;;
;; See file COPYING for details ;;
;; 04.02.2007 LFN create folder - diamond ;;
;; 08.10.2006 LFN delete file/folder - diamond ;;
;; 20.08.2006 LFN set file size (truncate/extend) - diamond ;;
;; 17.08.2006 LFN write/append to file - diamond ;;
;; 23.06.2006 LFN start application - diamond ;;
;; 15.06.2006 LFN get/set file/folder info - diamond ;;
;; 27.05.2006 LFN create/rewrite file - diamond ;;
;; 04.05.2006 LFN read folder - diamond ;;
;; 29.04.2006 Elimination of hangup after the ;;
;; expiration hd_wait_timeout - Mario79 ;;
;; 23.04.2006 LFN read file - diamond ;;
;; 28.01.2006 find all Fat16/32 partition in all input point ;;
;; to MBR, see file part_set.inc - Mario79 ;;
;; 15.01.2005 get file size/attr/date, file_append - ATV ;;
;; 04.12.2004 skip volume label, file delete bug fixed - ATV ;;
;; 29.11.2004 get_free_FAT changed, append dir bug fixed - ATV ;;
;; 23.11.2004 don't allow overwrite dir with file - ATV ;;
;; 18.11.2004 get_disk_info and more error codes - ATV ;;
;; 17.11.2004 set_FAT/get_FAT and disk cache rewritten - ATV ;;
;; 10.11.2004 removedir clear whole directory structure - ATV ;;
;; 08.11.2004 rename - ATV ;;
;; 30.10.2004 file_read return also dirsize in bytes - ATV ;;
;; 20.10.2004 Makedir/Removedir - ATV ;;
;; 14.10.2004 Partition chain/Fat16 - ATV (thanks drh3xx) ;;
;; 06.9.2004 Fix free space by Mario79 added - MH ;;
;; 24.5.2004 Write back buffer for File_write -VT ;;
;; 20.5.2004 File_read function to work with syscall 58 - VT ;;
;; 30.3.2004 Error parameters at function return - VT ;;
;; 01.5.2002 Bugfix in device write - VT ;;
;; 20.5.2002 Hd status check - VT ;;
;; 29.6.2002 Improved fat32 verification - VT ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
cache_max equ 1919 ; max. is 1919*512+0x610000=0x6ffe00
 
PUSHAD_EAX equ [esp+28]
PUSHAD_ECX equ [esp+24]
PUSHAD_EDX equ [esp+20]
PUSHAD_EBX equ [esp+16]
PUSHAD_EBP equ [esp+8]
PUSHAD_ESI equ [esp+4]
PUSHAD_EDI equ [esp+0]
 
; Internal data for every FAT partition.
struct FAT PARTITION
fs_type db ?
fat16_root db 0 ; flag for fat16 rootdir
fat_change db 0 ; 1=fat has changed
db ? ; alignment
Lock MUTEX ? ; currently operations with one partition
; can not be executed in parallel since the
; legacy code is not ready; this mutex guards
; all operations
SECTORS_PER_FAT dd 0x1f3a
NUMBER_OF_FATS dd 0x2
SECTORS_PER_CLUSTER dd 0x8
BYTES_PER_SECTOR dd 0x200 ; Note: if BPS <> 512 need lots of changes
ROOT_CLUSTER dd 2 ; first rootdir cluster
FAT_START dd 0 ; start of fat table
ROOT_START dd 0 ; start of rootdir (only fat16)
ROOT_SECTORS dd 0 ; count of rootdir sectors (only fat16)
DATA_START dd 0 ; start of data area (=first cluster 2)
LAST_CLUSTER dd 0 ; last availabe cluster
ADR_FSINFO dd 0 ; used only by fat32
 
fatRESERVED dd 0x0FFFFFF6
fatBAD dd 0x0FFFFFF7
fatEND dd 0x0FFFFFF8
fatMASK dd 0x0FFFFFFF
 
fatStartScan dd 2
 
cluster_tmp dd 0 ; used by analyze_directory
; and analyze_directory_to_write
 
longname_sec1 dd 0 ; used by analyze_directory to save 2 previous
longname_sec2 dd 0 ; directory sectors for delete long filename
 
fat_in_cache dd -1
 
; For FAT16/FAT32, this points to 512-byte buffer for the current sector of FAT.
; For FAT12, the entire FAT structure is read
; and unpacked from 12bit per cluster to word per cluster.
;
; Note: work with unpacked copy of FAT12 means
; additional memory and additional code for packing/unpacking.
; I'm not sure that the economy justifies the cost, but anyway,
; there is how work was done before my edits, and I'm just keeping the principle.
fat_cache_ptr dd ?
fat12_unpacked_ptr dd ?
buffer rb 512
fsinfo_buffer rb 512
ends
 
uglobal
align 4
partition_count dd 0 ; partitions found by set_FAT32_variables
 
hd_error dd 0 ; set by wait_for_sector_buffer
hd_setup dd 0
hd_wait_timeout dd 0
 
cache_search_start dd 0 ; used by find_empty_slot
endg
 
uglobal
align 4
Sector512: ; label for dev_hdcd.inc
buffer:
times 512 db 0
endg
 
iglobal
align 4
fat_user_functions:
dd fat_free
dd (fat_user_functions_end - fat_user_functions - 4) / 4
dd fat_Read
dd fat_ReadFolder
dd fat_Rewrite
dd fat_Write
dd fat_SetFileEnd
dd fat_GetFileInfo
dd fat_SetFileInfo
dd 0
dd fat_Delete
dd fat_CreateFolder
fat_user_functions_end:
endg
 
; these labels are located before the main function to make
; most of jumps to these be short
fat_create_partition.free_return0:
mov eax, ebp
call free
pop ebp
fat_create_partition.return0:
xor eax, eax
ret
fat_create_partition:
; bootsector must have been successfully read
cmp dword [esp+4], 0
jnz .return0
; bootsector signature must be correct
cmp word [ebx+0x1fe], 0xaa55
jnz .return0
; sectors per cluster must be nonzero
cmp byte [ebx+0xd], 0
jz .return0
; bytes per sector must be 0x200
cmp word [ebx+0xb], 0x200
jnz .return0
; number of fats must be nonzero
cmp byte [ebx+0x10], 0
jz .return0
; The only reason to be invalid partition now is FAT12. Since the test for
; FAT size requires knowledge of some calculated values, which are also used
; in the normal operation, let's hope for the best and allocate data now; if
; it will prove wrong, just deallocate it.
movi eax, sizeof.FAT
call malloc
test eax, eax
jz .return0
mov ecx, dword [ebp+PARTITION.FirstSector]
mov dword [eax+FAT.FirstSector], ecx
mov ecx, dword [ebp+PARTITION.FirstSector+4]
mov dword [eax+FAT.FirstSector+4], ecx
mov ecx, dword [ebp+PARTITION.Length]
mov dword [eax+FAT.Length], ecx
mov ecx, dword [ebp+PARTITION.Length+4]
mov dword [eax+FAT.Length+4], ecx
mov ecx, [ebp+PARTITION.Disk]
mov [eax+FAT.Disk], ecx
mov [eax+FAT.FSUserFunctions], fat_user_functions
or [eax+FAT.fat_in_cache], -1
mov [eax+FAT.fat_change], 0
push ebp
mov ebp, eax
 
lea ecx, [ebp+FAT.Lock]
call mutex_init
 
movzx eax, word [ebx+0xe] ; sectors reserved
mov [ebp+FAT.FAT_START], eax
 
movzx eax, byte [ebx+0xd] ; sectors per cluster
mov [ebp+FAT.SECTORS_PER_CLUSTER], eax
 
movzx ecx, word [ebx+0xb] ; bytes per sector
mov [ebp+FAT.BYTES_PER_SECTOR], ecx
 
movzx eax, word [ebx+0x11] ; count of rootdir entries (=0 fat32)
shl eax, 5 ; mul 32
dec ecx
add eax, ecx ; round up if not equal count
inc ecx ; bytes per sector
xor edx, edx
div ecx
mov [ebp+FAT.ROOT_SECTORS], eax ; count of rootdir sectors
 
movzx eax, word [ebx+0x16] ; sectors per fat <65536
test eax, eax
jnz @f
mov eax, [ebx+0x24] ; sectors per fat
@@:
mov [ebp+FAT.SECTORS_PER_FAT], eax
 
movzx eax, byte [ebx+0x10] ; number of fats
mov [ebp+FAT.NUMBER_OF_FATS], eax
mul [ebp+FAT.SECTORS_PER_FAT]
test edx, edx
jnz .free_return0
add eax, [ebp+FAT.FAT_START]
jc .free_return0
mov [ebp+FAT.ROOT_START], eax ; rootdir = fat_start + fat_size * fat_count
add eax, [ebp+FAT.ROOT_SECTORS] ; rootdir sectors should be 0 on fat32
jc .free_return0
mov [ebp+FAT.DATA_START], eax ; data area = rootdir + rootdir_size
 
movzx eax, word [ebx+0x13] ; total sector count <65536
test eax, eax
jnz @f
mov eax, [ebx+0x20] ; total sector count
@@:
; total sector count must not exceed partition size
cmp dword [ebp+FAT.Length+4], 0
jnz @f
cmp eax, dword [ebp+FAT.Length]
ja .free_return0
@@:
mov dword [ebp+FAT.Length], eax
and dword [ebp+FAT.Length+4], 0
sub eax, [ebp+FAT.DATA_START] ; eax = count of data sectors
jc .free_return0
xor edx, edx
div [ebp+FAT.SECTORS_PER_CLUSTER]
inc eax
mov [ebp+FAT.LAST_CLUSTER], eax
dec eax ; cluster count
jz .free_return0
mov [ebp+FAT.fatStartScan], 2
 
; limits by Microsoft Hardware White Paper v1.03
cmp eax, 4085 ; 0xff5
jb .fat12
cmp eax, 65525 ; 0xfff5
jb .fat16
.fat32:
mov eax, [ebx+0x2c] ; rootdir cluster
mov [ebp+FAT.ROOT_CLUSTER], eax
movzx eax, word [ebx+0x30]
mov [ebp+FAT.ADR_FSINFO], eax
push ebx
add ebx, 512
call fs_read32_sys
test eax, eax
jnz @f
mov eax, [ebx+0x1ec]
cmp eax, -1
jz @f
mov [ebp+FAT.fatStartScan], eax
@@:
pop ebx
mov [ebp+FAT.fatRESERVED], 0x0FFFFFF6
mov [ebp+FAT.fatBAD], 0x0FFFFFF7
mov [ebp+FAT.fatEND], 0x0FFFFFF8
mov [ebp+FAT.fatMASK], 0x0FFFFFFF
mov al, 32
.fat_not_12_finalize:
mov [ebp+FAT.fs_type], al
; For FAT16 and FAT32, allocate 512 bytes for FAT cache.
mov eax, 512
call malloc
test eax, eax
jz .free_return0
mov [ebp+FAT.fat_cache_ptr], eax
mov eax, ebp
pop ebp
ret
.fat16:
and [ebp+FAT.ROOT_CLUSTER], 0
mov [ebp+FAT.fatRESERVED], 0x0000FFF6
mov [ebp+FAT.fatBAD], 0x0000FFF7
mov [ebp+FAT.fatEND], 0x0000FFF8
mov [ebp+FAT.fatMASK], 0x0000FFFF
mov al, 16
jmp .fat_not_12_finalize
.fat12:
and [ebp+FAT.ROOT_CLUSTER], 0
mov [ebp+FAT.fatRESERVED], 0xFF6
mov [ebp+FAT.fatBAD], 0xFF7
mov [ebp+FAT.fatEND], 0xFFF
mov [ebp+FAT.fatMASK], 0xFFF
mov al, 12
mov [ebp+FAT.fs_type], al
; For FAT12, allocate&read data for entire table:
; calculate A = ALIGN_UP(NUM_CLUSTERS, 8),
; calculatefatchain/restorefatchain will process A items,
; allocate ALIGN_UP(A*3/2, 512) bytes for FAT table plus A*2 bytes for unpacked data.
mov eax, [ebp+FAT.LAST_CLUSTER]
and eax, not 7
add eax, 8
mov edx, eax
lea eax, [eax*3]
add eax, 512*2-1
shr eax, 10
shl eax, 9
lea eax, [eax+edx*2]
call malloc
test eax, eax
jz .free_return0
; Read ALIGN_UP(NUM_CLUSTERS*3/2, 512) bytes.
; Note that this can be less than allocated, this is ok,
; overallocation simplifies calculatefatchain/restorefatchain.
push ebx
mov [ebp+FAT.fat_cache_ptr], eax
mov edx, [ebp+FAT.LAST_CLUSTER]
lea edx, [(edx+1)*3 + 512*2-1]
shr edx, 10
xchg eax, ebx
xor eax, eax
.read_fat:
push eax
add eax, [ebp+FAT.FAT_START]
call fs_read32_sys
test eax, eax
pop eax
jz @f
dbgstr 'Failed to read FAT table'
mov eax, [ebp+FAT.fat_cache_ptr]
call free
pop ebx
jmp .free_return0
@@:
add ebx, 512
inc eax
cmp eax, edx
jb .read_fat
mov [ebp+FAT.fat12_unpacked_ptr], ebx
call calculatefatchain
pop ebx
mov eax, ebp
pop ebp
ret
 
fat_free:
push eax
mov eax, [eax+FAT.fat_cache_ptr]
call free
pop eax
jmp free
 
calculatefatchain:
 
pushad
 
mov esi, [ebp+FAT.fat_cache_ptr]
mov edi, [ebp+FAT.fat12_unpacked_ptr]
 
mov edx, [ebp+FAT.LAST_CLUSTER]
and edx, not 7
lea edx, [edi+(edx+8)*2]
push edx
 
fcnew:
mov eax, dword [esi]
mov ebx, dword [esi+4]
mov ecx, dword [esi+8]
mov edx, ecx
shr edx, 4;8 ok
shr dx, 4;7 ok
xor ch, ch
shld ecx, ebx, 20;6 ok
shr cx, 4;5 ok
shld ebx, eax, 12
and ebx, 0x0fffffff;4 ok
shr bx, 4;3 ok
shl eax, 4
and eax, 0x0fffffff;2 ok
shr ax, 4;1 ok
mov dword [edi], eax
mov dword [edi+4], ebx
mov dword [edi+8], ecx
mov dword [edi+12], edx
add edi, 16
add esi, 12
 
cmp edi, [esp]
jnz fcnew
pop eax
 
popad
ret
 
 
restorefatchain: ; restore fat chain
 
pushad
 
mov esi, [ebp+FAT.fat12_unpacked_ptr]
mov edi, [ebp+FAT.fat_cache_ptr]
 
mov edx, [ebp+FAT.LAST_CLUSTER]
and edx, not 7
lea edx, [esi+(edx+8)*2]
 
fcnew2:
mov eax, dword [esi]
mov ebx, dword [esi+4]
shl ax, 4
shl eax, 4
shl bx, 4
shr ebx, 4
shrd eax, ebx, 8
shr ebx, 8
mov dword [edi], eax
mov word [edi+4], bx
add edi, 6
add esi, 8
 
cmp esi, edx
jb fcnew2
 
mov esi, [ebp+FAT.NUMBER_OF_FATS]
mov edx, [ebp+FAT.LAST_CLUSTER]
lea edx, [(edx+1)*3 + 512*2-1]
shr edx, 10
push [ebp+FAT.FAT_START]
 
.write_fats:
xor eax, eax
mov ebx, [ebp+FAT.fat_cache_ptr]
.loop1:
push eax
add eax, [esp+4]
call fs_write32_sys
test eax, eax
pop eax
jnz .fail
add ebx, 512
inc eax
cmp eax, edx
jb .loop1
pop eax
add eax, [ebp+FAT.SECTORS_PER_FAT]
push eax
dec esi
jnz .write_fats
pop eax
 
popad
ret
.fail:
dbgstr 'Failed to save FAT'
popad
ret
 
iglobal
label fat_legal_chars byte
; 0 = not allowed
; 1 = allowed only in long names
; 3 = allowed
times 32 db 0
; ! " # $ % & ' ( ) * + , - . /
db 1,3,0,3,3,3,3,3,3,3,0,1,1,3,3,0
; 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
db 3,3,3,3,3,3,3,3,3,3,0,1,0,1,0,0
; @ A B C D E F G H I J K L M N O
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
; P Q R S T U V W X Y Z [ \ ] ^ _
db 3,3,3,3,3,3,3,3,3,3,3,1,0,1,3,3
; ` a b c d e f g h i j k l m n o
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
; p q r s t u v w x y z { | } ~
db 3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,0
endg
 
fat_name_is_legal:
; in: esi->(long) name
; out: CF set <=> legal
; destroys eax
push esi
xor eax, eax
@@:
lodsb
test al, al
jz .done
cmp al, 80h
jae .big
test [fat_legal_chars+eax], 1
jnz @b
.err:
pop esi
clc
ret
.big:
; 0x80-0xAF, 0xE0-0xEF
cmp al, 0xB0
jb @b
cmp al, 0xE0
jb .err
cmp al, 0xF0
jb @b
jmp .err
.done:
sub esi, [esp]
cmp esi, 257
pop esi
ret
 
fat_next_short_name:
; in: edi->8+3 name
; out: name corrected
; CF=1 <=> error
pushad
mov ecx, 8
mov al, '~'
std
push edi
add edi, 7
repnz scasb
pop edi
cld
jz .tilde
; tilde is not found, insert "~1" at end
add edi, 6
cmp word [edi], ' '
jnz .insert_tilde
@@:
dec edi
cmp byte [edi], ' '
jz @b
inc edi
.insert_tilde:
mov word [edi], '~1'
popad
clc
ret
.tilde:
push edi
add edi, 7
xor ecx, ecx
@@:
; after tilde may be only digits and trailing spaces
cmp byte [edi], '~'
jz .break
cmp byte [edi], ' '
jz .space
cmp byte [edi], '9'
jnz .found
dec edi
jmp @b
.space:
dec edi
inc ecx
jmp @b
.found:
inc byte [edi]
add dword [esp], 8
jmp .zerorest
.break:
jecxz .noplace
inc edi
mov al, '1'
@@:
xchg al, [edi]
inc edi
cmp al, ' '
mov al, '0'
jnz @b
.succ:
pop edi
popad
clc
ret
.noplace:
dec edi
cmp edi, [esp]
jz .err
add dword [esp], 8
mov word [edi], '~1'
inc edi
inc edi
@@:
mov byte [edi], '0'
.zerorest:
inc edi
cmp edi, [esp]
jb @b
pop edi
popad
;clc ; automatically
ret
.err:
pop edi
popad
stc
ret
 
fat_gen_short_name:
; in: esi->long name
; edi->buffer (8+3=11 chars)
; out: buffer filled
pushad
mov eax, ' '
push edi
stosd
stosd
stosd
pop edi
xor eax, eax
movi ebx, 8
lea ecx, [edi+8]
.loop:
lodsb
test al, al
jz .done
call char_toupper
cmp al, ' '
jz .space
cmp al, 80h
ja .big
test [fat_legal_chars+eax], 2
jnz .symbol
.inv_symbol:
mov al, '_'
or bh, 1
.symbol:
cmp al, '.'
jz .dot
.normal_symbol:
dec bl
jns .store
mov bl, 0
.space:
or bh, 1
jmp .loop
.store:
stosb
jmp .loop
.big:
cmp al, 0xB0
jb .normal_symbol
cmp al, 0xE0
jb .inv_symbol
cmp al, 0xF0
jb .normal_symbol
jmp .inv_symbol
.dot:
test bh, 2
jz .firstdot
pop ebx
add ebx, edi
sub ebx, ecx
push ebx
cmp ebx, ecx
jb @f
pop ebx
push ecx
@@:
cmp edi, ecx
jbe .skip
@@:
dec edi
mov al, [edi]
dec ebx
mov [ebx], al
mov byte [edi], ' '
cmp edi, ecx
ja @b
.skip:
mov bh, 3
jmp @f
.firstdot:
cmp bl, 8
jz .space
push edi
or bh, 2
@@:
mov edi, ecx
mov bl, 3
jmp .loop
.done:
test bh, 2
jz @f
pop edi
@@:
lea edi, [ecx-8]
test bh, 1
jz @f
call fat_next_short_name
@@:
popad
ret
 
fat12_free_space:
;---------------------------------------------
;
; returns free space in edi
; rewr.by Mihasik
;---------------------------------------------
 
push eax ebx ecx
 
mov edi, [ebp+FAT.fat12_unpacked_ptr];start of FAT
xor ax, ax;Free cluster=0x0000 in FAT
xor ebx, ebx;counter
mov ecx, [ebp+FAT.LAST_CLUSTER]
inc ecx
cld
rdfs1:
repne scasw
jnz rdfs2 ;if last cluster not 0
inc ebx
test ecx, ecx
jnz rdfs1
rdfs2:
shl ebx, 9;free clusters*512
mov edi, ebx
 
pop ecx ebx eax
ret
 
 
 
set_FAT:
;--------------------------------
; input : EAX = cluster
; EDX = value to save
; EBP = pointer to FAT structure
; output : EDX = old value
;--------------------------------
; out: CF set <=> error
push eax ebx esi
 
cmp eax, 2
jb sfc_error
cmp eax, [ebp+FAT.LAST_CLUSTER]
ja sfc_error
cmp [ebp+FAT.fs_type], 12
je set_FAT12
cmp [ebp+FAT.fs_type], 16
je sfc_1
add eax, eax
sfc_1:
add eax, eax
mov esi, 511
and esi, eax ; esi = position in fat sector
shr eax, 9 ; eax = fat sector
add eax, [ebp+FAT.FAT_START]
mov ebx, [ebp+FAT.fat_cache_ptr]
 
cmp eax, [ebp+FAT.fat_in_cache]; is fat sector already in memory?
je sfc_in_cache ; yes
 
cmp [ebp+FAT.fat_change], 0; is fat changed?
je sfc_no_change ; no
call write_fat_sector; yes. write it into disk
jc sfc_error
 
sfc_no_change:
mov [ebp+FAT.fat_in_cache], eax; save fat sector
call fs_read32_sys
test eax, eax
jne sfc_error
 
 
sfc_in_cache:
cmp [ebp+FAT.fs_type], 16
jne sfc_test32
 
sfc_set16:
xchg [ebx+esi], dx ; save new value and get old value
jmp sfc_write
 
sfc_test32:
mov eax, [ebp+FAT.fatMASK]
 
sfc_set32:
and edx, eax
xor eax, -1 ; mask for high bits
and eax, [ebx+esi] ; get high 4 bits
or eax, edx
mov edx, [ebx+esi] ; get old value
mov [ebx+esi], eax ; save new value
 
sfc_write:
mov [ebp+FAT.fat_change], 1; fat has changed
 
sfc_nonzero:
and edx, [ebp+FAT.fatMASK]
 
sfc_return:
pop esi ebx eax
ret
sfc_error:
stc
jmp sfc_return
 
set_FAT12:
test edx, 0xF000
jnz sfc_error
mov ebx, [ebp+FAT.fat12_unpacked_ptr]
xchg [ebx+eax*2], dx
mov [ebp+FAT.fat_change], 1
pop esi ebx eax
clc
ret
 
get_FAT:
;--------------------------------
; input : EAX = cluster
; EBP = pointer to FAT structure
; output : EAX = next cluster
;--------------------------------
; out: CF set <=> error
push ebx esi
 
cmp [ebp+FAT.fs_type], 12
je get_FAT12
 
cmp [ebp+FAT.fs_type], 16
je gfc_1
add eax, eax
gfc_1:
add eax, eax
mov esi, 511
and esi, eax ; esi = position in fat sector
shr eax, 9 ; eax = fat sector
add eax, [ebp+FAT.FAT_START]
mov ebx, [ebp+FAT.fat_cache_ptr]
 
cmp eax, [ebp+FAT.fat_in_cache]; is fat sector already in memory?
je gfc_in_cache
 
cmp [ebp+FAT.fat_change], 0; is fat changed?
je gfc_no_change ; no
call write_fat_sector; yes. write it into disk
jc hd_error_01
 
gfc_no_change:
mov [ebp+FAT.fat_in_cache], eax
call fs_read32_sys
test eax, eax
jne hd_error_01
 
gfc_in_cache:
mov eax, [ebx+esi]
and eax, [ebp+FAT.fatMASK]
gfc_return:
pop esi ebx
ret
hd_error_01:
stc
jmp gfc_return
 
get_FAT12:
mov ebx, [ebp+FAT.fat12_unpacked_ptr]
movzx eax, word [ebx+eax*2]
pop esi ebx
clc
ret
 
 
get_free_FAT:
;-----------------------------------------------------------
; output : if CARRY=0 EAX = # first cluster found free
; if CARRY=1 disk full
; Note : for more speed need to use fat_cache directly
;-----------------------------------------------------------
push ecx
mov ecx, [ebp+FAT.LAST_CLUSTER]; counter for full disk
mov eax, [ebp+FAT.fatStartScan]
cmp [ebp+FAT.fs_type], 12
jz get_free_FAT12
dec ecx
cmp eax, 2
jb gff_reset
 
gff_test:
cmp eax, [ebp+FAT.LAST_CLUSTER]; if above last cluster start at cluster 2
jbe gff_in_range
gff_reset:
mov eax, 2
 
gff_in_range:
push eax
call get_FAT ; get cluster state
jc gff_not_found_1
 
test eax, eax ; is it free?
pop eax
je gff_found ; yes
inc eax ; next cluster
dec ecx ; is all checked?
jnz gff_test ; no
 
gff_not_found:
pop ecx ; yes. disk is full
stc
ret
 
gff_not_found_1:
pop eax
jmp gff_not_found
 
gff_found:
lea ecx, [eax+1]
mov [ebp+FAT.fatStartScan], ecx
pop ecx
clc
ret
 
get_free_FAT12:
push edx edi
mov edi, [ebp+FAT.fat12_unpacked_ptr]
cmp eax, 2
jb .reset
cmp eax, ecx
jbe @f
.reset:
mov eax, 2
@@:
mov edx, eax
lea edi, [edi+eax*2]
sub ecx, eax
inc ecx
xor eax, eax
repnz scasw
jz .found
cmp edx, 2
jz .notfound
mov edi, [ebp+FAT.fat12_unpacked_ptr]
lea ecx, [edx-2]
repnz scasw
jnz .notfound
.found:
sub edi, [ebp+FAT.fat12_unpacked_ptr]
shr edi, 1
mov [ebp+FAT.fatStartScan], edi
lea eax, [edi-1]
pop edi edx ecx
ret
.notfound:
pop edi edx ecx
stc
ret
 
 
write_fat_sector:
;-----------------------------------------------------------
; write changed fat to disk
;-----------------------------------------------------------
push eax ebx ecx
 
mov [ebp+FAT.fat_change], 0
mov eax, [ebp+FAT.fat_in_cache]
cmp eax, -1
jz write_fat_not_used
mov ebx, [ebp+FAT.fat_cache_ptr]
mov ecx, [ebp+FAT.NUMBER_OF_FATS]
 
write_next_fat:
push eax
call fs_write32_sys
test eax, eax
pop eax
jnz write_fat_not_used
 
add eax, [ebp+FAT.SECTORS_PER_FAT]
dec ecx
jnz write_next_fat
 
write_fat_not_used:
pop ecx ebx eax
ret
 
 
 
 
 
bcd2bin:
;----------------------------------
; input : AL=BCD number (eg. 0x11)
; output : AH=0
; AL=decimal number (eg. 11)
;----------------------------------
xor ah, ah
shl ax, 4
shr al, 4
aad
ret
 
 
get_date_for_file:
;-----------------------------------------------------
; Get date from CMOS and pack day,month,year in AX
; DATE bits 0..4 : day of month 0..31
; 5..8 : month of year 1..12
; 9..15 : count of years from 1980
;-----------------------------------------------------
mov al, 0x7 ;day
out 0x70, al
in al, 0x71
call bcd2bin
ror eax, 5
 
mov al, 0x8 ;month
out 0x70, al
in al, 0x71
call bcd2bin
ror eax, 4
 
mov al, 0x9 ;year
out 0x70, al
in al, 0x71
call bcd2bin
add ax, 20 ;because CMOS return only the two last
;digit (eg. 2000 -> 00 , 2001 -> 01) and we
rol eax, 9 ;need the difference with 1980 (eg. 2001-1980)
ret
 
 
get_time_for_file:
;-----------------------------------------------------
; Get time from CMOS and pack hour,minute,second in AX
; TIME bits 0..4 : second (the low bit is lost)
; 5..10 : minute 0..59
; 11..15 : hour 0..23
;-----------------------------------------------------
mov al, 0x0 ;second
out 0x70, al
in al, 0x71
call bcd2bin
ror eax, 6
 
mov al, 0x2 ;minute
out 0x70, al
in al, 0x71
call bcd2bin
ror eax, 6
 
mov al, 0x4 ;hour
out 0x70, al
in al, 0x71
call bcd2bin
rol eax, 11
ret
 
 
set_current_time_for_entry:
;-----------------------------------------------------
; Set current time/date for file entry
; input : ebx = file entry pointer
;-----------------------------------------------------
push eax
call get_time_for_file; update files date/time
mov [ebx+22], ax
call get_date_for_file
mov [ebx+24], ax
pop eax
ret
 
 
 
add_disk_free_space:
;-----------------------------------------------------
; input : ecx = cluster count
; Note : negative = remove clusters from free space
; positive = add clusters to free space
;-----------------------------------------------------
test ecx, ecx ; no change
je add_dfs_no
cmp [ebp+FAT.fs_type], 32 ; free disk space only used by fat32
jne add_dfs_no
 
push eax ebx
mov eax, [ebp+FAT.ADR_FSINFO]
lea ebx, [ebp+FAT.fsinfo_buffer]
call fs_read32_sys
test eax, eax
jnz add_not_fs
 
cmp dword [ebx+0x1fc], 0xaa550000; check sector id
jne add_not_fs
 
add [ebx+0x1e8], ecx
push [ebp+FAT.fatStartScan]
pop dword [ebx+0x1ec]
mov eax, [ebp+FAT.ADR_FSINFO]
call fs_write32_sys
; jc add_not_fs
 
add_not_fs:
pop ebx eax
 
add_dfs_no:
ret
 
 
 
clear_cluster_chain:
;-----------------------------------------------------
; input : eax = first cluster
;-----------------------------------------------------
push eax ecx edx
xor ecx, ecx ; cluster count
 
clean_new_chain:
cmp eax, [ebp+FAT.LAST_CLUSTER]; end of file
ja delete_OK
cmp eax, 2 ; unfinished fat chain or zero length file
jb delete_OK
cmp eax, [ebp+FAT.ROOT_CLUSTER]; don't remove root cluster
jz delete_OK
 
xor edx, edx
call set_FAT ; clear fat entry
jc access_denied_01
 
inc ecx ; update cluster count
mov eax, edx ; old cluster
jmp clean_new_chain
 
delete_OK:
call add_disk_free_space; add clusters to free disk space
clc
access_denied_01:
pop edx ecx eax
ret
 
 
if 0
get_hd_info:
;-----------------------------------------------------------
; output : eax = 0 - ok
; 3 - unknown FS
; 10 - access denied
; edx = cluster size in bytes
; ebx = total clusters on disk
; ecx = free clusters on disk
;-----------------------------------------------------------
cmp [ebp+FAT.fs_type], 16
jz info_fat_ok
cmp [ebp+FAT.fs_type], 32
jz info_fat_ok
xor edx, edx
xor ebx, ebx
xor ecx, ecx
mov eax, ERROR_UNKNOWN_FS
ret
 
info_fat_ok:
; call reserve_hd1
 
xor ecx, ecx ; count of free clusters
mov eax, 2
mov ebx, [ebp+FAT.LAST_CLUSTER]
 
info_cluster:
push eax
call get_FAT ; get cluster info
jc info_access_denied
 
test eax, eax ; is it free?
jnz info_used ; no
inc ecx
 
info_used:
pop eax
inc eax
cmp eax, ebx ; is above last cluster?
jbe info_cluster ; no. test next cluster
 
dec ebx ; cluster count
imul edx, [ebp+FAT.SECTORS_PER_CLUSTER], 512; cluster size in bytes
xor eax, eax
ret
 
info_access_denied:
add esp, 4
xor edx, edx
xor ebx, ebx
xor ecx, ecx
mov eax, ERROR_ACCESS_DENIED
ret
end if
 
update_disk:
cmp [ebp+FAT.fat_change], 0 ; is fat changed?
je upd_no_change
cmp [ebp+FAT.fs_type], 12
jz .fat12
;-----------------------------------------------------------
; write changed fat and cache to disk
;-----------------------------------------------------------
 
call write_fat_sector
jc update_disk_acces_denied
jmp upd_no_change
.fat12:
call restorefatchain
mov [ebp+FAT.fat_change], 0
 
upd_no_change:
 
push esi
mov esi, [ebp+PARTITION.Disk]
call disk_sync
pop esi
update_disk_acces_denied:
ret
 
fat_lock:
lea ecx, [ebp+FAT.Lock]
jmp mutex_lock
fat_unlock:
lea ecx, [ebp+FAT.Lock]
jmp mutex_unlock
 
; \begin{diamond}
uni2ansi_str:
; convert UNICODE zero-terminated string to ASCII-string (codepage 866)
; in: esi->source, edi->buffer (may be esi=edi)
; destroys: eax,esi,edi
lodsw
test ax, ax
jz .done
cmp ax, 0x80
jb .ascii
cmp ax, 0x401
jz .yo1
cmp ax, 0x451
jz .yo2
cmp ax, 0x410
jb .unk
cmp ax, 0x440
jb .rus1
cmp ax, 0x450
jb .rus2
.unk:
mov al, '_'
jmp .doit
.yo1:
mov al, 0xF0 ; 'Ё'
jmp .doit
.yo2:
mov al, 0xF1 ; 'ё'
jmp .doit
.rus1:
; 0x410-0x43F -> 0x80-0xAF
add al, 0x70
jmp .doit
.rus2:
; 0x440-0x44F -> 0xE0-0xEF
add al, 0xA0
.ascii:
.doit:
stosb
jmp uni2ansi_str
.done:
mov byte [edi], 0
ret
 
ansi2uni_char:
; convert ANSI character in al to UNICODE character in ax, using cp866 encoding
mov ah, 0
; 0x00-0x7F - trivial map
cmp al, 0x80
jb .ret
; 0x80-0xAF -> 0x410-0x43F
cmp al, 0xB0
jae @f
add ax, 0x410-0x80
.ret:
ret
@@:
; 0xE0-0xEF -> 0x440-0x44F
cmp al, 0xE0
jb .unk
cmp al, 0xF0
jae @f
add ax, 0x440-0xE0
ret
; 0xF0 -> 0x401
; 0xF1 -> 0x451
@@:
cmp al, 0xF0 ; 'Ё'
jz .yo1
cmp al, 0xF1 ; 'ё'
jz .yo2
.unk:
mov al, '_' ; ah=0
ret
.yo1:
mov ax, 0x401
ret
.yo2:
mov ax, 0x451
ret
 
char_toupper:
; convert character to uppercase, using cp866 encoding
; in: al=symbol
; out: al=converted symbol
cmp al, 'a'
jb .ret
cmp al, 'z'
jbe .az
cmp al, 0xF1 ; 'ё'
jz .yo1
cmp al, 0xA0 ; 'а'
jb .ret
cmp al, 0xE0 ; 'р'
jb .rus1
cmp al, 0xEF ; 'я'
ja .ret
; 0xE0-0xEF -> 0x90-0x9F
sub al, 0xE0-0x90
.ret:
ret
.rus1:
; 0xA0-0xAF -> 0x80-0x8F
.az:
and al, not 0x20
ret
.yo1:
; 0xF1 -> 0xF0
dec ax
ret
 
fat_get_name:
; in: edi->FAT entry
; out: CF=1 - no valid entry
; else CF=0 and ebp->ASCIIZ-name
; (maximum length of filename is 255 (wide) symbols without trailing 0,
; but implementation requires buffer 261 words)
; destroys eax
cmp byte [edi], 0
jz .no
cmp byte [edi], 0xE5
jnz @f
.no:
stc
ret
@@:
cmp byte [edi+11], 0xF
jz .longname
test byte [edi+11], 8
jnz .no
push ecx
push edi ebp
test byte [ebp-4], 1
jnz .unicode_short
 
mov eax, [edi]
mov ecx, [edi+4]
mov [ebp], eax
mov [ebp+4], ecx
 
mov ecx, 8
@@:
cmp byte [ebp+ecx-1], ' '
loope @b
 
mov eax, [edi+8]
cmp al, ' '
je .done
shl eax, 8
mov al, '.'
 
lea ebp, [ebp+ecx+1]
mov [ebp], eax
mov ecx, 3
@@:
rol eax, 8
cmp al, ' '
jne .done
loop @b
dec ebp
.done:
and byte [ebp+ecx+1], 0 ; CF=0
pop ebp edi ecx
ret
.unicode_short:
mov ecx, 8
push ecx
@@:
mov al, [edi]
inc edi
call ansi2uni_char
mov [ebp], ax
inc ebp
inc ebp
loop @b
pop ecx
@@:
cmp word [ebp-2], ' '
jnz @f
dec ebp
dec ebp
loop @b
@@:
mov word [ebp], '.'
inc ebp
inc ebp
mov ecx, 3
push ecx
@@:
mov al, [edi]
inc edi
call ansi2uni_char
mov [ebp], ax
inc ebp
inc ebp
loop @b
pop ecx
@@:
cmp word [ebp-2], ' '
jnz @f
dec ebp
dec ebp
loop @b
dec ebp
dec ebp
@@:
and word [ebp], 0 ; CF=0
pop ebp edi ecx
ret
.longname:
; LFN
mov al, byte [edi]
and eax, 0x3F
dec eax
cmp al, 20
jae .no ; ignore invalid entries
mov word [ebp+260*2], 0 ; force null-terminating for orphans
imul eax, 13*2
add ebp, eax
test byte [edi], 0x40
jz @f
mov word [ebp+13*2], 0
@@:
push eax
; now copy name from edi to ebp ...
mov eax, [edi+1]
mov [ebp], eax ; symbols 1,2
mov eax, [edi+5]
mov [ebp+4], eax ; 3,4
mov eax, [edi+9]
mov [ebp+8], ax ; 5
mov eax, [edi+14]
mov [ebp+10], eax ; 6,7
mov eax, [edi+18]
mov [ebp+14], eax ; 8,9
mov eax, [edi+22]
mov [ebp+18], eax ; 10,11
mov eax, [edi+28]
mov [ebp+22], eax ; 12,13
; ... done
pop eax
sub ebp, eax
test eax, eax
jz @f
; if this is not first entry, more processing required
stc
ret
@@:
; if this is first entry:
test byte [ebp-4], 1
jnz .ret
; buffer at ebp contains UNICODE name, convert it to ANSI
push esi edi
mov esi, ebp
mov edi, ebp
call uni2ansi_str
pop edi esi
.ret:
clc
ret
 
fat_compare_name:
; compares ASCIIZ-names, case-insensitive (cp866 encoding)
; in: esi->name, ebp->name
; out: if names match: ZF=1 and esi->next component of name
; else: ZF=0, esi is not changed
; destroys eax
push ebp esi
.loop:
mov al, [ebp]
inc ebp
call char_toupper
push eax
lodsb
call char_toupper
cmp al, [esp]
jnz .done
pop eax
test al, al
jnz .loop
dec esi
pop eax
pop ebp
xor eax, eax ; set ZF flag
ret
.done:
cmp al, '/'
jnz @f
cmp byte [esp], 0
jnz @f
mov [esp+4], esi
@@:
pop eax
pop esi ebp
ret
 
fat_find_lfn:
; in: esi->name
; [esp+4] = next
; [esp+8] = first
; [esp+C]... - possibly parameters for first and next
; out: CF=1 - file not found, eax=error code
; else CF=0, esi->next name component, edi->direntry
pusha
lea eax, [esp+0Ch+20h]
call dword [eax-4]
jc .reterr
sub esp, 262*2 ; reserve place for LFN
push 0 ; for fat_get_name: read ASCII name
.l1:
lea ebp, [esp+4]
call fat_get_name
jc .l2
call fat_compare_name
jz .found
.l2:
mov ebp, [esp+8+262*2+4]
lea eax, [esp+0Ch+20h+262*2+4]
call dword [eax-8]
jnc .l1
add esp, 262*2+4
.reterr:
mov [esp+28], eax
stc
popa
ret
.found:
add esp, 262*2+4
mov ebp, [esp+8]
; if this is LFN entry, advance to true entry
cmp byte [edi+11], 0xF
jnz @f
lea eax, [esp+0Ch+20h]
call dword [eax-8]
jc .reterr
@@:
add esp, 8 ; CF=0
push esi
push edi
popa
ret
 
fat_time_to_bdfe:
; in: eax=FAT time
; out: eax=BDFE time
push ecx edx
mov ecx, eax
mov edx, eax
shr eax, 11
shl eax, 16 ; hours
and edx, 0x1F
add edx, edx
mov al, dl ; seconds
shr ecx, 5
and ecx, 0x3F
mov ah, cl ; minutes
pop edx ecx
ret
 
fat_date_to_bdfe:
push ecx edx
mov ecx, eax
mov edx, eax
shr eax, 9
add ax, 1980
shl eax, 16 ; year
and edx, 0x1F
mov al, dl ; day
shr ecx, 5
and ecx, 0xF
mov ah, cl ; month
pop edx ecx
ret
 
bdfe_to_fat_time:
push edx
mov edx, eax
shr eax, 16
and dh, 0x3F
shl eax, 6
or al, dh
shr dl, 1
and dl, 0x1F
shl eax, 5
or al, dl
pop edx
ret
 
bdfe_to_fat_date:
push edx
mov edx, eax
shr eax, 16
sub ax, 1980
and dh, 0xF
shl eax, 4
or al, dh
and dl, 0x1F
shl eax, 5
or al, dl
pop edx
ret
 
fat_entry_to_bdfe:
; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi
; destroys eax
mov eax, [ebp-4]
mov [esi+4], eax ; ASCII/UNICODE name
fat_entry_to_bdfe2:
movzx eax, byte [edi+11]
mov [esi], eax ; attributes
movzx eax, word [edi+14]
call fat_time_to_bdfe
mov [esi+8], eax ; creation time
movzx eax, word [edi+16]
call fat_date_to_bdfe
mov [esi+12], eax ; creation date
and dword [esi+16], 0 ; last access time is not supported on FAT
movzx eax, word [edi+18]
call fat_date_to_bdfe
mov [esi+20], eax ; last access date
movzx eax, word [edi+22]
call fat_time_to_bdfe
mov [esi+24], eax ; last write time
movzx eax, word [edi+24]
call fat_date_to_bdfe
mov [esi+28], eax ; last write date
mov eax, [edi+28]
mov [esi+32], eax ; file size (low dword)
xor eax, eax
mov [esi+36], eax ; file size (high dword)
test ebp, ebp
jz .ret
push ecx edi
lea edi, [esi+40]
mov esi, ebp
test byte [esi-4], 1
jz .ansi
mov ecx, 260/2
rep movsd
mov [edi-2], ax
@@:
mov esi, edi
pop edi ecx
.ret:
ret
.ansi:
mov ecx, 264/4
rep movsd
mov [edi-1], al
jmp @b
 
bdfe_to_fat_entry:
; convert BDFE at edx to FAT entry at edi
; destroys eax
; attributes byte
test byte [edi+11], 8 ; volume label?
jnz @f
mov al, [edx]
and al, 0x27
and byte [edi+11], 0x10
or byte [edi+11], al
@@:
mov eax, [edx+8]
call bdfe_to_fat_time
mov [edi+14], ax ; creation time
mov eax, [edx+12]
call bdfe_to_fat_date
mov [edi+16], ax ; creation date
mov eax, [edx+20]
call bdfe_to_fat_date
mov [edi+18], ax ; last access date
mov eax, [edx+24]
call bdfe_to_fat_time
mov [edi+22], ax ; last write time
mov eax, [edx+28]
call bdfe_to_fat_date
mov [edi+24], ax ; last write date
ret
 
hd_find_lfn:
; in: ebp -> FAT structure
; in: esi+[esp+4] -> name
; out: CF=1 - file not found, eax=error code
; else CF=0 and edi->direntry, eax=sector
; destroys eax
push esi edi
push 0
push 0
push fat1x_root_first
push fat1x_root_next
mov eax, [ebp+FAT.ROOT_CLUSTER]
cmp [ebp+FAT.fs_type], 32
jz .fat32
.loop:
and [ebp+FAT.longname_sec1], 0
and [ebp+FAT.longname_sec2], 0
call fat_find_lfn
jc .notfound
cmp byte [esi], 0
jz .found
.continue:
test byte [edi+11], 10h
jz .notfound
and dword [esp+12], 0
mov eax, [edi+20-2]
mov ax, [edi+26] ; cluster
.fat32:
mov [esp+8], eax
mov dword [esp+4], fat_notroot_first
mov dword [esp], fat_notroot_next
jmp .loop
.notfound:
add esp, 16
pop edi esi
stc
ret 4
.found:
lea eax, [esp+4+24]
cmp dword [eax], 0
jz @f
mov esi, [eax]
and dword [eax], 0
jmp .continue
@@:
lea eax, [esp+8]
cmp dword [eax], 0
jz .root
call fat_get_sector
jmp .cmn
.root:
mov eax, [eax+4]
add eax, [ebp+FAT.ROOT_START]
.cmn:
add esp, 20 ; CF=0
pop esi
ret 4
 
;----------------------------------------------------------------
; fat_Read - FAT implementation of reading a file
; in: ebp = pointer to FAT structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
fat_Read:
call fat_lock
push edi
cmp byte [esi], 0
jnz @f
.noaccess:
pop edi
.noaccess_2:
call fat_unlock
or ebx, -1
mov eax, ERROR_ACCESS_DENIED
ret
 
@@:
stdcall hd_find_lfn, [esp+4+4]
jnc .found
pop edi
push eax
call fat_unlock
pop eax
or ebx, -1
ret
 
.found:
test byte [edi+11], 0x10; do not allow read directories
jnz .noaccess
cmp dword [ebx+8], 0
jz @f
xor ebx, ebx
.reteof:
call fat_unlock
mov eax, ERROR_END_OF_FILE
pop edi
ret
@@:
mov ecx, [ebx+12] ; size
mov edx, [ebx+16] ; pointer
mov ebx, [ebx+4] ; file offset
push edx
push 0
mov eax, [edi+28]
sub eax, ebx
jb .eof
cmp eax, ecx
jae @f
mov ecx, eax
mov byte [esp], 6
@@:
mov eax, [edi+20-2]
mov ax, [edi+26]
; now eax=cluster, ebx=position, ecx=count, edx=buffer for data
.new_cluster:
jecxz .new_sector
cmp eax, 2
jb .eof
cmp eax, [ebp+FAT.fatRESERVED]
jae .eof
mov [ebp+FAT.cluster_tmp], eax
dec eax
dec eax
mov edi, [ebp+FAT.SECTORS_PER_CLUSTER]
imul eax, edi
add eax, [ebp+FAT.DATA_START]
.new_sector:
test ecx, ecx
jz .done
sub ebx, 512
jae .skip
add ebx, 512
jnz .force_buf
cmp ecx, 512
jb .force_buf
; we may read directly to given buffer
push eax ebx
mov ebx, edx
call fs_read32_app
test eax, eax
pop ebx eax
jne .noaccess_1
add edx, 512
sub ecx, 512
jmp .skip
.force_buf:
; we must read sector to temporary buffer and then copy it to destination
push eax ebx
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
test eax, eax
mov eax, ebx
pop ebx
jne .noaccess_3
add eax, ebx
push ecx
add ecx, ebx
cmp ecx, 512
jbe @f
mov ecx, 512
@@:
sub ecx, ebx
mov ebx, edx
call memmove
add edx, ecx
sub [esp], ecx
pop ecx
pop eax
xor ebx, ebx
.skip:
inc eax
dec edi
jnz .new_sector
mov eax, [ebp+FAT.cluster_tmp]
call get_FAT
jc .noaccess_1
 
jmp .new_cluster
.noaccess_3:
pop eax
.noaccess_1:
pop eax
push ERROR_DEVICE
.done:
mov ebx, edx
call fat_unlock
pop eax edx edi
sub ebx, edx
ret
.eof:
mov ebx, edx
pop eax edx
sub ebx, edx
jmp .reteof
 
;----------------------------------------------------------------
; fat_ReadFolder - FAT implementation of reading a folder
; in: ebp = pointer to FAT structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
fat_ReadFolder:
call fat_lock
mov eax, [ebp+FAT.ROOT_CLUSTER]
push edi
cmp byte [esi], 0
jz .doit
stdcall hd_find_lfn, [esp+4+4]
jnc .found
pop edi
push eax
call fat_unlock
pop eax
or ebx, -1
ret
.found:
test byte [edi+11], 0x10 ; do not allow read files
jnz .found_dir
pop edi
call fat_unlock
or ebx, -1
mov eax, ERROR_ACCESS_DENIED
ret
.found_dir:
mov eax, [edi+20-2]
mov ax, [edi+26] ; eax=cluster
.doit:
push esi
sub esp, 262*2 ; reserve space for LFN
push dword [ebx+8] ; for fat_get_name: read ANSI/UNICODE name
mov edx, [ebx+16] ; pointer to buffer
; init header
push eax
mov edi, edx
mov ecx, 32/4
xor eax, eax
rep stosd
pop eax
mov byte [edx], 1 ; version
mov esi, edi ; esi points to BDFE
mov ecx, [ebx+12] ; number of blocks to read
mov ebx, [ebx+4] ; index of the first block
.new_cluster:
mov [ebp+FAT.cluster_tmp], eax
test eax, eax
jnz @f
cmp [ebp+FAT.fs_type], 32
jz .notfound
mov eax, [ebp+FAT.ROOT_START]
push [ebp+FAT.ROOT_SECTORS]
push ebx
jmp .new_sector
@@:
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
push [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
push ebx
.new_sector:
lea ebx, [ebp+FAT.buffer]
mov edi, ebx
push eax
call fs_read32_sys
test eax, eax
pop eax
jnz .notfound2
add ebx, 512
push eax
.l1:
push ebp
lea ebp, [esp+20]
call fat_get_name
pop ebp
jc .l2
cmp byte [edi+11], 0xF
jnz .do_bdfe
add edi, 0x20
cmp edi, ebx
jb .do_bdfe
pop eax
inc eax
dec dword [esp+4]
jnz @f
mov eax, [ebp+FAT.cluster_tmp]
test eax, eax
jz .done
call get_FAT
jc .notfound2
cmp eax, 2
jb .done
cmp eax, [ebp+FAT.fatRESERVED]
jae .done
push eax
mov eax, [ebp+FAT.SECTORS_PER_CLUSTER]
mov [esp+8], eax
pop eax
mov [ebp+FAT.cluster_tmp], eax
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
@@:
lea ebx, [ebp+FAT.buffer]
mov edi, ebx
push eax
call fs_read32_sys
test eax, eax
pop eax
jnz .notfound2
add ebx, 512
push eax
.do_bdfe:
inc dword [edx+8] ; new file found
dec dword [esp+4]
jns .l2
dec ecx
js .l2
inc dword [edx+4] ; new file block copied
push ebp
lea ebp, [esp+20]
call fat_entry_to_bdfe
pop ebp
.l2:
add edi, 0x20
cmp edi, ebx
jb .l1
pop eax
inc eax
dec dword [esp+4]
jnz .new_sector
mov eax, [ebp+FAT.cluster_tmp]
test eax, eax
jz .done
call get_FAT
jc .notfound2
cmp eax, 2
jb .done
cmp eax, [ebp+FAT.fatRESERVED]
jae .done
push eax
mov eax, [ebp+FAT.SECTORS_PER_CLUSTER]
mov [esp+8], eax
pop eax
pop ebx
add esp, 4
jmp .new_cluster
.notfound2:
add esp, 8
.notfound:
add esp, 262*2+4
pop esi edi
mov ebx, [edx+4]
call fat_unlock
mov eax, ERROR_DEVICE
ret
.done:
add esp, 262*2+4+8
mov ebx, [edx+4]
xor eax, eax
dec ecx
js @f
mov al, ERROR_END_OF_FILE
@@:
push eax
call fat_unlock
pop eax
pop esi edi
ret
 
fat1x_root_next:
push ecx
lea ecx, [ebp+FAT.buffer+0x200-0x20]
cmp edi, ecx
jae fat1x_root_next_sector
pop ecx
add edi, 0x20
ret ; CF=0
fat1x_root_next_sector:
; read next sector
push [ebp+FAT.longname_sec2]
pop [ebp+FAT.longname_sec1]
mov ecx, [eax+4]
push ecx
add ecx, [ebp+FAT.ROOT_START]
mov [ebp+FAT.longname_sec2], ecx
pop ecx
inc ecx
mov [eax+4], ecx
cmp ecx, [ebp+FAT.ROOT_SECTORS]
pop ecx
jb fat1x_root_first
mov eax, ERROR_FILE_NOT_FOUND
stc
ret
fat1x_root_first:
mov eax, [eax+4]
add eax, [ebp+FAT.ROOT_START]
push ebx
lea edi, [ebp+FAT.buffer]
mov ebx, edi
call fs_read32_sys
pop ebx
test eax, eax
jnz .readerr
ret ; CF=0
.readerr:
mov eax, ERROR_DEVICE
stc
ret
.notfound:
mov eax, ERROR_FILE_NOT_FOUND
stc
ret
fat1x_root_begin_write:
push edi eax
call fat1x_root_first
pop eax edi
ret
fat1x_root_end_write:
pusha
mov eax, [eax+4]
add eax, [ebp+FAT.ROOT_START]
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
popa
ret
fat1x_root_next_write:
push ecx
lea ecx, [ebp+FAT.buffer+0x200]
cmp edi, ecx
jae @f
pop ecx
ret
@@:
call fat1x_root_end_write
jmp fat1x_root_next_sector
fat1x_root_extend_dir:
stc
ret
 
fat_notroot_next:
push ecx
lea ecx, [ebp+FAT.buffer+0x200-0x20]
cmp edi, ecx
jae fat_notroot_next_sector
pop ecx
add edi, 0x20
ret ; CF=0
fat_notroot_next_sector:
push [ebp+FAT.longname_sec2]
pop [ebp+FAT.longname_sec1]
push eax
call fat_get_sector
mov [ebp+FAT.longname_sec2], eax
pop eax
mov ecx, [eax+4]
inc ecx
cmp ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
jae fat_notroot_next_cluster
mov [eax+4], ecx
jmp @f
fat_notroot_next_cluster:
push eax
mov eax, [eax]
call get_FAT
mov ecx, eax
pop eax
jc fat_notroot_first.deverr
cmp ecx, 2
jb fat_notroot_next_err
cmp ecx, [ebp+FAT.fatRESERVED]
jae fat_notroot_next_err
mov [eax], ecx
and dword [eax+4], 0
@@:
pop ecx
fat_notroot_first:
call fat_get_sector
push ebx
lea edi, [ebp+FAT.buffer]
mov ebx, edi
call fs_read32_sys
pop ebx
test eax, eax
jz .ret ; CF=0
push ecx
.deverr:
pop ecx
mov eax, ERROR_DEVICE
stc
.ret:
ret
fat_notroot_next_err:
pop ecx
mov eax, ERROR_FILE_NOT_FOUND
stc
ret
fat_notroot_begin_write:
push eax edi
call fat_notroot_first
pop edi eax
ret
fat_notroot_end_write:
call fat_get_sector
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
ret
fat_notroot_next_write:
push ecx
lea ecx, [ebp+FAT.buffer+0x200]
cmp edi, ecx
jae @f
pop ecx
ret
@@:
push eax
call fat_notroot_end_write
pop eax
jmp fat_notroot_next_sector
fat_notroot_extend_dir:
push eax
call get_free_FAT
jnc .found
pop eax
ret ; CF=1
.found:
push edx
mov edx, [ebp+FAT.fatEND]
call set_FAT
jc .writeerr
mov edx, eax
mov eax, [esp+4]
mov eax, [eax]
push edx
call set_FAT
pop edx
jnc @f
.writeerr:
pop edx
pop eax
stc
ret
@@:
push ecx
or ecx, -1
call add_disk_free_space
; zero new cluster
mov ecx, 512/4
lea edi, [ebp+FAT.buffer]
push edi
xor eax, eax
rep stosd
pop edi
pop ecx
mov eax, [esp+4]
mov [eax], edx
and dword [eax+4], 0
pop edx
mov eax, [eax]
dec eax
dec eax
push ebx ecx
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
imul eax, ecx
add eax, [ebp+FAT.DATA_START]
mov ebx, edi
@@:
push eax
call fs_write32_sys
pop eax
inc eax
loop @b
pop ecx ebx eax
clc
ret
 
fat_get_sector:
push ecx
mov ecx, [eax]
dec ecx
dec ecx
imul ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
add ecx, [ebp+FAT.DATA_START]
add ecx, [eax+4]
mov eax, ecx
pop ecx
ret
 
fshrad:
call fat_unlock
mov eax, ERROR_ACCESS_DENIED
xor ebx, ebx
ret
 
;----------------------------------------------------------------
; fat_CreateFolder - FAT implementation of creating a folder
; in: ebp = pointer to FAT structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
fat_CreateFolder:
push 1
jmp fat_Rewrite.common
 
;----------------------------------------------------------------
; fat_Rewrite - FAT implementation of creating a new file
; in: ebp = pointer to FAT structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
fat_Rewrite:
push 0
.common:
call fat_lock
pop eax
cmp byte [esi], 0
jz fshrad
mov ecx, [ebx+12]
mov edx, [ebx+16]
pushad
xor edi, edi
mov edx, [esp+4+20h]
push esi
test edx, edx
jz @f
mov esi, edx
@@:
lodsb
test al, al
jz @f
cmp al, '/'
jnz @b
lea edi, [esi-1]
jmp @b
@@:
pop esi
test edi, edi
jnz .noroot
test edx, edx
jnz .hasebp
mov edx, [ebp+FAT.ROOT_CLUSTER]
cmp [ebp+FAT.fs_type], 32
jz .pushnotroot
xor edx, edx
push edx
push fat1x_root_extend_dir
push fat1x_root_end_write
push fat1x_root_next_write
push fat1x_root_begin_write
push edx
push edx
push fat1x_root_first
push fat1x_root_next
jmp .common1
.hasebp:
mov eax, ERROR_ACCESS_DENIED
cmp byte [edx], 0
jz .ret1
stdcall hd_find_lfn, 0
mov esi, [esp+4+20h]
jc .ret1
jmp .common0
.noroot:
mov eax, ERROR_ACCESS_DENIED
cmp byte [edi+1], 0
jz .ret1
; check existence
mov byte [edi], 0
push edi
stdcall hd_find_lfn, [esp+4+24h]
pop esi
mov byte [esi], '/'
jnc @f
.notfound0:
mov eax, ERROR_FILE_NOT_FOUND
.ret1:
mov [esp+28], eax
call fat_unlock
popad
xor ebx, ebx
ret
@@:
inc esi
.common0:
test byte [edi+11], 0x10 ; must be directory
mov eax, ERROR_ACCESS_DENIED
jz .ret1
mov edx, [edi+20-2]
mov dx, [edi+26] ; ebp=cluster
mov eax, ERROR_FAT_TABLE
cmp edx, 2
jb .ret1
.pushnotroot:
push edx
push fat_notroot_extend_dir
push fat_notroot_end_write
push fat_notroot_next_write
push fat_notroot_begin_write
push 0
push edx
push fat_notroot_first
push fat_notroot_next
.common1:
call fat_find_lfn
jc .notfound
; found
test byte [edi+11], 10h
jz .exists_file
; found directory; if we are creating directory, return OK,
; if we are creating file, say "access denied"
add esp, 36
call fat_unlock
popad
test al, al
mov eax, ERROR_ACCESS_DENIED
jz @f
mov al, 0
@@:
xor ebx, ebx
ret
.exists_file:
; found file; if we are creating directory, return "access denied",
; if we are creating file, delete existing file and continue
cmp byte [esp+36+28], 0
jz @f
add esp, 36
call fat_unlock
popad
mov eax, ERROR_ACCESS_DENIED
xor ebx, ebx
ret
@@:
; delete FAT chain
push edi
xor eax, eax
mov dword [edi+28], eax ; zero size
xor ecx, ecx
mov eax, [edi+20-2]
mov ax, [edi+26]
mov word [edi+20], cx
mov word [edi+26], cx
test eax, eax
jz .done1
@@:
cmp eax, [ebp+FAT.fatRESERVED]
jae .done1
push edx
xor edx, edx
call set_FAT
mov eax, edx
pop edx
jc .done1
inc ecx
jmp @b
.done1:
pop edi
call get_time_for_file
mov [edi+22], ax
call get_date_for_file
mov [edi+24], ax
mov [edi+18], ax
or byte [edi+11], 20h ; set 'archive' attribute
jmp .doit
.notfound:
; file is not found; generate short name
call fat_name_is_legal
jc @f
add esp, 36
call fat_unlock
popad
mov eax, ERROR_FILE_NOT_FOUND
xor ebx, ebx
ret
@@:
sub esp, 12
mov edi, esp
call fat_gen_short_name
.test_short_name_loop:
push esi edi ecx
mov esi, edi
lea eax, [esp+12+12+8]
mov edx, [eax+24]
mov [eax], edx
and dword [eax+4], 0
call dword [eax-4]
jc .found
.test_short_name_entry:
cmp byte [edi+11], 0xF
jz .test_short_name_cont
mov ecx, 11
push esi edi
repz cmpsb
pop edi esi
jz .short_name_found
.test_short_name_cont:
lea eax, [esp+12+12+8]
call dword [eax-8]
jnc .test_short_name_entry
jmp .found
.short_name_found:
pop ecx edi esi
call fat_next_short_name
jnc .test_short_name_loop
.disk_full:
add esp, 12+36
call fat_unlock
popa
mov eax, ERROR_DISK_FULL
xor ebx, ebx
ret
.found:
pop ecx edi esi
; now find space in directory
; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~'
mov al, '~'
push ecx edi
mov ecx, 8
repnz scasb
movi eax, 1 ; 1 entry
jnz .notilde
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total
xor eax, eax
@@:
cmp byte [esi], 0
jz @f
inc esi
inc eax
jmp @b
@@:
sub esi, eax
add eax, 12+13
mov ecx, 13
push edx
cdq
div ecx
pop edx
.notilde:
push -1
push -1
push -1
; find <eax> successive entries in directory
xor ecx, ecx
push eax
lea eax, [esp+16+8+12+8]
mov edx, [eax+24]
mov [eax], edx
and dword [eax+4], 0
call dword [eax-4]
pop eax
jnc .scan_dir
.fsfrfe3:
add esp, 12+8+12+36
call fat_unlock
popad
mov eax, ERROR_DEVICE
xor ebx, ebx
ret
.scan_dir:
cmp byte [edi], 0
jz .free
cmp byte [edi], 0xE5
jz .free
xor ecx, ecx
.scan_cont:
push eax
lea eax, [esp+16+8+12+8]
call dword [eax-8]
mov edx, eax
pop eax
jnc .scan_dir
cmp edx, ERROR_DEVICE
jz .fsfrfe3
push eax
lea eax, [esp+16+8+12+8]
call dword [eax+20] ; extend directory
pop eax
jnc .scan_dir
add esp, 12+8+12+36
call fat_unlock
popad
mov eax, ERROR_DISK_FULL
xor ebx, ebx
ret
.free:
test ecx, ecx
jnz @f
mov [esp], edi
mov ecx, [esp+12+8+12+8]
mov [esp+4], ecx
mov ecx, [esp+12+8+12+12]
mov [esp+8], ecx
xor ecx, ecx
@@:
inc ecx
cmp ecx, eax
jb .scan_cont
; found!
push esi ecx
; If creating a directory, allocate one data cluster now and fail immediately
; if this is impossible. This prevents from creating an invalid directory entry
; on a full disk.
; yup, the argument is quite non-intuitive... but what should I do if
; the entire function uses such arguments? BTW, it refers to al from pushad,
; which in turn is filled with 0 in fat_Rewrite and 1 in fat_CreateFolder.
cmp byte [esp+8+12+8+12+36+28], 0
jz .no.preallocate.folder.data
call get_free_FAT
jnc @f
add esp, 8+12+8
jmp .disk_full
@@:
mov [esp+8+12+8+12+36+20], eax ; store the cluster somewhere
.no.preallocate.folder.data:
; calculate name checksum
mov esi, [esp+8+12]
mov ecx, 11
xor eax, eax
@@:
ror al, 1
add al, [esi]
inc esi
loop @b
pop ecx esi
pop edi
pop dword [esp+8+12+12]
pop dword [esp+8+12+12]
; edi points to first entry in free chunk
dec ecx
jz .nolfn
push esi
push eax
lea eax, [esp+8+8+12+8]
call dword [eax+8] ; begin write
mov al, 40h
.writelfn:
or al, cl
mov esi, [esp+4]
push ecx
dec ecx
imul ecx, 13
add esi, ecx
stosb
mov cl, 5
call fat_read_symbols
mov ax, 0xF
stosw
mov al, [esp+4]
stosb
mov cl, 6
call fat_read_symbols
xor eax, eax
stosw
mov cl, 2
call fat_read_symbols
pop ecx
lea eax, [esp+8+8+12+8]
call dword [eax+12] ; next write
xor eax, eax
loop .writelfn
pop eax
pop esi
; lea eax, [esp+8+12+8]
; call dword [eax+16] ; end write
.nolfn:
xchg esi, [esp]
mov ecx, 11
rep movsb
mov word [edi], 20h ; attributes
sub edi, 11
pop esi ecx
add esp, 12
mov byte [edi+13], 0 ; tenths of a second at file creation time
call get_time_for_file
mov [edi+14], ax ; creation time
mov [edi+22], ax ; last write time
call get_date_for_file
mov [edi+16], ax ; creation date
mov [edi+24], ax ; last write date
mov [edi+18], ax ; last access date
xor ecx, ecx
mov word [edi+20], cx ; high word of cluster
mov word [edi+26], cx ; low word of cluster - to be filled
mov dword [edi+28], ecx ; file size - to be filled
cmp byte [esp+36+28], cl
jz .doit
; create directory
mov byte [edi+11], 10h ; attributes: folder
mov esi, edi
lea eax, [esp+8]
call dword [eax+16] ; flush directory
mov eax, [esp+36+20] ; extract saved cluster
mov [esp+36+20], edi ; this is needed for calculating arg of add_disk_free_space!
push ecx
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
shl ecx, 9
push ecx
push edi
jmp .doit2
.doit:
mov esi, [esp+36+20]
lea eax, [esp+8]
call dword [eax+16] ; flush directory
push ecx
mov ecx, [esp+4+36+24]
push ecx
push edi
test ecx, ecx
jz .done
call get_free_FAT
jc .diskfull
.doit2:
push eax
mov [edi+26], ax
shr eax, 16
mov [edi+20], ax
lea eax, [esp+16+8]
call dword [eax+16] ; flush directory
pop eax
push edx
mov edx, [ebp+FAT.fatEND]
call set_FAT
pop edx
.write_cluster:
push eax
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
push [ebp+FAT.SECTORS_PER_CLUSTER]
; write data
.write_sector:
cmp byte [esp+20+36+28], 0
jnz .writedir
mov ecx, 512
cmp dword [esp+12], ecx
jb .writeshort
; we can write directly from given buffer
mov ebx, esi
add esi, ecx
jmp .writecommon
.writeshort:
mov ecx, [esp+12]
push ecx
lea edi, [ebp+FAT.buffer]
mov ebx, edi
rep movsb
.writedircont:
lea ecx, [ebp+FAT.buffer+0x200]
sub ecx, edi
push eax
xor eax, eax
rep stosb
pop eax
pop ecx
.writecommon:
push eax
call fs_write32_app
test eax, eax
pop eax
jnz .writeerr
inc eax
sub dword [esp+12], ecx
jz .writedone
dec dword [esp]
jnz .write_sector
pop eax
; allocate new cluster
pop eax
mov ecx, eax
call get_free_FAT
jc .diskfull
push edx
mov edx, [ebp+FAT.fatEND]
call set_FAT
xchg eax, ecx
mov edx, ecx
call set_FAT
pop edx
xchg eax, ecx
jmp .write_cluster
.diskfull:
mov eax, ERROR_DISK_FULL
jmp .ret
.writeerr:
pop eax eax
sub esi, ecx
mov eax, ERROR_DEVICE
jmp .ret
.writedone:
pop eax eax
.done:
xor eax, eax
.ret:
pop edi ecx
sub esi, [esp+4+36+20]
mov [esp+4+36+28], eax
mov [esp+4+36+16], esi
lea eax, [esp+12]
call dword [eax+8]
mov [edi+28], esi
call dword [eax+16]
mov [esp+36+16], ebx
lea eax, [esi+511]
shr eax, 9
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
lea eax, [eax+ecx-1]
xor edx, edx
div ecx
pop ecx
sub ecx, eax
call add_disk_free_space
add esp, 36
call update_disk
call fat_unlock
popad
ret
.writedir:
push 512
lea edi, [ebp+FAT.buffer]
mov ebx, edi
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
shl ecx, 9
cmp ecx, [esp+16]
jnz .writedircont
dec dword [esp+20]
push esi
mov ecx, 32/4
rep movsd
pop esi
mov dword [edi-32], '. '
mov dword [edi-32+4], ' '
mov dword [edi-32+8], ' '
mov byte [edi-32+11], 10h
push esi
mov ecx, 32/4
rep movsd
pop esi
mov dword [edi-32], '.. '
mov dword [edi-32+4], ' '
mov dword [edi-32+8], ' '
mov byte [edi-32+11], 10h
mov ecx, [esp+20+36]
cmp ecx, [ebp+FAT.ROOT_CLUSTER]
jnz @f
xor ecx, ecx
@@:
mov word [edi-32+26], cx
shr ecx, 16
mov [edi-32+20], cx
jmp .writedircont
 
fat_read_symbol:
or ax, -1
test esi, esi
jz .retFFFF
lodsb
test al, al
jnz ansi2uni_char
xor eax, eax
xor esi, esi
.retFFFF:
ret
 
fat_read_symbols:
call fat_read_symbol
stosw
loop fat_read_symbols
ret
 
 
fat_Write.access_denied:
push ERROR_ACCESS_DENIED
fat_Write.ret0:
pop eax
xor ebx, ebx
ret
 
fat_Write.ret11:
push ERROR_DEVICE
jmp fat_Write.ret0
 
;----------------------------------------------------------------
; fat_Write - FAT implementation of writing to file
; in: ebp = pointer to FAT structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
fat_Write:
cmp byte [esi], 0
jz .access_denied
call fat_lock
push edi
stdcall hd_find_lfn, [esp+4+4]
jnc .found
pop edi
push eax
call fat_unlock
jmp .ret0
.found:
; FAT does not support files larger than 4GB
cmp dword [ebx+8], 0
jz @f
.eof:
pop edi
push ERROR_END_OF_FILE
call fat_unlock
jmp .ret0
@@:
mov ecx, [ebx+12]
mov edx, [ebx+16]
mov ebx, [ebx+4]
; now edi points to direntry, ebx=start byte to write,
; ecx=number of bytes to write, edx=data pointer
 
; extend file if needed
add ecx, ebx
jc .eof ; FAT does not support files larger than 4GB
push edx
push eax ; save directory sector
push 0 ; return value=0
 
call get_time_for_file
mov [edi+22], ax ; last write time
call get_date_for_file
mov [edi+24], ax ; last write date
mov [edi+18], ax ; last access date
 
push dword [edi+28] ; save current file size
cmp ecx, [edi+28]
jbe .length_ok
cmp ecx, ebx
jz .length_ok
call hd_extend_file
jnc .length_ok
mov [esp+4], eax
; hd_extend_file can return three error codes: FAT table error, device error or disk full.
; First two cases are fatal errors, in third case we may write some data
cmp al, ERROR_DISK_FULL
jz .disk_full
call fat_unlock
pop eax
pop eax
pop ecx
pop edx
pop edi
xor ebx, ebx
ret
.disk_full:
; correct number of bytes to write
mov ecx, [edi+28]
cmp ecx, ebx
ja .length_ok
push 0
.ret:
pop eax
sub edx, [esp+12]
mov ebx, edx ; ebx=number of written bytes
call update_disk
test eax, eax
jz @f
mov byte [esp+4], ERROR_DEVICE
@@:
call fat_unlock
pop eax
pop eax
pop ecx
pop edx
pop edi
ret
.length_ok:
mov esi, [edi+28]
mov eax, [edi+20-2]
mov ax, [edi+26]
mov edi, eax ; edi=current cluster
push 0 ; current sector in cluster
; save directory
mov eax, [esp+12]
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
test eax, eax
jz @f
.device_err:
mov byte [esp+8], ERROR_DEVICE
jmp .ret
.fat_err:
mov byte [esp+8], ERROR_FAT_TABLE
jmp .ret
@@:
 
; now ebx=start pos, ecx=end pos, both lie inside file
sub ecx, ebx
jz .ret
.write_loop:
; skip unmodified sectors
cmp dword [esp+4], 0x200
jb .modify
sub ebx, 0x200
jae .skip
add ebx, 0x200
.modify:
; get length of data in current sector
push ecx
sub ebx, 0x200
jb .hasdata
neg ebx
xor ecx, ecx
jmp @f
.hasdata:
neg ebx
cmp ecx, ebx
jbe @f
mov ecx, ebx
@@:
; get current sector number
mov eax, edi
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add eax, [esp+4]
; load sector if needed
cmp dword [esp+8], 0 ; we don't need to read uninitialized data
jz .noread
cmp ecx, 0x200 ; we don't need to read sector if it is fully rewritten
jz .noread
cmp ecx, esi ; (same for the last sector)
jz .noread
push eax ebx
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
test eax, eax
pop ebx eax
jz @f
.device_err2:
pop ecx
jmp .device_err
@@:
.noread:
; zero uninitialized data if file was extended (because hd_extend_file does not this)
push eax ecx edi
xor eax, eax
mov ecx, 0x200
sub ecx, [esp+8+12]
jbe @f
lea edi, [ebp+FAT.buffer]
add edi, [esp+8+12]
rep stosb
@@:
; zero uninitialized data in the last sector
mov ecx, 0x200
sub ecx, esi
jbe @f
lea edi, [ebp+FAT.buffer+esi]
rep stosb
@@:
pop edi ecx
; copy new data
mov eax, edx
neg ebx
jecxz @f
lea ebx, [ebp+FAT.buffer+0x200+ebx]
call memmove
xor ebx, ebx
@@:
pop eax
; save sector
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_app
pop ebx
test eax, eax
jnz .device_err2
add edx, ecx
sub [esp], ecx
pop ecx
jz .ret
.skip:
; next sector
pop eax
inc eax
push eax
cmp eax, [ebp+FAT.SECTORS_PER_CLUSTER]
jb @f
and dword [esp], 0
mov eax, edi
call get_FAT
mov edi, eax
jc .device_err
cmp edi, 2
jb .fat_err
cmp edi, [ebp+FAT.fatRESERVED]
jae .fat_err
@@:
sub esi, 0x200
jae @f
xor esi, esi
@@:
sub dword [esp+4], 0x200
jae @f
and dword [esp+4], 0
@@:
jmp .write_loop
 
hd_extend_file.zero_size:
xor eax, eax
jmp hd_extend_file.start_extend
 
; extends file on hd to given size (new data area is undefined)
; in: edi->direntry, ecx=new size
; out: CF=0 => OK, eax=0
; CF=1 => error, eax=code (ERROR_FAT_TABLE or ERROR_DISK_FULL or ERROR_DEVICE)
hd_extend_file:
push esi
mov esi, [ebp+FAT.SECTORS_PER_CLUSTER]
imul esi, [ebp+FAT.BYTES_PER_SECTOR]
push ecx
; find the last cluster of file
mov eax, [edi+20-2]
mov ax, [edi+26]
mov ecx, [edi+28]
jecxz .zero_size
.last_loop:
sub ecx, esi
jbe .last_found
call get_FAT
jnc @f
.device_err:
pop ecx
.device_err2:
pop esi
push ERROR_DEVICE
.ret_err:
pop eax
stc
ret
@@:
cmp eax, 2
jb .fat_err
cmp eax, [ebp+FAT.fatRESERVED]
jb .last_loop
.fat_err:
pop ecx esi
push ERROR_FAT_TABLE
jmp .ret_err
.last_found:
push eax
call get_FAT
jnc @f
pop eax
jmp .device_err
@@:
cmp eax, [ebp+FAT.fatRESERVED]
pop eax
jb .fat_err
; set length to full number of clusters
sub [edi+28], ecx
.start_extend:
pop ecx
; now do extend
push edx
mov edx, 2 ; start scan from cluster 2
.extend_loop:
cmp [edi+28], ecx
jae .extend_done
; add new cluster
push eax
call get_free_FAT
jc .disk_full
mov edx, [ebp+FAT.fatEND]
call set_FAT
mov edx, eax
pop eax
test eax, eax
jz .first_cluster
push edx
call set_FAT
pop edx
jmp @f
.first_cluster:
ror edx, 16
mov [edi+20], dx
ror edx, 16
mov [edi+26], dx
@@:
push ecx
mov ecx, -1
call add_disk_free_space
pop ecx
mov eax, edx
add [edi+28], esi
jmp .extend_loop
.extend_done:
mov [edi+28], ecx
pop edx esi
xor eax, eax ; CF=0
ret
.device_err3:
pop edx
jmp .device_err2
.disk_full:
pop eax edx esi
movi eax, ERROR_DISK_FULL
stc
ret
 
fat_update_datetime:
call get_time_for_file
mov [edi+22], ax ; last write time
call get_date_for_file
mov [edi+24], ax ; last write date
mov [edi+18], ax ; last access date
ret
 
 
;----------------------------------------------------------------
; fat_SetFileEnd - FAT implementation of setting end-of-file
; in: ebp = pointer to FAT structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
fat_SetFileEnd:
call fat_lock
push edi
cmp byte [esi], 0
jnz @f
.access_denied:
push ERROR_ACCESS_DENIED
.ret:
call fat_unlock
pop eax
pop edi
ret
@@:
stdcall hd_find_lfn, [esp+4+4]
jnc @f
.reteax:
push eax
jmp .ret
@@:
; must not be directory
test byte [edi+11], 10h
jnz .access_denied
; file size must not exceed 4 Gb
cmp dword [ebx+8], 0
jz @f
push ERROR_END_OF_FILE
jmp .ret
@@:
push eax ; save directory sector
; set file modification date/time to current
call fat_update_datetime
mov eax, [ebx+4]
cmp eax, [edi+28]
jb .truncate
ja .expand
pop eax
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
test eax, eax
jz @f
push ERROR_DEVICE
jmp .ret
@@:
push 0
jmp .ret
.expand:
push ebx ebp ecx
push dword [edi+28] ; save old size
mov ecx, eax
call hd_extend_file
push eax ; return code
jnc .expand_ok
cmp al, ERROR_DISK_FULL
jz .disk_full
.pop_ret:
call update_disk
pop eax ecx ecx ebp ebx ecx
jmp .reteax
.expand_ok:
.disk_full:
; save directory
mov eax, [edi+28]
xchg eax, [esp+20]
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
test eax, eax
mov eax, [edi+20-2]
mov ax, [edi+26]
mov edi, eax
jz @f
.pop_ret11:
mov byte [esp], ERROR_DEVICE
jmp .pop_ret
@@:
test edi, edi
jz .pop_ret
; now zero new data
push 0
; edi=current cluster, [esp]=sector in cluster
; [esp+24]=new size, [esp+8]=old size, [esp+4]=return code
.zero_loop:
cmp edi, 2
jb .error_fat
cmp edi, [ebp+FAT.fatRESERVED]
jae .error_fat
sub dword [esp+8], 0x200
jae .next_cluster
lea eax, [edi-2]
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add eax, [esp]
cmp dword [esp+8], -0x200
jz .noread
push eax
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
test eax, eax
pop eax
jnz .err_next
.noread:
mov ecx, [esp+8]
neg ecx
push edi
lea edi, [ebp+FAT.buffer+0x200]
add edi, [esp+12]
push eax
xor eax, eax
mov [esp+16], eax
rep stosb
pop eax
pop edi
call fs_write32_app
test eax, eax
jz .next_cluster
.err_next:
mov byte [esp+4], ERROR_DEVICE
.next_cluster:
pop eax
sub dword [esp+20], 0x200
jbe .pop_ret
inc eax
push eax
cmp eax, [ebp+FAT.SECTORS_PER_CLUSTER]
jb .zero_loop
and dword [esp], 0
mov eax, edi
call get_FAT
mov edi, eax
jnc .zero_loop
pop eax
jmp .pop_ret11
.truncate:
mov [edi+28], eax
push ecx
mov ecx, [edi+20-2]
mov cx, [edi+26]
push eax
test eax, eax
jz .zero_size
; find new last cluster
@@:
cmp ecx, 2
jb .error_fat2
cmp ecx, [ebp+FAT.fatRESERVED]
jae .error_fat2
mov eax, [ebp+FAT.SECTORS_PER_CLUSTER]
shl eax, 9
sub [esp], eax
jbe @f
mov eax, ecx
call get_FAT
mov ecx, eax
jnc @b
.device_err3:
pop eax ecx eax edi
call update_disk
call fat_unlock
movi eax, ERROR_DEVICE
ret
@@:
; we will zero data at the end of last sector - remember it
push ecx
; terminate FAT chain
push edx
mov eax, ecx
mov edx, [ebp+FAT.fatEND]
call set_FAT
mov eax, edx
pop edx
jnc @f
.device_err4:
pop ecx
jmp .device_err3
.zero_size:
and word [edi+20], 0
and word [edi+26], 0
push 0
mov eax, ecx
@@:
; delete FAT chain
call clear_cluster_chain
jc .device_err4
; save directory
mov eax, [esp+12]
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
test eax, eax
jnz .device_err4
; zero last sector, ignore errors
pop ecx
pop eax
dec ecx
imul ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
add ecx, [ebp+FAT.DATA_START]
push eax
sar eax, 9
add ecx, eax
pop eax
and eax, 0x1FF
jz .truncate_done
push ebx eax
mov eax, ecx
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
pop eax
lea edi, [ebp+FAT.buffer+eax]
push ecx
mov ecx, 0x200
sub ecx, eax
xor eax, eax
rep stosb
pop eax
call fs_write32_app
pop ebx
.truncate_done:
pop ecx eax edi
call update_disk
call fat_unlock
xor eax, eax
ret
.error_fat:
pop eax
mov byte [esp], ERROR_FAT_TABLE
jmp .pop_ret
.error_fat2:
pop eax ecx eax edi
call update_disk
call fat_unlock
movi eax, ERROR_FAT_TABLE
ret
 
;----------------------------------------------------------------
; fat_GetFileInfo - FAT implementation of getting file info
; in: ebp = pointer to FAT structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
fat_GetFileInfo:
cmp byte [esi], 0
jnz @f
mov eax, 2
ret
@@:
push edi
call fat_lock
stdcall hd_find_lfn, [esp+4+4]
jc .error
push ebp
xor ebp, ebp
mov esi, [ebx+16]
mov dword [esi+4], ebp
call fat_entry_to_bdfe2
pop ebp
call fat_unlock
xor eax, eax
pop edi
ret
.error:
push eax
call fat_unlock
pop eax
pop edi
ret
 
;----------------------------------------------------------------
; fat_SetFileInfo - FAT implementation of setting file info
; in: ebp = pointer to FAT structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
fat_SetFileInfo:
cmp byte [esi], 0
jnz @f
mov eax, 2
ret
@@:
push edi
call fat_lock
stdcall hd_find_lfn, [esp+4+4]
jc .error
push eax
mov edx, [ebx+16]
call bdfe_to_fat_entry
pop eax
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
call update_disk
call fat_unlock
pop edi
xor eax, eax
ret
.error:
push eax
call fat_unlock
pop eax
pop edi
ret
 
;----------------------------------------------------------------
; fat_Delete - FAT implementation of deleting a file/folder
; in: ebp = pointer to FAT structure
; in: esi+[esp+4] = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
fat_Delete:
call fat_lock
cmp byte [esi], 0
jnz @f
; cannot delete root!
.access_denied:
push ERROR_ACCESS_DENIED
.pop_ret:
call fat_unlock
pop eax
xor ebx, ebx
ret
@@:
and [ebp+FAT.longname_sec1], 0
and [ebp+FAT.longname_sec2], 0
push edi
stdcall hd_find_lfn, [esp+4+4]
jnc .found
pop edi
push ERROR_FILE_NOT_FOUND
jmp .pop_ret
.found:
cmp dword [edi], '. '
jz .access_denied2
cmp dword [edi], '.. '
jz .access_denied2
test byte [edi+11], 10h
jz .dodel
; we can delete only empty folders!
pushad
mov esi, [edi+20-2]
mov si, [edi+26]
xor ecx, ecx
lea eax, [esi-2]
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
lea ebx, [ebp+FAT.buffer]
call fs_read32_sys
test eax, eax
jnz .err1
lea eax, [ebx+0x200]
add ebx, 2*0x20
.checkempty:
cmp byte [ebx], 0
jz .empty
cmp byte [ebx], 0xE5
jnz .notempty
add ebx, 0x20
cmp ebx, eax
jb .checkempty
inc ecx
cmp ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
jb @f
mov eax, esi
call get_FAT
jc .err1
cmp eax, 2
jb .error_fat
cmp eax, [ebp+FAT.fatRESERVED]
jae .empty
mov esi, eax
xor ecx, ecx
@@:
lea eax, [esi-2]
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add eax, ecx
lea ebx, [ebp+FAT.buffer]
call fs_read32_sys
test eax, eax
lea eax, [ebx+0x200]
jz .checkempty
.err1:
popad
.err2:
pop edi
call fat_unlock
movi eax, ERROR_DEVICE
ret
.error_fat:
popad
pop edi
call fat_unlock
movi eax, ERROR_FAT_TABLE
ret
.notempty:
popad
.access_denied2:
pop edi
call fat_unlock
movi eax, ERROR_ACCESS_DENIED
ret
.empty:
popad
push eax ebx
lea ebx, [ebp+FAT.buffer]
call fs_read32_sys
test eax, eax
pop ebx eax
jnz .err2
.dodel:
push eax
mov eax, [edi+20-2]
mov ax, [edi+26]
xchg eax, [esp]
; delete folder entry
mov byte [edi], 0xE5
; delete LFN (if present)
.lfndel:
lea edx, [ebp+FAT.buffer]
cmp edi, edx
ja @f
cmp [ebp+FAT.longname_sec2], 0
jz .lfndone
push [ebp+FAT.longname_sec2]
push [ebp+FAT.longname_sec1]
pop [ebp+FAT.longname_sec2]
and [ebp+FAT.longname_sec1], 0
push ebx
mov ebx, edx
call fs_write32_sys
mov eax, [esp+4]
call fs_read32_sys
pop ebx
pop eax
lea edi, [ebp+FAT.buffer+0x200]
@@:
sub edi, 0x20
cmp byte [edi], 0xE5
jz .lfndone
cmp byte [edi+11], 0xF
jnz .lfndone
mov byte [edi], 0xE5
jmp .lfndel
.lfndone:
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
; delete FAT chain
pop eax
call clear_cluster_chain
call update_disk
call fat_unlock
pop edi
xor eax, eax
ret
 
; \end{diamond}
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/trunk/fs/fs_lfn.inc
30,18 → 30,6
iglobal
; in this table names must be in lowercase
rootdirs:
db 2,'rd'
dd fs_OnRamdisk
dd fs_NextRamdisk
db 7,'ramdisk'
dd fs_OnRamdisk
dd fs_NextRamdisk
db 2,'fd'
dd fs_OnFloppy
dd fs_NextFloppy
db 10,'floppydisk'
dd fs_OnFloppy
dd fs_NextFloppy
;**********************************************
db 3,'cd0'
dd fs_OnCd0
60,10 → 48,6
 
 
virtual_root_query:
dd fs_HasRamdisk
db 'rd',0
dd fs_HasFloppy
db 'fd',0
;**********************************************
dd fs_HasCd0
db 'cd0',0
436,72 → 420,10
; ebp = 0 or pointer to rest of name from folder addressed by esi
; out: [image_of_eax]=image of eax, [image_of_ebx]=image of ebx
 
fs_OnRamdisk:
cmp ecx, 1
jnz file_system_lfn.notfound
mov eax, [ebx]
cmp eax, fs_NumRamdiskServices
jae .not_impl
mov ecx, [ebx+12]
mov edx, [ebx+16]
; add edx, std_application_base_address
add ebx, 4
call dword [fs_RamdiskServices + eax*4]
mov [image_of_eax], eax
mov [image_of_ebx], ebx
ret
.not_impl:
mov dword [image_of_eax], 2 ; not implemented
ret
 
fs_NotImplemented:
mov eax, 2
ret
 
fs_RamdiskServices:
dd fs_RamdiskRead
dd fs_RamdiskReadFolder
dd fs_RamdiskRewrite
dd fs_RamdiskWrite
dd fs_RamdiskSetFileEnd
dd fs_RamdiskGetFileInfo
dd fs_RamdiskSetFileInfo
dd 0
dd fs_RamdiskDelete
dd fs_RamdiskCreateFolder
fs_NumRamdiskServices = ($ - fs_RamdiskServices)/4
 
fs_OnFloppy:
cmp ecx, 2
ja file_system_lfn.notfound
mov eax, [ebx]
cmp eax, fs_NumFloppyServices
jae fs_OnRamdisk.not_impl
call reserve_flp
mov [flp_number], cl
mov ecx, [ebx+12]
mov edx, [ebx+16]
; add edx, std_application_base_address
add ebx, 4
call dword [fs_FloppyServices + eax*4]
and [flp_status], 0
mov [image_of_eax], eax
mov [image_of_ebx], ebx
ret
 
fs_FloppyServices:
dd fs_FloppyRead
dd fs_FloppyReadFolder
dd fs_FloppyRewrite
dd fs_FloppyWrite
dd fs_FloppySetFileEnd
dd fs_FloppyGetFileInfo
dd fs_FloppySetFileInfo
dd 0
dd fs_FloppyDelete
dd fs_FloppyCreateFolder
fs_NumFloppyServices = ($ - fs_FloppyServices)/4
 
;*******************************************************
fs_OnCd0:
call reserve_cd
584,16 → 506,6
fs_NumCdServices = ($ - fs_CdServices)/4
 
;*******************************************************
 
fs_HasRamdisk:
mov al, 1 ; we always have ramdisk
ret
fs_HasFloppy:
cmp byte [DRIVE_DATA], 0
setnz al
ret
 
;*******************************************************
fs_HasCd0:
test byte [DRIVE_DATA+1], 10000000b
setnz al
617,36 → 529,6
; out: CF=1 => no more partitions
; CF=0 => eax=next partition number
 
fs_NextRamdisk:
; we always have /rd/1
test eax, eax
stc
jnz @f
mov al, 1
clc
@@:
ret
 
fs_NextFloppy:
; we have /fd/1 iff (([DRIVE_DATA] and 0xF0) != 0) and /fd/2 iff (([DRIVE_DATA] and 0x0F) != 0)
test byte [DRIVE_DATA], 0xF0
jz .no1
test eax, eax
jnz .no1
inc eax
ret ; CF cleared
.no1:
test byte [DRIVE_DATA], 0x0F
jz .no2
cmp al, 2
jae .no2
mov al, 2
clc
ret
.no2:
stc
ret
 
;*******************************************************
fs_NextCd:
; we always have /cdX/1
/kernel/trunk/kernel.asm
759,10 → 759,11
; Initialize system timer (IRQ0)
call PIT_init
 
; CALCULATE FAT CHAIN FOR RAMDISK
; Register ramdisk file system
mov esi, boot_initramdisk
call boot_log
call ramdisk_init
 
call calculatefatchain
 
mov esi, boot_initapic
call boot_log
; Try to Initialize APIC
1333,8 → 1334,8
jnz .yes
call stack_handler_has_work?
jnz .yes
; call check_fdd_motor_status_has_work?
; jnz .yes
call check_fdd_motor_status_has_work?
jnz .yes
call check_ATAPI_device_event_has_work?
jnz .yes
call check_lights_state_has_work?
2673,29 → 2674,14
align 4
sys_cachetodiskette:
cmp ebx, 1
jne .no_floppy_a_save
mov [flp_number], 1
jmp .save_image_on_floppy
;--------------------------------------
align 4
.no_floppy_a_save:
jb .no_floppy_save
cmp ebx, 2
jne .no_floppy_b_save
mov [flp_number], 2
;--------------------------------------
align 4
.save_image_on_floppy:
ja .no_floppy_save
call save_image
mov [esp + 32], dword 0
cmp [FDC_Status], 0
je .yes_floppy_save
;--------------------------------------
align 4
.no_floppy_b_save:
mov [esp + 32], eax
ret
.no_floppy_save:
mov [esp + 32], dword 1
;--------------------------------------
align 4
.yes_floppy_save:
ret
;------------------------------------------------------------------------------
uglobal
5266,19 → 5252,6
 
align 4
 
syscall_openramdiskfile: ; OpenRamdiskFile
 
mov eax, ebx
mov ebx, ecx
mov ecx, edx
mov edx, esi
mov esi, 12
call fileread
mov [esp+32], eax
ret
 
align 4
 
syscall_drawrect: ; DrawRect
 
mov edi, edx ; color + gradient
5783,12 → 5756,11
cli
 
if ~ defined extended_primary_loader
mov eax, kernel_file ; load kernel.mnt to 0x7000:0
movi esi, 12
xor ebx, ebx
or ecx, -1
mov edx, OS_BASE+0x70000
call fileread
; load kernel.mnt to 0x7000:0
mov ebx, kernel_file_load
pushad
call file_system_lfn
popad
 
mov esi, restart_kernel_4000+OS_BASE+0x10000 ; move kernel re-starter to 0x4000:0
mov edi, OS_BASE+0x40000
5802,8 → 5774,6
; cld
; rep movsd
 
call restorefatchain
 
call IRQ_mask_all
 
if 0
/kernel/trunk/kernel32.inc
185,11 → 185,9
 
include "blkdev/disk.inc" ; support for plug-n-play disks
include "blkdev/disk_cache.inc" ; caching for plug-n-play disks
include "fs/fs.inc" ; syscall
include "fs/fat32.inc" ; read / write for fat32 filesystem
include "blkdev/rd.inc" ; ramdisk read /write
include "fs/fat.inc" ; read / write for fat filesystem
include "fs/ntfs.inc" ; read / write for ntfs filesystem
include "fs/fat12.inc" ; read / write for fat12 filesystem
include "blkdev/rd.inc" ; ramdisk read /write
include "fs/fs_lfn.inc" ; syscall, version 2
include "fs/iso9660.inc" ; read for iso9660 filesystem CD
include "fs/ext2/ext2.asm" ; read / write for ext2 filesystem
/kernel/trunk/memmap.inc
198,8 → 198,7
; 0x800A0000 -> AFFFF screen access area
; 0x800B0000 -> FFFFF bios rest in peace -area (320k) ?
; 0x80100000 -> 27FFFF diskette image (1m5)
; 0x80280000 -> 281FFF ramdisk fat (8k)
; 0x80282000 -> 283FFF floppy fat (8k)
; 0x80280000 -> 283FFF free (16k)
;
; 0x80284000 -> 28BFFF HDD DMA AREA (32k)
; 0x8028C000 -> 297FFF free (48k)