From 1e5f55f29cafb375ff2c9f148e900811eab639a7 Mon Sep 17 00:00:00 2001 From: "Evgeny Grechnikov (Diamond)" Date: Tue, 30 May 2006 07:32:30 +0000 Subject: [PATCH] File system additions: create/rewrite files with long names git-svn-id: svn://kolibrios.org@83 a494cfbc-eb01-0410-851d-a64ba20cac60 --- kernel/trunk/blkdev/rd.inc | 910 ++++++++++++++++++++++++++------- kernel/trunk/docs/sysfuncr.txt | 40 +- kernel/trunk/fs/fat12.inc | 679 ++++++++++++++++++++---- kernel/trunk/fs/fat32.inc | 753 +++++++++++++++++++++++---- kernel/trunk/fs/fs.inc | 1 + kernel/trunk/fs/fs_lfn.inc | 30 +- 6 files changed, 2005 insertions(+), 408 deletions(-) diff --git a/kernel/trunk/blkdev/rd.inc b/kernel/trunk/blkdev/rd.inc index 029a4a13fc..010579a92a 100644 --- a/kernel/trunk/blkdev/rd.inc +++ b/kernel/trunk/blkdev/rd.inc @@ -3,6 +3,7 @@ ;; RAMDISK functions ;; ;; (C) 2004 Ville Turjanmaa, License: GPL ;; ;; Addings by M.Lisovin ;; +;; LFN support by diamond ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; calculate fat chain @@ -379,7 +380,6 @@ filesave: ; find an empty spot for filename in the root dir l20ds: dec edx - test edx,edx jz frnoreadds l21ds: cmp [edi],byte 0xE5 @@ -516,44 +516,44 @@ 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 + 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 + mov al, '_' + jmp .doit .yo1: - mov al, 'Ё' - jmp .doit + mov al, 'Ё' + jmp .doit .yo2: - mov al, 'ё' - jmp .doit + mov al, 'ё' + jmp .doit .rus1: ; 0x410-0x43F -> 0x80-0xAF - add al, 0x70 - jmp .doit + add al, 0x70 + jmp .doit .rus2: ; 0x440-0x44F -> 0xE0-0xEF - add al, 0xA0 + add al, 0xA0 .ascii: .doit: - stosb - jmp uni2ansi_str + stosb + jmp uni2ansi_str .done: - mov byte [edi], 0 - ret + mov byte [edi], 0 + ret ansi2uni_char: ; convert ANSI character in al to UNICODE character in ax, using cp866 encoding @@ -596,25 +596,25 @@ 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, 'а' - jb .ret - cmp al, 'р' - jb .rus1 - cmp al, 'я' - ja .ret + cmp al, 'a' + jb .ret + cmp al, 'z' + jbe .az + cmp al, 'а' + jb .ret + cmp al, 'р' + jb .rus1 + cmp al, 'я' + ja .ret ; 0xE0-0xEF -> 0x90-0x9F - sub al, 'р'-'Р' + sub al, 'р'-'Р' .ret: - ret + ret .rus1: ; 0xA0-0xAF -> 0x80-0x8F .az: - and al, not 0x20 - ret + and al, not 0x20 + ret fat_get_name: ; in: edi->FAT entry @@ -623,55 +623,55 @@ fat_get_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 + cmp byte [edi], 0 + jz .no + cmp byte [edi], 0xE5 + jnz @f .no: - stc - ret + stc + ret @@: - cmp byte [edi+11], 0xF - jz .longname - push ecx - mov ecx, 8 - push edi ebp ecx + cmp byte [edi+11], 0xF + jz .longname + push ecx + mov ecx, 8 + push edi ebp ecx test byte [ebp-4], 1 jnz .unicode_short @@: - mov al, [edi] - inc edi - mov [ebp], al - inc ebp - loop @b - pop ecx + mov al, [edi] + inc edi + mov [ebp], al + inc ebp + loop @b + pop ecx @@: - cmp byte [ebp-1], ' ' - jnz @f - dec ebp - loop @b + cmp byte [ebp-1], ' ' + jnz @f + dec ebp + loop @b @@: - mov byte [ebp], '.' - inc ebp - mov ecx, 3 - push ecx + mov byte [ebp], '.' + inc ebp + mov ecx, 3 + push ecx @@: - mov al, [edi] - inc edi - mov [ebp], al - inc ebp - loop @b - pop ecx + mov al, [edi] + inc edi + mov [ebp], al + inc ebp + loop @b + pop ecx @@: - cmp byte [ebp-1], ' ' - jnz @f - dec ebp - loop @b - dec ebp + cmp byte [ebp-1], ' ' + jnz @f + dec ebp + loop @b + dec ebp @@: - and byte [ebp], 0 ; CF=0 - pop ebp edi ecx - ret + and byte [ebp], 0 ; CF=0 + pop ebp edi ecx + ret .unicode_short: @@: mov al, [edi] @@ -683,89 +683,89 @@ fat_get_name: loop @b pop ecx @@: - cmp word [ebp-2], ' ' - jnz @f - dec ebp - dec ebp - loop @b + 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 word [ebp], '.' + inc ebp + inc ebp + mov ecx, 3 + push ecx @@: - mov al, [edi] - inc edi - call ansi2uni_char - mov [ebp], ax + 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 + 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 + 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 + 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 + 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 + 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 + pop eax + sub ebp, eax + test eax, eax + jz @f ; if this is not first entry, more processing required - stc - ret + 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 + push esi edi + mov esi, ebp + mov edi, ebp + call uni2ansi_str + pop edi esi .ret: - clc - ret + clc + ret fat_compare_name: ; compares ASCIIZ-names, case-insensitive (cp866 encoding) @@ -773,66 +773,66 @@ fat_compare_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 + 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 + 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 + cmp al, '/' + jnz @f + cmp byte [esp], 0 + jnz @f + mov [esp+4], esi @@: - pop eax - pop esi ebp - ret + 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 + 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 + 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 fat_entry_to_bdfe: ; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi @@ -1076,4 +1076,522 @@ fs_RamdiskReadFolder: pop ecx edi esi 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 ; CF already cleared + 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] +.succ: + pop edi + popad + clc + ret +.break: + jecxz .noplace + inc edi + mov al, '1' +@@: + xchg al, [edi] + inc edi + cmp al, ' ' + mov al, '0' + jnz @b + jmp .succ +.noplace: + dec edi + cmp edi, [esp] + jz .err + add dword [esp], 8 + mov word [edi], '~1' + inc edi + inc edi +@@: + mov byte [edi], '0' + 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 + push 8 + pop ebx + 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 edi, ecx + jbe .skip +@@: + dec edi + mov al, ' ' + xchg al, [edi] + dec ebx + mov [ebx], al + 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 + +;---------------------------------------------------------------- +; +; fs_RamdiskRewrite - LFN variant for writing sys floppy +; +; esi points to filename +; ebx ignored (reserved) +; ecx number of bytes to write, 0+ +; edx mem location to data +; +; ret ebx = number of written bytes +; eax = 0 ok read or other = errormsg +; +;-------------------------------------------------------------- +@@: + mov eax, ERROR_ACCESS_DENIED + xor ebx, ebx + ret + +fs_RamdiskRewrite: + cmp byte [esi], 0 + jz @b +; ramdisk doesn't support folders + push esi +@@: + lodsb + test al, al + jz @f + cmp al, '/' + jnz @b + pop esi +.err5: + mov eax, 5 ; file not found + xor ebx, ebx + ret +@@: + pop esi +; check existence + push edi + call rd_find_lfn + jc .notfound +; found, 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, [0x280000 + 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 + pop edi + jmp .err5 +@@: + sub esp, 12 + mov edi, esp + call fat_gen_short_name +.test_short_name_loop: + push esi ecx + mov esi, 0x100000+512*19 +.test_short_name_entry: + cmp byte [esi+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: + add esi, 20h + cmp esi, 0x100000+512*33 + jb .test_short_name_entry + pop ecx esi + jmp .found +.short_name_found: + call fat_next_short_name + pop ecx esi + jnc .test_short_name_loop +.disk_full: + add esp, 12 + pop edi + mov eax, ERROR_DISK_FULL + xor ebx, ebx + ret +.found: +; 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 + push 1 + pop eax ; 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: +; find successive entries in directory + xor ecx, ecx + mov edi, 0x100000+512*19 +.scan_dir: + cmp byte [edi], 0 + jz .free + cmp byte [edi], 0xE5 + jz .free + xor ecx, ecx +.scan_cont: + add edi, 0x20 + cmp edi, 0x100000+512*33 + jb .scan_dir + pop edi ecx + jmp .disk_full +.free: + inc ecx + cmp ecx, eax + jb .scan_cont +; found! +; calculate name checksum + push esi ecx + mov esi, [esp+8] + mov ecx, 11 + xor eax, eax +@@: + ror al, 1 + add al, [esi] + inc esi + loop @b + pop ecx esi +; edi points to last entry in free chunk + dec ecx + jz .nolfn + push esi + push edi +.writelfn: + sub edi, 20h + push ecx eax + mov eax, [esp+8] + sub eax, edi + shr eax, 5 + cmp ecx, 1 + jnz @f + or al, 40h +@@: + stosb + mov cl, 5 + call .read_symbols + mov ax, 0xF + stosw + pop eax + stosb + push eax + mov cl, 6 + call .read_symbols + xor eax, eax + stosw + mov cl, 2 + call .read_symbols + pop eax ecx + sub edi, 0x20 + loop .writelfn + pop edi + 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 +.doit: + push ecx edx + push ecx + push edi + add edi, 26 ; edi points to low word of cluster + push edi + jecxz .done + mov ecx, 2849 + mov edi, 0x280000 +.write_loop: +; allocate new cluster + xor eax, eax + repnz scasw + jnz .disk_full2 + dec edi + dec edi + lea eax, [edi-0x280000] + 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 + shl eax, 9 + add eax, 0x100000+31*512 + 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 ecx + sub ebx, edx + mov [edi+28], ebx + pop edi + xor eax, eax + ret +.disk_full2: + mov ebx, edx + pop edi edi ecx edx ecx + sub ebx, edx + mov [edi+28], ebx + pop edi + push ERROR_DISK_FULL + pop eax + ret + +.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 + +.read_symbols: + call .read_symbol + stosw + loop .read_symbols + ret + ; \end{diamond} diff --git a/kernel/trunk/docs/sysfuncr.txt b/kernel/trunk/docs/sysfuncr.txt index 334a7c90f7..643e709f29 100644 --- a/kernel/trunk/docs/sysfuncr.txt +++ b/kernel/trunk/docs/sysfuncr.txt @@ -2770,7 +2770,7 @@ dword- Возвращаемое значение: * eax = 0 - успешно, иначе код ошибки файловой системы Замечания: - * Эта функция устарела; функция 58 позволяет выполнять + * Эта функция устарела; функция 70 позволяет выполнять те же действия с расширенными возможностями. * Данная функция предполагает, что во время её вызова одним приложением никакое другое приложение не работает @@ -2862,7 +2862,7 @@ dword- * +12 = +0xC: dword: указатель на буфер, куда будут записаны данные * +16 = +0x10: dword: указатель на буфер для работы системы (4096 байт) - * +20 = +0x14: ASCIIZ-имя файла, правила формирования имён указаны в + * +20 = +0x14: ASCIIZ-имя файла, правила формирования имён указаны в общем описании Возвращаемое значение: * eax = 0 - успешно, иначе код ошибки файловой системы @@ -2925,11 +2925,13 @@ dword- * +12 = +0xC: dword: указатель на данные для записи * +16 = +0x10: dword: указатель на буфер для работы системы (4096 байт) - * +20 = +0x14: ASCIIZ-имя файла, правила формирования имён указаны в + * +20 = +0x14: ASCIIZ-имя файла, правила формирования имён указаны в общем описании Возвращаемое значение: * eax = 0 - успешно, иначе код ошибки файловой системы * ebx разрушается +Замечания: + * Эта функция устарела, используйте подфункцию 2 функции 70. ====================================================================== =========== Функция 58, подфункция 2 - удалить файл/папку. =========== @@ -3085,9 +3087,6 @@ dword- подфункцией 11 функции 21. Узнать это можно вызовом подфункцией 11 функции 26. * LBA-чтение дискеты не поддерживается. - * Обращение к несуществующему жёсткому диску намертво вешает поток. - Узнать, существует ли диск, можно из структуры, возвращаемой - подфункцией 11 функции 18. * Функция считывает данные физического жёсткого диска; если по каким-то причинам нужны данные конкретного раздела, придётся определять начальный сектор этого раздела @@ -4055,14 +4054,14 @@ Architecture Software Developer's Manual, Volume 3, Appendix B); x - номер раздела на выбранном винчестере, изменяется от 1 до 255 (на каждом из винчестеров нумерация начинается с 1) Примеры: - * '/RAMDISK/FIRST/KERNEL.ASM',0 - '/rd/1/kernel.asm',0 + * '/rd/1/kernel.asm',0 * '/HD0/1/kernel.asm',0 * '/hd0/2/menuet/pics/tanzania.bmp',0 * '/hd0/1/Program files/NameOfProgram/SomeFile.SomeExtension',0 Доступные подфункции: * подфункция 0 - чтение файла * подфункция 1 - чтение папки + * подфункция 2 - создание/перезапись файла ====================================================================== = Функция 70, подфункция 0 - чтение файла с поддержкой длинных имён. = @@ -4185,6 +4184,30 @@ Architecture Software Developer's Manual, Volume 3, Appendix B); 0x10, а времена и даты обнулены. Альтернативный способ получения информации об оборудовании - подфункция 11 функции 18. +====================================================================== +====================== Функция 70, подфункция 2 ====================== +======== Создание/перезапись файла с поддержкой длинных имён. ======== +====================================================================== +Параметры: + * eax = 70 - номер функции + * ebx = указатель на информационную структуру +Формат информационной структуры: + * +0: dword: 2 = номер подфункции + * +4: dword: 0 (зарезервировано) + * +8: dword: 0 (зарезервировано) + * +12 = +0xC: dword: сколько байт писать + * +16 = +0x10: dword: указатель на данные + * +20 = +0x14: ASCIIZ-имя файла, правила формирования имён указаны в + общем описании +Возвращаемое значение: + * eax = 0 - успешно, иначе код ошибки файловой системы + * ebx = число записанных байт (возможно, 0) +Замечания: + * Если файл с таким именем не существовал, он создаётся; если + существовал, то перезаписывается. + * Если свободного места на диске недостаточно, то функция запишет, + сколько сможет, после чего вернёт код ошибки 8. + ====================================================================== ========== Функция -1 - завершить выполнение потока/процесса ========= ====================================================================== @@ -4254,6 +4277,7 @@ Architecture Software Developer's Manual, Volume 3, Appendix B); * 8 = диск заполнен * 9 = таблица FAT разрушена * 10 = доступ запрещён + * 11 = ошибка устройства При запуске программы возможны также следующие коды ошибок: * 30 = 0x1E = недостаточно памяти * 31 = 0x1F = файл не является исполнимым diff --git a/kernel/trunk/fs/fat12.inc b/kernel/trunk/fs/fat12.inc index d16f8a1424..b04ad77bce 100644 --- a/kernel/trunk/fs/fat12.inc +++ b/kernel/trunk/fs/fat12.inc @@ -545,10 +545,8 @@ l.21_2: add ecx,21 add edi, ecx ;Advance to next entry dec dl - cmp dl,0 jne l.21_2 dec dh - cmp dh,0 jne l.20_2 jmp frnoreadd_1 @@ -561,9 +559,7 @@ fifoundd_1: mov eax,[path_pointer_flp] cmp [eax+36],byte 0 je fifoundd_2 - add edi,0xf - mov eax,[edi] - and eax,65535 + movzx eax, word [edi+0xf] mov ebx,[path_pointer_flp] add ebx,36 call get_cluster_of_a_path_flp @@ -575,10 +571,7 @@ fifoundd_2: dec [FDD_Sector] fifoundd_2_1: mov [edi-11],byte 0xE5 ;mark filename deleted - add edi,0xf - mov eax,[edi] - and eax,65535 - mov edi,eax ;edi = cluster + movzx edi, word [edi+0xf] ;edi = cluster frnewd_1: shl edi,1 ;find next cluster from FAT add edi,0x282000 @@ -674,9 +667,7 @@ rd_do_save_1: ; find an empty spot for filename in the root dir l20ds_1: sub edx,1 - cmp edx,0 - jnz l21ds_1 - jmp frnoreadds_1 + jz frnoreadds_1 l21ds_1: cmp [edi],byte 0xE5 jz fifoundds_1 @@ -709,10 +700,8 @@ l.21_3: add ecx,21 add edi, ecx ;Advance to next entry dec dl - cmp dl,0 jne l.21_3 dec dh - cmp dh,0 jne l.20_3 fdc_status_error_8: pop edi esi edx ecx ebx eax @@ -797,7 +786,6 @@ frnewds_2: add edi,0x282000 mov eax,[edi] and eax,4095 - cmp eax,0x0 jnz frnewds_2 mov [edx],bx ; save next cluster pos. to prev cl. mov edx,edi ; next save pos abs mem add @@ -1083,84 +1071,201 @@ check_new_flp: ret ; \begin{diamond} +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 +; 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 + mov ebp, esp + push 0 ; for fat_get_name: read ASCII name +.l1: + call fat_get_name + jc .l2 + call fat_compare_name + jz .found +.l2: + lea eax, [esp+0Ch+20h+262*2+4] + call dword [eax-8] + jnc .l1 + add esp, 262*2+4 +.reterr: + stc + popa + ret +.found: + add esp, 262*2+4 +; 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 + +flp_root_next: + cmp edi, 0xD200-0x20 + jae @f + add edi, 0x20 + ret ; CF=0 +@@: +; read next sector + inc dword [eax] + cmp dword [eax], 14 + jae flp_root_first.readerr +flp_root_first: + mov eax, [eax] + pusha + add eax, 19 + call read_chs_sector + popa + cmp [FDC_Status], 0 + jnz .readerr + mov edi, 0xD000 + ret ; CF=0 +.readerr: + stc + ret + +flp_rootmem_first: + mov edi, 0x8000 + clc + ret +flp_rootmem_next: + add edi, 0x20 + cmp edi, 0x8000+14*0x200 + cmc +flp_rootmem_next_write: +flp_rootmem_begin_write: +flp_rootmem_end_write: + ret +flp_rootmem_extend_dir: + stc + ret + +flp_notroot_next: + cmp edi, 0xD200-0x20 + jae flp_notroot_next_sector + add edi, 0x20 + ret ; CF=0 +flp_notroot_next_sector: + push ecx + mov ecx, [eax] + mov ecx, [ecx*2+0x282000] + and ecx, 0xFFF + cmp ecx, 2849 + jae flp_notroot_first.err2 + mov [eax], ecx + pop ecx +flp_notroot_first: + mov eax, [eax] + cmp eax, 2 + jb .err + cmp eax, 2849 + jae .err + pusha + add eax, 31 + call read_chs_sector + popa + mov edi, 0xD000 + cmp [FDC_Status], 0 + jnz .err + ret ; CF=0 +.err2: + pop ecx +.err: + stc + ret +flp_notroot_begin_write: + pusha + mov eax, [eax] + add eax, 31 + call read_chs_sector + popa + ret +flp_notroot_end_write: + pusha + mov eax, [eax] + add eax, 31 + call save_chs_sector + popa + ret +flp_notroot_next_write: + cmp edi, 0xD200 + jae @f + ret +@@: + call flp_notroot_end_write + jmp flp_notroot_next_sector +flp_notroot_extend_dir: +; find free cluster in FAT + pusha + xor eax, eax + mov edi, 0x282000 + mov ecx, 2849 + repnz scasw + jnz .notfound + mov word [edi-2], 0xFFF ; mark as last cluster + sub edi, 0x282000 + shr edi, 1 + dec edi + mov eax, [esp+28] + mov ecx, [eax] + mov [0x282000+ecx*2], di + mov [eax], edi + xor eax, eax + mov edi, 0xD000 + mov ecx, 128 + rep stosd + popa + call flp_notroot_end_write + mov edi, 0xD000 + clc + ret +.notfound: + popa + stc + ret + fd_find_lfn: ; in: esi->name ; out: CF=1 - file not found ; else CF=0 and edi->direntry - pusha - sub esp, 262*2 ; reserve place for LFN - mov ebp, esp - push 0 ; for fat_get_name: read ASCII name - call read_flp_fat - cmp [FDC_Status], 0 - jnz .error - mov eax, 19 - mov dh, 14 -.main_loop: -.20_1: - pusha - call read_chs_sector - popa - cmp [FDC_Status], 0 - jnz .error - mov edi, 0xD000 - inc [FDD_Sector] - push eax -.21_1: - call fat_get_name - jc @f - call fat_compare_name + push esi edi + push 0 + push flp_root_first + push flp_root_next +.loop: + call fat_find_lfn + jc .notfound + cmp byte [esi], 0 jz .found -@@: - add edi, 0x20 - cmp edi, 0xD200 - jb .21_1 - pop eax - inc eax - dec dh - js @f - jnz .20_1 -.error: - add esp, 262*2+4 - popa + test byte [edi+11], 10h + jz .notfound + movzx eax, word [edi+26] ; cluster + mov [esp+8], eax + mov dword [esp+4], flp_notroot_first + mov dword [esp], flp_notroot_next + jmp .loop +.notfound: + add esp, 12 + pop edi esi stc ret -@@: -; read next sector from FAT - mov eax, [(eax-31-1)*2+0x282000] - and eax, 0xFFF - cmp eax, 0xFF8 - jae .error - add eax, 31 - jmp .main_loop .found: - pop eax -; if LFN entry, advance to corresponding short entry - cmp byte [edi+11], 0xF - jnz .entryfound - add edi, 0x20 - cmp edi, 0xD200 - jb .entryfound - dec dh - jz .error - inc eax - call read_chs_sector - cmp [FDC_Status], 0 - jnz .error - mov edi, 0xD000 -.entryfound: - cmp byte [esi], 0 - jz .done - test byte [edi+11], 10h ; is a directory? - jz .error - movzx eax, word [edi+26] - add eax, 31 - mov dh, 0 - jmp .main_loop -.done: - add esp, 262*2+4+4 - push edi - popad + add esp, 16 ; CF=0 + pop esi ret ;---------------------------------------------------------------- @@ -1259,7 +1364,7 @@ fs_FloppyRead: mov ebx, edx pop eax edx ecx edi sub ebx, edx - mov al, 5 ; may be other error code? + mov al, 11 ret ;---------------------------------------------------------------- @@ -1398,4 +1503,406 @@ fs_FloppyReadFolder: pop ecx edi edi ret +;---------------------------------------------------------------- +; +; fs_FloppyRewrite - LFN variant for writing sys floppy +; +; esi points to filename +; ebx ignored (reserved) +; ecx number of bytes to write, 0+ +; edx mem location to data +; +; ret ebx = number of written bytes +; eax = 0 ok read or other = errormsg +; +;-------------------------------------------------------------- +@@: + mov eax, ERROR_ACCESS_DENIED + xor ebx, ebx + ret +fsfrfe2: + popad +fsfrfe: + mov eax, 11 + xor ebx, ebx + ret + +fs_FloppyRewrite: + cmp byte [esi], 0 + jz @b + call read_flp_fat + cmp [FDC_Status], 0 + jnz fsfrfe + pushad + xor ebp, ebp + push esi +@@: + lodsb + test al, al + jz @f + cmp al, '/' + jnz @b + lea ebp, [esi-1] + jmp @b +@@: + pop esi + test ebp, ebp + jnz .noroot + call read_flp_root + cmp [FDC_Status], 0 + jnz fsfrfe2 + push flp_rootmem_extend_dir + push flp_rootmem_end_write + push flp_rootmem_next_write + push flp_rootmem_begin_write + xor ebp, ebp + push ebp + push flp_rootmem_first + push flp_rootmem_next + jmp .common1 +.noroot: +; check existence + mov byte [ebp], 0 + call fd_find_lfn + mov byte [ebp], '/' + lea esi, [ebp+1] + jnc @f + mov eax, ERROR_FILE_NOT_FOUND +.ret1: + mov [esp+28], eax + popad + xor ebx, ebx + ret +@@: + 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 flp_notroot_extend_dir + push flp_notroot_end_write + push flp_notroot_next_write + push flp_notroot_begin_write + push ebp + push flp_notroot_first + push flp_notroot_next +.common1: + call fat_find_lfn + jc .notfound +; found, 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, [0x282000 + 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, 28 + 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+28 + 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 + push 1 + pop eax ; 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 successive entries in directory + xor ecx, ecx + push eax + lea eax, [esp+12+8+12+8] + mov [eax], ebp + call dword [eax-4] + pop eax + jnc .scan_dir +.fsfrfe3: + add esp, 8+8+12+28 + popad + mov eax, 11 + 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+12+8+12+8] + call dword [eax-8] + pop eax + jnc .scan_dir + cmp [FDC_Status], 0 + jnz .fsfrfe3 + push eax + lea eax, [esp+12+8+12+8] + call dword [eax+16] ; extend directory + pop eax + jnc .scan_dir + add esp, 8+8+12+28 + 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 + cmp ecx, eax + jb .scan_cont +; found! +; calculate name checksum + push esi ecx + 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 first entry in free chunk + dec ecx + jz .nolfn + push esi + push eax + lea eax, [esp+8+8+12+8] + call dword [eax+4] ; 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 fs_RamdiskRewrite.read_symbols + mov ax, 0xF + stosw + mov al, [esp+4] + stosb + mov cl, 6 + call fs_RamdiskRewrite.read_symbols + xor eax, eax + stosw + mov cl, 2 + call fs_RamdiskRewrite.read_symbols + pop ecx + lea eax, [esp+8+8+12+8] + call dword [eax+8] ; next write + xor eax, eax + loop .writelfn + pop eax + pop esi +; lea eax, [esp+8+12+8] +; call dword [eax+12] ; 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 + 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 +.doit: + lea eax, [esp+8] + call dword [eax+12] ; flush directory + push ecx + push edi + add edi, 26 ; edi points to low word of cluster + push edi + mov esi, edx + jecxz .done + mov ecx, 2849 + mov edi, 0x282000 + push 0 ; first cluster +.write_loop: +; allocate new cluster + xor eax, eax + repnz scasw + mov al, ERROR_DISK_FULL + jnz .ret + dec edi + dec edi + lea eax, [edi-0x282000] + shr eax, 1 ; eax = cluster + mov word [edi], 0xFFF ; mark as last cluster + cmp dword [esp], 0 + jz .first + xchg edi, [esp+4] + stosw + mov edi, [esp+4] + jmp @f +.first: + mov [esp], eax +@@: + inc ecx +; write data + push ecx edi + mov ecx, 512 + cmp dword [esp+20], ecx + jae @f + mov ecx, [esp+20] +@@: + push ecx + mov edi, 0xD000 + rep movsb + pop ecx + push ecx + sub ecx, 512 + neg ecx + push eax + xor eax, eax + rep stosb + pop eax + add eax, 31 + pusha + call save_chs_sector + popa + pop ecx + cmp [FDC_Status], 0 + jnz .diskerr + sub [esp+20], ecx + pop edi ecx + jnz .write_loop +.done: + xor eax, eax +.ret: + pop ebx edi edi ecx + mov [esp+28+28], eax + lea eax, [esp+8] + call dword [eax+4] + mov [edi+26], bx + mov ebx, esi + sub ebx, edx + mov [edi+28], ebx + call dword [eax+12] + mov [esp+28+16], ebx + test ebp, ebp + jnz @f + call save_flp_root +@@: + add esp, 28 + cmp [FDC_Status], 0 + jnz .err3 + call save_flp_fat + cmp [FDC_Status], 0 + jnz .err3 + popa + ret +.err3: + popa + mov al, 11 + xor ebx, ebx + ret +.diskerr: + sub esi, ecx + mov eax, 11 + pop edi ecx + jmp .ret + ; \end{diamond} diff --git a/kernel/trunk/fs/fat32.inc b/kernel/trunk/fs/fat32.inc index 9be05019b4..e99811c3db 100644 --- a/kernel/trunk/fs/fat32.inc +++ b/kernel/trunk/fs/fat32.inc @@ -7,6 +7,7 @@ ;; Copyright 2002 Paolo Minazzi, paolo.minazzi@inwind.it ;; ;; ;; ;; See file COPYING for details ;; +;; 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 ;; @@ -2934,114 +2935,38 @@ hd_find_lfn: ; in: esi->name ; out: CF=1 - file not found ; else CF=0 and edi->direntry - pusha - sub esp, 262*2 ; allocate space for LFN - mov ebp, esp - push 0 ; for fat_get_name: read ASCII name - mov eax, [ROOT_CLUSTER] ; start from root -.mainloop: -.new_cluster: - mov [cluster_tmp], eax - mov [fat16_root], 0 - cmp eax, [LAST_CLUSTER] - ja .notfound - cmp eax, 2 - jae .data_cluster - cmp [fat_type], 16 - jnz .notfound - mov eax, [ROOT_START] - mov ecx, [ROOT_SECTORS] - mov [fat16_root], 1 - jmp .new_sector -.data_cluster: - dec eax - dec eax - mov ecx, [SECTORS_PER_CLUSTER] - mul ecx - add eax, [DATA_START] -.new_sector: - mov ebx, buffer - call hd_read - cmp [hd_error],0 - jne .notfound - - mov edi, ebx - add ebx, 512 - push eax -.l1: - call fat_get_name - jc .l2 - call fat_compare_name - jz .found -.l2: - add edi, 0x20 - cmp edi, ebx - jb .l1 - pop eax - inc eax - loop .new_sector - cmp [fat16_root], 0 - jnz .notfound - mov eax, [cluster_tmp] - call get_FAT - cmp [hd_error],0 - jne .notfound - - cmp eax, 2 - jb .notfound - cmp eax, [fatRESERVED] - jb .new_cluster +; destroys eax + push esi edi + push 0 + push 0 + push fat16_root_first + push fat16_root_next + mov eax, [ROOT_CLUSTER] + cmp [fat_type], 32 + jz .fat32 +.loop: + call fat_find_lfn + jc .notfound + cmp byte [esi], 0 + jz .found + test byte [edi+11], 10h + jz .notfound + and dword [esp+12], 0 + movzx eax, word [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, 262*2+4 - popa - stc - ret + add esp, 16 + pop edi esi + stc + ret .found: - pop eax -; if this is LFN entry, advance to true entry - cmp byte [edi+11], 0xF - jnz .entryfound - add edi, 0x20 - cmp edi, ebx - jb .entryfound - inc eax - dec ecx - jnz .read_entry - cmp [fat16_root], 0 - jnz .notfound - mov eax, [cluster_tmp] - call get_FAT - cmp [hd_error],0 - jne .notfound - - cmp eax, 2 - jb .notfound - cmp eax, [fatRESERVED] - jae .notfound - dec eax - dec eax - mul [SECTORS_PER_CLUSTER] - add eax, [DATA_START] -.read_entry: - mov ebx, [buffer] - call hd_read - cmp [hd_error],0 - jne .notfound - - mov edi, ebx -.entryfound: - cmp byte [esi], 0 - jz .done - test byte [edi+11], 10h ; is a directory? - jz .notfound - mov eax, [edi+20-2] - mov ax, [edi+26] - jmp .mainloop -.done: - add esp, 262*2+4+4 ; CF=0 - push edi - popad - ret + add esp, 20 ; CF=0 + pop esi + ret ;---------------------------------------------------------------- ; @@ -3366,4 +3291,620 @@ fs_HdReadFolder: pop ecx esi edi ret +fat16_root_next: + cmp edi, buffer+0x200-0x20 + jae fat16_root_next_sector + add edi, 0x20 + ret ; CF=0 +fat16_root_next_sector: +; read next sector + push ecx + mov ecx, [eax+4] + inc ecx + mov [eax+4], ecx + cmp ecx, [ROOT_SECTORS] + pop ecx + jae fat16_root_first.readerr +fat16_root_first: + mov eax, [eax+4] + add eax, [ROOT_START] + push ebx + mov edi, buffer + mov ebx, edi + call hd_read + pop ebx + cmp [hd_error], 0 + jnz .readerr + ret ; CF=0 +.readerr: + stc + ret +fat16_root_begin_write: + push edi eax + call fat16_root_first + pop eax edi + ret +fat16_root_end_write: + pusha + mov eax, [eax+4] + add eax, [ROOT_START] + mov ebx, buffer + call hd_write + popa + ret +fat16_root_next_write: + cmp edi, buffer+0x200 + jae @f + ret +@@: + call fat16_root_end_write + jmp fat16_root_next_sector +fat16_root_extend_dir: + stc + ret + +fat_notroot_next: + cmp edi, buffer+0x200-0x20 + jae fat_notroot_next_sector + add edi, 0x20 + ret ; CF=0 +fat_notroot_next_sector: + push ecx + mov ecx, [eax+4] + inc ecx + cmp ecx, [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 + cmp [hd_error], 0 + jnz fat_notroot_next_err + cmp ecx, [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 + mov edi, buffer + mov ebx, edi + call hd_read + pop ebx + cmp [hd_error], 0 + jnz @f + ret ; CF=0 +fat_notroot_next_err: + pop ecx +@@: + 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 + mov ebx, buffer + call hd_write + pop ebx + ret +fat_notroot_next_write: + cmp edi, buffer+0x200 + jae @f + ret +@@: + push eax + call fat_notroot_end_write + pop eax + jmp fat_notroot_next_sector +fat_notroot_extend_dir: + push eax + mov eax, [eax] + call get_free_FAT + jnc .found + pop eax + ret ; CF=1 +.found: + push edx + mov edx, [fatEND] + call set_FAT + mov edx, eax + mov eax, [esp+4] + mov eax, [eax] + push edx + mov [f_del], 1 + call set_FAT + pop edx + cmp [hd_error], 0 + jz @f + pop edx + pop eax + stc + ret +@@: + push ecx + or ecx, -1 + call add_disk_free_space +; zero new cluster + mov ecx, 512/4 + mov edi, 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, [SECTORS_PER_CLUSTER] + imul eax, ecx + add eax, [DATA_START] + mov ebx, edi +@@: + call hd_write + inc eax + loop @b + pop ecx ebx eax + clc + ret + +fat_get_sector: + push ecx + mov ecx, [eax] + dec ecx + dec ecx + imul ecx, [SECTORS_PER_CLUSTER] + add ecx, [DATA_START] + add ecx, [eax+4] + mov eax, ecx + pop ecx + ret + +;---------------------------------------------------------------- +; +; fs_HdRewrite - LFN variant for writing hard disk +; +; esi points to filename +; ebx ignored (reserved) +; ecx number of bytes to write, 0+ +; edx mem location to data +; +; ret ebx = number of written bytes +; eax = 0 ok read or other = errormsg +; +;-------------------------------------------------------------- +fshrad: + mov eax, ERROR_ACCESS_DENIED + xor ebx, ebx + ret +fshrfs: + mov eax, ERROR_UNKNOWN_FS + xor ebx, ebx + ret + +fs_HdRewrite: + cmp [fat_type], 0 + jz fshrfs + cmp byte [esi], 0 + jz fshrad + pushad + xor ebp, ebp + push esi +@@: + lodsb + test al, al + jz @f + cmp al, '/' + jnz @b + lea ebp, [esi-1] + jmp @b +@@: + pop esi + test ebp, ebp + jnz .noroot + mov ebp, [ROOT_CLUSTER] + cmp [fat_type], 32 + jz .pushnotroot + push fat16_root_extend_dir + push fat16_root_end_write + push fat16_root_next_write + push fat16_root_begin_write + xor ebp, ebp + push ebp + push ebp + push fat16_root_first + push fat16_root_next + jmp .common1 +.noroot: +; check existence + mov byte [ebp], 0 + call hd_find_lfn + mov byte [ebp], '/' + lea esi, [ebp+1] + jnc @f + mov eax, ERROR_FILE_NOT_FOUND +.ret1: + mov [esp+28], eax + popad + xor ebx, ebx + ret +@@: + test byte [edi+11], 0x10 ; must be directory + mov eax, ERROR_ACCESS_DENIED + jz .ret1 + mov ebp, [edi+20-2] + mov bp, [edi+26] ; ebp=cluster + mov eax, ERROR_FAT_TABLE + cmp ebp, 2 + jb .ret1 +.pushnotroot: + push fat_notroot_extend_dir + push fat_notroot_end_write + push fat_notroot_next_write + push fat_notroot_begin_write + push 0 + push ebp + push fat_notroot_first + push fat_notroot_next +.common1: + call fat_find_lfn + jc .notfound +; found, 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 + mov [f_del], 1 +@@: + cmp eax, [fatRESERVED] + jae .done1 + push edx + xor edx, edx + call set_FAT + mov eax, edx + pop edx + 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, 32 + 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 + 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+32 + 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 + push 1 + pop eax ; 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 successive entries in directory + xor ecx, ecx + push eax + lea eax, [esp+16+8+12+8] + mov [eax], ebp + and dword [eax+4], 0 + call dword [eax-4] + pop eax + jnc .scan_dir +.fsfrfe3: + add esp, 12+8+12+32 + popad + mov eax, 11 + 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] + pop eax + jnc .scan_dir + cmp [hd_error], 0 + jnz .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+32 + 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! +; calculate name checksum + push esi ecx + 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 fs_RamdiskRewrite.read_symbols + mov ax, 0xF + stosw + mov al, [esp+4] + stosb + mov cl, 6 + call fs_RamdiskRewrite.read_symbols + xor eax, eax + stosw + mov cl, 2 + call fs_RamdiskRewrite.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 +.doit: + lea eax, [esp+8] + call dword [eax+16] ; flush directory + push ecx + mov ecx, [esp+4+32+24] + push ecx + push edi + mov esi, edx + test ecx, ecx + jz .done + mov eax, 2 + call get_free_FAT + jc .diskfull + 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, [fatEND] + call set_FAT + pop edx +.write_cluster: + push eax + dec eax + dec eax + mov ebp, [SECTORS_PER_CLUSTER] + imul eax, ebp + add eax, [DATA_START] +; write data +.write_sector: + mov ecx, 512 + cmp dword [esp+8], ecx + jb .writeshort +; we can write directly from given buffer + mov ebx, esi + add esi, ecx + jmp .writecommon +.writeshort: + mov ecx, [esp+8] + push ecx + mov edi, buffer + mov ebx, edi + rep movsb + mov ecx, buffer+0x200 + sub ecx, edi + push eax + xor eax, eax + rep stosb + pop eax + pop ecx +.writecommon: + call hd_write + cmp [hd_error], 0 + jnz .writeerr + inc eax + sub dword [esp+8], ecx + jz .writedone + dec ebp + jnz .write_sector +; allocate new cluster + pop eax + mov ecx, eax + call get_free_FAT + jc .diskfull + mov [f_del], 1 + push edx + mov edx, [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 + sub esi, ecx + mov eax, 11 + jmp .ret +.writedone: + pop eax +.done: + xor eax, eax +.ret: + pop edi ecx + mov ebx, esi + sub ebx, edx + pop ebp + mov [esp+32+28], eax + lea eax, [esp+8] + call dword [eax+8] + mov [edi+28], ebx + call dword [eax+16] + mov [esp+32+16], ebx + lea eax, [ebx+511] + shr eax, 9 + mov ecx, [SECTORS_PER_CLUSTER] + lea eax, [eax+ecx-1] + xor edx, edx + div ecx + mov ecx, ebp + sub ecx, eax + call add_disk_free_space + add esp, 32 + call update_disk + popad + ret + ; \end{diamond} diff --git a/kernel/trunk/fs/fs.inc b/kernel/trunk/fs/fs.inc index 8f8d76c35e..1f4ec1b9b9 100644 --- a/kernel/trunk/fs/fs.inc +++ b/kernel/trunk/fs/fs.inc @@ -61,6 +61,7 @@ file_system: ; eax = 8 : disk full ; eax = 9 : fat table corrupted ; eax = 10 : access denied +; eax = 11 : disk error ; ; ebx = size diff --git a/kernel/trunk/fs/fs_lfn.inc b/kernel/trunk/fs/fs_lfn.inc index 9d725f3f61..2db058e9f4 100644 --- a/kernel/trunk/fs/fs_lfn.inc +++ b/kernel/trunk/fs/fs_lfn.inc @@ -51,13 +51,13 @@ file_system_lfn: ; operation codes: ; 0 : read file ; 1 : read folder -; 2 : rewrite file - not implemented yet +; 2 : create/rewrite file ; 3 : write/append to file - not implemented yet -; 4 : start application - not implemented yet -; 5 : delete file - not implemented yet -; 6 : create directory - not implemented yet -; 7 : rename file/directory - not implemented yet -; 8 : get file attributes structure - not implemented yet +; 4 : delete file - not implemented yet +; 5 : create directory - not implemented yet +; 6 : rename file/directory - not implemented yet +; 7 : get file attributes structure - not implemented yet +; 8 : start application - not implemented yet add eax, std_application_base_address ; parse file name @@ -290,8 +290,8 @@ fs_OnRamdisk: cmp ecx, 1 jnz file_system_lfn.notfound mov eax, [ebx] - cmp eax, 1 - ja .not_impl + cmp eax, fs_NumRamdiskServices + jae .not_impl mov ecx, [ebx+12] mov edx, [ebx+16] add edx, std_application_base_address @@ -307,13 +307,15 @@ fs_OnRamdisk: fs_RamdiskServices: dd fs_RamdiskRead dd fs_RamdiskReadFolder + dd fs_RamdiskRewrite +fs_NumRamdiskServices = ($ - fs_RamdiskServices)/4 fs_OnFloppy: cmp ecx, 2 ja file_system_lfn.notfound mov eax, [ebx] - cmp eax, 1 - ja fs_OnRamdisk.not_impl + cmp eax, fs_NumFloppyServices + jae fs_OnRamdisk.not_impl call reserve_flp mov [flp_number], cl mov ecx, [ebx+12] @@ -329,6 +331,8 @@ fs_OnFloppy: fs_FloppyServices: dd fs_FloppyRead dd fs_FloppyReadFolder + dd fs_FloppyRewrite +fs_NumFloppyServices = ($ - fs_FloppyServices)/4 fs_OnHd0: call reserve_hd1 @@ -373,8 +377,8 @@ fs_OnHd: mov edx, [ebx+16] add edx, std_application_base_address mov eax, [ebx] - cmp eax, 1 - ja .not_impl + cmp eax, fs_NumHdServices + jae .not_impl add ebx, 4 call dword [fs_HdServices + eax*4] and [hd1_status], 0 @@ -389,6 +393,8 @@ fs_OnHd: fs_HdServices: dd fs_HdRead dd fs_HdReadFolder + dd fs_HdRewrite +fs_NumHdServices = ($ - fs_HdServices)/4 fs_HasRamdisk: mov al, 1 ; we always have ramdisk