Krn: Fixed the number of functions in the file system drivers
[kolibrios.git] / kernel / trunk / fs / ext.inc
blob84a97c2052350b194df9bb88c95e46dabd41c105
1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2 ;;                                                              ;;
3 ;; Copyright (C) KolibriOS team 2013-2016. All rights reserved. ;;
4 ;;  Distributed under terms of the GNU General Public License.  ;;
5 ;;                                                              ;;
6 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
8 $Revision$
10 ; EXT external functions
11 ;   in:
12 ; ebx -> parameter structure of sysfunc 70
13 ; ebp -> EXTFS structure
14 ; esi -> path string in UTF-8
15 ;   out:
16 ; eax, ebx = return values for sysfunc 70
17 iglobal
18 align 4
19 ext_user_functions:
20         dd      ext_free
21         dd      (ext_user_functions_end - ext_user_functions - 8) / 4
22         dd      ext_ReadFile
23         dd      ext_ReadFolder
24         dd      ext_CreateFile
25         dd      ext_WriteFile
26         dd      ext_SetFileEnd
27         dd      ext_GetFileInfo
28         dd      ext_SetFileInfo
29         dd      0
30         dd      ext_Delete
31         dd      ext_CreateFolder
32         dd      ext_Rename
33 ext_user_functions_end:
34 endg
36 struct DIRENTRY
37 inodeNumber     dd  ?
38 entryLength     dw  ?
39 nameLength      db  ?
40 fileType        db  ?
41 name            db  ?   ; rb [nameLength]
42 ends
44 struct INODE
45 accessMode      dw  ?
46 UID             dw  ?
47 fileSize        dd  ?
48 accessedTime    dd  ?
49 inodeModified   dd  ?
50 dataModified    dd  ?
51 deletedTime     dd  ?
52 GID             dw  ?
53 linksCount      dw  ?
54 sectorsUsed     dd  ?
55 featureFlags    dd  ?
56 reserved        dd  ?
57 blockNumbers    rd  12
58 addressBlock    dd  ?
59 doubleAddress   dd  ?
60 tripleAddress   dd  ?
61 generation      dd  ?
62 ACL             dd  ?
63 fileSizeHigh    dd  ?
64 ends
66 struct BGDESCR  ; block group descriptor
67 blockBitmap         dd  ?
68 inodeBitmap         dd  ?
69 inodeTable          dd  ?
70 blocksFree          dw  ?
71 inodesFree          dw  ?
72 directoriesCount    dw  ?
73 reserved            rb  14
74 ends
76 struct SUPERBLOCK
77 inodesTotal         dd  ?
78 blocksTotal         dd  ?
79 blocksReserved      dd  ?
80 blocksFree          dd  ?
81 inodesFree          dd  ?
82 firstGroupBlock     dd  ?
83 sectorsPerBlockLog  dd  ?   ; shift for 1024
84 fragmentSizeLog     dd  ?
85 blocksPerGroup      dd  ?
86 fragmentsPerGroup   dd  ?
87 inodesPerGroup      dd  ?
88 lastMountTime       dd  ?
89 lastWriteTime       dd  ?
90 mountCount          dw  ?
91 mountMax            dw  ?
92 magic               dw  ?
93 state               dw  ?
94 errorHandling       dw  ?
95 additionalVersion   dw  ?
96 lastCheck           dd  ?
97 checkInterval       dd  ?
98 creatorOS           dd  ?
99 dynamicVersionFlag  dd  ?
100 reservedUID         dw  ?
101 reservedGID         dw  ?
102 firstInode          dd  ?
103 inodeSize           dw  ?
104 thisBlockGroup      dw  ?
105 compatibleFlags     dd  ?
106 incompatibleFlags   dd  ?
107 RO_compatibleFlags  dd  ?
108 UUID                rb  16
109 volumeLabel         rb  16
110 ends
112 ; ext4 extent tree
113 struct NODEHEADER       ; tree node header
114 magic           dw  ?   ; 0xF30A
115 entriesFolow    dw  ?
116 entriesMax      dw  ?
117 currentDepth    dw  ?
118 generation      dd  ?
119 ends
121 struct INDEX    ; root/branch
122 fileBlock       dd  ?
123 nodeBlock       dd  ?
124 nodeBlockHigh   dw  ?
125 reserved        dw  ?
126 ends
128 struct EXTENT   ; leaf
129 fileBlock       dd  ?
130 blocksCount     dw  ?
131 fsBlockHigh     dw  ?
132 fsBlock         dd  ?
133 ends
135 ROOT_INODE = 2
136 EXTENTS_USED = 80000h
137 TYPE_MASK = 0F000h
138 FLAG_FILE = 8000h
139 DIRECTORY = 4000h
140 DIR_FLAG_FILE = 1
141 DIR_DIRECTORY = 2
142 KOS_HIDDEN = 2
143 KOS_DIRECTORY = 10h
144 READ_ONLY = 1
146 ; Implemented "incompatible" features:
147 ; 2 = have file type in directory entry
148 ; 40h = extents
149 ; 200h = flexible block groups
150 INCOMPATIBLE_SUPPORT = 242h
151 ; Read only support for "incompatible" features:
152 INCOMPATIBLE_READ_SUPPORT = 240h
154 ; Implemented "read-only" features:
155 ; 1 = sparse superblock
156 ; 2 = 64-bit file size
157 READ_ONLY_SUPPORT = 3
159 struct EXTFS PARTITION
160 Lock                MUTEX
161 mountType           dd  ?
162 bytesPerBlock       dd  ?
163 sectorsPerBlock     dd  ?
164 dwordsPerBlock      dd  ?
165 dwordsPerBranch     dd  ?   ; dwordsPerBlock ^ 2
166 mainBlockBuffer     dd  ?
167 tempBlockBuffer     dd  ?
168 descriptorTable     dd  ?
169 descriptorTableEnd  dd  ?
170 align0  rb  200h-EXTFS.align0
171 superblock          SUPERBLOCK
172 align1  rb  400h-EXTFS.align1
173 rootInodeBuffer     INODE
174 align2  rb  600h-EXTFS.align2
175 inodeBuffer         INODE
176 align3  rb  800h-EXTFS.align3
177 ends
179 ; mount if it's a valid EXT partition
180 ext2_create_partition:
181 ;   in:
182 ; ebp -> PARTITION structure
183 ; ebx -> boot sector
184 ; ebx+512 -> buffer
185 ;   out:
186 ; eax -> EXTFS structure, 0 = not EXT
187         push    ebx
188         cmp     dword [esi+DISK.MediaInfo.SectorSize], 512
189         jnz     .fail
190         mov     eax, 2
191         add     ebx, 512
192         call    fs_read32_sys
193         test    eax, eax
194         jnz     .fail
195         cmp     [ebx+SUPERBLOCK.magic], 0xEF53
196         jne     .fail
197         cmp     [ebx+SUPERBLOCK.state], 1
198         ja      .fail
199         test    [ebx+SUPERBLOCK.incompatibleFlags], not INCOMPATIBLE_SUPPORT
200         jnz     .fail
201         cmp     [ebx+SUPERBLOCK.sectorsPerBlockLog], 6  ; 64KB
202         ja      .fail
203         cmp     [ebx+SUPERBLOCK.inodeSize], 512
204         ja      .fail
205         cmp     [ebx+SUPERBLOCK.blocksPerGroup], 0
206         je      .fail
207         cmp     [ebx+SUPERBLOCK.inodesPerGroup], 0
208         je      .fail
209         movi    eax, sizeof.EXTFS
210         call    malloc
211         test    eax, eax
212         jz      .fail
213         mov     ecx, dword [ebp+PARTITION.FirstSector]
214         mov     dword [eax+EXTFS.FirstSector], ecx
215         mov     ecx, dword [ebp+PARTITION.FirstSector+4]
216         mov     dword [eax+EXTFS.FirstSector+4], ecx
217         mov     ecx, dword [ebp+PARTITION.Length]
218         mov     dword [eax+EXTFS.Length], ecx
219         mov     ecx, dword [ebp+PARTITION.Length+4]
220         mov     dword [eax+EXTFS.Length+4], ecx
221         mov     ecx, [ebp+PARTITION.Disk]
222         mov     [eax+EXTFS.Disk], ecx
223         mov     [eax+EXTFS.FSUserFunctions], ext_user_functions
225         push    ebp esi edi
226         mov     ebp, eax
227         lea     ecx, [eax+EXTFS.Lock]
228         call    mutex_init
229         mov     esi, ebx
230         lea     edi, [ebp+EXTFS.superblock]
231         mov     ecx, 512/4
232         rep movsd   ; copy superblock
233         mov     ecx, [ebx+SUPERBLOCK.sectorsPerBlockLog]
234         inc     ecx
235         mov     eax, 1
236         shl     eax, cl
237         mov     [ebp+EXTFS.sectorsPerBlock], eax
238         shl     eax, 9
239         mov     [ebp+EXTFS.bytesPerBlock], eax
240         shl     eax, 1
241         push    eax
242         shr     eax, 3
243         mov     [ebp+EXTFS.dwordsPerBlock], eax
244         mul     eax
245         mov     [ebp+EXTFS.dwordsPerBranch], eax
246         call    kernel_alloc
247         test    eax, eax
248         jz      .error
249         mov     [ebp+EXTFS.mainBlockBuffer], eax
250         add     eax, [ebp+EXTFS.bytesPerBlock]
251         mov     [ebp+EXTFS.tempBlockBuffer], eax
252         mov     [ebp+EXTFS.mountType], 0
253         test    [ebx+SUPERBLOCK.RO_compatibleFlags], not READ_ONLY_SUPPORT
254         jnz     .read_only
255         test    [ebx+SUPERBLOCK.incompatibleFlags], INCOMPATIBLE_READ_SUPPORT
256         jz      @f
257 .read_only:
258         or      [ebp+EXTFS.mountType], READ_ONLY
260         mov     eax, [ebx+SUPERBLOCK.inodesTotal]
261         dec     eax
262         xor     edx, edx
263         div     [ebx+SUPERBLOCK.inodesPerGroup]
264         inc     eax
265         shl     eax, 5
266         push    eax eax
267         call    kernel_alloc
268         pop     ecx
269         test    eax, eax
270         jz      .error2
271         mov     [ebp+EXTFS.descriptorTable], eax
272         mov     ebx, eax
273         add     eax, ecx
274         mov     [ebp+EXTFS.descriptorTableEnd], eax
275         mov     eax, [ebp+EXTFS.superblock.firstGroupBlock]
276         inc     eax
277         mul     [ebp+EXTFS.sectorsPerBlock]
278         dec     ecx
279         shr     ecx, 9
280         inc     ecx
281         call    fs_read64_sys
282         test    eax, eax
283         jnz     @f
284         mov     al, ROOT_INODE
285         lea     ebx, [ebp+EXTFS.rootInodeBuffer]
286         call    readInode
287         test    eax, eax
288         jnz     @f
289         mov     eax, ebp
290         pop     edi esi ebp ebx
291         ret
294         stdcall kernel_free, [ebp+EXTFS.descriptorTable]
295 .error2:
296         stdcall kernel_free, [ebp+EXTFS.mainBlockBuffer]
297 .error:
298         mov     eax, ebp
299         call    free
300         pop     edi esi ebp
301 .fail:
302         pop     ebx
303         xor     eax, eax
304         ret
306 ; unmount EXT partition
307 ext_free:
308 ; in: eax -> EXTFS structure
309         push    eax [eax+EXTFS.mainBlockBuffer]
310         stdcall kernel_free, [eax+EXTFS.descriptorTable]
311         call    kernel_free
312         pop     eax
313         jmp     free
315 extfsWriteBlock:
316         push    fs_write64_sys
317         jmp     @f
318 ; in: eax = block number, ebx -> buffer
319 extfsReadBlock:
320         push    fs_read64_sys
322         push    ecx edx
323         mov     ecx, [ebp+EXTFS.sectorsPerBlock]
324         mul     ecx
325         call    dword[esp+8]
326         pop     edx ecx
327         add     esp, 4
328         test    eax, eax
329         jz      @f
330         movi    eax, ERROR_DEVICE
331         stc
333         ret
335 extfsWriteDescriptor:
336 ; in: ebx = block group descriptor
337         mov     eax, [ebp+EXTFS.superblock.firstGroupBlock]
338         inc     eax
339         mul     [ebp+EXTFS.sectorsPerBlock]
340         sub     ebx, [ebp+EXTFS.descriptorTable]
341         shr     ebx, 9
342         add     eax, ebx
343         shl     ebx, 9
344         add     ebx, [ebp+EXTFS.descriptorTable]
345         call    fs_write32_sys
346         ret
348 extfsExtentFree:
349 ; in: eax = first block number, ecx = extent size
350         push    ebx edx edi
351         sub     eax, [ebp+EXTFS.superblock.firstGroupBlock]
352         xor     edx, edx
353         mov     ebx, [ebp+EXTFS.superblock.blocksPerGroup]
354         div     ebx
355         sub     ebx, edx
356         sub     ebx, ecx
357         jc      .ret
358         push    edx
359         mov     ebx, [ebp+EXTFS.descriptorTable]
360         shl     eax, 5
361         add     ebx, eax
362         mov     eax, ecx
363         mul     [ebp+EXTFS.sectorsPerBlock]
364         add     [ebx+BGDESCR.blocksFree], cx
365         add     [ebp+EXTFS.superblock.blocksFree], ecx
366         sub     [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
367         push    [ebx+BGDESCR.blockBitmap]
368         call    extfsWriteDescriptor
369         pop     eax
370         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
371         mov     edx, eax
372         call    extfsReadBlock
373         pop     eax
374         jc      .ret
375         push    ebx edx
376         mov     edi, eax
377         shr     edi, 5
378         shl     edi, 2
379         add     edi, ebx
380         mov     edx, ecx
381         and     eax, 31
382         jz      .aligned
383         mov     ecx, 32
384         sub     ecx, eax
385         sub     edx, ecx
386         jnc     @f
387         add     ecx, edx
388         xor     edx, edx
390         or      ebx, -1
391         shl     ebx, cl
392         not     ebx
393         mov     ecx, eax
394         shl     ebx, cl
395         not     ebx
396         and     [edi], ebx
397         add     edi, 4
398         xor     eax, eax
399 .aligned:
400         mov     ecx, edx
401         shr     ecx, 5
402         rep stosd
403         and     edx, 31
404         jz      @f
405         mov     ecx, edx
406         not     eax
407         shl     eax, cl
408         and     [edi], eax
410         pop     eax ebx
411         call    extfsWriteBlock
412 .ret:
413         pop     edi edx ebx
414         xor     eax, eax
415         ret
417 extfsInodeAlloc:
418 ; in: eax = parent inode number
419 ; out: ebx = allocated inode number
420         push    ecx edx edi
421         dec     eax
422         xor     edx, edx
423         div     [ebp+EXTFS.superblock.inodesPerGroup]
424         mov     ebx, [ebp+EXTFS.descriptorTable]
425         shl     eax, 5
426         add     ebx, eax
427         push    ebx
428 .test_block_group:
429         push    ebx
430         cmp     [ebx+BGDESCR.blocksFree], 0
431         jz      .next
432         cmp     [ebx+BGDESCR.inodesFree], 0
433         jz      .next
434         dec     [ebx+BGDESCR.inodesFree]
435         dec     [ebp+EXTFS.superblock.inodesFree]
436         push    [ebx+BGDESCR.inodeBitmap]
437         call    extfsWriteDescriptor
438         pop     eax
439         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
440         mov     edx, eax
441         mov     edi, ebx
442         call    extfsReadBlock
443         jc      .fail
444         mov     ecx, [ebp+EXTFS.superblock.inodesPerGroup]
445         or      eax, -1
446         shr     ecx, 5
447         repz scasd
448         jz      .next
449         sub     edi, 4
450         mov     eax, [edi]
451         not     eax
452         bsf     eax, eax
453         bts     [edi], eax
454         sub     edi, [ebp+EXTFS.tempBlockBuffer]
455         shl     edi, 3
456         add     eax, edi
457         mov     ecx, eax
458         mov     eax, edx
459         call    extfsWriteBlock
460         pop     eax
461         sub     eax, [ebp+EXTFS.descriptorTable]
462         shr     eax, 5
463         mul     [ebp+EXTFS.superblock.inodesPerGroup]
464         lea     ebx, [eax+ecx+1]
465         xor     eax, eax
466 .ret:
467         pop     edi edi edx ecx
468         ret
470 .next:      ; search forward, then backward
471         pop     ebx
472         cmp     ebx, [esp]
473         jc      .backward
474         add     ebx, 32
475         cmp     ebx, [ebp+EXTFS.descriptorTableEnd]
476         jc      .test_block_group
477         mov     ebx, [esp]
478 .backward:
479         sub     ebx, 32
480         cmp     ebx, [ebp+EXTFS.descriptorTable]
481         jnc     .test_block_group
482         movi    eax, ERROR_DISK_FULL
483         push    eax
484 .fail:
485         pop     edi
486         jmp     .ret
488 extfsExtentAlloc:
489 ; in: eax = parent inode number, ecx = blocks max
490 ; out: ebx = first block number, ecx = blocks allocated
491         push    edx esi edi ecx
492         dec     eax
493         xor     edx, edx
494         div     [ebp+EXTFS.superblock.inodesPerGroup]
495         mov     ebx, [ebp+EXTFS.descriptorTable]
496         shl     eax, 5
497         add     ebx, eax
498         push    ebx
499 .test_block_group:
500         push    ebx
501         cmp     [ebx+BGDESCR.blocksFree], 0
502         jz      .next
503         mov     eax, [ebx+BGDESCR.blockBitmap]
504         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
505         mov     edx, eax
506         mov     edi, ebx
507         call    extfsReadBlock
508         jc      .fail
509         mov     ecx, [ebp+EXTFS.superblock.blocksPerGroup]
510         shr     ecx, 5
511         or      eax, -1
512         repz scasd
513         jz      .next
514         mov     esi, edi
515         sub     esi, 4
516         push    edx ecx
517         mov     eax, [esi]
518         not     eax
519         bsf     ecx, eax
520         not     eax
521         shr     eax, cl
522         shl     eax, cl
523         mov     ebx, 32
524         bsf     ebx, eax
525         sub     ebx, ecx
526         mov     eax, [esp+16]
527         cmp     ebx, eax
528         jc      @f
529         mov     ebx, eax
531         or      eax, -1
532         cmp     ebx, 32
533         jz      @f
534         xchg    ebx, ecx
535         shl     eax, cl
536         not     eax
537         xchg    ebx, ecx
538         shl     eax, cl
540         or      [esi], eax
541         sub     esi, [ebp+EXTFS.tempBlockBuffer]
542         shl     esi, 3
543         add     esi, ecx
544         mov     eax, [esp+16]
545         sub     eax, ebx
546         mov     [esp+16], ebx
547         add     ebx, ecx
548         pop     ecx
549         test    eax, eax
550         jz      .done
551         cmp     ebx, 32
552         jnz     .done
553         jecxz   .done
554         mov     ebx, eax
555         shr     eax, 5
556         inc     eax
557         and     ebx, 31
558         cmp     ecx, eax
559         jnc     @f
560         mov     eax, ecx
561         mov     bl, 32
563         mov     ecx, eax
564         shl     eax, 5
565         add     [esp+12], eax
566         xor     eax, eax
567         push    edi
568         repz scasd
569         jz      @f
570         mov     eax, [edi-4]
571         bsf     eax, eax
572         xchg    eax, ebx
573         test    ecx, ecx
574         jnz     @f
575         cmp     ebx, eax
576         jc      @f
577         mov     ebx, eax
579         inc     ecx
580         shl     ecx, 5
581         sub     ecx, ebx
582         sub     [esp+16], ecx
583         mov     ecx, edi
584         pop     edi
585         sub     ecx, edi
586         shr     ecx, 2
587         dec     ecx
588         or      eax, -1
589         rep stosd
590         mov     ecx, ebx
591         jecxz   .done
592         neg     ecx
593         add     ecx, 32
594         shr     eax, cl
595         or      [edi], eax
596 .done:
597         pop     eax
598         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
599         call    extfsWriteBlock
600         mov     ebx, [esp]
601         mov     ecx, [esp+8]
602         sub     [ebx+BGDESCR.blocksFree], cx
603         jnc     @f
604         mov     [ebx+BGDESCR.blocksFree], 0
606         sub     [ebp+EXTFS.superblock.blocksFree], ecx
607         call    extfsWriteDescriptor
608         pop     eax ebx
609         sub     eax, [ebp+EXTFS.descriptorTable]
610         shr     eax, 5
611         mul     [ebp+EXTFS.superblock.blocksPerGroup]
612         mov     ebx, eax
613         add     ebx, esi
614         add     ebx, [ebp+EXTFS.superblock.firstGroupBlock]
615         pop     ecx
616         mov     eax, ecx
617         mul     [ebp+EXTFS.sectorsPerBlock]
618         add     [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
619         xor     eax, eax
620 .ret:
621         pop     edi esi edx
622         ret
624 .next:      ; search forward, then backward
625         pop     ebx
626         cmp     ebx, [esp]
627         jc      .backward
628         add     ebx, 32
629         cmp     ebx, [ebp+EXTFS.descriptorTableEnd]
630         jc      .test_block_group
631         mov     ebx, [esp]
632 .backward:
633         sub     ebx, 32
634         cmp     ebx, [ebp+EXTFS.descriptorTable]
635         jnc     .test_block_group
636         movi    eax, ERROR_DISK_FULL
637         push    eax
638 .fail:
639         add     esp, 12
640         xor     ecx, ecx
641         stc
642         jmp     .ret
644 extfsGetExtent:
645 ; in: ecx = starting file block
646 ; out: eax = first block number, ecx = extent size
647         push    ebx edx esi
648         lea     esi, [ebp+EXTFS.inodeBuffer]
649         test    [esi+INODE.featureFlags], EXTENTS_USED
650         jz      .listTreeSearch
651         add     esi, INODE.blockNumbers
652 .extentTreeSearch:
653         cmp     word [esi+NODEHEADER.magic], 0xF30A
654         jne     .fail
655         movzx   ebx, [esi+NODEHEADER.entriesFolow]
656         add     esi, sizeof.NODEHEADER
657         test    ebx, ebx
658         jz      .noBlock
659         cmp     word [esi-sizeof.NODEHEADER+NODEHEADER.currentDepth], 0
660         je      .leaf_block
661         dec     ebx
662         jz      .end_search_index
664         cmp     ecx, [esi+sizeof.INDEX+INDEX.fileBlock]
665         jb      .end_search_index
666         add     esi, sizeof.INDEX
667         dec     ebx
668         jnz     @b
669 .end_search_index:
670         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
671         mov     eax, [esi+INDEX.nodeBlock]
672         call    extfsReadBlock
673         jc      .fail2
674         mov     esi, ebx
675         jmp     .extentTreeSearch
677 .fail:
678         movi    eax, ERROR_FS_FAIL
679         jmp     .fail2
681 .leaf_block:
682         movzx   edx, [esi+EXTENT.blocksCount]
683         add     edx, [esi+EXTENT.fileBlock]
684         sub     edx, ecx
685         ja      .end_search_extent
686         add     esi, sizeof.EXTENT
687         dec     ebx
688         jnz     .leaf_block
689 .noBlock:
690         movi    eax, ERROR_END_OF_FILE
691 .fail2:
692         pop     esi edx ebx
693         stc
694         ret
696 .end_search_extent:
697         sub     ecx, [esi+EXTENT.fileBlock]
698         jc      .fail
699         add     ecx, [esi+EXTENT.fsBlock]
700         mov     eax, ecx
701         mov     ecx, edx
702         pop     esi edx ebx
703         ret
705 .listTreeSearch:
706         cmp     ecx, 12
707         jb      .get_direct_block
708         sub     ecx, 12
709         cmp     ecx, [ebp+EXTFS.dwordsPerBlock]
710         jb      .get_indirect_block
711         sub     ecx, [ebp+EXTFS.dwordsPerBlock]
712         cmp     ecx, [ebp+EXTFS.dwordsPerBranch]
713         jb      .get_double_indirect_block
714 ; triply-indirect blocks
715         sub     ecx, [ebp+EXTFS.dwordsPerBranch]
716         mov     eax, [esi+INODE.tripleAddress]
717         test    eax, eax
718         jz      .noBlock
719         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
720         call    extfsReadBlock
721         jc      .fail2
722         xor     edx, edx
723         mov     eax, ecx
724         div     [ebp+EXTFS.dwordsPerBranch]
725 ; eax = number in triply-indirect block, edx = number in branch
726         mov     eax, [ebx+eax*4]
727         test    eax, eax
728         jz      .noBlock
729         call    extfsReadBlock
730         jc      .fail2
731         mov     eax, edx
732         jmp     @f
734 .get_direct_block:
735         mov     edx, ecx
736         mov     cl, 12
737         lea     ebx, [esi+INODE.blockNumbers]
738         jmp     .calculateExtent
740 .get_indirect_block:
741         mov     eax, [esi+INODE.addressBlock]
742         test    eax, eax
743         jz      .noBlock
744         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
745         call    extfsReadBlock
746         jc      .fail2
747         mov     edx, ecx
748         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
749         jmp     .calculateExtent
751 .get_double_indirect_block:
752         mov     eax, [esi+INODE.doubleAddress]
753         test    eax, eax
754         jz      .noBlock
755         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
756         call    extfsReadBlock
757         jc      .fail2
758         mov     eax, ecx
760         xor     edx, edx
761         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
762         div     ecx
763 ; eax = number in doubly-indirect block, edx = number in indirect block
764         mov     eax, [ebx+eax*4]
765         test    eax, eax
766         jz      .noBlock
767         call    extfsReadBlock
768         jc      .fail2
769 .calculateExtent:
770         lea     esi, [ebx+edx*4]
771         lodsd
772         test    eax, eax
773         jz      .noBlock
774         mov     ebx, eax
775         sub     ecx, edx
776         xor     edx, edx
778         inc     edx
779         dec     ecx
780         jz      @f
781         lodsd
782         sub     eax, ebx
783         sub     eax, edx
784         jz      @b
786         mov     eax, ebx
787         mov     ecx, edx
788         pop     esi edx ebx
789         clc
790         ret
792 getInodeLocation:
793 ; in: eax = inode number
794 ; out: eax = inode sector, edx = offset in sector
795         dec     eax
796         xor     edx, edx
797         div     [ebp+EXTFS.superblock.inodesPerGroup]
798         shl     eax, 5
799         add     eax, [ebp+EXTFS.descriptorTable]
800         mov     ebx, [eax+BGDESCR.inodeTable]
801         imul    ebx, [ebp+EXTFS.sectorsPerBlock]
802         movzx   eax, [ebp+EXTFS.superblock.inodeSize]
803         mul     edx
804         mov     edx, eax
805         shr     eax, 9
806         and     edx, 511
807         add     eax, ebx
808         ret
810 writeInode:
811 ; in: eax = inode number, ebx -> inode data
812         push    edx edi esi ecx ebx eax
813         mov     edi, ebx
814         call    fsGetTime
815         add     eax, 978307200
816         mov     [edi+INODE.inodeModified], eax
817         pop     eax
818         cmp     eax, ROOT_INODE
819         jnz     @f
820         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
821         mov     esi, edi
822         lea     edi, [ebp+EXTFS.rootInodeBuffer]
823         rep movsb
825         call    getInodeLocation
826         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
827         mov     ecx, eax
828         call    fs_read32_sys
829         test    eax, eax
830         jnz     @f
831         mov     eax, ecx
832         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
833         mov     edi, edx
834         add     edi, ebx
835         mov     esi, [esp]
836         rep movsb
837         call    fs_write32_sys
838 .ret:
839         pop     ebx ecx esi edi edx
840         ret
843         movi    eax, ERROR_DEVICE
844         stc
845         jmp     .ret
847 readInode:
848 ; in: eax = inode number, ebx -> inode buffer
849         push    edx edi esi ecx ebx
850         mov     edi, ebx
851         call    getInodeLocation
852         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
853         call    fs_read32_sys
854         test    eax, eax
855         jnz     @b
856         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
857         mov     esi, edx
858         add     esi, ebx
859         rep movsb
860         xor     eax, eax
861         pop     ebx ecx esi edi edx
862         ret
864 indirectBlockAlloc:
865 ;   in:
866 ; edi -> indirect block number
867 ; ebx = starting extent block
868 ; ecx = extent size
869 ; edx = starting file block
870         mov     eax, [edi]
871         test    eax, eax
872         jz      .newBlock
873         push    edi ebx ecx
874         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
875         call    extfsReadBlock
876         jc      .err2
877         lea     edi, [ebx+edx*4]
878         test    edx, edx
879         jz      @f
880         cmp     dword[edi-4], 0
881         jnz     @f
882         pop     ecx ebx edi
883 .err:
884         mov     al, ERROR_FS_FAIL
885         stc
886         ret
888 .err2:
889         pop     ecx ebx edi
890         ret
892 .newBlock:
893         test    edx, edx
894         jnz     .err
895         mov     [edi], ebx
896         inc     ebx
897         dec     ecx
898         push    edi ebx ecx
899         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
900         mov     edi, [ebp+EXTFS.tempBlockBuffer]
901         push    edi
902         rep stosd
903         pop     edi
905         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
906         sub     ecx, edx
907         pop     ebx eax
908         sub     ebx, ecx
909         jnc     @f
910         add     ecx, ebx
911         xor     ebx, ebx
913         jecxz   .done
914         add     edx, ecx
916         stosd
917         inc     eax
918         loop    @b
919 .done:
920         pop     edi
921         push    eax ebx
922         mov     eax, [edi]
923         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
924         call    extfsWriteBlock
925         pop     ecx ebx
926         ret
928 doublyIndirectBlockAlloc:
929 ;   in:
930 ; edi -> indirect block number
931 ; edx = starting file block
932 ; ebx = starting extent block
933 ; ecx = extent size
934 ; [esp+4] = rest of size
935 ; [esp+8] = parent inode number
936         mov     eax, [edi]
937         test    eax, eax
938         jz      .newBlock
939         push    edi ecx ebx
940         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
941         call    extfsReadBlock
942         jc      .err2
943         mov     eax, edx
944         xor     edx, edx
945         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
946         div     ecx
947         lea     edi, [ebx+eax*4]
948         pop     ebx
949         test    eax, eax
950         jz      @f
951         cmp     dword[edi-4], 0
952         jnz     @f
953         pop     ecx edi
954 .err:
955         mov     al, ERROR_FS_FAIL
956         stc
957         ret
959 .err2:
960         pop     ebx ecx edi
961         ret
963 .newBlock:
964         test    edx, edx
965         jnz     .err
966         mov     [edi], ebx
967         inc     ebx
968         dec     ecx
969         inc     dword[esp+4]
970         push    edi ecx
971         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
972         mov     edi, [ebp+EXTFS.mainBlockBuffer]
973         push    ecx edi
974         rep stosd
975         pop     edi ecx
977         sub     ecx, eax
978         xchg    [esp], ecx
979 .loop:
980         cmp     dword[edi], 0
981         jnz     @f
982         inc     dword[esp+12]
984         jecxz   .extentAlloc
985         call    indirectBlockAlloc
986         jc      .end
987         cmp     edx, [ebp+EXTFS.dwordsPerBlock]
988         jnz     @b
989         add     edi, 4
990         xor     edx, edx
991         dec     dword[esp]
992         jnz     .loop
993 .end:
994         pop     edi edi
995         push    ebx eax
996         mov     eax, [edi]
997         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
998         call    extfsWriteBlock
999         pop     ebx
1000         add     eax, ebx
1001         xor     ebx, ebx
1002         cmp     ebx, eax
1003         pop     ebx
1004         ret
1006 .extentAlloc:
1007         mov     ecx, [esp+12]
1008         xor     eax, eax
1009         jecxz   .end
1010         mov     eax, [esp+16]
1011         call    extfsExtentAlloc
1012         jc      .end
1013         sub     [esp+12], ecx
1014         jmp     @b
1016 extfsExtendFile:
1017 ;   in:
1018 ; [ebp+EXTFS.inodeBuffer] = inode
1019 ; ecx = inode number
1020 ; edx:eax = new size
1021         push    ebx esi edi ecx
1022         lea     esi, [ebp+EXTFS.inodeBuffer]
1023         mov     ebx, [esi+INODE.fileSize]
1024         mov     ecx, [esi+INODE.fileSizeHigh]
1025         cmp     ebx, eax
1026         sbb     ecx, edx
1027         jnc     .ret
1028         mov     ecx, [esi+INODE.fileSizeHigh]
1029         mov     [esi+INODE.fileSize], eax
1030         mov     [esi+INODE.fileSizeHigh], edx
1031         sub     eax, 1
1032         sbb     edx, 0
1033         div     [ebp+EXTFS.bytesPerBlock]
1034         inc     eax
1035         xchg    eax, ebx
1036         mov     edx, ecx
1037         sub     eax, 1
1038         sbb     edx, 0
1039         jc      @f
1040         div     [ebp+EXTFS.bytesPerBlock]
1042         inc     eax
1043         sub     ebx, eax
1044         jz      .ret
1045         push    ebx
1046         mov     edx, eax
1048         mov     ecx, [esp]
1049         mov     eax, [esp+4]
1050         test    ecx, ecx
1051         jz      .done
1052         call    extfsExtentAlloc
1053         jc      .errDone
1054         sub     [esp], ecx
1055         cmp     edx, 12
1056         jc      .directBlocks
1057         sub     edx, 12
1058         cmp     edx, [ebp+EXTFS.dwordsPerBlock]
1059         jc      .indirectBlocks
1060         sub     edx, [ebp+EXTFS.dwordsPerBlock]
1061         cmp     edx, [ebp+EXTFS.dwordsPerBranch]
1062         jc      .doublyIndirectBlock
1063         sub     edx, [ebp+EXTFS.dwordsPerBranch]
1064         jmp     .triplyIndirectBlock
1066 .newExtent:
1067         jmp     @b
1069 .directBlocks:
1070         lea     edi, [esi+INODE.blockNumbers+edx*4]
1071         test    edx, edx
1072         jz      @f
1073         cmp     dword[edi-4], 0
1074         jz      .errDone
1076         mov     eax, ebx
1077         mov     ebx, ecx
1078         mov     ecx, 12
1079         sub     ecx, edx
1080         sub     ebx, ecx
1081         jnc     @f
1082         add     ecx, ebx
1083         xor     ebx, ebx
1085         add     edx, ecx
1087         stosd
1088         inc     eax
1089         loop    @b
1090         mov     ecx, ebx
1091         mov     ebx, eax
1092         jecxz   .newExtent
1093         xor     edx, edx
1094 .indirectBlocks:
1095         lea     edi, [esi+INODE.addressBlock]
1096         cmp     dword[edi], 0
1097         jnz     @f
1098         inc     dword[esp]
1100         call    indirectBlockAlloc
1101         jc      .errDone
1102         add     edx, 12
1103         jecxz   .newExtent
1104         xor     edx, edx
1105 .doublyIndirectBlock:
1106         lea     edi, [esi+INODE.doubleAddress]
1107         call    doublyIndirectBlockAlloc
1108         jc      .errDone
1109         mov     edx, [ebp+EXTFS.dwordsPerBranch]
1110         add     edx, [ebp+EXTFS.dwordsPerBlock]
1111         add     edx, 12
1112         jecxz   .newExtent
1113         xor     edx, edx
1114 .triplyIndirectBlock:
1115         push    ecx ebx edx
1116         stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
1117         pop     edx
1118         mov     esi, eax
1119         mov     eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
1120         test    eax, eax
1121         jz      .newBlock
1122         mov     ebx, esi
1123         call    extfsReadBlock
1124         pop     ebx ecx
1125         jc      .errFree
1126         mov     eax, edx
1127         xor     edx, edx
1128         div     [ebp+EXTFS.dwordsPerBranch]
1129         lea     edi, [esi+eax*4]
1130         test    eax, eax
1131         jz      @f
1132         cmp     dword[edi-4], 0
1133         jnz     @f
1134         mov     al, ERROR_FS_FAIL
1135 .errFree:
1136         push    ecx eax
1137         stdcall kernel_free, esi
1138         pop     eax ecx
1139 .errDone:
1140         imul    ecx, [ebp+EXTFS.sectorsPerBlock]
1141         sub     [ebp+EXTFS.inodeBuffer.sectorsUsed], ecx
1142         pop     ebx
1143         imul    ebx, [ebp+EXTFS.sectorsPerBlock]
1144         add     ebx, ecx
1145         shl     ebx, 9
1146         sub     [ebp+EXTFS.inodeBuffer.fileSize], ebx
1147         stc
1148         jmp     .ret
1150 .newBlock:
1151         pop     ebx ecx
1152         mov     al, ERROR_FS_FAIL
1153         test    edx, edx
1154         jnz     .errFree
1155         mov     [ebp+EXTFS.inodeBuffer.tripleAddress], ebx
1156         inc     ebx
1157         dec     ecx
1158         inc     dword[esp]
1159         push    ecx
1160         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
1161         mov     edi, esi
1162         xor     eax, eax
1163         rep stosd
1164         mov     edi, esi
1165         pop     ecx
1167         jecxz   .extentAlloc
1168         call    doublyIndirectBlockAlloc
1169         jc      .errSave
1170         add     edi, 4
1171         jmp     @b
1173 .extentAlloc:
1174         mov     ecx, [esp]
1175         mov     eax, [esp+4]
1176         jecxz   @f
1177         call    extfsExtentAlloc
1178         jc      .errSave
1179         sub     [esp], ecx
1180         jmp     @b
1183         mov     eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
1184         mov     ebx, esi
1185         call    extfsWriteBlock
1186         stdcall kernel_free, esi
1187 .done:
1188         xor     eax, eax
1189         pop     edi
1190 .ret:
1191         pop     edi edi esi ebx
1192         ret
1194 .errSave:
1195         push    eax
1196         mov     eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
1197         mov     ebx, esi
1198         call    extfsWriteBlock
1199         pop     eax
1200         jmp     .errFree
1202 freeBlockList:
1203 ; in: edi -> list of blocks, edx = amount of blocks
1204 ; out: ebx=0 -> end of list
1205         mov     ebx, [edi]
1206         test    ebx, ebx
1207         jz      .ret
1208         xor     eax, eax
1209         xor     ecx, ecx
1211         stosd
1212         inc     ecx
1213         dec     edx
1214         jz      @f
1215         mov     eax, [edi]
1216         sub     eax, ebx
1217         sub     eax, ecx
1218         jz      @b
1220         mov     eax, ebx
1221         call    extfsExtentFree
1222         test    edx, edx
1223         jnz     freeBlockList
1224 .ret:
1225         ret
1227 freeIndirectBlock:
1228 ; in: edi -> indirect block number, edx = starting block
1229 ; out: edi = edi+4, eax=0 -> end
1230         pushd   ecx 0 edi edx
1231         mov     eax, [edi]
1232         test    eax, eax
1233         jz      .ret
1234         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
1235         call    extfsReadBlock
1236         jc      .ret
1237         lea     edi, [ebx+edx*4]
1238         neg     edx
1239         add     edx, [ebp+EXTFS.dwordsPerBlock]
1240         call    freeBlockList
1241         test    ebx, ebx
1242         jz      @f
1243         inc     dword[esp+8]
1245         pop     edx edi
1246         mov     eax, [edi]
1247         test    edx, edx
1248         jnz     @f
1249         xor     ecx, ecx
1250         inc     ecx
1251         call    extfsExtentFree
1252         stosd
1253         jmp     .done
1256         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
1257         call    extfsWriteBlock
1258         add     edi, 4
1259 .done:
1260         pop     eax ecx
1261         xor     edx, edx
1262         ret
1264 .ret:
1265         pop     edi edi edx ecx
1266         ret
1268 freeDoublyIndirectBlock:
1269 ; in: edi -> doubly-indirect block number, edx = starting block
1270 ; out: edi = edi+4, eax=-1 -> done, eax=0 -> end
1271         mov     eax, [edi]
1272         test    eax, eax
1273         jz      .ret
1274         push    ecx eax edx
1275         stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
1276         mov     ebx, eax
1277         pop     edx eax
1278         pushd   0 ebx edx
1279         call    extfsReadBlock
1280         jc      .err
1281         mov     eax, edx
1282         xor     edx, edx
1283         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
1284         div     ecx
1285         sub     ecx, eax
1286         push    edi
1287         lea     edi, [ebx+eax*4]
1289         call    freeIndirectBlock
1290         test    eax, eax
1291         jz      .end
1292         dec     ecx
1293         jnz     @b
1294         dec     dword[esp+12]
1295 .end:
1296         pop     edi edx
1297         mov     eax, [edi]
1298         test    edx, edx
1299         jnz     @f
1300         xor     ecx, ecx
1301         inc     ecx
1302         call    extfsExtentFree
1303         stosd
1304         jmp     .done
1307         mov     ebx, [esp]
1308         call    extfsWriteBlock
1309         add     edi, 4
1310         jmp     .done
1312 .err:
1313         mov     [esp+8], eax
1314         pop     eax
1315 .done:
1316         call    kernel_free
1317         pop     eax ecx
1318 .ret:
1319         xor     edx, edx
1320         ret
1322 extfsTruncateFile:
1323 ; in: edx:eax = new size, [ebp+EXTFS.inodeBuffer] = inode
1324         lea     esi, [ebp+EXTFS.inodeBuffer]
1325         mov     ecx, edx
1326         cmp     eax, [esi+INODE.fileSize]
1327         sbb     ecx, [esi+INODE.fileSizeHigh]
1328         jnc     .ret
1329         mov     [esi+INODE.fileSize], eax
1330         mov     [esi+INODE.fileSizeHigh], edx
1331         sub     eax, 1
1332         sbb     edx, 0
1333         jc      @f
1334         div     [ebp+EXTFS.bytesPerBlock]
1336         inc     eax
1337         mov     edx, eax
1338         cmp     edx, 12
1339         jc      .directBlocks
1340         sub     edx, 12
1341         cmp     edx, [ebp+EXTFS.dwordsPerBlock]
1342         jc      .indirectBlocks
1343         sub     edx, [ebp+EXTFS.dwordsPerBlock]
1344         cmp     edx, [ebp+EXTFS.dwordsPerBranch]
1345         jc      .doublyIndirectBlock
1346         sub     edx, [ebp+EXTFS.dwordsPerBranch]
1347         jmp     .triplyIndirectBlock
1349 .directBlocks:
1350         lea     edi, [esi+INODE.blockNumbers+edx*4]
1351         neg     edx
1352         add     edx, 12
1353         call    freeBlockList
1354         test    ebx, ebx
1355         jz      .ret
1356 .indirectBlocks:
1357         lea     edi, [esi+INODE.addressBlock]
1358         call    freeIndirectBlock
1359         test    eax, eax
1360         jz      .ret
1361 .doublyIndirectBlock:
1362         lea     edi, [esi+INODE.doubleAddress]
1363         call    freeDoublyIndirectBlock
1364         test    eax, eax
1365         jz      .ret
1366 .triplyIndirectBlock:
1367         mov     eax, [esi+INODE.tripleAddress]
1368         test    eax, eax
1369         jz      .ret
1370         push    eax edx
1371         stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
1372         mov     ebx, eax
1373         pop     edx eax
1374         push    ebx eax edx
1375         call    extfsReadBlock
1376         jc      .err
1377         mov     eax, edx
1378         xor     edx, edx
1379         div     [ebp+EXTFS.dwordsPerBranch]
1380         mov     ecx, [ebp+EXTFS.dwordsPerBlock]
1381         sub     ecx, eax
1382         lea     edi, [ebx+eax*4]
1384         call    freeDoublyIndirectBlock
1385         test    eax, eax
1386         jz      .end
1387         dec     ecx
1388         jnz     @b
1389 .end:
1390         pop     edx eax
1391         test    edx, edx
1392         jnz     @f
1393         xor     ecx, ecx
1394         inc     ecx
1395         call    extfsExtentFree
1396         mov     [esi+INODE.tripleAddress], eax
1397         jmp     .done
1400         mov     ebx, [esp]
1401         call    extfsWriteBlock
1402         jmp     .done
1404 .err:
1405         pop     eax eax
1406 .done:
1407         call    kernel_free
1408 .ret:
1409         ret
1411 linkInode:
1412 ;   in:
1413 ; eax = inode on which to link
1414 ; ebx = inode to link
1415 ; esi -> name in UTF-8
1416 ;  dl = file type
1417         push    esi edi ebx ecx eax edx
1418         call    strlen
1419         push    esi ebx ecx
1420         lea     esi, [ebp+EXTFS.inodeBuffer]
1421         mov     ebx, esi
1422         call    readInode
1423         jc      .error_inode_read
1424         mov     eax, [esi+INODE.fileSize]
1425         xor     edx, edx
1426         div     [ebp+EXTFS.bytesPerBlock]
1427         xor     ecx, ecx
1428 .searchBlock:
1429         push    eax     ; blocks total
1430         push    ecx     ; current file block number
1431         cmp     eax, ecx
1432         jz      .alloc_block
1433         call    extfsGetExtent
1434         jc      .error_get_inode_block
1435         push    eax
1436         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
1437         call    extfsReadBlock
1438         jc      .error_block_read
1439         mov     ecx, [esp+12]
1440         add     ecx, 8  ; directory entry size
1441         mov     edi, [ebp+EXTFS.tempBlockBuffer]
1442         mov     edx, edi
1443         add     edx, [ebp+EXTFS.bytesPerBlock]
1444 .searchSpace:
1445         movzx   eax, [edi+DIRENTRY.entryLength]
1446         test    eax, eax
1447         jz      .zeroLength
1448         cmp     [edi+DIRENTRY.inodeNumber], 0
1449         je      .unusedEntry
1450         movzx   ebx, [edi+DIRENTRY.nameLength]
1451         add     ebx, 8+3
1452         and     ebx, -4
1453         sub     eax, ebx
1454         add     edi, ebx
1455         cmp     eax, ecx
1456         jb      .nextEntry
1457         sub     edi, ebx
1458         mov     [edi+DIRENTRY.entryLength], bx
1459         add     edi, ebx
1460         mov     [edi+DIRENTRY.entryLength], ax
1461         jmp     .found
1463 .unusedEntry:
1464         cmp     eax, ecx
1465         jge     .found
1466 .nextEntry:
1467         add     edi, eax
1468         cmp     edi, edx
1469         jb      .searchSpace
1470         pop     ecx
1472         pop     ecx eax
1473         inc     ecx
1474         jmp     .searchBlock
1476 .zeroLength:
1477         mov     eax, edx
1478         sub     eax, edi
1479         mov     [edi+DIRENTRY.entryLength], ax
1480         cmp     eax, ecx
1481         jge     .found
1482         mov     [edi+DIRENTRY.inodeNumber], 0
1483         pop     eax
1484         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
1485         call    extfsWriteBlock
1486         jmp     @b
1488 .alloc_block:
1489         mov     eax, [esi+INODE.fileSize]
1490         add     eax, [ebp+EXTFS.bytesPerBlock]
1491         xor     edx, edx
1492         mov     ecx, [esp+24]
1493         call    extfsExtendFile
1494         jc      .error_get_inode_block
1495         mov     eax, [esp+24]
1496         mov     ebx, esi
1497         call    writeInode
1498         jc      .error_get_inode_block
1499         mov     ecx, [esp]
1500         call    extfsGetExtent
1501         jc      .error_get_inode_block
1502         push    eax
1503         mov     edi, [ebp+EXTFS.tempBlockBuffer]
1504         mov     eax, [ebp+EXTFS.bytesPerBlock]
1505         mov     [edi+DIRENTRY.entryLength], ax
1506 .found:
1507         pop     edx ecx ecx ecx ebx esi
1508         mov     [edi+DIRENTRY.inodeNumber], ebx
1509         mov     word [edi+DIRENTRY.nameLength], cx
1510         sub     eax, 8
1511         cmp     ecx, eax
1512         adc     ecx, 0
1513         test    [ebp+EXTFS.superblock.incompatibleFlags], 2
1514         jz      @f
1515         mov     eax, [esp]
1516         mov     [edi+DIRENTRY.fileType], al
1518         add     edi, 8
1519         rep movsb
1520         mov     eax, edx
1521         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
1522         call    extfsWriteBlock
1524         pop     edx ecx ecx ebx edi esi
1525         ret
1527 .error_block_read:
1528         pop     ebx
1529 .error_get_inode_block:
1530         pop     ebx ebx
1531 .error_inode_read:
1532         pop     ebx ebx ebx
1533         jmp     @b
1535 unlinkInode:
1536 ; in: eax = directory inode number, esi = inode to unlink
1537         push    edi
1538         lea     ebx, [ebp+EXTFS.inodeBuffer]
1539         call    readInode
1540         jc      .ret
1541         xor     ecx, ecx
1542 .loop:
1543         push    ecx
1544         call    extfsGetExtent
1545         jc      .fail_loop
1546         mov     edi, eax
1547         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
1548         call    extfsReadBlock
1549         jc      .fail_loop
1550 .first_dir_entry:   ; edi -> block
1551         cmp     [ebx+DIRENTRY.inodeNumber], esi
1552         jne     @f
1553         mov     [ebx+DIRENTRY.inodeNumber], 0
1554         mov     word [ebx+DIRENTRY.nameLength], 0   ; fileType = 0
1555         jmp     .write_block
1557 .fail:
1558         pop     edi
1559         movi    eax, ERROR_FS_FAIL
1560         stc
1561 .fail_loop:
1562         pop     edi
1563         jmp     .ret
1565 .next:
1566         pop     ecx ecx
1567         inc     ecx
1568         jmp     .loop
1571         mov     edx, ebx
1572         add     edx, [ebp+EXTFS.bytesPerBlock]
1573         push    edx
1575         movzx   ecx, [ebx+DIRENTRY.entryLength]
1576         jecxz   .fail
1577         mov     edx, ebx
1578         add     ebx, ecx
1579         cmp     ebx, [esp]
1580         jnc     .next
1581         cmp     [ebx+DIRENTRY.inodeNumber], esi
1582         jnz     @b
1583         mov     cx, [ebx+DIRENTRY.entryLength]
1584         add     [edx+DIRENTRY.entryLength], cx
1585         pop     eax
1586 .write_block:
1587         pop     eax
1588         mov     eax, edi
1589         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
1590         call    extfsWriteBlock
1591 .ret:
1592         pop     edi
1593         ret
1595 findInode:
1596 ; in: esi -> path string in UTF-8
1597 ;   out:
1598 ; edi -> file name in UTF-8
1599 ; esi = last inode number
1600 ; [ebp+EXTFS.inodeBuffer] = last inode
1601 ; ecx = parent inode number
1602 ; CF=1 -> file not found, edi=0 -> error
1603         push    esi
1604         lea     esi, [ebp+EXTFS.rootInodeBuffer]
1605         lea     edi, [ebp+EXTFS.inodeBuffer]
1606         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
1607         mov     edx, esi
1608         rep movsb
1609         pop     esi
1610         pushd   ebx 0 ROOT_INODE
1611         mov     edi, esi
1612         cmp     [edx+INODE.fileSize], 0
1613         jz      .not_found
1614         cmp     byte [esi], 0
1615         jnz     .next_path_part
1616         xor     eax, eax
1617         pop     esi ecx ebx
1618         ret
1621         pop     esi esi
1622 .error:
1623         pop     esi ecx ebx
1624         xor     edi, edi
1625         stc
1626         ret
1628 .next_path_part:
1629         push    [edx+INODE.fileSize]
1630         xor     ecx, ecx
1631 .folder_block_cycle:
1632         push    ecx
1633         call    extfsGetExtent
1634         jc      @b
1635         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
1636         call    extfsReadBlock
1637         jc      @b
1638         push    esi edx
1639         mov     edx, ebx
1640         add     edx, [ebp+EXTFS.bytesPerBlock]
1641 .start_rec:
1642         cmp     [ebx+DIRENTRY.inodeNumber], 0
1643         jz      .next_rec
1644         push    esi
1645         movzx   ecx, [ebx+DIRENTRY.nameLength]
1646         lea     edi, [ebx+DIRENTRY.name]
1647         repz cmpsb
1648         jz      .test_find
1649 @@: ; doesn't match
1650         pop     esi
1651 .next_rec:
1652         movzx   ecx, [ebx+DIRENTRY.entryLength]
1653         jecxz   .stop
1654         add     ebx, ecx
1655         cmp     ebx, edx
1656         jb      .start_rec
1657         jmp     .stop
1659 .test_find:
1660         cmp     byte [esi], 0
1661         je      @f
1662         cmp     byte [esi], '/'
1663         jne     @b
1664         inc     esi
1666         pop     edx
1667 .stop:
1668         pop     edx edi ecx eax
1669 ; ebx -> matched directory entry, esi -> name without parent, or not changed
1670         cmp     edi, esi
1671         jnz     @f
1672         sub     eax, [ebp+EXTFS.bytesPerBlock]
1673         jle     .not_found
1674         push    eax
1675         inc     ecx
1676         jmp     .folder_block_cycle
1679         pop     eax
1680         mov     [esp], eax
1681         mov     eax, [ebx+DIRENTRY.inodeNumber]
1682         lea     ebx, [ebp+EXTFS.inodeBuffer]
1683         push    eax
1684         call    readInode
1685         jc      .error
1686         cmp     byte [esi], 0
1687         je      .ret
1688         mov     edx, ebx
1689         movzx   eax, [ebx+INODE.accessMode]
1690         and     eax, TYPE_MASK
1691         cmp     eax, DIRECTORY
1692         jz      .next_path_part
1693         xor     edi, edi    ; path folder is a file
1694         jmp     @f
1696 .not_found:
1697         mov     esi, edi
1698         call    strlen
1699         mov     al, '/'
1700         repnz scasb
1701         mov     edi, esi
1702         jnz     @f
1703         xor     edi, edi    ; path folder not found
1705         movi    eax, ERROR_FILE_NOT_FOUND
1706         stc
1707 .ret:
1708         pop     esi ecx ebx
1709         ret
1711 writeSuperblock:
1712         push    ebx
1713         mov     eax, 2
1714         lea     ebx, [ebp+EXTFS.superblock]
1715         call    fs_write32_sys
1716         pop     ebx
1717         ret
1719 extfsWritingInit:
1720         movi    eax, ERROR_UNSUPPORTED_FS
1721         test    [ebp+EXTFS.mountType], READ_ONLY
1722         jnz     @f
1723 ext_lock:
1724         lea     ecx, [ebp+EXTFS.Lock]
1725         jmp     mutex_lock
1728         pop     ebx
1729         xor     ebx, ebx
1730         ret
1732 ext_unlock:
1733         lea     ecx, [ebp+EXTFS.Lock]
1734         jmp     mutex_unlock
1736 ;----------------------------------------------------------------
1737 ext_ReadFolder:
1738         call    ext_lock
1739         cmp     byte [esi], 0
1740         jz      .root_folder
1741         call    findInode
1742         jc      .error_ret
1743         lea     esi, [ebp+EXTFS.inodeBuffer]
1744         test    [esi+INODE.accessMode], FLAG_FILE
1745         jnz     .error_not_found
1746         jmp     @f
1748 .root_folder:
1749         lea     esi, [ebp+EXTFS.rootInodeBuffer]
1750         lea     edi, [ebp+EXTFS.inodeBuffer]
1751         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
1752         shr     ecx, 2
1753         push    edi
1754         rep movsd
1755         pop     esi
1757         cmp     [esi+INODE.fileSize], 0
1758         je      .error_empty_dir
1759         mov     edx, [ebx+16]
1760         push    edx         ; [edi+28] result buffer
1761         push    0           ; [edi+24] end of the current block in folder
1762         pushd   [ebx+12]    ; [edi+20] files to read
1763         pushd   [ebx+4]     ; [edi+16] first wanted file
1764         pushd   [ebx+8]     ; [edi+12] flags
1765         push    0           ; [edi+8]  read files
1766         push    0           ; [edi+4]  files in folder
1767         push    0           ; [edi]    current block index
1768         mov     edi, esp    ; edi -> local variables
1769         add     edx, 32
1770         xor     ecx, ecx
1771         call    extfsGetExtent
1772         jc      .error_get_block
1773         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
1774         call    extfsReadBlock
1775         jc      .error_get_block
1776         mov     eax, ebx
1777         add     eax, [ebp+EXTFS.bytesPerBlock]
1778         mov     [edi+24], eax
1779         mov     ecx, [edi+16]
1780 .find_wanted_start:
1781         jecxz   .find_wanted_end
1782 .find_wanted_cycle:
1783         cmp     [ebx+DIRENTRY.inodeNumber], 0
1784         jz      @f
1785         inc     dword [edi+4]
1786         dec     ecx
1788         movzx   eax, [ebx+DIRENTRY.entryLength]
1789         cmp     eax, 12     ; minimum entry length
1790         jb      .error_bad_len
1791         test    eax, 3      ; length must be aligned
1792         jnz     .error_bad_len
1793         sub     [esi+INODE.fileSize], eax
1794         add     ebx, eax
1795         cmp     ebx, [edi+24]
1796         jb      .find_wanted_start
1797         push    .find_wanted_start
1798 .end_block: ; read next block
1799         cmp     [esi+INODE.fileSize], 0
1800         jle     .end_dir
1801         inc     dword [edi]
1802         push    ecx
1803         mov     ecx, [edi]
1804         call    extfsGetExtent
1805         jc      .error_get_block
1806         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
1807         call    extfsReadBlock
1808         jc      .error_get_block
1809         pop     ecx
1810         mov     eax, ebx
1811         add     eax, [ebp+EXTFS.bytesPerBlock]
1812         mov     [edi+24], eax
1813         ret
1815 .wanted_end:
1816         loop    .find_wanted_cycle
1817 .find_wanted_end:
1818         mov     ecx, [edi+20]
1819 .wanted_start:
1820         jecxz   .wanted_end
1821         cmp     [ebx+DIRENTRY.inodeNumber], 0
1822         jz      .empty_rec
1823         inc     dword [edi+8]
1824         inc     dword [edi+4]
1825         push    ebx edi ecx esi edx edi
1826         pushd   [edi+12]
1827         mov     edi, edx
1828         xor     eax, eax
1829         mov     ecx, 40 / 4
1830         rep stosd
1831         popd    [edx+4] edi
1832         mov     eax, [ebx+DIRENTRY.inodeNumber]
1833         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
1834         call    readInode
1835         jc      .error_read_subinode
1836         mov     esi, ebx
1837         lea     edi, [edx+8]
1838         mov     eax, [ebx+INODE.inodeModified]
1839         sub     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
1840         call    fsTime2bdfe
1842         mov     eax, [esi+INODE.accessedTime]
1843         sub     eax, 978307200
1844         call    fsTime2bdfe
1846         mov     eax, [esi+INODE.dataModified]
1847         sub     eax, 978307200
1848         call    fsTime2bdfe
1849         pop     edx
1850         or      dword [edx], KOS_DIRECTORY
1851         test    [esi+INODE.accessMode], FLAG_FILE
1852         jz      @f
1853         xor     dword [edx], KOS_DIRECTORY  ; mark as file
1854         mov     eax, [esi+INODE.fileSize]
1855         stosd
1856         mov     eax, [esi+INODE.fileSizeHigh]
1857         stosd
1859         mov     esi, [esp+12]
1860         movzx   ecx, [esi+DIRENTRY.nameLength]
1861         lea     esi, [esi+DIRENTRY.name]
1862         cmp     byte [esi], '.'
1863         jnz     @f
1864         or      byte [edx], KOS_HIDDEN
1866         lea     edi, [edx+40]
1867         cmp     byte [edx+4], 3
1868         jz      .utf8
1869         add     ecx, esi
1870         cmp     byte [edx+4], 2
1871         jz      .utf16
1873         call    utf8to16
1874         call    uni2ansi_char
1875         stosb
1876         cmp     esi, ecx
1877         jc      @b
1878         and     byte [edi], 0
1879         add     edx, 40+264
1881         pop     esi ecx edi ebx
1882         dec     ecx
1883 .empty_rec:
1884         movzx   eax, [ebx+DIRENTRY.entryLength]
1885         cmp     eax, 12
1886         jb      .error_bad_len
1887         test    eax, 3
1888         jnz     .error_bad_len
1889         sub     [esi+INODE.fileSize], eax
1890         add     ebx, eax
1891         cmp     ebx, [edi+24]
1892         jb      .wanted_start
1893         push    .wanted_start
1894         jmp     .end_block
1896 .utf8:
1897         rep movsb
1898         mov     byte [edi], 0
1899         add     edx, 40+520
1900         jmp     @b
1902 .utf16:
1903         call    utf8to16
1904         stosw
1905         cmp     esi, ecx
1906         jc      .utf16
1907         and     word [edi], 0
1908         add     edx, 40+520
1909         jmp     @b
1911 .end_dir:
1912         call    ext_unlock
1913         mov     edx, [edi+28]
1914         mov     ebx, [edi+8]
1915         mov     ecx, [edi+4]
1916         mov     dword [edx], 1  ; version
1917         mov     [edx+4], ebx
1918         mov     [edx+8], ecx
1919         lea     esp, [edi+32]
1920         mov     ecx, 20/4
1921         lea     edi, [edx+12]
1922         xor     eax, eax
1923         rep stosd
1924         ret
1926 .error_bad_len:
1927         movi    eax, ERROR_FS_FAIL
1928 .error_read_subinode:
1929 .error_get_block:
1930         lea     esp, [edi+32]
1931 .error_ret:
1932         xor     ebx, ebx
1933         push    eax
1934         call    ext_unlock
1935         pop     eax
1936         ret
1938 .error_empty_dir:
1939         movi    eax, ERROR_FS_FAIL
1940         jmp     .error_ret
1942 .error_not_found:
1943         movi    eax, ERROR_FILE_NOT_FOUND
1944         jmp     .error_ret
1946 ;----------------------------------------------------------------
1947 ext_ReadFile:
1948         call    ext_lock
1949         call    findInode
1950         pushd   0 eax
1951         jc      .ret
1952         lea     esi, [ebp+EXTFS.inodeBuffer]
1953         mov     byte [esp], ERROR_ACCESS_DENIED
1954         test    [esi+INODE.accessMode], FLAG_FILE
1955         jz      .ret    ; not a file
1956         mov     byte [esp], ERROR_END_OF_FILE
1957         mov     eax, [esi+INODE.fileSize]
1958         mov     edx, [esi+INODE.fileSizeHigh]
1959         sub     eax, [ebx+4]
1960         sbb     edx, [ebx+8]
1961         jc      .ret
1962         mov     ecx, [ebx+12]
1963         sub     eax, ecx
1964         sbb     edx, 0
1965         jc      @f
1966         xor     eax, eax
1967         mov     [esp], eax
1969         add     ecx, eax
1970         mov     eax, [ebx+4]
1971         mov     edx, [ebx+8]
1972         mov     edi, [ebx+16]
1973         div     [ebp+EXTFS.bytesPerBlock]
1974         test    edx, edx
1975         jz      .aligned
1976 .piece:
1977         push    eax ecx
1978         mov     esi, edx
1979         mov     ecx, eax
1980         call    extfsGetExtent
1981         jc      .errorGet
1982         mov     ecx, [ebp+EXTFS.sectorsPerBlock]
1983         mul     ecx
1984         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
1985         call    fs_read64_sys
1986         test    eax, eax
1987         jnz     .errorRead
1988         pop     eax
1989         mov     ecx, [ebp+EXTFS.bytesPerBlock]
1990         sub     ecx, esi
1991         sub     eax, ecx
1992         jnc     @f
1993         add     ecx, eax
1994         xor     eax, eax
1996         add     esi, ebx
1997         add     [esp+8], ecx
1998         rep movsb
1999         mov     ecx, eax
2000         pop     eax
2001         inc     eax
2002         xor     edx, edx
2003         jecxz   .ret
2004 .aligned:
2005         xchg    eax, ecx
2006         div     [ebp+EXTFS.bytesPerBlock]
2007         push    edx
2008         mov     edx, eax
2009 .writeExtent:
2010         test    edx, edx
2011         jz      .end
2012         push    ecx
2013         call    extfsGetExtent
2014         jc      .errorGet
2015         sub     edx, ecx
2016         jnc     @f
2017         add     ecx, edx
2018         xor     edx, edx
2020         add     [esp], ecx
2021         imul    ecx, [ebp+EXTFS.sectorsPerBlock]
2022         mov     ebx, edi
2023         push    edx ecx
2024         mul     [ebp+EXTFS.sectorsPerBlock]
2025         call    fs_read64_sys
2026         pop     ecx edx
2027         test    eax, eax
2028         jnz     .errorRead
2029         shl     ecx, 9
2030         add     edi, ecx
2031         add     [esp+12], ecx
2032         pop     ecx
2033         jmp     .writeExtent
2035 .end:
2036         mov     eax, ecx
2037         pop     ecx
2038         jecxz   .ret
2039         jmp     .piece
2041 .errorRead:
2042         movi    eax, ERROR_DEVICE
2043 .errorGet:
2044         pop     ebx ebx
2045         mov     [esp], eax
2046 .ret:
2047         call    ext_unlock
2048         pop     eax ebx
2049         ret
2051 ;----------------------------------------------------------------
2052 ext_GetFileInfo:
2053         cmp     byte [esi], 0
2054         jz      .volume
2055         call    ext_lock
2056         call    findInode
2057         jc      .ret
2058         lea     esi, [ebp+EXTFS.inodeBuffer]
2059         mov     edx, [ebx+16]
2060         mov     bl, [edi]
2061         xor     eax, eax
2062         mov     edi, edx
2063         mov     ecx, 40/4
2064         rep stosd
2065         cmp     bl, '.'
2066         jne     @f
2067         or      dword [edx], KOS_HIDDEN
2069         or      dword [edx], KOS_DIRECTORY
2070         test    [esi+INODE.accessMode], FLAG_FILE
2071         jz      @f
2072         xor     dword [edx], KOS_DIRECTORY  ; mark as file
2073         mov     eax, [esi+INODE.fileSize]
2074         mov     ebx, [esi+INODE.fileSizeHigh]
2075         mov     dword [edx+32], eax
2076         mov     dword [edx+36], ebx
2078         lea     edi, [edx+8]
2079         mov     eax, [esi+INODE.inodeModified]
2080         sub     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
2081         call    fsTime2bdfe
2083         mov     eax, [esi+INODE.accessedTime]
2084         sub     eax, 978307200
2085         call    fsTime2bdfe
2087         mov     eax, [esi+INODE.dataModified]
2088         sub     eax, 978307200
2089         call    fsTime2bdfe
2090         xor     eax, eax
2091 .ret:
2092         push    eax
2093         call    ext_unlock
2094         pop     eax
2096         ret
2098 .volume:
2099         mov     eax, dword[ebp+EXTFS.Length]
2100         mov     edx, dword[ebp+EXTFS.Length+4]
2101         mov     edi, [ebx+16]
2102         shld    edx, eax, 9
2103         shl     eax, 9
2104         mov     [edi+36], edx
2105         mov     [edi+32], eax
2106         mov     eax, [ebx+8]
2107         mov     byte [edi], 8
2108         mov     [edi+4], eax
2109         test    eax, eax
2110         jz      @b
2111         lea     esi, [ebp+EXTFS.superblock.volumeLabel]
2112         mov     ecx, 16
2113         add     edi, 40
2114         cmp     eax, 3
2115         jz      .utf8
2116         add     ecx, esi
2117         cmp     eax, 2
2118         jz      .utf16
2120         call    utf8to16
2121         call    uni2ansi_char
2122         stosb
2123         cmp     esi, ecx
2124         jc      @b
2125         jmp     @f
2127 .utf8:
2128         rep movsb
2129         jmp     @f
2131 .utf16:
2132         call    utf8to16
2133         stosw
2134         cmp     esi, ecx
2135         jc      .utf16
2137         xor     eax, eax
2138         mov     [edi], ax
2139         ret
2141 ;----------------------------------------------------------------
2142 ext_SetFileInfo:
2143         call    extfsWritingInit
2144         call    findInode
2145         jc      @f
2146         push    esi
2147         mov     esi, [ebx+16]
2148         add     esi, 16
2149         lea     edi, [ebp+EXTFS.inodeBuffer]
2150         call    fsCalculateTime
2151         add     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
2152         mov     [edi+INODE.accessedTime], eax
2154         add     esi, 8
2155         call    fsCalculateTime
2156         add     eax, 978307200
2157         mov     [edi+INODE.dataModified], eax
2158         mov     ebx, edi
2159         pop     eax
2160         call    writeInode
2162         push    eax
2163         jc      @f
2164         call    writeSuperblock
2165         mov     esi, [ebp+PARTITION.Disk]
2166         call    disk_sync
2168         call    ext_unlock
2169         pop     eax
2170         ret
2172 ;----------------------------------------------------------------
2173 ext_Delete:
2174         call    extfsWritingInit
2175         call    findInode
2176         jc      .error
2177         push    ecx
2178         movzx   edi, [ebp+EXTFS.inodeBuffer.accessMode]
2179         and     edi, TYPE_MASK
2180         cmp     edi, DIRECTORY
2181         jne     .file
2182         xor     ecx, ecx
2183 .checkDirectory:
2184         push    ecx
2185         call    extfsGetExtent
2186         jc      .empty
2187         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
2188         call    extfsReadBlock
2189         jc      .error8
2190         mov     edx, ebx
2191         add     edx, [ebp+EXTFS.bytesPerBlock]
2192 .dir_entry:
2193         movzx   ecx, [ebx+DIRENTRY.nameLength]
2194         mov     ax, word [ebx+DIRENTRY.name]
2195         jecxz   @f
2196         cmp     al, '.'
2197         jnz     .not_empty
2198         dec     ecx
2199         jz      @f
2200         cmp     al, ah
2201         jnz     .not_empty
2202         dec     ecx
2203         jnz     .not_empty
2205         mov     cx, [ebx+DIRENTRY.entryLength]
2206         jecxz   @f
2207         add     ebx, ecx
2208         cmp     ebx, edx
2209         jb      .dir_entry
2211         pop     ecx
2212         inc     ecx
2213         jmp     .checkDirectory
2215 .not_empty:
2216         pop     eax eax
2217         push    ERROR_ACCESS_DENIED
2218         jmp     .ret
2220 .error8:
2221         pop     ebx
2222 .error4:
2223         pop     ebx
2224 .error:
2225         push    eax
2226         jmp     .ret
2228 .empty:
2229         pop     ecx ecx
2230         cmp     eax, ERROR_END_OF_FILE
2231         jnz     .error
2232         push    ecx
2233 .file:
2234         mov     eax, ecx
2235         call    unlinkInode
2236         jc      .error4
2237         pop     eax
2238         lea     ebx, [ebp+EXTFS.inodeBuffer]
2239         cmp     edi, DIRECTORY
2240         jnz     @f
2241         dec     [ebx+INODE.linksCount]
2242         call    writeInode
2244         mov     eax, esi
2245         call    readInode
2246         jc      .error
2247         dec     [ebx+INODE.linksCount]
2248         jz      @f
2249         cmp     edi, DIRECTORY
2250         jnz     .hardlinks
2252         push    esi edi
2253         xor     eax, eax
2254         xor     edx, edx
2255         call    extfsTruncateFile   ; free file's data
2256         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
2257         lea     edi, [ebp+EXTFS.inodeBuffer]
2258         xor     eax, eax
2259         push    edi
2260         rep stosb
2261         call    fsGetTime
2262         pop     ebx edi esi
2263         add     eax, 978307200
2264         mov     [ebx+INODE.deletedTime], eax
2265         mov     eax, esi
2266         dec     eax
2267         xor     edx, edx
2268         div     [ebp+EXTFS.superblock.inodesPerGroup]
2269         push    edx
2270         mov     ebx, [ebp+EXTFS.descriptorTable]
2271         shl     eax, 5
2272         add     ebx, eax
2273         cmp     edi, DIRECTORY
2274         jnz     @f
2275         dec     [ebx+BGDESCR.directoriesCount]
2277         inc     [ebx+BGDESCR.inodesFree]
2278         push    [ebx+BGDESCR.inodeBitmap]
2279         call    extfsWriteDescriptor
2280         pop     eax
2281         mov     ebx, [ebp+EXTFS.tempBlockBuffer]
2282         mov     ecx, eax
2283         call    extfsReadBlock
2284         pop     edx
2285         jc      .error
2286         mov     eax, edx
2287         and     edx, 31
2288         shr     eax, 5
2289         shl     eax, 2
2290         add     eax, ebx
2291         btr     [eax], edx
2292         mov     eax, ecx
2293         call    extfsWriteBlock
2294         inc     [ebp+EXTFS.superblock.inodesFree]
2295 .hardlinks:
2296         mov     eax, esi
2297         lea     ebx, [ebp+EXTFS.inodeBuffer]
2298         call    writeInode
2299         push    eax
2300         call    writeSuperblock
2301         mov     esi, [ebp+PARTITION.Disk]
2302         call    disk_sync
2303 .ret:
2304         call    ext_unlock
2305         xor     ebx, ebx
2306         pop     eax
2307         ret
2309 ;----------------------------------------------------------------
2310 ext_CreateFolder:
2311         call    extfsWritingInit
2312         call    findInode
2313         jnc     .success    ; exist
2314         test    edi, edi
2315         jz      .error
2316         mov     eax, esi
2317         call    extfsInodeAlloc
2318         jc      .error
2319         push    ebx esi edi
2320         lea     edi, [ebp+EXTFS.inodeBuffer]
2321         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
2322         xor     eax, eax
2323         rep stosb
2324         call    fsGetTime
2325         add     eax, 978307200
2326         lea     ebx, [ebp+EXTFS.inodeBuffer]
2327         mov     [ebx+INODE.accessedTime], eax
2328         mov     [ebx+INODE.dataModified], eax
2329         pop     edi esi edx
2330 ; edx = allocated inode number, edi -> filename, esi = parent inode number
2331         mov     [ebx+INODE.accessMode], DIRECTORY or 511
2332         mov     byte [ebx+INODE.linksCount], 2
2333         mov     eax, edx
2334         call    writeInode
2335         jc      .error
2336 ; link to self
2337         push    edx esi
2338         mov     eax, edx
2339         mov     ebx, eax
2340         mov     dl, DIR_DIRECTORY
2341         mov     esi, self_link
2342         call    linkInode
2343         pop     esi edx
2344         jc      .error
2345 ; link to parent
2346         push    edx esi
2347         mov     eax, ebx
2348         mov     ebx, esi
2349         mov     dl, DIR_DIRECTORY
2350         mov     esi, parent_link
2351         call    linkInode
2352         pop     esi edx
2353         jc      .error
2354 ; link parent to child
2355         push    esi
2356         mov     eax, esi
2357         mov     ebx, edx
2358         mov     esi, edi
2359         mov     dl, DIR_DIRECTORY
2360         call    linkInode
2361         pop     edx
2362         jc      .error
2363         push    ebx
2364         lea     ebx, [ebp+EXTFS.inodeBuffer]
2365         inc     [ebx+INODE.linksCount]
2366         mov     eax, edx
2367         call    writeInode
2368         pop     ebx
2369         jc      .error
2370         mov     eax, ebx
2371         dec     eax
2372         xor     edx, edx
2373         div     [ebp+EXTFS.superblock.inodesPerGroup]
2374         mov     ebx, [ebp+EXTFS.descriptorTable]
2375         shl     eax, 5
2376         add     ebx, eax
2377         inc     [ebx+BGDESCR.directoriesCount]
2378         call    extfsWriteDescriptor
2379 .success:
2380 .error:
2381         push    eax
2382         call    writeSuperblock
2383         mov     esi, [ebp+PARTITION.Disk]
2384         call    disk_sync
2385         call    ext_unlock
2386         pop     eax
2387         ret
2389 self_link   db ".", 0
2390 parent_link db "..", 0
2392 ;----------------------------------------------------------------
2393 ext_CreateFile:
2394         call    extfsWritingInit
2395         pushd   0 0 ebx
2396         call    findInode
2397         jnc     .exist
2398         test    edi, edi
2399         jz      .error
2400         mov     eax, esi
2401         call    extfsInodeAlloc
2402         jc      .error
2403         push    ebx ebx esi edi
2404         lea     edi, [ebp+EXTFS.inodeBuffer]
2405         movzx   ecx, [ebp+EXTFS.superblock.inodeSize]
2406         xor     eax, eax
2407         rep stosb
2408         call    fsGetTime
2409         add     eax, 978307200
2410         lea     ebx, [ebp+EXTFS.inodeBuffer]
2411         mov     [ebx+INODE.accessedTime], eax
2412         mov     [ebx+INODE.dataModified], eax
2413         pop     edi esi edx
2414 ; edx = allocated inode number, edi -> filename, esi = parent inode number
2415         mov     [ebx+INODE.accessMode], FLAG_FILE or 110110110b
2416         mov     byte [ebx+INODE.linksCount], 1
2417         mov     eax, edx
2418         call    writeInode
2419         jc      .error2
2420 ; link parent to child
2421         mov     eax, esi
2422         mov     ebx, edx
2423         mov     esi, edi
2424         mov     dl, DIR_FLAG_FILE
2425         call    linkInode
2426         jc      .error2
2427         mov     eax, ebx
2428         lea     ebx, [ebp+EXTFS.inodeBuffer]
2429         call    readInode
2430         jc      .error2
2431         pop     esi ebx
2432         mov     eax, [ebx+12]
2433         xor     edx, edx
2434         jmp     ext_WriteFile.start
2436 .exist:
2437         movi    eax, ERROR_ACCESS_DENIED
2438         test    [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
2439         jz      .error  ; not a file
2440         pop     ebx
2441         mov     eax, [ebx+12]
2442         xor     edx, edx
2443         push    eax edx ebx esi
2444         call    extfsTruncateFile
2445         pop     esi ebx edx eax
2446         jmp     ext_WriteFile.start
2448 .error2:
2449         pop     ebx
2450 .error:
2451         push    eax
2452         call    ext_unlock
2453         pop     eax ebx ebx ebx
2454         ret
2456 ;----------------------------------------------------------------
2457 ext_WriteFile:
2458         call    extfsWritingInit
2459         call    findInode
2460         pushd   0 eax
2461         jc      .ret
2462         mov     byte [esp], ERROR_ACCESS_DENIED
2463         test    [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
2464         jz      .ret    ; not a file
2465         mov     byte [esp], 0
2466         mov     eax, [ebx+4]
2467         mov     edx, [ebx+8]
2468         add     eax, [ebx+12]
2469         adc     edx, 0
2470 .start:
2471         push    esi
2472         mov     ecx, esi
2473         call    extfsExtendFile
2474         jc      .errorExtend
2475         mov     eax, [ebx+4]
2476         mov     edx, [ebx+8]
2477         mov     ecx, [ebx+12]
2478         mov     esi, [ebx+16]
2479 .write:
2480         jecxz   .zero
2481         div     [ebp+EXTFS.bytesPerBlock]
2482         test    edx, edx
2483         jz      .aligned
2484 .piece:
2485         mov     ebx, ecx
2486         mov     edi, edx
2487         mov     ecx, eax
2488         push    eax
2489         call    extfsGetExtent
2490         jc      .errorGet
2491         mov     ecx, [ebp+EXTFS.sectorsPerBlock]
2492         mul     ecx
2493         push    ecx eax ebx
2494         mov     ebx, [ebp+EXTFS.mainBlockBuffer]
2495         call    fs_read64_sys
2496         test    eax, eax
2497         jnz     .errorDevice
2498         pop     eax
2499         mov     ecx, [ebp+EXTFS.bytesPerBlock]
2500         sub     ecx, edi
2501         sub     eax, ecx
2502         jnc     @f
2503         add     ecx, eax
2504         xor     eax, eax
2506         add     edi, ebx
2507         add     [esp+20], ecx
2508         rep movsb
2509         mov     edi, eax
2510         pop     eax ecx
2511         xor     edx, edx
2512         call    fs_write64_sys
2513         mov     ecx, edi
2514         pop     eax
2515         inc     eax
2516         xor     edx, edx
2517 .zero:
2518         jecxz   .done
2519 .aligned:
2520         xchg    eax, ecx
2521         div     [ebp+EXTFS.bytesPerBlock]
2522         push    edx
2523         mov     edx, eax
2524 .writeExtent:
2525         test    edx, edx
2526         jz      .end
2527         push    ecx
2528         call    extfsGetExtent
2529         jc      .errorGet2
2530         sub     edx, ecx
2531         jnc     @f
2532         add     ecx, edx
2533         xor     edx, edx
2535         add     [esp], ecx
2536         imul    ecx, [ebp+EXTFS.sectorsPerBlock]
2537         mov     ebx, esi
2538         push    edx ecx
2539         mul     [ebp+EXTFS.sectorsPerBlock]
2540         call    fs_write64_sys
2541         test    eax, eax
2542         jnz     .errorDevice
2543         pop     ebx edx ecx
2544         shl     ebx, 9
2545         add     esi, ebx
2546         add     [esp+12], ebx
2547         jmp     .writeExtent
2549 .end:
2550         mov     eax, ecx
2551         pop     ecx
2552         jecxz   .done
2553         jmp     .piece
2555 .errorDevice:
2556         pop     eax eax
2557         movi    eax, ERROR_DEVICE
2558 .errorGet2:
2559         pop     ebx
2560 .errorGet:
2561         pop     ebx
2562 .errorExtend:
2563         mov     [esp+4], eax
2564 .done:
2565         lea     ebx, [ebp+EXTFS.inodeBuffer]
2566         pop     eax
2567         call    writeInode
2568         add     [esp], eax
2569         call    writeSuperblock
2570         mov     esi, [ebp+PARTITION.Disk]
2571         call    disk_sync
2572 .ret:
2573         call    ext_unlock
2574         pop     eax ebx
2575         ret
2577 .erase:
2578         push    eax eax edi
2579         mov     eax, ebx
2580         jmp     .write
2582 ;----------------------------------------------------------------
2583 ext_SetFileEnd:
2584         call    extfsWritingInit
2585         call    findInode
2586         jc      .error2
2587         lea     edi, [ebp+EXTFS.inodeBuffer]
2588         movi    eax, ERROR_ACCESS_DENIED
2589         test    [edi+INODE.accessMode], FLAG_FILE
2590         jz      .error2 ; not a file
2591         mov     eax, [ebx+4]
2592         mov     edx, [ebx+8]
2593         mov     ebx, [edi+INODE.fileSize]
2594         mov     ecx, [edi+INODE.fileSizeHigh]
2595         push    esi ecx
2596         cmp     ebx, eax
2597         sbb     ecx, edx
2598         mov     ecx, esi
2599         jnc     @f
2600         call    extfsExtendFile
2601         pop     esi
2602         jc      .error
2603         mov     eax, [edi+INODE.fileSize]
2604         mov     edx, [edi+INODE.fileSizeHigh]
2605         sub     eax, ebx
2606         sbb     edx, esi
2607         jnz     .done
2608         cmp     eax, 1000001h
2609         jnc     .done
2610         push    eax
2611         stdcall kernel_alloc, eax
2612         pop     ecx
2613         test    eax, eax
2614         jz      .error
2615         push    ecx
2616         add     ecx, 3
2617         shr     ecx, 2
2618         mov     edx, esi
2619         mov     esi, eax
2620         mov     edi, eax
2621         xor     eax, eax
2622         rep stosd
2623         pop     ecx edi
2624         push    esi
2625         call    ext_WriteFile.erase
2626         call    kernel_free
2627         xor     eax, eax
2628         ret
2631         call    extfsTruncateFile
2632         pop     eax
2633 .done:
2634         xor     eax, eax
2635 .error:
2636         xchg    eax, [esp]
2637         lea     ebx, [ebp+EXTFS.inodeBuffer]
2638         call    writeInode
2639         add     [esp], eax
2640         call    writeSuperblock
2641         mov     esi, [ebp+PARTITION.Disk]
2642         call    disk_sync
2643         pop     eax
2644 .error2:
2645         push    eax
2646         call    ext_unlock
2647         pop     eax
2648         ret
2650 ;----------------------------------------------------------------
2651 ext_Rename:
2652         call    extfsWritingInit
2653         push    esi
2654         mov     esi, edi
2655         call    findInode
2656         jnc     .error
2657         test    edi, edi
2658         jz      .error
2659         xchg    [esp], esi
2660         push    edi
2661         call    findInode
2662         pop     edi
2663         jc      .error
2664         xor     edx, edx
2665         inc     edx
2666         test    [ebp+EXTFS.inodeBuffer.accessMode], DIRECTORY
2667         jz      @f
2668         inc     edx
2670         mov     eax, ecx
2671         push    ecx edx
2672         call    unlinkInode
2673         pop     edx ecx
2674         jc      .error
2675         cmp     edx, 1
2676         jz      @f
2677         lea     ebx, [ebp+EXTFS.inodeBuffer]
2678         dec     [ebx+INODE.linksCount]
2679         mov     eax, ecx
2680         call    writeInode
2681         jc      .error
2683         mov     ebx, esi
2684         mov     esi, edi
2685         pop     eax
2686         push    eax edx
2687         call    linkInode
2688         pop     edx
2689         jc      .error
2690         pop     eax
2691         cmp     edx, 1
2692         jz      @f
2693         lea     ebx, [ebp+EXTFS.inodeBuffer]
2694         inc     [ebx+INODE.linksCount]
2695         call    writeInode
2697         call    writeSuperblock
2698         mov     esi, [ebp+PARTITION.Disk]
2699         call    disk_sync
2700         call    ext_unlock
2701         xor     eax, eax
2702         ret
2704 .error:
2705         push    eax
2706         call    ext_unlock
2707         pop     eax ebx
2708         ret