/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) |