Subversion Repositories Kolibri OS

Rev

Rev 5363 | Rev 9888 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4850 mario79 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
6462 pathoswith 3
;; Copyright (C) KolibriOS team 2013-2016. All rights reserved. ;;
4
;;  Distributed under terms of the GNU General Public License.  ;;
4850 mario79 5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
8
$Revision: 6462 $
9
 
6462 pathoswith 10
; XFS external functions
11
;   in:
12
; ebx -> parameter structure of sysfunc 70
13
; ebp -> XFS structure
14
; [esi]+[[esp+4]] = name
15
;   out:
16
; eax, ebx = return values for sysfunc 70
17
iglobal
18
align 4
19
xfs_user_functions:
20
        dd      xfs_free
21
        dd      (xfs_user_functions_end - xfs_user_functions - 4) / 4
22
        dd      xfs_ReadFile
23
        dd      xfs_ReadFolder
24
        dd      0;xfs_CreateFile
25
        dd      0;xfs_WriteFile
26
        dd      0;xfs_SetFileEnd
27
        dd      xfs_GetFileInfo
28
        dd      0;xfs_SetFileInfo
29
        dd      0
30
        dd      0;xfs_Delete
31
        dd      0;xfs_CreateFolder
32
xfs_user_functions_end:
33
endg
4850 mario79 34
 
3913 dunkaist 35
include 'xfs.inc'
36
 
6462 pathoswith 37
; Mount if it's a valid XFS partition.
3913 dunkaist 38
xfs_create_partition:
6462 pathoswith 39
;   in:
40
; ebp -> PARTITION structure
41
; ebx -> boot sector
42
;   out:
43
; eax -> XFS structure, 0 = not XFS
3913 dunkaist 44
        push    ebx ecx edx esi edi
5089 clevermous 45
        cmp     dword [esi+DISK.MediaInfo.SectorSize], 512
46
        jnz     .error
3913 dunkaist 47
        cmp     dword[ebx + xfs_sb.sb_magicnum], XFS_SB_MAGIC   ; signature
48
        jne     .error
49
 
50
        ; TODO: check XFS.versionnum and XFS.features2
51
        ;       print superblock params for debugging (waiting for bug reports)
52
 
53
        movi    eax, sizeof.XFS
54
        call    malloc
55
        test    eax, eax
56
        jz      .error
57
 
58
        ; standard partition initialization, common for all file systems
59
 
60
        mov     edi, eax
61
        mov     eax, dword[ebp + PARTITION.FirstSector]
62
        mov     dword[edi + XFS.FirstSector], eax
63
        mov     eax, dword[ebp + PARTITION.FirstSector + 4]
64
        mov     dword[edi + XFS.FirstSector + 4], eax
65
        mov     eax, dword[ebp + PARTITION.Length]
66
        mov     dword[edi + XFS.Length], eax
67
        mov     eax, dword[ebp + PARTITION.Length + 4]
68
        mov     dword[edi + XFS.Length + 4], eax
69
        mov     eax, [ebp + PARTITION.Disk]
70
        mov     [edi + XFS.Disk], eax
71
        mov     [edi + XFS.FSUserFunctions], xfs_user_functions
72
 
73
        ; here we initialize only one mutex so far (for the entire partition)
74
        ; XFS potentially allows parallel r/w access to several AGs, keep it in mind for SMP times
75
 
76
        lea     ecx, [edi + XFS.Lock]
77
        call    mutex_init
78
 
79
        ; read superblock and fill just allocated XFS partition structure
80
 
81
        mov     eax, [ebx + xfs_sb.sb_blocksize]
82
        bswap   eax                                     ; XFS is big endian
83
        mov     [edi + XFS.blocksize], eax
84
        movzx   eax, word[ebx + xfs_sb.sb_sectsize]
85
        xchg    al, ah
86
        mov     [edi + XFS.sectsize], eax
87
        movzx   eax, word[ebx + xfs_sb.sb_versionnum]
88
        xchg    al, ah
89
        mov     [edi + XFS.versionnum], eax
90
        mov     eax, [ebx + xfs_sb.sb_features2]
91
        bswap   eax
92
        mov     [edi + XFS.features2], eax
93
        movzx   eax, word[ebx + xfs_sb.sb_inodesize]
94
        xchg    al, ah
95
        mov     [edi + XFS.inodesize], eax
96
        movzx   eax, word[ebx + xfs_sb.sb_inopblock]    ; inodes per block
97
        xchg    al, ah
98
        mov     [edi + XFS.inopblock], eax
99
        movzx   eax, byte[ebx + xfs_sb.sb_blocklog]     ; log2 of block size, in bytes
100
        mov     [edi + XFS.blocklog], eax
101
        movzx   eax, byte[ebx + xfs_sb.sb_sectlog]
102
        mov     [edi + XFS.sectlog], eax
103
        movzx   eax, byte[ebx + xfs_sb.sb_inodelog]
104
        mov     [edi + XFS.inodelog], eax
105
        movzx   eax, byte[ebx + xfs_sb.sb_inopblog]
106
        mov     [edi + XFS.inopblog], eax
107
        movzx   eax, byte[ebx + xfs_sb.sb_dirblklog]
108
        mov     [edi + XFS.dirblklog], eax
109
        mov     eax, dword[ebx + xfs_sb.sb_rootino + 4] ;
110
        bswap   eax                                     ; big
111
        mov     dword[edi + XFS.rootino + 0], eax       ; endian
112
        mov     eax, dword[ebx + xfs_sb.sb_rootino + 0] ; 64bit
113
        bswap   eax                                     ; number
6462 pathoswith 114
        mov     dword[edi + XFS.rootino + 4], eax       ;
3913 dunkaist 115
 
116
        mov     eax, [edi + XFS.blocksize]
117
        mov     ecx, [edi + XFS.dirblklog]
118
        shl     eax, cl
119
        mov     [edi + XFS.dirblocksize], eax           ; blocks for files, dirblocks for directories
120
 
121
        ; sector is always smaller than block
122
        ; so precalculate shift order to allow faster sector_num->block_num conversion
123
 
124
        mov     ecx, [edi + XFS.blocklog]
125
        sub     ecx, [edi + XFS.sectlog]
126
        mov     [edi + XFS.blockmsectlog], ecx
127
 
128
        mov     eax, 1
129
        shl     eax, cl
130
        mov     [edi + XFS.sectpblock], eax
131
 
132
        ; shift order for inode_num->block_num conversion
133
 
134
        mov     eax, [edi + XFS.blocklog]
135
        sub     eax, [edi + XFS.inodelog]
136
        mov     [edi + XFS.inodetoblocklog], eax
137
 
138
        mov     eax, [ebx + xfs_sb.sb_agblocks]
139
        bswap   eax
140
        mov     [edi + XFS.agblocks], eax
141
        movzx   ecx, byte[ebx + xfs_sb.sb_agblklog]
142
        mov     [edi + XFS.agblklog], ecx
143
 
144
        ; get the mask for block numbers
145
        ; block numbers are AG relative!
146
        ; bitfield length may vary between partitions
147
 
148
        mov     eax, 1
149
        shl     eax, cl
150
        dec     eax
151
        mov     dword[edi + XFS.agblockmask + 0], eax
152
        mov     eax, 1
153
        sub     ecx, 32
154
        jc      @f
155
        shl     eax, cl
156
    @@:
157
        dec     eax
158
        mov     dword[edi + XFS.agblockmask + 4], eax
159
 
160
        ; calculate magic offsets for directories
161
 
162
        mov     ecx, [edi + XFS.blocklog]
163
        mov     eax, XFS_DIR2_LEAF_OFFSET AND 0xffffffff        ; lo
164
        mov     edx, XFS_DIR2_LEAF_OFFSET SHR 32                ; hi
165
        shrd    eax, edx, cl
166
        mov     [edi + XFS.dir2_leaf_offset_blocks], eax
167
 
168
        mov     ecx, [edi + XFS.blocklog]
169
        mov     eax, XFS_DIR2_FREE_OFFSET AND 0xffffffff        ; lo
170
        mov     edx, XFS_DIR2_FREE_OFFSET SHR 32                ; hi
171
        shrd    eax, edx, cl
172
        mov     [edi + XFS.dir2_free_offset_blocks], eax
173
 
174
;        mov     ecx, [edi + XFS.dirblklog]
175
;        mov     eax, [edi + XFS.blocksize]
176
;        shl     eax, cl
177
;        mov     [edi + XFS.dirblocksize], eax
178
 
179
        mov     eax, [edi + XFS.blocksize]
180
        call    malloc
181
        test    eax, eax
182
        jz      .error
183
        mov     [edi + XFS.cur_block], eax
184
 
185
        ; we do need XFS.blocksize bytes for single inode
186
        ; minimal file system structure is block, inodes are packed in blocks
187
 
188
        mov     eax, [edi + XFS.blocksize]
189
        call    malloc
190
        test    eax, eax
191
        jz      .error
192
        mov     [edi + XFS.cur_inode], eax
193
 
194
        ; temporary inode
195
        ; used for browsing directories
196
 
197
        mov     eax, [edi + XFS.blocksize]
198
        call    malloc
199
        test    eax, eax
200
        jz      .error
201
        mov     [edi + XFS.tmp_inode], eax
202
 
203
        ; current sector
204
        ; only for sector size structures like AGI
205
        ; inodes has usually the same size, but never store them here
206
 
207
        mov     eax, [edi + XFS.sectsize]
208
        call    malloc
209
        test    eax, eax
210
        jz      .error
211
        mov     [edi + XFS.cur_sect], eax
212
 
213
        ; current directory block
214
 
215
        mov     eax, [edi + XFS.dirblocksize]
216
        call    malloc
217
        test    eax, eax
218
        jz      .error
219
        mov     [edi + XFS.cur_dirblock], eax
220
 
221
  .quit:
222
        mov     eax, edi                ; return pointer to allocated XFS partition structure
223
        pop     edi esi edx ecx ebx
224
        ret
225
  .error:
226
        xor     eax, eax
227
        pop     edi esi edx ecx ebx
228
        ret
229
 
230
 
231
; lock partition access mutex
232
proc xfs_lock
233
;DEBUGF 1,"xfs_lock\n"
234
        lea     ecx, [ebp + XFS.Lock]
235
        jmp     mutex_lock
236
endp
237
 
238
 
239
; unlock partition access mutex
240
proc xfs_unlock
241
;DEBUGF 1,"xfs_unlock\n"
242
        lea     ecx, [ebp + XFS.Lock]
243
        jmp     mutex_unlock
244
endp
245
 
246
 
247
; free all the allocated memory
248
; called on partition destroy
249
proc xfs_free
250
        push    ebp
251
        xchg    ebp, eax
252
        stdcall kernel_free, [ebp + XFS.cur_block]
253
        stdcall kernel_free, [ebp + XFS.cur_inode]
254
        stdcall kernel_free, [ebp + XFS.cur_sect]
255
        stdcall kernel_free, [ebp + XFS.cur_dirblock]
256
        stdcall kernel_free, [ebp + XFS.tmp_inode]
257
        xchg    ebp, eax
258
        call    free
259
        pop     ebp
260
        ret
261
endp
262
 
263
 
264
;---------------------------------------------------------------
265
; block number (AG relative)
266
; eax -- inode_lo
267
; edx -- inode_hi
268
; ebx -- buffer
269
;---------------------------------------------------------------
270
xfs_read_block:
271
        push    ebx esi
272
 
273
        push    edx
274
        push    eax
275
 
276
        ; XFS block numbers are AG relative
277
        ; they come in bitfield form of concatenated AG and block numbers
278
        ; to get absolute block number for fs_read32_sys we should
279
        ; 1. extract AG number (using precalculated mask)
280
        ; 2. multiply it by the AG size in blocks
281
        ; 3. add AG relative block number
282
 
283
        ; 1.
284
        mov     ecx, [ebp + XFS.agblklog]
285
        shrd    eax, edx, cl
286
        shr     edx, cl
287
        ; 2.
288
        mul     dword[ebp + XFS.agblocks]
289
        pop     ecx
290
        pop     esi
291
        and     ecx, dword[ebp + XFS.agblockmask + 0]
292
        and     esi, dword[ebp + XFS.agblockmask + 4]
293
        ; 3.
294
        add     eax, ecx
295
        adc     edx, esi
296
 
297
;DEBUGF 1,"read block: 0x%x%x\n",edx,eax
298
        ; there is no way to read file system block at once, therefore we
299
        ; 1. calculate the number of sectors first
300
        ; 2. and then read them in series
301
 
302
        ; 1.
303
        mov     ecx, [ebp + XFS.blockmsectlog]
304
        shld    edx, eax, cl
305
        shl     eax, cl
306
        mov     esi, [ebp + XFS.sectpblock]
307
 
308
        ; 2.
309
  .next_sector:
310
        push    eax edx
311
        call    fs_read32_sys
312
        mov     ecx, eax
313
        pop     edx eax
314
        test    ecx, ecx
315
        jnz     .error
316
        add     eax, 1                          ; be ready to fs_read64_sys
317
        adc     edx, 0
318
        add     ebx, [ebp + XFS.sectsize]       ; update buffer offset
319
        dec     esi
320
        jnz     .next_sector
321
 
322
  .quit:
323
        xor     eax, eax
324
        pop     esi ebx
325
        ret
326
  .error:
327
        mov     eax, ecx
328
        pop     esi ebx
329
        ret
330
 
331
 
332
;---------------------------------------------------------------
333
; push buffer
334
; push startblock_hi
335
; push startblock_lo
336
; call xfs_read_dirblock
337
; test eax, eax
338
;---------------------------------------------------------------
339
xfs_read_dirblock:
340
;mov eax, [esp + 4]
341
;mov edx, [esp + 8]
342
;DEBUGF 1,"read dirblock at: %d %d\n",edx,eax
343
;DEBUGF 1,"dirblklog: %d\n",[ebp + XFS.dirblklog]
344
        push    ebx esi
345
 
346
        mov     eax, [esp + 12]         ; startblock_lo
347
        mov     edx, [esp + 16]         ; startblock_hi
348
        mov     ebx, [esp + 20]         ; buffer
349
 
350
        ; dirblock >= block
351
        ; read dirblocks by blocks
352
 
353
        mov     ecx, [ebp + XFS.dirblklog]
354
        mov     esi, 1
355
        shl     esi, cl
356
  .next_block:
357
        push    eax edx
358
        call    xfs_read_block
359
        mov     ecx, eax
360
        pop     edx eax
361
        test    ecx, ecx
362
        jnz     .error
363
        add     eax, 1          ; be ready to fs_read64_sys
364
        adc     edx, 0
365
        add     ebx, [ebp + XFS.blocksize]
366
        dec     esi
367
        jnz     .next_block
368
 
369
  .quit:
370
        xor     eax, eax
371
        pop     esi ebx
372
        ret     12
373
  .error:
374
        mov     eax, ecx
375
        pop     esi ebx
376
        ret     12
377
 
378
 
379
;---------------------------------------------------------------
380
; push buffer
381
; push inode_hi
382
; push inode_lo
383
; call xfs_read_inode
384
; test eax, eax
385
;---------------------------------------------------------------
386
xfs_read_inode:
387
;DEBUGF 1,"reading inode: 0x%x%x\n",[esp+8],[esp+4]
388
        push    ebx
389
        mov     eax, [esp + 8]  ; inode_lo
390
        mov     edx, [esp + 12] ; inode_hi
391
        mov     ebx, [esp + 16] ; buffer
392
 
393
        ; inodes are packed into blocks
394
        ; 1. calculate block number
395
        ; 2. read the block
396
        ; 3. add inode offset to block base address
397
 
398
        ; 1.
399
        mov     ecx, [ebp + XFS.inodetoblocklog]
400
        shrd    eax, edx, cl
401
        shr     edx, cl
402
        ; 2.
403
        call    xfs_read_block
404
        test    eax, eax
405
        jnz     .error
406
 
407
        ; note that inode numbers should be first extracted from bitfields using mask
408
 
409
        mov     eax, [esp + 8]
410
        mov     edx, 1
411
        mov     ecx, [ebp + XFS.inopblog]
412
        shl     edx, cl
413
        dec     edx             ; get inode number mask
414
        and     eax, edx        ; apply mask
415
        mov     ecx, [ebp + XFS.inodelog]
416
        shl     eax, cl
417
        add     ebx, eax
418
 
419
        cmp     word[ebx], XFS_DINODE_MAGIC     ; test signature
420
        jne     .error
421
  .quit:
422
        xor     eax, eax
423
        mov     edx, ebx
424
        pop     ebx
425
        ret     12
426
  .error:
427
        movi    eax, ERROR_FS_FAIL
428
        mov     edx, ebx
429
        pop     ebx
430
        ret     12
431
 
432
 
433
;----------------------------------------------------------------
434
; push encoding         ; ASCII / UNICODE
435
; push src              ; inode
436
; push dst              ; bdfe
437
; push entries_to_read
438
; push start_number     ; from 0
439
;----------------------------------------------------------------
440
xfs_dir_get_bdfes:
441
DEBUGF 1,"xfs_dir_get_bdfes: %d entries from %d\n",[esp+8],[esp+4]
442
        sub     esp, 4     ; local vars
443
        push    ecx edx esi edi
444
 
445
        mov     ebx, [esp + 36]         ; src
446
        mov     edx, [esp + 32]         ; dst
447
        mov     ecx, [esp + 24]         ; start_number
448
 
449
        ; define directory ondisk format and jump to corresponding label
450
 
451
        cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_LOCAL
452
        jne     .not_shortdir
453
        jmp     .shortdir
454
  .not_shortdir:
455
        cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
456
        jne     .not_blockdir
457
        mov     eax, [ebx + xfs_inode.di_core.di_nextents]
458
        bswap   eax
459
        cmp     eax, 1
460
        jne     .not_blockdir
461
        jmp     .blockdir
462
  .not_blockdir:
463
        cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
464
        jne     .not_leafdir
465
        mov     eax, [ebx + xfs_inode.di_core.di_nextents]
466
        bswap   eax
467
        cmp     eax, 4
468
        ja      .not_leafdir
469
        jmp     .leafdir
470
  .not_leafdir:
471
        cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
472
        jne     .not_nodedir
473
        jmp     .nodedir
474
  .not_nodedir:
475
        cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
476
        jne     .not_btreedir
477
        jmp     .btreedir
478
  .not_btreedir:
479
        movi    eax, ERROR_FS_FAIL
480
        jmp     .error
481
 
482
        ; short form directory (all the data fits into inode)
483
  .shortdir:
484
;DEBUGF 1,"shortdir\n",
485
        movzx   eax, word[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count]
486
        test    al, al                  ; is count zero?
487
        jnz     @f                      ; if not, use it (i8count must be zero then)
488
        shr     eax, 8                  ; use i8count
489
    @@:
490
        add     eax, 1                  ; '..' and '.' are implicit
491
        mov     dword[edx + 0], 1       ; version
492
        mov     [edx + 8], eax          ; total entries
493
        sub     eax, [esp + 24]         ; start number
494
        cmp     eax, [esp + 28]         ; entries to read
495
        jbe     @f
496
        mov     eax, [esp + 28]
497
    @@:
498
        mov     [esp + 28], eax
499
        mov     [edx + 4], eax          ; number of actually read entries
500
        mov     [ebp + XFS.entries_read], eax
501
 
502
        ; inode numbers are often saved as 4 bytes (iff they fit)
503
        ; compute the length of inode numbers
504
 
505
        mov     eax, 4          ; 4 by default
506
        cmp     byte[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.i8count], 0
507
        je      @f
508
        add     eax, eax        ; 4+4=8, iff i8count != 0
509
    @@:
510
        mov     dword[edx + 12], 0      ; reserved
6462 pathoswith 511
        mov     dword[edx + 16], 0      ;
512
        mov     dword[edx + 20], 0      ;
513
        mov     dword[edx + 24], 0      ;
514
        mov     dword[edx + 28], 0      ;
3913 dunkaist 515
        add     edx, 32
516
        lea     esi, [ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + eax]
517
        dec     ecx
518
        js      .shortdir.fill
519
 
520
        ; skip some entries if the first entry to read is not 0
521
 
522
  .shortdir.skip:
523
        test    ecx, ecx
524
        jz      .shortdir.skipped
525
        movzx   edi, byte[esi + xfs_dir2_sf_entry.namelen]
526
        lea     esi, [esi + xfs_dir2_sf_entry.name + edi]
527
        add     esi, eax
528
        dec     ecx
529
        jnz     .shortdir.skip
530
        mov     ecx, [esp + 28]         ; entries to read
531
        jmp     .shortdir.skipped
532
  .shortdir.fill:
533
        mov     ecx, [esp + 28]         ; total number
534
        test    ecx, ecx
535
        jz      .quit
536
        push    ecx
537
;DEBUGF 1,"ecx: %d\n",ecx
538
        lea     edi, [edx + 40]         ; get file name offset
539
;DEBUGF 1,"filename: ..\n"
540
        mov     dword[edi], '..'
541
        mov     edi, edx
542
        push    eax ebx edx esi
543
        stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + 4], dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent]
544
        stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
545
;        test    eax, eax
546
;        jnz     .error
547
        stdcall xfs_get_inode_info, edx, edi
548
        test    eax, eax
549
        pop     esi edx ebx eax
550
        jnz     .error
551
        mov     ecx, [esp + 44]         ; file name encding
552
        mov     [edx + 4], ecx
553
        add     edx, 304                ; ASCII only for now
554
        pop     ecx
555
        dec     ecx
556
        jz      .quit
557
 
558
;        push    ecx
559
;        lea     edi, [edx + 40]
560
;DEBUGF 1,"filename: .\n"
561
;        mov     dword[edi], '.'
562
;        mov     edi, edx
563
;        push    eax edx
564
;        stdcall xfs_get_inode_info, [ebp + XFS.cur_inode], edi
565
;        test    eax, eax
566
;        pop     edx eax
567
;        jnz     .error
568
;        mov     ecx, [esp + 44]
569
;        mov     [edx + 4], ecx
570
;        add     edx, 304                ; ASCII only for now
571
;        pop     ecx
572
;        dec     ecx
573
;        jz      .quit
574
 
575
        ; we skipped some entries
576
        ; now we fill min(required, present) number of bdfe's
577
 
578
  .shortdir.skipped:
579
;DEBUGF 1,"ecx: %d\n",ecx
580
        push    ecx
581
        movzx   ecx, byte[esi + xfs_dir2_sf_entry.namelen]
582
        add     esi, xfs_dir2_sf_entry.name
583
        lea     edi, [edx + 40]         ; bdfe offset of file name
584
;DEBUGF 1,"filename: |%s|\n",esi
585
        rep movsb
586
        mov     word[edi], 0            ; terminator (ASCIIZ)
587
 
588
        push    eax ebx ecx edx esi
589
;        push    edx     ; for xfs_get_inode_info
590
        mov     edi, edx
591
        stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], [esi + 4], [esi]
592
        stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
593
;        test    eax, eax
594
;        jnz     .error
595
        stdcall xfs_get_inode_info, edx, edi
596
        test    eax, eax
597
        pop     esi edx ecx ebx eax
598
        jnz     .error
599
        mov     ecx, [esp + 44]         ; file name encoding
600
        mov     [edx + 4], ecx
601
 
602
        add     edx, 304                ; ASCII only for now
603
        add     esi, eax
604
        pop     ecx
605
        dec     ecx
606
        jnz     .shortdir.skipped
607
        jmp     .quit
608
 
609
  .blockdir:
610
;DEBUGF 1,"blockdir\n"
611
        push    edx
612
        lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
613
        stdcall xfs_extent_unpack, eax
614
;DEBUGF 1,"extent.br_startoff  : 0x%x%x\n",[ebp+XFS.extent.br_startoff+4],[ebp+XFS.extent.br_startoff+0]
615
;DEBUGF 1,"extent.br_startblock: 0x%x%x\n",[ebp+XFS.extent.br_startblock+4],[ebp+XFS.extent.br_startblock+0]
616
;DEBUGF 1,"extent.br_blockcount: %d\n",[ebp+XFS.extent.br_blockcount]
617
;DEBUGF 1,"extent.br_state     : %d\n",[ebp+XFS.extent.br_state]
618
        stdcall xfs_read_dirblock, dword[ebp + XFS.extent.br_startblock + 0], dword[ebp + XFS.extent.br_startblock + 4], [ebp + XFS.cur_dirblock]
619
        test    eax, eax
620
        pop     edx
621
        jnz     .error
622
;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock]
623
        mov     ebx, [ebp + XFS.cur_dirblock]
624
        mov     dword[edx + 0], 1       ; version
625
        mov     eax, [ebp + XFS.dirblocksize]
626
        mov     ecx, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.stale]
627
        mov     eax, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.count]
628
        bswap   ecx
629
        bswap   eax
630
        sub     eax, ecx                ; actual number of entries = count - stale
631
        mov     [edx + 8], eax          ; total entries
632
;DEBUGF 1,"total entries: %d\n",eax
633
        sub     eax, [esp + 24]         ; start number
634
        cmp     eax, [esp + 28]         ; entries to read
635
        jbe     @f
636
        mov     eax, [esp + 28]
637
    @@:
638
        mov     [esp + 28], eax
639
        mov     [edx + 4], eax          ; number of actually read entries
640
        mov     [ebp + XFS.entries_read], eax
641
;DEBUGF 1,"actually read entries: %d\n",eax
642
        mov     dword[edx + 12], 0      ; reserved
6462 pathoswith 643
        mov     dword[edx + 16], 0      ;
644
        mov     dword[edx + 20], 0      ;
645
        mov     dword[edx + 24], 0      ;
646
        mov     dword[edx + 28], 0      ;
3913 dunkaist 647
        add     ebx, xfs_dir2_block.u
648
 
649
        mov     ecx, [esp + 24]         ; start entry number
650
                                        ; also means how many to skip
651
        test    ecx, ecx
652
        jz      .blockdir.skipped
653
  .blockdir.skip:
654
        cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
655
        jne     @f
656
        movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
657
        xchg    al, ah
658
        add     ebx, eax
659
        jmp     .blockdir.skip
660
    @@:
661
        movzx   eax, [ebx + xfs_dir2_data_union.xentry.namelen]
662
        lea     ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2]       ; 2 bytes for 'tag'
663
        add     ebx, 7                  ; align on 8 bytes
664
        and     ebx, not 7
665
        dec     ecx
666
        jnz     .blockdir.skip
667
  .blockdir.skipped:
668
        mov     ecx, [edx + 4]          ; actually read entries
669
        test    ecx, ecx
670
        jz      .quit
671
        add     edx, 32                 ; set edx to the first bdfe
672
  .blockdir.next_entry:
673
        cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_NULL
674
        jne     @f
675
        movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
676
        xchg    al, ah
677
        add     ebx, eax
678
        jmp     .blockdir.next_entry
679
    @@:
680
        push    ecx
681
        push    eax ebx ecx edx esi
682
        mov     edi, edx
683
        mov     edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0]
684
        mov     eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4]
685
        bswap   edx
686
        bswap   eax
687
        stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
688
        stdcall xfs_get_inode_info, edx, edi
689
        test    eax, eax
690
        pop     esi edx ecx ebx eax
691
        jnz     .error
692
        mov     ecx, [esp + 44]
693
        mov     [edx + 4], ecx
694
        lea     edi, [edx + 40]
695
        movzx   ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen]
696
        lea     esi, [ebx + xfs_dir2_data_union.xentry.name]
697
;DEBUGF 1,"filename: |%s|\n",esi
698
        rep movsb
699
;        call    utf8_to_cp866
700
        mov     word[edi], 0            ; terminator
701
        lea     ebx, [esi + 2]          ; skip 'tag'
702
        add     ebx, 7                  ; xfs_dir2_data_entries are aligned to 8 bytes
703
        and     ebx, not 7
704
        add     edx, 304
705
        pop     ecx
706
        dec     ecx
707
        jnz     .blockdir.next_entry
708
        jmp     .quit
709
 
710
  .leafdir:
711
;DEBUGF 1,"readdir: leaf\n"
712
        mov     [ebp + XFS.cur_inode_save], ebx
713
        push    ebx ecx edx
714
        lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
715
        mov     edx, [ebx + xfs_inode.di_core.di_nextents]
716
        bswap   edx
717
        stdcall xfs_extent_list_read_dirblock, eax, [ebp + XFS.dir2_leaf_offset_blocks], 0, edx, 0xffffffff, 0xffffffff
718
        mov     ecx, eax
719
        and     ecx, edx
720
        inc     ecx
721
        pop     edx ecx ebx
722
        jz      .error
723
 
724
        mov     eax, [ebp + XFS.cur_dirblock]
725
        movzx   ecx, word[eax + xfs_dir2_leaf.hdr.stale]
726
        movzx   eax, word[eax + xfs_dir2_leaf.hdr.count]
727
        xchg    cl, ch
728
        xchg    al, ah
729
        sub     eax, ecx
730
;DEBUGF 1,"total count: %d\n",eax
731
 
732
        mov     dword[edx + 0], 1       ; version
733
        mov     [edx + 8], eax          ; total entries
734
        sub     eax, [esp + 24]         ; start number
735
        cmp     eax, [esp + 28]         ; entries to read
736
        jbe     @f
737
        mov     eax, [esp + 28]
738
    @@:
739
        mov     [esp + 28], eax
740
        mov     [edx + 4], eax          ; number of actually read entries
741
 
742
        mov     dword[edx + 12], 0      ; reserved
6462 pathoswith 743
        mov     dword[edx + 16], 0      ;
744
        mov     dword[edx + 20], 0      ;
745
        mov     dword[edx + 24], 0      ;
746
        mov     dword[edx + 28], 0      ;
3913 dunkaist 747
 
748
        mov     eax, [ebp + XFS.cur_dirblock]
749
        add     eax, [ebp + XFS.dirblocksize]
750
        mov     [ebp + XFS.max_dirblockaddr], eax
751
        mov     dword[ebp + XFS.next_block_num + 0], 0
752
        mov     dword[ebp + XFS.next_block_num + 4], 0
753
 
754
        mov     ebx, [ebp + XFS.max_dirblockaddr]       ; to read dirblock immediately
755
        mov     ecx, [esp + 24]         ; start number
756
        test    ecx, ecx
757
        jz      .leafdir.skipped
758
  .leafdir.skip:
759
        cmp     ebx, [ebp + XFS.max_dirblockaddr]
760
        jne     @f
761
        push    ecx edx
762
        mov     ebx, [ebp + XFS.cur_inode_save]
763
        lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
764
        mov     edx, [ebx + xfs_inode.di_core.di_nextents]
765
        bswap   edx
766
        stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
767
        mov     ecx, eax
768
        and     ecx, edx
769
        inc     ecx
770
        jz      .error
771
        add     eax, 1
772
        adc     edx, 0
773
        mov     dword[ebp + XFS.next_block_num + 0], eax
774
        mov     dword[ebp + XFS.next_block_num + 4], edx
775
        mov     ebx, [ebp + XFS.cur_dirblock]
776
        add     ebx, sizeof.xfs_dir2_data_hdr
777
        pop     edx ecx
778
    @@:
779
        cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
780
        jne     @f
781
        movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
782
        xchg    al, ah
783
        add     ebx, eax
784
        jmp     .leafdir.skip
785
    @@:
786
        movzx   eax, [ebx + xfs_dir2_data_union.xentry.namelen]
787
        lea     ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2]       ; 2 for 'tag'
788
        add     ebx, 7
789
        and     ebx, not 7
790
        dec     ecx
791
        jnz     .leafdir.skip
792
  .leafdir.skipped:
793
        mov     [ebp + XFS.entries_read], 0
794
        mov     ecx, [edx + 4]          ; actually read entries
795
        test    ecx, ecx
796
        jz      .quit
797
        add     edx, 32                 ; first bdfe entry
798
  .leafdir.next_entry:
799
;DEBUGF 1,"next_extry\n"
800
        cmp     ebx, [ebp + XFS.max_dirblockaddr]
801
        jne     .leafdir.process_current_block
802
        push    ecx edx
803
        mov     ebx, [ebp + XFS.cur_inode_save]
804
        lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
805
        mov     edx, [ebx + xfs_inode.di_core.di_nextents]
806
        bswap   edx
807
        stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
808
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
809
        mov     ecx, eax
810
        and     ecx, edx
811
        inc     ecx
812
        jnz     @f
813
        pop     edx ecx
814
        jmp     .quit
815
    @@:
816
        add     eax, 1
817
        adc     edx, 0
818
        mov     dword[ebp + XFS.next_block_num + 0], eax
819
        mov     dword[ebp + XFS.next_block_num + 4], edx
820
        mov     ebx, [ebp + XFS.cur_dirblock]
821
        add     ebx, sizeof.xfs_dir2_data_hdr
822
        pop     edx ecx
823
  .leafdir.process_current_block:
824
        cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
825
        jne     @f
826
        movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
827
        xchg    al, ah
828
        add     ebx, eax
829
        jmp     .leafdir.next_entry
830
    @@:
831
        push    eax ebx ecx edx esi
832
        mov     edi, edx
833
        mov     edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0]
834
        mov     eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4]
835
        bswap   edx
836
        bswap   eax
837
        stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
838
        stdcall xfs_get_inode_info, edx, edi
839
        test    eax, eax
840
        pop     esi edx ecx ebx eax
841
        jnz     .error
842
        push    ecx
843
        mov     ecx, [esp + 44]
844
        mov     [edx + 4], ecx
845
        lea     edi, [edx + 40]
846
        movzx   ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen]
847
        lea     esi, [ebx + xfs_dir2_data_union.xentry.name]
848
;DEBUGF 1,"filename: |%s|\n",esi
849
        rep movsb
850
        pop     ecx
851
        mov     word[edi], 0
852
        lea     ebx, [esi + 2]  ; skip 'tag'
853
        add     ebx, 7          ; xfs_dir2_data_entries are aligned to 8 bytes
854
        and     ebx, not 7
855
        add     edx, 304        ; ASCII only for now
856
        inc     [ebp + XFS.entries_read]
857
        dec     ecx
858
        jnz     .leafdir.next_entry
859
        jmp     .quit
860
 
861
  .nodedir:
862
;DEBUGF 1,"readdir: node\n"
863
        push    edx
864
        mov     [ebp + XFS.cur_inode_save], ebx
865
        mov     [ebp + XFS.entries_read], 0
866
        lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
867
        mov     edx, [ebx + xfs_inode.di_core.di_nextents]
868
        bswap   edx
869
        stdcall xfs_dir2_node_get_numfiles, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks]
870
        pop     edx
871
        test    eax, eax
872
        jnz     .error
873
        mov     eax, [ebp + XFS.entries_read]
874
        mov     [ebp + XFS.entries_read], 0
875
;DEBUGF 1,"numfiles: %d\n",eax
876
        mov     dword[edx + 0], 1       ; version
877
        mov     [edx + 8], eax          ; total entries
878
        sub     eax, [esp + 24]         ; start number
879
        cmp     eax, [esp + 28]         ; entries to read
880
        jbe     @f
881
        mov     eax, [esp + 28]
882
    @@:
883
        mov     [esp + 28], eax
884
        mov     [edx + 4], eax          ; number of actually read entries
885
 
886
        mov     dword[edx + 12], 0      ; reserved
6462 pathoswith 887
        mov     dword[edx + 16], 0      ;
888
        mov     dword[edx + 20], 0      ;
889
        mov     dword[edx + 24], 0      ;
890
        mov     dword[edx + 28], 0      ;
3913 dunkaist 891
 
892
        mov     eax, [ebp + XFS.cur_dirblock]
893
        add     eax, [ebp + XFS.dirblocksize]
894
        mov     [ebp + XFS.max_dirblockaddr], eax
895
        mov     dword[ebp + XFS.next_block_num + 0], 0
896
        mov     dword[ebp + XFS.next_block_num + 4], 0
897
 
898
        mov     ebx, [ebp + XFS.max_dirblockaddr]       ; to read dirblock immediately
899
        mov     ecx, [esp + 24]         ; start number
900
        test    ecx, ecx
901
        jz      .leafdir.skipped
902
        jmp     .leafdir.skip
903
 
904
  .btreedir:
905
;DEBUGF 1,"readdir: btree\n"
906
        mov     [ebp + XFS.cur_inode_save], ebx
907
        push    ebx edx
908
        mov     eax, [ebx + xfs_inode.di_core.di_nextents]
909
        bswap   eax
910
        mov     [ebp + XFS.ro_nextents], eax
911
        mov     eax, [ebp + XFS.inodesize]
912
        sub     eax, xfs_inode.di_u
913
        sub     eax, sizeof.xfs_bmdr_block
914
        shr     eax, 4
915
;DEBUGF 1,"maxnumresc: %d\n",eax
916
        mov     edx, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 0]
917
        mov     eax, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 4]
918
        bswap   eax
919
        bswap   edx
920
        mov     ebx, [ebp + XFS.cur_block]
921
;DEBUGF 1,"read_block: %x %x ",edx,eax
922
        stdcall xfs_read_block
923
        pop     edx ebx
924
        test    eax, eax
925
        jnz     .error
926
;DEBUGF 1,"ok\n"
927
 
928
        mov     ebx, [ebp + XFS.cur_block]
929
        push    edx
930
        mov     [ebp + XFS.entries_read], 0
931
        lea     eax, [ebx + sizeof.xfs_bmbt_block]
932
        mov     edx, [ebp + XFS.ro_nextents]
933
        stdcall xfs_dir2_node_get_numfiles, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks]
934
        pop     edx
935
        test    eax, eax
936
        jnz     .error
937
        mov     eax, [ebp + XFS.entries_read]
938
        mov     [ebp + XFS.entries_read], 0
939
;DEBUGF 1,"numfiles: %d\n",eax
940
 
941
        mov     dword[edx + 0], 1       ; version
942
        mov     [edx + 8], eax          ; total entries
943
        sub     eax, [esp + 24]         ; start number
944
        cmp     eax, [esp + 28]         ; entries to read
945
        jbe     @f
946
        mov     eax, [esp + 28]
947
    @@:
948
        mov     [esp + 28], eax
949
        mov     [edx + 4], eax          ; number of actually read entries
950
 
951
        mov     dword[edx + 12], 0
952
        mov     dword[edx + 16], 0
953
        mov     dword[edx + 20], 0
954
        mov     dword[edx + 24], 0
955
        mov     dword[edx + 28], 0
956
 
957
        mov     eax, [ebp + XFS.cur_dirblock]   ; fsblock?
958
        add     eax, [ebp + XFS.dirblocksize]
959
        mov     [ebp + XFS.max_dirblockaddr], eax
960
        mov     dword[ebp + XFS.next_block_num + 0], 0
961
        mov     dword[ebp + XFS.next_block_num + 4], 0
962
 
963
        mov     ebx, [ebp + XFS.max_dirblockaddr]       ; to read dirblock immediately
964
        mov     ecx, [esp + 24]         ; start number
965
        test    ecx, ecx
966
        jz      .btreedir.skipped
967
;        jmp     .btreedir.skip
968
  .btreedir.skip:
969
        cmp     ebx, [ebp + XFS.max_dirblockaddr]
970
        jne     @f
971
        push    ecx edx
972
        mov     ebx, [ebp + XFS.cur_block]
973
        lea     eax, [ebx + sizeof.xfs_bmbt_block]
974
        mov     edx, [ebp + XFS.ro_nextents]
975
        stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
976
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
977
        mov     ecx, eax
978
        and     ecx, edx
979
        inc     ecx
980
        jz      .error
981
        add     eax, 1
982
        adc     edx, 0
983
        mov     dword[ebp + XFS.next_block_num + 0], eax
984
        mov     dword[ebp + XFS.next_block_num + 4], edx
985
        mov     ebx, [ebp + XFS.cur_dirblock]
986
        add     ebx, sizeof.xfs_dir2_data_hdr
987
        pop     edx ecx
988
    @@:
989
        cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
990
        jne     @f
991
        movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
992
        xchg    al, ah
993
        add     ebx, eax
994
        jmp     .btreedir.skip
995
    @@:
996
        movzx   eax, [ebx + xfs_dir2_data_union.xentry.namelen]
997
        lea     ebx, [ebx + xfs_dir2_data_union.xentry.name + eax + 2]       ; 2 for 'tag'
998
        add     ebx, 7
999
        and     ebx, not 7
1000
        dec     ecx
1001
        jnz     .btreedir.skip
1002
  .btreedir.skipped:
1003
        mov     [ebp + XFS.entries_read], 0
1004
        mov     ecx, [edx + 4]          ; actually read entries
1005
        test    ecx, ecx
1006
        jz      .quit
1007
        add     edx, 32
1008
  .btreedir.next_entry:
1009
;mov eax, [ebp + XFS.entries_read]
1010
;DEBUGF 1,"next_extry: %d\n",eax
1011
        cmp     ebx, [ebp + XFS.max_dirblockaddr]
1012
        jne     .btreedir.process_current_block
1013
        push    ecx edx
1014
        mov     ebx, [ebp + XFS.cur_block]
1015
        lea     eax, [ebx + sizeof.xfs_bmbt_block]
1016
        mov     edx, [ebp + XFS.ro_nextents]
1017
        stdcall xfs_extent_list_read_dirblock, eax, dword[ebp + XFS.next_block_num + 0], dword[ebp + XFS.next_block_num + 4], edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
1018
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
1019
        mov     ecx, eax
1020
        and     ecx, edx
1021
        inc     ecx
1022
        jnz     @f
1023
        pop     edx ecx
1024
        jmp     .quit
1025
    @@:
1026
        add     eax, 1
1027
        adc     edx, 0
1028
        mov     dword[ebp + XFS.next_block_num + 0], eax
1029
        mov     dword[ebp + XFS.next_block_num + 4], edx
1030
        mov     ebx, [ebp + XFS.cur_dirblock]
1031
        add     ebx, sizeof.xfs_dir2_data_hdr
1032
        pop     edx ecx
1033
  .btreedir.process_current_block:
1034
        cmp     word[ebx + xfs_dir2_data_union.unused.freetag], XFS_DIR2_DATA_FREE_TAG
1035
        jne     @f
1036
        movzx   eax, word[ebx + xfs_dir2_data_union.unused.length]
1037
        xchg    al, ah
1038
        add     ebx, eax
1039
        jmp     .btreedir.next_entry
1040
    @@:
1041
        push    eax ebx ecx edx esi
1042
        mov     edi, edx
1043
        mov     edx, dword[ebx + xfs_dir2_data_union.xentry.inumber + 0]
1044
        mov     eax, dword[ebx + xfs_dir2_data_union.xentry.inumber + 4]
1045
        bswap   edx
1046
        bswap   eax
1047
        stdcall xfs_read_inode, eax, edx, [ebp + XFS.tmp_inode]
1048
        stdcall xfs_get_inode_info, edx, edi
1049
        test    eax, eax
1050
        pop     esi edx ecx ebx eax
1051
        jnz     .error
1052
        push    ecx
1053
        mov     ecx, [esp + 44]
1054
        mov     [edx + 4], ecx
1055
        lea     edi, [edx + 40]
1056
        movzx   ecx, byte[ebx + xfs_dir2_data_union.xentry.namelen]
1057
        lea     esi, [ebx + xfs_dir2_data_union.xentry.name]
1058
;DEBUGF 1,"filename: |%s|\n",esi
1059
        rep movsb
1060
        pop     ecx
1061
        mov     word[edi], 0
1062
        lea     ebx, [esi + 2]  ; skip 'tag'
1063
        add     ebx, 7          ; xfs_dir2_data_entries are aligned to 8 bytes
1064
        and     ebx, not 7
1065
        add     edx, 304
1066
        inc     [ebp + XFS.entries_read]
1067
        dec     ecx
1068
        jnz     .btreedir.next_entry
1069
        jmp     .quit
1070
 
1071
 
1072
  .quit:
1073
        pop     edi esi edx ecx
1074
        add     esp, 4  ; pop vars
1075
        xor     eax, eax
1076
;        mov     ebx, [esp + 8]
1077
        mov     ebx, [ebp + XFS.entries_read]
1078
DEBUGF 1,"xfs_dir_get_bdfes done: %d\n",ebx
1079
        ret     20
1080
  .error:
1081
        pop     edi esi edx ecx
1082
        add     esp, 4  ; pop vars
1083
        mov     eax, ERROR_FS_FAIL
1084
        movi    ebx, -1
1085
        ret     20
1086
 
1087
 
1088
;----------------------------------------------------------------
1089
; push inode_hi
1090
; push inode_lo
1091
; push name
1092
;----------------------------------------------------------------
1093
xfs_get_inode_short:
1094
        ; this function searches for the file in _current_ dir
1095
        ; it is called recursively for all the subdirs /path/to/my/file
1096
 
1097
;DEBUGF 1,"xfs_get_inode_short: %s\n",[esp+4]
1098
        mov     esi, [esp + 4]  ; name
1099
        movzx   eax, word[esi]
1100
        cmp     eax, '.'        ; current dir; it is already read, just return
1101
        je      .quit
1102
        cmp     eax, './'       ; same thing
1103
        je      .quit
1104
 
1105
        ; read inode
1106
 
1107
        mov     eax, [esp + 8]  ; inode_lo
1108
        mov     edx, [esp + 12] ; inode_hi
1109
        stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
1110
        test    eax, eax
1111
        movi    eax, ERROR_FS_FAIL
1112
        jnz     .error
1113
 
1114
        ; find file name in directory
1115
        ; switch directory ondisk format
1116
 
1117
        mov     ebx, edx
1118
        mov     [ebp + XFS.cur_inode_save], ebx
1119
        cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_LOCAL
1120
        jne     .not_shortdir
1121
;DEBUGF 1,"dir: shortdir\n"
1122
        jmp     .shortdir
1123
  .not_shortdir:
1124
        cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
1125
        jne     .not_blockdir
1126
        mov     eax, [ebx + xfs_inode.di_core.di_nextents]
1127
        bswap   eax
1128
        cmp     eax, 1
1129
        jne     .not_blockdir
1130
        jmp     .blockdir
1131
  .not_blockdir:
1132
        cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
1133
        jne     .not_leafdir
1134
        mov     eax, [ebx + xfs_inode.di_core.di_nextents]
1135
        bswap   eax
1136
        cmp     eax, 4
1137
        ja      .not_leafdir
1138
        jmp     .leafdir
1139
  .not_leafdir:
1140
        cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
1141
        jne     .not_nodedir
1142
        jmp     .nodedir
1143
  .not_nodedir:
1144
        cmp     byte[ebx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
1145
        jne     .not_btreedir
1146
        jmp     .btreedir
1147
  .not_btreedir:
1148
DEBUGF 1,"NOT IMPLEMENTED: DIR FORMAT\n"
1149
        jmp     .error
1150
 
1151
  .shortdir:
1152
  .shortdir.check_parent:
1153
        ; parent inode number in shortform directories is always implicit, check this case
1154
        mov     eax, [esi]
1155
        and     eax, 0x00ffffff
1156
        cmp     eax, '..'
1157
        je      .shortdir.parent2
1158
        cmp     eax, '../'
1159
        je      .shortdir.parent3
1160
        jmp     .shortdir.common
1161
  .shortdir.parent3:
1162
        inc     esi
1163
  .shortdir.parent2:
1164
        add     esi, 2
1165
        add     ebx, xfs_inode.di_u
1166
        stdcall xfs_get_inode_number_sf, dword[ebx + xfs_dir2_sf_hdr.count], dword[ebx + xfs_dir2_sf_hdr.parent + 4], dword[ebx + xfs_dir2_sf_hdr.parent]
1167
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
1168
        jmp     .quit
1169
 
1170
        ; not a parent inode?
1171
        ; search in the list, all the other files are stored uniformly
1172
 
1173
  .shortdir.common:
1174
        mov     eax, 4
1175
        movzx   edx, word[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count] ; read count (byte) and i8count (byte) at once
1176
        test    dl, dl          ; is count zero?
1177
        jnz     @f
1178
        shr     edx, 8          ; use i8count
1179
        add     eax, eax        ; inode_num size
1180
    @@:
1181
        lea     edi, [ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.parent + eax]
1182
 
1183
  .next_name:
1184
        movzx   ecx, byte[edi + xfs_dir2_sf_entry.namelen]
1185
        add     edi, xfs_dir2_sf_entry.name
1186
        mov     esi, [esp + 4]
1187
;DEBUGF 1,"esi: %s\n",esi
1188
;DEBUGF 1,"edi: %s\n",edi
1189
        repe cmpsb
1190
        jne     @f
1191
        cmp     byte[esi], 0            ; HINT: use adc here?
1192
        je      .found
1193
        cmp     byte[esi], '/'
1194
        je      .found_inc
1195
    @@:
1196
        add     edi, ecx
1197
        add     edi, eax
1198
        dec     edx
1199
        jnz     .next_name
1200
        movi    eax, ERROR_FILE_NOT_FOUND
1201
        jmp     .error
1202
  .found_inc:           ; increment esi to skip '/' symbol
1203
                        ; this means esi always points to valid file name or zero terminator byte
1204
        inc     esi
1205
  .found:
1206
        stdcall xfs_get_inode_number_sf, dword[ebx + xfs_inode.di_u + xfs_dir2_sf_hdr.count], [edi + 4], [edi]
1207
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
1208
        jmp     .quit
1209
 
1210
  .blockdir:
1211
        lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
1212
        stdcall xfs_extent_unpack, eax
1213
        stdcall xfs_read_dirblock, dword[ebp + XFS.extent.br_startblock + 0], dword[ebp + XFS.extent.br_startblock + 4], [ebp + XFS.cur_dirblock]
1214
        test    eax, eax
1215
        jnz     .error
1216
;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock]
1217
        mov     ebx, [ebp + XFS.cur_dirblock]
1218
        mov     eax, [ebp + XFS.dirblocksize]
1219
        mov     eax, [ebx + eax - sizeof.xfs_dir2_block_tail + xfs_dir2_block_tail.count]
1220
        ; note that we don't subtract xfs_dir2_block_tail.stale here,
1221
        ; since we need the number of leaf entries rather than file number
1222
        bswap   eax
1223
        add     ebx, [ebp + XFS.dirblocksize]
1224
;        mov     ecx, sizeof.xfs_dir2_leaf_entry
1225
        imul    ecx, eax, sizeof.xfs_dir2_leaf_entry
1226
        sub     ebx, sizeof.xfs_dir2_block_tail
1227
        sub     ebx, ecx
1228
        shr     ecx, 3
1229
        push    ecx     ; for xfs_get_inode_by_hash
1230
        push    ebx     ; for xfs_get_inode_by_hash
1231
 
1232
        mov     edi, esi
1233
        xor     eax, eax
1234
        mov     ecx, 4096       ; MAX_PATH_LEN
1235
        repne scasb
1236
        movi    eax, ERROR_FS_FAIL
1237
        jne     .error
1238
        neg     ecx
1239
        add     ecx, 4096       ; MAX_PATH_LEN
1240
        dec     ecx
1241
        mov     edx, ecx
1242
;DEBUGF 1,"strlen total  : %d\n",edx
1243
        mov     edi, esi
1244
        mov     eax, '/'
1245
        mov     ecx, edx
1246
        repne scasb
1247
        jne     @f
1248
        inc     ecx
1249
    @@:
1250
        neg     ecx
1251
        add     ecx, edx
1252
;DEBUGF 1,"strlen current: %d\n",ecx
1253
        stdcall xfs_hashname, esi, ecx
1254
        add     esi, ecx
1255
        cmp     byte[esi], '/'
1256
        jne     @f
1257
        inc     esi
1258
    @@:
1259
;DEBUGF 1,"hashed: 0x%x\n",eax
1260
;        bswap   eax
1261
        stdcall xfs_get_addr_by_hash
1262
        bswap   eax
1263
;DEBUGF 1,"got address: 0x%x\n",eax
1264
        cmp     eax, -1
1265
        jne     @f
1266
        movi    eax, ERROR_FILE_NOT_FOUND
1267
        mov     ebx, -1
1268
        jmp     .error
1269
    @@:
1270
        shl     eax, 3
1271
        mov     ebx, [ebp + XFS.cur_dirblock]
1272
        add     ebx, eax
1273
        mov     edx, [ebx + 0]
1274
        mov     eax, [ebx + 4]
1275
        bswap   edx
1276
        bswap   eax
1277
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
1278
        jmp     .quit
1279
 
1280
  .leafdir:
1281
;DEBUGF 1,"dirblock signature: %s\n",[ebp+XFS.cur_dirblock]
1282
        lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
1283
        mov     edx, [ebx + xfs_inode.di_core.di_nextents]
1284
        bswap   edx
1285
        stdcall xfs_extent_list_read_dirblock, eax, [ebp + XFS.dir2_leaf_offset_blocks], 0, edx, -1, -1
1286
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
1287
        mov     ecx, eax
1288
        and     ecx, edx
1289
        inc     ecx
1290
        jz      .error
1291
 
1292
        mov     ebx, [ebp + XFS.cur_dirblock]
1293
        movzx   eax, [ebx + xfs_dir2_leaf.hdr.count]
1294
        ; note that we don't subtract xfs_dir2_leaf.hdr.stale here,
1295
        ; since we need the number of leaf entries rather than file number
1296
        xchg    al, ah
1297
        add     ebx, xfs_dir2_leaf.ents
1298
;        imul    ecx, eax, sizeof.xfs_dir2_leaf_entry
1299
;        shr     ecx, 3
1300
        push    eax     ; for xfs_get_addr_by_hash: len
1301
        push    ebx     ; for xfs_get_addr_by_hash: base
1302
 
1303
        mov     edi, esi
1304
        xor     eax, eax
1305
        mov     ecx, 4096       ; MAX_PATH_LEN
1306
        repne scasb
1307
        movi    eax, ERROR_FS_FAIL
1308
        jne     .error
1309
        neg     ecx
1310
        add     ecx, 4096
1311
        dec     ecx
1312
        mov     edx, ecx
1313
;DEBUGF 1,"strlen total  : %d\n",edx
1314
        mov     edi, esi
1315
        mov     eax, '/'
1316
        mov     ecx, edx
1317
        repne scasb
1318
        jne     @f
1319
        inc     ecx
1320
    @@:
1321
        neg     ecx
1322
        add     ecx, edx
1323
;DEBUGF 1,"strlen current: %d\n",ecx
1324
        stdcall xfs_hashname, esi, ecx
1325
        add     esi, ecx
1326
        cmp     byte[esi], '/'
1327
        jne     @f
1328
        inc     esi
1329
    @@:
1330
;DEBUGF 1,"hashed: 0x%x\n",eax
1331
        stdcall xfs_get_addr_by_hash
1332
        bswap   eax
1333
;DEBUGF 1,"got address: 0x%x\n",eax
1334
        cmp     eax, -1
1335
        jne     @f
1336
        movi    eax, ERROR_FILE_NOT_FOUND
1337
        mov     ebx, -1
1338
        jmp     .error
1339
    @@:
1340
 
1341
        mov     ebx, [ebp + XFS.cur_inode_save]
1342
        push    esi edi
1343
        xor     edi, edi
1344
        mov     esi, eax
1345
        shld    edi, esi, 3     ; get offset
1346
        shl     esi, 3          ; 2^3 = 8 byte align
1347
        mov     edx, esi
1348
        mov     ecx, [ebp + XFS.dirblklog]
1349
        add     ecx, [ebp + XFS.blocklog]
1350
        mov     eax, 1
1351
        shl     eax, cl
1352
        dec     eax
1353
        and     edx, eax
1354
        push    edx
1355
        shrd    esi, edi, cl
1356
        shr     edi, cl
1357
        lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
1358
        mov     edx, [ebx + xfs_inode.di_core.di_nextents]
1359
        bswap   edx
1360
        stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
1361
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
1362
        pop     edx
1363
        pop     edi esi
1364
        mov     ecx, eax
1365
        and     ecx, edx
1366
        inc     ecx
1367
        jz      .error
1368
 
1369
        mov     ebx, [ebp + XFS.cur_dirblock]
1370
        add     ebx, edx
1371
        mov     edx, [ebx + 0]
1372
        mov     eax, [ebx + 4]
1373
        bswap   edx
1374
        bswap   eax
1375
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
1376
        jmp     .quit
1377
 
1378
  .nodedir:
1379
;DEBUGF 1,"lookupdir: node\n"
1380
        mov     [ebp + XFS.cur_inode_save], ebx
1381
 
1382
        mov     edi, esi
1383
        xor     eax, eax
1384
        mov     ecx, 4096       ; MAX_PATH_LEN
1385
        repne scasb
1386
        movi    eax, ERROR_FS_FAIL
1387
        jne     .error
1388
        neg     ecx
1389
        add     ecx, 4096       ; MAX_PATH_LEN
1390
        dec     ecx
1391
        mov     edx, ecx
1392
;DEBUGF 1,"strlen total  : %d\n",edx
1393
        mov     edi, esi
1394
        mov     eax, '/'
1395
        mov     ecx, edx
1396
        repne scasb
1397
        jne     @f
1398
        inc     ecx
1399
    @@:
1400
        neg     ecx
1401
        add     ecx, edx
1402
;DEBUGF 1,"strlen current: %d\n",ecx
1403
        stdcall xfs_hashname, esi, ecx
1404
        add     esi, ecx
1405
        cmp     byte[esi], '/'
1406
        jne     @f
1407
        inc     esi
1408
    @@:
1409
;DEBUGF 1,"hashed: 0x%x\n",eax
1410
        push    edi edx
1411
        mov     edi, eax
1412
        mov     [ebp + XFS.entries_read], 0
1413
        lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
1414
        mov     edx, [ebx + xfs_inode.di_core.di_nextents]
1415
        bswap   edx
1416
        stdcall xfs_dir2_lookupdir_node, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks], edi
1417
        pop     edx edi
1418
        test    eax, eax
1419
        jnz     .error
1420
        bswap   ecx
1421
;DEBUGF 1,"got address: 0x%x\n",ecx
1422
 
1423
        mov     ebx, [ebp + XFS.cur_inode_save]
1424
        push    esi edi
1425
        xor     edi, edi
1426
        mov     esi, ecx
1427
        shld    edi, esi, 3     ; get offset
1428
        shl     esi, 3          ; 8 byte align
1429
        mov     edx, esi
1430
        mov     ecx, [ebp + XFS.dirblklog]
1431
        add     ecx, [ebp + XFS.blocklog]
1432
        mov     eax, 1
1433
        shl     eax, cl
1434
        dec     eax
1435
        and     edx, eax
1436
        push    edx
1437
        shrd    esi, edi, cl
1438
        shr     edi, cl
1439
        lea     eax, [ebx + xfs_inode.di_u + xfs_bmbt_rec.l0]
1440
        mov     edx, [ebx + xfs_inode.di_core.di_nextents]
1441
        bswap   edx
1442
        stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
1443
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
1444
        pop     edx
1445
        pop     edi esi
1446
        mov     ecx, eax
1447
        and     ecx, edx
1448
        inc     ecx
1449
        jz      .error
1450
 
1451
        mov     ebx, [ebp + XFS.cur_dirblock]
1452
        add     ebx, edx
1453
        mov     edx, [ebx + 0]
1454
        mov     eax, [ebx + 4]
1455
        bswap   edx
1456
        bswap   eax
1457
;DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
1458
        jmp     .quit
1459
 
1460
  .btreedir:
1461
DEBUGF 1,"lookupdir: btree\n"
1462
        mov     [ebp + XFS.cur_inode_save], ebx
1463
 
1464
        push    ebx edx
1465
        mov     eax, [ebx + xfs_inode.di_core.di_nextents]
1466
        bswap   eax
1467
        mov     [ebp + XFS.ro_nextents], eax
1468
        mov     eax, [ebp + XFS.inodesize]
1469
        sub     eax, xfs_inode.di_u
1470
        sub     eax, sizeof.xfs_bmdr_block
1471
        shr     eax, 4  ; FIXME forkoff
1472
;DEBUGF 1,"maxnumresc: %d\n",eax
1473
        mov     edx, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 0]
1474
        mov     eax, dword[ebx + xfs_inode.di_u + sizeof.xfs_bmdr_block + sizeof.xfs_bmbt_key*eax + 4]
1475
        bswap   eax
1476
        bswap   edx
1477
        mov     ebx, [ebp + XFS.cur_block]
1478
;DEBUGF 1,"read_block: %x %x ",edx,eax
1479
        stdcall xfs_read_block
1480
        pop     edx ebx
1481
        test    eax, eax
1482
        jnz     .error
1483
;DEBUGF 1,"ok\n"
1484
        mov     ebx, [ebp + XFS.cur_block]
1485
 
1486
        mov     edi, esi
1487
        xor     eax, eax
1488
        mov     ecx, 4096       ; MAX_PATH_LEN
1489
        repne scasb
1490
        movi    eax, ERROR_FS_FAIL
1491
        jne     .error
1492
        neg     ecx
1493
        add     ecx, 4096
1494
        dec     ecx
1495
        mov     edx, ecx
1496
DEBUGF 1,"strlen total  : %d\n",edx
1497
        mov     edi, esi
1498
        mov     eax, '/'
1499
        mov     ecx, edx
1500
        repne scasb
1501
        jne     @f
1502
        inc     ecx
1503
    @@:
1504
        neg     ecx
1505
        add     ecx, edx
1506
DEBUGF 1,"strlen current: %d\n",ecx
1507
        stdcall xfs_hashname, esi, ecx
1508
        add     esi, ecx
1509
        cmp     byte[esi], '/'
1510
        jne     @f
1511
        inc     esi
1512
    @@:
1513
DEBUGF 1,"hashed: 0x%x\n",eax
1514
        push    edi edx
1515
        mov     edi, eax
1516
        mov     [ebp + XFS.entries_read], 0
1517
        lea     eax, [ebx + sizeof.xfs_bmbt_block]
1518
        mov     edx, [ebp + XFS.ro_nextents]
1519
;push eax
1520
;mov eax, [ebp + XFS.dir2_leaf_offset_blocks]
1521
;DEBUGF 1,": 0x%x %d\n",eax,eax
1522
;pop eax
1523
        stdcall xfs_dir2_lookupdir_node, eax, edx, [ebp + XFS.dir2_leaf_offset_blocks], edi
1524
        pop     edx edi
1525
        test    eax, eax
1526
        jnz     .error
1527
        bswap   ecx
1528
DEBUGF 1,"got address: 0x%x\n",ecx
1529
 
1530
        mov     ebx, [ebp + XFS.cur_block]
1531
        push    esi edi
1532
        xor     edi, edi
1533
        mov     esi, ecx
1534
        shld    edi, esi, 3  ; get offset
1535
        shl     esi, 3
1536
        mov     edx, esi
1537
        mov     ecx, [ebp + XFS.dirblklog]
1538
        add     ecx, [ebp + XFS.blocklog]
1539
        mov     eax, 1
1540
        shl     eax, cl
1541
        dec     eax
1542
        and     edx, eax
1543
        push    edx
1544
        shrd    esi, edi, cl
1545
        shr     edi, cl
1546
        lea     eax, [ebx + sizeof.xfs_bmbt_block]
1547
        mov     edx, [ebp + XFS.ro_nextents]
1548
        stdcall xfs_extent_list_read_dirblock, eax, esi, edi, edx, [ebp + XFS.dir2_leaf_offset_blocks], 0
1549
;DEBUGF 1,"RETVALUE: %d %d\n",edx,eax
1550
        pop     edx
1551
        pop     edi esi
1552
        mov     ecx, eax
1553
        and     ecx, edx
1554
        inc     ecx
1555
        jz      .error
1556
 
1557
        mov     ebx, [ebp + XFS.cur_dirblock]
1558
        add     ebx, edx
1559
        mov     edx, [ebx + 0]
1560
        mov     eax, [ebx + 4]
1561
        bswap   edx
1562
        bswap   eax
1563
DEBUGF 1,"found inode: 0x%x%x\n",edx,eax
1564
        jmp     .quit
1565
 
1566
  .quit:
1567
        ret     12
1568
  .error:
1569
        xor     eax, eax
1570
        mov     edx, eax
1571
        ret     12
1572
 
1573
 
1574
;----------------------------------------------------------------
1575
; push name
1576
; call xfs_get_inode
1577
; test eax, eax
1578
;----------------------------------------------------------------
1579
xfs_get_inode:
1580
        ; call xfs_get_inode_short until file is found / error returned
1581
 
1582
;DEBUGF 1,"getting inode of: %s\n",[esp+4]
1583
        push    ebx esi edi
1584
 
1585
        ; start from the root inode
1586
 
1587
        mov     edx, dword[ebp + XFS.rootino + 4]       ; hi
1588
        mov     eax, dword[ebp + XFS.rootino + 0]       ; lo
1589
        mov     esi, [esp + 16] ; name
1590
 
1591
  .next_dir:
1592
        cmp     byte[esi], 0
1593
        je      .found
1594
 
1595
;DEBUGF 1,"next_level: |%s|\n",esi
1596
        stdcall xfs_get_inode_short, esi, eax, edx
1597
        test    edx, edx
1598
        jnz     @f
1599
        test    eax, eax
1600
        jz      .error
1601
    @@:
1602
        jmp     .next_dir       ; file name found, go to next directory level
1603
 
1604
  .found:
1605
 
1606
  .quit:
1607
        pop     edi esi ebx
1608
        ret     4
1609
  .error:
1610
        pop     edi esi ebx
1611
        xor     eax, eax
1612
        mov     edx, eax
1613
        ret     4
1614
 
1615
 
1616
;----------------------------------------------------------------
1617
; xfs_ReadFolder - XFS implementation of reading a folder
1618
; in:  ebp = pointer to XFS structure
1619
; in:  esi+[esp+4] = name
1620
; in:  ebx = pointer to parameters from sysfunc 70
1621
; out: eax, ebx = return values for sysfunc 70
1622
;----------------------------------------------------------------
1623
xfs_ReadFolder:
1624
 
1625
        ; to read folder
1626
        ; 1. lock partition
1627
        ; 2. find inode number
1628
        ; 3. read this inode
1629
        ; 4. get bdfe's
1630
        ; 5. unlock partition
1631
 
1632
        ; 1.
1633
        call    xfs_lock
1634
        push    ecx edx esi edi
1635
 
1636
        ; 2.
1637
        push    ebx esi edi
1638
        add     esi, [esp + 32]         ; directory name
1639
;DEBUGF 1,"xfs_ReadFolder: |%s|\n",esi
1640
        stdcall xfs_get_inode, esi
1641
        pop     edi esi ebx
1642
        mov     ecx, edx
1643
        or      ecx, eax
1644
        jnz     @f
1645
        movi    eax, ERROR_FILE_NOT_FOUND
1646
    @@:
1647
 
1648
        ; 3.
1649
        stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
1650
        test    eax, eax
1651
        movi    eax, ERROR_FS_FAIL
1652
        jnz     .error
1653
 
1654
        ; 4.
1655
        mov     eax, [ebx + 8]          ; encoding
1656
        and     eax, 1
1657
        stdcall xfs_dir_get_bdfes, [ebx + 4], [ebx + 12], [ebx + 16], edx, eax
1658
        test    eax, eax
1659
        jnz     .error
1660
 
1661
  .quit:
1662
;DEBUGF 1,"\n\n"
1663
        pop     edi esi edx ecx
1664
        ; 5.
1665
        call    xfs_unlock
1666
        xor     eax, eax
1667
        ret
1668
  .error:
1669
;DEBUGF 1,"\n\n"
1670
        pop     edi esi edx ecx
1671
        push    eax
1672
        call    xfs_unlock
1673
        pop     eax
1674
        ret
1675
 
1676
 
1677
;----------------------------------------------------------------
1678
; push inode_num_hi
1679
; push inode_num_lo
1680
; push [count]
1681
; call xfs_get_inode_number_sf
1682
;----------------------------------------------------------------
1683
xfs_get_inode_number_sf:
1684
 
1685
        ; inode numbers in short form directories may be 4 or 8 bytes long
1686
        ; determine the length in run time and read inode number at given address
1687
 
1688
        cmp     byte[esp + 4 + xfs_dir2_sf_hdr.i8count], 0      ; i8count == 0 means 4 byte per inode number
1689
        je      .i4bytes
1690
  .i8bytes:
1691
        mov     edx, [esp + 12] ; hi
1692
        mov     eax, [esp + 8]  ; lo
1693
        bswap   edx             ; big endian
1694
        bswap   eax
1695
        ret     12
1696
  .i4bytes:
1697
        xor     edx, edx        ; no hi
1698
        mov     eax, [esp + 12] ; hi = lo
1699
        bswap   eax             ; big endian
1700
        ret     12
1701
 
1702
 
1703
;----------------------------------------------------------------
1704
; push dest
1705
; push src
1706
; call xfs_get_inode_info
1707
;----------------------------------------------------------------
1708
xfs_get_inode_info:
1709
 
1710
        ; get access time and other file properties
1711
        ; useful for browsing directories
1712
        ; called for each dir entry
1713
 
1714
;DEBUGF 1,"get_inode_info\n"
1715
        xor     eax, eax
1716
        mov     edx, [esp + 4]
1717
        movzx   ecx, word[edx + xfs_inode.di_core.di_mode]
1718
        xchg    cl, ch
1719
;DEBUGF 1,"di_mode: %x\n",ecx
1720
        test    ecx, S_IFDIR    ; directory?
1721
        jz      @f
1722
        mov     eax, 0x10       ; set directory flag
1723
    @@:
1724
 
1725
        mov     edi, [esp + 8]
1726
        mov     [edi + 0], eax
1727
        mov     eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi
1728
        bswap   eax
1729
        mov     dword[edi + 36], eax    ; file size hi
1730
;DEBUGF 1,"file_size hi: %d\n",eax
1731
        mov     eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo
1732
        bswap   eax
1733
        mov     dword[edi + 32], eax    ; file size lo
1734
;DEBUGF 1,"file_size lo: %d\n",eax
1735
 
1736
        add     edi, 8
1737
        mov     eax, [edx + xfs_inode.di_core.di_ctime.t_sec]
1738
        bswap   eax
1739
        push    edx
6462 pathoswith 1740
        sub     eax, 978307200  ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
1741
        call    fsTime2bdfe
3913 dunkaist 1742
        pop     edx
1743
 
1744
        mov     eax, [edx + xfs_inode.di_core.di_atime.t_sec]
1745
        bswap   eax
1746
        push    edx
6462 pathoswith 1747
        sub     eax, 978307200
1748
        call    fsTime2bdfe
3913 dunkaist 1749
        pop     edx
1750
 
1751
        mov     eax, [edx + xfs_inode.di_core.di_mtime.t_sec]
1752
        bswap   eax
1753
        push    edx
6462 pathoswith 1754
        sub     eax, 978307200
1755
        call    fsTime2bdfe
3913 dunkaist 1756
        pop     edx
1757
 
1758
  .quit:
1759
        xor     eax, eax
1760
        ret     8
1761
  .error:
1762
        movi    eax, ERROR_FS_FAIL
1763
        ret     8
1764
 
1765
 
1766
;----------------------------------------------------------------
1767
; push extent_data
1768
; call xfs_extent_unpack
1769
;----------------------------------------------------------------
1770
xfs_extent_unpack:
1771
 
1772
        ; extents come as packet 128bit bitfields
1773
        ; lets unpack them to access internal fields
1774
        ; write result to the XFS.extent structure
1775
 
1776
        push    eax ebx ecx edx
1777
        mov     ebx, [esp + 20]
1778
 
1779
        xor     eax, eax
1780
        mov     edx, [ebx + 0]
1781
        bswap   edx
1782
        test    edx, 0x80000000         ; mask, see documentation
1783
        setnz   al
1784
        mov     [ebp + XFS.extent.br_state], eax
1785
 
1786
        and     edx, 0x7fffffff         ; mask
1787
        mov     eax, [ebx + 4]
1788
        bswap   eax
1789
        shrd    eax, edx, 9
1790
        shr     edx, 9
1791
        mov     dword[ebp + XFS.extent.br_startoff + 0], eax
1792
        mov     dword[ebp + XFS.extent.br_startoff + 4], edx
1793
 
1794
        mov     edx, [ebx + 4]
1795
        mov     eax, [ebx + 8]
1796
        mov     ecx, [ebx + 12]
1797
        bswap   edx
1798
        bswap   eax
1799
        bswap   ecx
1800
        and     edx, 0x000001ff         ; mask
1801
        shrd    ecx, eax, 21
1802
        shrd    eax, edx, 21
1803
        mov     dword[ebp + XFS.extent.br_startblock + 0], ecx
1804
        mov     dword[ebp + XFS.extent.br_startblock + 4], eax
1805
 
1806
        mov     eax, [ebx + 12]
1807
        bswap   eax
1808
        and     eax, 0x001fffff         ; mask
1809
        mov     [ebp + XFS.extent.br_blockcount], eax
1810
 
1811
        pop     edx ecx ebx eax
1812
;DEBUGF 1,"extent.br_startoff  : %d %d\n",[ebp+XFS.extent.br_startoff+4],[ebp+XFS.extent.br_startoff+0]
1813
;DEBUGF 1,"extent.br_startblock: %d %d\n",[ebp+XFS.extent.br_startblock+4],[ebp+XFS.extent.br_startblock+0]
1814
;DEBUGF 1,"extent.br_blockcount: %d\n",[ebp+XFS.extent.br_blockcount]
1815
;DEBUGF 1,"extent.br_state     : %d\n",[ebp+XFS.extent.br_state]
1816
        ret     4
1817
 
1818
 
1819
;----------------------------------------------------------------
1820
; push namelen
1821
; push name
1822
; call xfs_hashname
1823
;----------------------------------------------------------------
1824
xfs_hashname:   ; xfs_da_hashname
1825
 
1826
        ; simple hash function
1827
        ; never fails)
1828
 
1829
        push    ecx esi
1830
        xor     eax, eax
1831
        mov     esi, [esp + 12] ; name
1832
        mov     ecx, [esp + 16] ; namelen
1833
;mov esi, '.'
1834
;mov ecx, 1
1835
;DEBUGF 1,"hashname: %d %s\n",ecx,esi
1836
 
1837
    @@:
1838
        rol     eax, 7
1839
        xor     al, [esi]
1840
        add     esi, 1
1841
        loop    @b
1842
 
1843
        pop     esi ecx
1844
        ret     8
1845
 
1846
 
1847
;----------------------------------------------------------------
1848
; push  len
1849
; push  base
1850
; eax -- hash value
1851
; call xfs_get_addr_by_hash
1852
;----------------------------------------------------------------
1853
xfs_get_addr_by_hash:
1854
 
1855
        ; look for the directory entry offset by its file name hash
1856
        ; allows fast file search for block, leaf and node directories
1857
        ; binary (ternary) search
1858
 
1859
;DEBUGF 1,"get_addr_by_hash\n"
1860
        push    ebx esi
1861
        mov     ebx, [esp + 12] ; left
1862
        mov     edx, [esp + 16] ; len
1863
  .next:
1864
        mov     ecx, edx
1865
;        jecxz   .error
1866
        test    ecx, ecx
1867
        jz      .error
1868
        shr     ecx, 1
1869
        mov     esi, [ebx + ecx*8 + xfs_dir2_leaf_entry.hashval]
1870
        bswap   esi
1871
;DEBUGF 1,"cmp 0x%x",esi
1872
        cmp     eax, esi
1873
        jb      .below
1874
        ja      .above
1875
        mov     eax, [ebx + ecx*8 + xfs_dir2_leaf_entry.address]
1876
        pop     esi ebx
1877
        ret     8
1878
  .below:
1879
;DEBUGF 1,"b\n"
1880
        mov     edx, ecx
1881
        jmp     .next
1882
  .above:
1883
;DEBUGF 1,"a\n"
1884
        lea     ebx, [ebx + ecx*8 + 8]
1885
        sub     edx, ecx
1886
        dec     edx
1887
        jmp     .next
1888
  .error:
1889
        mov     eax, -1
1890
        pop     esi ebx
1891
        ret     8
1892
 
1893
 
1894
;----------------------------------------------------------------
1895
; xfs_GetFileInfo - XFS implementation of getting file info
1896
; in:  ebp = pointer to XFS structure
1897
; in:  esi+[esp+4] = name
1898
; in:  ebx = pointer to parameters from sysfunc 70
1899
; out: eax, ebx = return values for sysfunc 70
1900
;----------------------------------------------------------------
1901
xfs_GetFileInfo:
1902
 
1903
        ; lock partition
1904
        ; get inode number by file name
1905
        ; read inode
1906
        ; get info
1907
        ; unlock partition
1908
 
1909
        push    ecx edx esi edi
1910
        call    xfs_lock
1911
 
1912
        add     esi, [esp + 20]         ; name
1913
;DEBUGF 1,"xfs_GetFileInfo: |%s|\n",esi
1914
        stdcall xfs_get_inode, esi
1915
        mov     ecx, edx
1916
        or      ecx, eax
1917
        jnz     @f
1918
        movi    eax, ERROR_FILE_NOT_FOUND
1919
        jmp     .error
1920
    @@:
1921
        stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
1922
        test    eax, eax
1923
        movi    eax, ERROR_FS_FAIL
1924
        jnz     .error
1925
 
1926
        stdcall xfs_get_inode_info, edx, [ebx + 16]
1927
 
1928
  .quit:
1929
        call    xfs_unlock
1930
        pop     edi esi edx ecx
1931
        xor     eax, eax
1932
;DEBUGF 1,"quit\n\n"
1933
        ret
1934
  .error:
1935
        call    xfs_unlock
1936
        pop     edi esi edx ecx
1937
;DEBUGF 1,"error\n\n"
1938
        ret
1939
 
1940
 
1941
;----------------------------------------------------------------
6462 pathoswith 1942
; xfs_ReadFile - XFS implementation of reading a file
3913 dunkaist 1943
; in:  ebp = pointer to XFS structure
1944
; in:  esi+[esp+4] = name
1945
; in:  ebx = pointer to parameters from sysfunc 70
1946
; out: eax, ebx = return values for sysfunc 70
1947
;----------------------------------------------------------------
6462 pathoswith 1948
xfs_ReadFile:
3913 dunkaist 1949
        push    ebx ecx edx esi edi
1950
        call    xfs_lock
1951
        add     esi, [esp + 24]
1952
        stdcall xfs_get_inode, esi
1953
        mov     ecx, edx
1954
        or      ecx, eax
1955
        jnz     @f
1956
        movi    eax, ERROR_FILE_NOT_FOUND
1957
        jmp     .error
1958
    @@:
1959
        stdcall xfs_read_inode, eax, edx, [ebp + XFS.cur_inode]
1960
        test    eax, eax
1961
        movi    eax, ERROR_FS_FAIL
1962
        jnz     .error
1963
        mov     [ebp + XFS.cur_inode_save], edx
1964
 
1965
        cmp     byte[edx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
1966
        jne     .not_extent_list
1967
        jmp     .extent_list
1968
  .not_extent_list:
1969
        cmp     byte[edx + xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
1970
        jne     .not_btree
1971
        jmp     .btree
1972
  .not_btree:
1973
DEBUGF 1,"XFS: NOT IMPLEMENTED: FILE FORMAT\n"
1974
        movi    eax, ERROR_FS_FAIL
1975
        jmp     .error
1976
  .extent_list:
1977
        mov     ecx, [ebx + 12]         ; bytes to read
1978
        mov     edi, [ebx + 16]         ; buffer for data
1979
        mov     esi, [ebx + 8]          ; offset_hi
1980
        mov     ebx, [ebx + 4]          ; offset_lo
1981
 
1982
        mov     eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo
1983
        bswap   eax
1984
        mov     dword[ebp + XFS.bytes_left_in_file + 0], eax    ; lo
1985
        mov     eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi
1986
        bswap   eax
1987
        mov     dword[ebp + XFS.bytes_left_in_file + 4], eax    ; hi
1988
 
1989
        mov     eax, [edx + xfs_inode.di_core.di_nextents]
1990
        bswap   eax
1991
        mov     [ebp + XFS.left_extents], eax
1992
 
1993
        mov     dword[ebp + XFS.bytes_read], 0          ; actually read bytes
1994
 
1995
        xor     eax, eax                ; extent offset in list
1996
  .extent_list.next_extent:
1997
;DEBUGF 1,"extent_list.next_extent, eax: 0x%x\n",eax
1998
;DEBUGF 1,"bytes_to_read: %d\n",ecx
1999
;DEBUGF 1,"cur file offset: %d %d\n",esi,ebx
2000
;DEBUGF 1,"esp: 0x%x\n",esp
2001
        cmp     [ebp + XFS.left_extents], 0
2002
        jne     @f
2003
        test    ecx, ecx
2004
        jz      .quit
2005
        movi    eax, ERROR_END_OF_FILE
2006
        jmp     .error
2007
    @@:
2008
        push    eax
2009
        lea     eax, [edx + xfs_inode.di_u + eax + xfs_bmbt_rec.l0]
2010
        stdcall xfs_extent_unpack, eax
2011
        pop     eax
2012
        dec     [ebp + XFS.left_extents]
2013
        add     eax, sizeof.xfs_bmbt_rec
2014
        push    eax ebx ecx edx esi
2015
        mov     ecx, [ebp + XFS.blocklog]
2016
        shrd    ebx, esi, cl
2017
        shr     esi, cl
2018
        cmp     esi, dword[ebp + XFS.extent.br_startoff + 4]
2019
        jb      .extent_list.to_hole          ; handle sparse files
2020
        ja      @f
2021
        cmp     ebx, dword[ebp + XFS.extent.br_startoff + 0]
2022
        jb      .extent_list.to_hole          ; handle sparse files
2023
        je      .extent_list.to_extent        ; read from the start of current extent
2024
    @@:
2025
        xor     edx, edx
2026
        mov     eax, [ebp + XFS.extent.br_blockcount]
2027
        add     eax, dword[ebp + XFS.extent.br_startoff + 0]
2028
        adc     edx, dword[ebp + XFS.extent.br_startoff + 4]
2029
;DEBUGF 1,"br_startoff: %d %d\n",edx,eax
2030
        cmp     esi, edx
2031
        ja      .extent_list.skip_extent
2032
        jb      .extent_list.to_extent
2033
        cmp     ebx, eax
2034
        jae     .extent_list.skip_extent
2035
        jmp     .extent_list.to_extent
2036
  .extent_list.to_hole:
2037
;DEBUGF 1,"extent_list.to_hole\n"
2038
        pop     esi edx ecx ebx eax
2039
        jmp     .extent_list.read_hole
2040
  .extent_list.to_extent:
2041
;DEBUGF 1,"extent_list.to_extent\n"
2042
        pop     esi edx ecx ebx eax
2043
        jmp     .extent_list.read_extent
2044
  .extent_list.skip_extent:
2045
;DEBUGF 1,"extent_list.skip_extent\n"
2046
        pop     esi edx ecx ebx eax
2047
        jmp     .extent_list.next_extent
2048
 
2049
  .extent_list.read_hole:
2050
;DEBUGF 1,"hole: offt: 0x%x%x ",esi,ebx
2051
        push    eax edx
2052
        mov     eax, dword[ebp + XFS.extent.br_startoff + 0]
2053
        mov     edx, dword[ebp + XFS.extent.br_startoff + 4]
2054
        push    esi ebx
2055
        mov     ebx, ecx
2056
        sub     eax, ebx        ; get hole_size, it is 64 bit
2057
        sbb     edx, 0          ; now edx:eax contains the size of hole
2058
;DEBUGF 1,"size: 0x%x%x\n",edx,eax
2059
        jnz     @f              ; if hole size >= 2^32, write bytes_to_read zero bytes
2060
        cmp     eax, ecx        ; if hole size >= bytes_to_read, write bytes_to_read zeros
2061
        jae     @f
2062
        mov     ecx, eax        ; if hole is < than bytes_to_read, write hole size zeros
2063
    @@:
2064
        sub     ebx, ecx        ; bytes_to_read - hole_size = left_to_read
2065
        add     dword[esp + 0], ecx     ; update pushed file offset
2066
        adc     dword[esp + 4], 0
2067
        xor     eax, eax        ; hole is made of zeros
2068
        rep stosb
2069
        mov     ecx, ebx
2070
        pop     ebx esi
2071
 
2072
        test    ecx, ecx        ; all requested bytes are read?
2073
        pop     edx eax
2074
        jz      .quit
2075
        jmp     .extent_list.read_extent        ; continue from the start of unpacked extent
2076
 
2077
  .extent_list.read_extent:
2078
;DEBUGF 1,"extent_list.read_extent\n"
2079
        push    eax ebx ecx edx esi
2080
        mov     eax, ebx
2081
        mov     edx, esi
2082
        mov     ecx, [ebp + XFS.blocklog]
2083
        shrd    eax, edx, cl
2084
        shr     edx, cl
2085
        sub     eax, dword[ebp + XFS.extent.br_startoff + 0]    ; skip esi:ebx ?
2086
        sbb     edx, dword[ebp + XFS.extent.br_startoff + 4]
2087
        sub     [ebp + XFS.extent.br_blockcount], eax
2088
        add     dword[ebp + XFS.extent.br_startblock + 0], eax
2089
        adc     dword[ebp + XFS.extent.br_startblock + 4], 0
2090
  .extent_list.read_extent.next_block:
2091
;DEBUGF 1,"extent_list.read_extent.next_block\n"
2092
        cmp     [ebp + XFS.extent.br_blockcount], 0     ; out of blocks in current extent?
2093
        jne     @f
2094
        pop     esi edx ecx ebx eax
2095
        jmp     .extent_list.next_extent                ; go to next extent
2096
    @@:
2097
        mov     eax, dword[ebp + XFS.extent.br_startblock + 0]
2098
        mov     edx, dword[ebp + XFS.extent.br_startblock + 4]
2099
        push    ebx
2100
        mov     ebx, [ebp + XFS.cur_block]
2101
;DEBUGF 1,"read block: 0x%x%x\n",edx,eax
2102
        stdcall xfs_read_block
2103
        test    eax, eax
2104
        pop     ebx
2105
        jz      @f
2106
        pop     esi edx ecx ebx eax
2107
        movi    eax, ERROR_FS_FAIL
2108
        jmp     .error
2109
    @@:
2110
        dec     [ebp + XFS.extent.br_blockcount]
2111
        add     dword[ebp + XFS.extent.br_startblock + 0], 1
2112
        adc     dword[ebp + XFS.extent.br_startblock + 4], 0
2113
        mov     esi, [ebp + XFS.cur_block]
2114
        mov     ecx, [ebp + XFS.blocklog]
2115
        mov     eax, 1
2116
        shl     eax, cl
2117
        dec     eax             ; get blocklog mask
2118
        and     eax, ebx        ; offset in current block
2119
        add     esi, eax
2120
        neg     eax
2121
        add     eax, [ebp + XFS.blocksize]
2122
        mov     ecx, [esp + 8]  ; pushed ecx, bytes_to_read
2123
        cmp     ecx, eax        ; is current block enough?
2124
        jbe     @f              ; if so, read bytes_to_read bytes
2125
        mov     ecx, eax        ; otherwise read the block up to the end
2126
    @@:
2127
        sub     [esp + 8], ecx          ; left_to_read
2128
        add     [esp + 12], ecx         ; update current file offset, pushed ebx
2129
        sub     dword[ebp + XFS.bytes_left_in_file + 0], ecx
2130
        sbb     dword[ebp + XFS.bytes_left_in_file + 4], 0
2131
        jnc     @f
2132
        add     dword[ebp + XFS.bytes_left_in_file + 0], ecx
2133
        mov     ecx, dword[ebp + XFS.bytes_left_in_file + 0]
2134
        mov     dword[ebp + XFS.bytes_left_in_file + 0], 0
2135
        mov     dword[ebp + XFS.bytes_left_in_file + 4], 0
2136
    @@:
2137
        add     [ebp + XFS.bytes_read], ecx
2138
        adc     [esp + 0], dword 0      ; pushed esi
2139
;DEBUGF 1,"read data: %d\n",ecx
2140
        rep movsb
2141
        mov     ecx, [esp + 8]
2142
;DEBUGF 1,"left_to_read: %d\n",ecx
2143
        xor     ebx, ebx
2144
        test    ecx, ecx
2145
        jz      @f
2146
        cmp     dword[ebp + XFS.bytes_left_in_file + 4], 0
2147
        jne     .extent_list.read_extent.next_block
2148
        cmp     dword[ebp + XFS.bytes_left_in_file + 0], 0
2149
        jne     .extent_list.read_extent.next_block
2150
    @@:
2151
        pop     esi edx ecx ebx eax
2152
        jmp     .quit
2153
 
2154
  .btree:
2155
        mov     ecx, [ebx + 12]         ; bytes to read
2156
        mov     [ebp + XFS.bytes_to_read], ecx
2157
        mov     edi, [ebx + 16]         ; buffer for data
2158
        mov     esi, [ebx + 8]          ; offset_hi
2159
        mov     ebx, [ebx + 4]          ; offset_lo
2160
        mov     dword[ebp + XFS.file_offset + 0], ebx
2161
        mov     dword[ebp + XFS.file_offset + 4], esi
2162
        mov     [ebp + XFS.buffer_pos], edi
2163
 
2164
        mov     eax, dword[edx + xfs_inode.di_core.di_size + 4] ; lo
2165
        bswap   eax
2166
        mov     dword[ebp + XFS.bytes_left_in_file + 0], eax    ; lo
2167
        mov     eax, dword[edx + xfs_inode.di_core.di_size + 0] ; hi
2168
        bswap   eax
2169
        mov     dword[ebp + XFS.bytes_left_in_file + 4], eax    ; hi
2170
 
2171
        mov     eax, [edx + xfs_inode.di_core.di_nextents]
2172
        bswap   eax
2173
        mov     [ebp + XFS.left_extents], eax
2174
 
2175
        mov     dword[ebp + XFS.bytes_read], 0          ; actually read bytes
2176
 
2177
        push    ebx ecx edx esi edi
2178
        mov     [ebp + XFS.eof], 0
2179
        mov     eax, dword[ebp + XFS.file_offset + 0]
2180
        mov     edx, dword[ebp + XFS.file_offset + 4]
2181
        add     eax, [ebp + XFS.bytes_to_read]
2182
        adc     edx, 0
2183
        sub     eax, dword[ebp + XFS.bytes_left_in_file + 0]
2184
        sbb     edx, dword[ebp + XFS.bytes_left_in_file + 4]
2185
        jc      @f      ; file_offset + bytes_to_read < file_size
2186
        jz      @f      ; file_offset + bytes_to_read = file_size
2187
        mov     [ebp + XFS.eof], 1
2188
        cmp     edx, 0
2189
        jne     .error.eof
2190
        sub     dword[ebp + XFS.bytes_to_read], eax
2191
        jc      .error.eof
2192
        jz      .error.eof
2193
    @@:
2194
        stdcall xfs_btree_read, 0, 0, 1
2195
        pop     edi esi edx ecx ebx
2196
        test    eax, eax
2197
        jnz     .error
2198
        cmp     [ebp + XFS.eof], 1
2199
        jne     .quit
2200
        jmp     .error.eof
2201
 
2202
 
2203
  .quit:
2204
        call    xfs_unlock
2205
        pop     edi esi edx ecx ebx
2206
        xor     eax, eax
2207
        mov     ebx, [ebp + XFS.bytes_read]
2208
;DEBUGF 1,"quit: %d\n\n",ebx
2209
        ret
2210
  .error.eof:
2211
        movi    eax, ERROR_END_OF_FILE
2212
  .error:
2213
;DEBUGF 1,"error\n\n"
2214
        call    xfs_unlock
2215
        pop     edi esi edx ecx ebx
2216
        mov     ebx, [ebp + XFS.bytes_read]
2217
        ret
2218
 
2219
 
2220
;----------------------------------------------------------------
2221
; push  max_offset_hi
2222
; push  max_offset_lo
2223
; push  nextents
2224
; push  block_number_hi
2225
; push  block_number_lo
2226
; push  extent_list
2227
; -1 / read block number
2228
;----------------------------------------------------------------
2229
xfs_extent_list_read_dirblock:  ; skips holes
2230
;DEBUGF 1,"xfs_extent_list_read_dirblock\n"
2231
        push    ebx esi edi
2232
;mov eax, [esp+28]
2233
;DEBUGF 1,"nextents: %d\n",eax
2234
;mov eax, [esp+20]
2235
;mov edx, [esp+24]
2236
;DEBUGF 1,"block_number: 0x%x%x\n",edx,eax
2237
;mov eax, [esp+32]
2238
;mov edx, [esp+36]
2239
;DEBUGF 1,"max_addr    : 0x%x%x\n",edx,eax
2240
        mov     ebx, [esp + 16]
2241
        mov     esi, [esp + 20]
2242
        mov     edi, [esp + 24]
2243
;        mov     ecx, [esp + 28] ; nextents
2244
  .next_extent:
2245
;DEBUGF 1,"next_extent\n"
2246
        dec     dword[esp + 28]
2247
        js      .error
2248
        stdcall xfs_extent_unpack, ebx
2249
        add     ebx, sizeof.xfs_bmbt_rec        ; next extent
2250
        mov     edx, dword[ebp + XFS.extent.br_startoff + 4]
2251
        mov     eax, dword[ebp + XFS.extent.br_startoff + 0]
2252
        cmp     edx, [esp + 36] ; max_offset_hi
2253
        ja      .error
2254
        jb      @f
2255
        cmp     eax, [esp + 32] ; max_offset_lo
2256
        jae     .error
2257
    @@:
2258
        cmp     edi, edx
2259
        jb      .hole
2260
        ja      .check_count
2261
        cmp     esi, eax
2262
        jb      .hole
2263
        ja      .check_count
2264
        jmp     .read_block
2265
  .hole:
2266
;DEBUGF 1,"hole\n"
2267
        mov     esi, eax
2268
        mov     edi, edx
2269
        jmp     .read_block
2270
  .check_count:
2271
;DEBUGF 1,"check_count\n"
2272
        add     eax, [ebp + XFS.extent.br_blockcount]
2273
        adc     edx, 0
2274
        cmp     edi, edx
2275
        ja      .next_extent
2276
        jb      .read_block
2277
        cmp     esi, eax
2278
        jae     .next_extent
2279
;        jmp     .read_block
2280
  .read_block:
2281
;DEBUGF 1,"read_block\n"
2282
        push    esi edi
2283
        sub     esi, dword[ebp + XFS.extent.br_startoff + 0]
2284
        sbb     edi, dword[ebp + XFS.extent.br_startoff + 4]
2285
        add     esi, dword[ebp + XFS.extent.br_startblock + 0]
2286
        adc     edi, dword[ebp + XFS.extent.br_startblock + 4]
2287
        stdcall xfs_read_dirblock, esi, edi, [ebp + XFS.cur_dirblock]
2288
        pop     edx eax
2289
  .quit:
2290
;DEBUGF 1,"xfs_extent_list_read_dirblock: quit\n"
2291
        pop     edi esi ebx
2292
        ret     24
2293
  .error:
2294
;DEBUGF 1,"xfs_extent_list_read_dirblock: error\n"
2295
        xor     eax, eax
2296
        dec     eax
2297
        mov     edx, eax
2298
        pop     edi esi ebx
2299
        ret     24
2300
 
2301
 
2302
;----------------------------------------------------------------
2303
; push  dirblock_num
2304
; push  nextents
2305
; push  extent_list
2306
;----------------------------------------------------------------
2307
xfs_dir2_node_get_numfiles:
2308
 
2309
        ; unfortunately, we need to set 'total entries' field
2310
        ; this often requires additional effort, since there is no such a number in most directory ondisk formats
2311
 
2312
;DEBUGF 1,"xfs_dir2_node_get_numfiles\n"
2313
        push    ebx ecx edx esi edi
2314
 
2315
        mov     eax, [esp + 24]
2316
        mov     edx, [esp + 28]
2317
        mov     esi, [esp + 32]
2318
        stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1
2319
        mov     ecx, eax
2320
        and     ecx, edx
2321
        inc     ecx
2322
        jnz     @f
2323
        movi    eax, ERROR_FS_FAIL
2324
        jmp     .error
2325
    @@:
2326
        mov     ebx, [ebp + XFS.cur_dirblock]
2327
        cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
2328
        je      .node
2329
        cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
2330
        je      .leaf
2331
        mov     eax, ERROR_FS_FAIL
2332
        jmp     .error
2333
 
2334
  .node:
2335
;DEBUGF 1,".node\n"
2336
        mov     edi, [ebx + xfs_da_intnode.hdr.info.forw]
2337
        bswap   edi
2338
        mov     eax, [esp + 24]
2339
        mov     edx, [esp + 28]
2340
        mov     esi, [ebx + xfs_da_intnode.btree.before]
2341
        bswap   esi
2342
        stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
2343
        test    eax, eax
2344
        jnz     .error
2345
        jmp     .common
6462 pathoswith 2346
 
3913 dunkaist 2347
  .leaf:
2348
;DEBUGF 1,".leaf\n"
2349
        movzx   ecx, word[ebx + xfs_dir2_leaf.hdr.count]
2350
        xchg    cl, ch
2351
        movzx   eax, word[ebx + xfs_dir2_leaf.hdr.stale]
2352
        xchg    al, ah
2353
        sub     ecx, eax
2354
        add     [ebp + XFS.entries_read], ecx
2355
        mov     edi, [ebx + xfs_dir2_leaf.hdr.info.forw]
2356
        bswap   edi
2357
        jmp     .common
2358
 
2359
  .common:
2360
        test    edi, edi
2361
        jz      .quit
2362
        mov     esi, edi
2363
        mov     eax, [esp + 24]
2364
        mov     edx, [esp + 28]
2365
        stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
2366
        test    eax, eax
2367
        jnz     .error
2368
        jmp     .quit
2369
 
2370
  .quit:
2371
;DEBUGF 1,".quit\n"
2372
        pop     edi esi edx ecx ebx
2373
        xor     eax, eax
2374
        ret     12
2375
  .error:
2376
;DEBUGF 1,".error\n"
2377
        pop     edi esi edx ecx ebx
2378
        movi    eax, ERROR_FS_FAIL
2379
        ret     12
2380
 
2381
 
2382
;----------------------------------------------------------------
2383
; push  hash
2384
; push  dirblock_num
2385
; push  nextents
2386
; push  extent_list
2387
;----------------------------------------------------------------
2388
xfs_dir2_lookupdir_node:
2389
DEBUGF 1,"xfs_dir2_lookupdir_node\n"
2390
        push    ebx edx esi edi
2391
 
2392
        mov     eax, [esp + 20]
2393
        mov     edx, [esp + 24]
2394
        mov     esi, [esp + 28]
2395
DEBUGF 1,"read dirblock: 0x%x %d\n",esi,esi
2396
        stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1
2397
DEBUGF 1,"dirblock read: 0x%x%x\n",edx,eax
2398
        mov     ecx, eax
2399
        and     ecx, edx
2400
        inc     ecx
2401
        jnz     @f
2402
        movi    eax, ERROR_FS_FAIL
2403
        jmp     .error
2404
    @@:
2405
DEBUGF 1,"checkpoint #1\n"
2406
        mov     ebx, [ebp + XFS.cur_dirblock]
2407
        cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
2408
        je      .node
2409
        cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
2410
        je      .leaf
2411
        mov     eax, ERROR_FS_FAIL
2412
DEBUGF 1,"checkpoint #2\n"
2413
        jmp     .error
2414
 
2415
  .node:
2416
DEBUGF 1,".node\n"
2417
        mov     edi, [esp + 32] ; hash
2418
        movzx   ecx, word[ebx + xfs_da_intnode.hdr.count]
2419
        xchg    cl, ch
2420
        mov     [ebp + XFS.left_leaves], ecx
2421
        xor     ecx, ecx
2422
  .node.next_leaf:
2423
        mov     esi, [ebx + xfs_da_intnode.btree + ecx*sizeof.xfs_da_node_entry + xfs_da_node_entry.hashval]
2424
        bswap   esi
2425
        cmp     edi, esi
2426
        jbe     .node.leaf_found
2427
        inc     ecx
2428
        cmp     ecx, [ebp + XFS.left_leaves]
2429
        jne     .node.next_leaf
2430
        mov     eax, ERROR_FILE_NOT_FOUND
2431
        jmp     .error
2432
    @@:
2433
  .node.leaf_found:
2434
        mov     eax, [esp + 20]
2435
        mov     edx, [esp + 24]
2436
        mov     esi, [ebx + xfs_da_intnode.btree + ecx*sizeof.xfs_da_node_entry + xfs_da_node_entry.before]
2437
        bswap   esi
2438
        stdcall xfs_dir2_lookupdir_node, eax, edx, esi, edi
2439
        test    eax, eax
2440
        jz      .quit
2441
        movi    eax, ERROR_FILE_NOT_FOUND
2442
        jmp     .error
2443
 
2444
  .leaf:
2445
DEBUGF 1,".leaf\n"
2446
        movzx   ecx, [ebx + xfs_dir2_leaf.hdr.count]
2447
        xchg    cl, ch
2448
        lea     esi, [ebx + xfs_dir2_leaf.ents]
2449
        mov     eax, [esp + 32]
2450
        stdcall xfs_get_addr_by_hash, esi, ecx
2451
        cmp     eax, -1
2452
        je      .error
2453
        mov     ecx, eax
2454
        jmp     .quit
2455
 
2456
  .quit:
2457
DEBUGF 1,".quit\n"
2458
        pop     edi esi edx ebx
2459
        xor     eax, eax
2460
        ret     16
2461
  .error:
2462
DEBUGF 1,".error\n"
2463
        pop     edi esi edx ebx
2464
        ret     16
2465
 
2466
 
2467
;----------------------------------------------------------------
2468
; push  dirblock_num
2469
; push  nextents
2470
; push  extent_list
2471
;----------------------------------------------------------------
2472
xfs_dir2_btree_get_numfiles:
2473
;DEBUGF 1,"xfs_dir2_node_get_numfiles\n"
2474
        push    ebx ecx edx esi edi
2475
 
2476
        mov     eax, [esp + 24]
2477
        mov     edx, [esp + 28]
2478
        mov     esi, [esp + 32]
2479
        stdcall xfs_extent_list_read_dirblock, eax, esi, 0, edx, -1, -1
2480
        mov     ecx, eax
2481
        and     ecx, edx
2482
        inc     ecx
2483
        jnz     @f
2484
        movi    eax, ERROR_FS_FAIL
2485
        jmp     .error
2486
    @@:
2487
        mov     ebx, [ebp + XFS.cur_dirblock]
2488
        cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
2489
        je      .node
2490
        cmp     word[ebx + xfs_da_intnode.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
2491
        je      .leaf
2492
        mov     eax, ERROR_FS_FAIL
2493
        jmp     .error
2494
 
2495
  .node:
2496
;DEBUGF 1,".node\n"
2497
        mov     edi, [ebx + xfs_da_intnode.hdr.info.forw]
2498
        bswap   edi
2499
        mov     eax, [esp + 24]
2500
        mov     edx, [esp + 28]
2501
        mov     esi, [ebx + xfs_da_intnode.btree.before]
2502
        bswap   esi
2503
        stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
2504
        test    eax, eax
2505
        jnz     .error
2506
        jmp     .common
6462 pathoswith 2507
 
3913 dunkaist 2508
  .leaf:
2509
;DEBUGF 1,".leaf\n"
2510
        movzx   ecx, word[ebx + xfs_dir2_leaf.hdr.count]
2511
        xchg    cl, ch
2512
        movzx   eax, word[ebx + xfs_dir2_leaf.hdr.stale]
2513
        xchg    al, ah
2514
        sub     ecx, eax
2515
        add     [ebp + XFS.entries_read], ecx
2516
        mov     edi, [ebx + xfs_dir2_leaf.hdr.info.forw]
2517
        bswap   edi
2518
        jmp     .common
2519
 
2520
  .common:
2521
        test    edi, edi
2522
        jz      .quit
2523
        mov     esi, edi
2524
        mov     eax, [esp + 24]
2525
        mov     edx, [esp + 28]
2526
        stdcall xfs_dir2_node_get_numfiles, eax, edx, esi
2527
        test    eax, eax
2528
        jnz     .error
2529
        jmp     .quit
2530
 
2531
  .quit:
2532
;DEBUGF 1,".quit\n"
2533
        pop     edi esi edx ecx ebx
2534
        xor     eax, eax
2535
        ret     12
2536
  .error:
2537
;DEBUGF 1,".error\n"
2538
        pop     edi esi edx ecx ebx
2539
        movi    eax, ERROR_FS_FAIL
2540
        ret     12
2541
 
2542
 
2543
;----------------------------------------------------------------
2544
; push  is_root
2545
; push  block_hi
2546
; push  block_lo
2547
;----------------------------------------------------------------
2548
xfs_btree_read:
2549
        push    ebx ecx edx esi edi
2550
        cmp     dword[esp + 32], 1      ; is root?
2551
        je      .root
2552
        jmp     .not_root
2553
  .root:
2554
DEBUGF 1,".root\n"
2555
        mov     ebx, [ebp + XFS.cur_inode_save]
2556
        add     ebx, xfs_inode.di_u
2557
        movzx   edx, [ebx + xfs_bmdr_block.bb_numrecs]
2558
        xchg    dl, dh
2559
        dec     edx
2560
        add     ebx, sizeof.xfs_bmdr_block
2561
        xor     eax, eax
2562
        dec     eax
2563
 .root.next_key:
2564
DEBUGF 1,".root.next_key\n"
2565
        cmp     [ebp + XFS.bytes_to_read], 0
2566
        je      .quit
2567
        inc     eax
2568
        cmp     eax, edx        ; out of keys?
2569
        ja      .root.key_found ; there is no length field, so try the last key
2570
        lea     edi, [ebx + sizeof.xfs_bmbt_key*eax + 0]
2571
        lea     esi, [ebx + sizeof.xfs_bmbt_key*eax + 4]
2572
        bswap   edi
2573
        bswap   esi
2574
        mov     ecx, [ebp + XFS.blocklog]
2575
        shld    edi, esi, cl
2576
        shl     esi, cl
2577
        cmp     edi, dword[ebp + XFS.file_offset + 4]
2578
        ja      .root.prev_or_hole
2579
        jb      .root.next_key
2580
        cmp     esi, dword[ebp + XFS.file_offset + 0]
2581
        ja      .root.prev_or_hole
2582
        jb      .root.next_key
2583
        jmp     .root.key_found
2584
  .root.prev_or_hole:
2585
DEBUGF 1,".root.prev_or_hole\n"
2586
        test    eax, eax
2587
        jz      .root.hole
2588
        dec     eax
2589
        jmp     .root.key_found
2590
  .root.hole:
2591
DEBUGF 1,".root.hole\n"
2592
        push    eax edx esi edi
2593
        mov     ecx, [ebp + XFS.blocklog]
2594
        shld    edi, esi, cl
2595
        shl     esi, cl
2596
        sub     esi, dword[ebp + XFS.file_offset + 0]
2597
        sbb     edi, dword[ebp + XFS.file_offset + 4]
2598
        mov     ecx, [ebp + XFS.bytes_to_read]
2599
        cmp     edi, 0  ; hole size >= 2^32
2600
        jne     @f
2601
        cmp     ecx, esi
2602
        jbe     @f
2603
        mov     ecx, esi
2604
    @@:
2605
        add     dword[ebp + XFS.file_offset + 0], ecx
2606
        adc     dword[ebp + XFS.file_offset + 4], 0
2607
        sub     [ebp + XFS.bytes_to_read], ecx
2608
        xor     eax, eax
2609
        mov     edi, [ebp + XFS.buffer_pos]
2610
        rep stosb
2611
        mov     [ebp + XFS.buffer_pos], edi
2612
        pop     edi esi edx eax
2613
        jmp     .root.next_key
2614
  .root.key_found:
2615
DEBUGF 1,".root.key_found\n"
2616
        mov     edx, [ebp + XFS.cur_inode_save]
2617
        mov     eax, [ebp + XFS.inodesize]
2618
        sub     eax, xfs_inode.di_u
2619
        cmp     [edx + xfs_inode.di_core.di_forkoff], 0
2620
        je      @f
2621
        movzx   eax, [edx + xfs_inode.di_core.di_forkoff]
2622
        shl     eax, XFS_DIR2_DATA_ALIGN_LOG    ; 3
2623
    @@:
2624
        sub     eax, sizeof.xfs_bmdr_block
2625
        shr     eax, 4  ;log2(sizeof.xfs_bmbt_key + sizeof.xfs_bmdr_ptr)
2626
        mov     edx, [ebx + sizeof.xfs_bmbt_key*eax + 0]        ; hi
2627
        mov     eax, [ebx + sizeof.xfs_bmbt_key*eax + 4]        ; hi
2628
        bswap   edx
2629
        bswap   eax
2630
        stdcall xfs_btree_read, eax, edx, 0
2631
        test    eax, eax
2632
        jnz     .error
2633
        jmp     .root.next_key
2634
 
2635
  .not_root:
2636
DEBUGF 1,".root.not_root\n"
2637
        mov     eax, [esp + 24] ; block_lo
2638
        mov     edx, [esp + 28] ; block_hi
2639
        mov     ebx, [ebp + XFS.cur_block]
2640
        stdcall xfs_read_block
2641
        test    eax, eax
2642
        jnz     .error
2643
        mov     ebx, [ebp + XFS.cur_block]
2644
 
2645
        cmp     [ebx + xfs_bmbt_block.bb_magic], XFS_BMAP_MAGIC
2646
        jne     .error
2647
        cmp     [ebx + xfs_bmbt_block.bb_level], 0      ; leaf?
2648
        je      .leaf
2649
        jmp     .node
2650
 
2651
  .node:
2652
;        mov     eax, [ebp + XFS.blocksize]
2653
;        sub     eax, sizeof.xfs_bmbt_block
2654
;        shr     eax, 4  ; maxnumrecs
2655
        mov     eax, dword[ebp + XFS.file_offset + 0]   ; lo
2656
        mov     edx, dword[ebp + XFS.file_offset + 4]   ; hi
2657
        movzx   edx, [ebx + xfs_bmbt_block.bb_numrecs]
2658
        xchg    dl, dh
2659
        dec     edx
2660
        add     ebx, sizeof.xfs_bmbt_block
2661
        xor     eax, eax
2662
        dec     eax
2663
  .node.next_key:
2664
        push    eax ecx edx esi edi
2665
        mov     eax, [esp + 44] ; block_lo
2666
        mov     edx, [esp + 48] ; block_hi
2667
        mov     ebx, [ebp + XFS.cur_block]
2668
        stdcall xfs_read_block
2669
        test    eax, eax
2670
        jnz     .error
2671
        mov     ebx, [ebp + XFS.cur_block]
2672
        add     ebx, sizeof.xfs_bmbt_block
2673
        pop     edi esi edx ecx eax
2674
        cmp     [ebp + XFS.bytes_to_read], 0
2675
        je      .quit
2676
        inc     eax
2677
        cmp     eax, edx        ; out of keys?
2678
        ja      .node.key_found ; there is no length field, so try the last key
2679
        lea     edi, [ebx + sizeof.xfs_bmbt_key*eax + 0]
2680
        lea     esi, [ebx + sizeof.xfs_bmbt_key*eax + 4]
2681
        bswap   edi
2682
        bswap   esi
2683
        mov     ecx, [ebp + XFS.blocklog]
2684
        shld    edi, esi, cl
2685
        shl     esi, cl
2686
        cmp     edi, dword[ebp + XFS.file_offset + 4]
2687
        ja      .node.prev_or_hole
2688
        jb      .node.next_key
2689
        cmp     esi, dword[ebp + XFS.file_offset + 0]
2690
        ja      .node.prev_or_hole
2691
        jb      .node.next_key
2692
        jmp     .node.key_found
2693
  .node.prev_or_hole:
2694
        test    eax, eax
2695
        jz      .node.hole
2696
        dec     eax
2697
        jmp     .node.key_found
2698
  .node.hole:
2699
        push    eax edx esi edi
2700
        mov     ecx, [ebp + XFS.blocklog]
2701
        shld    edi, esi, cl
2702
        shl     esi, cl
2703
        sub     esi, dword[ebp + XFS.file_offset + 0]
2704
        sbb     edi, dword[ebp + XFS.file_offset + 4]
2705
        mov     ecx, [ebp + XFS.bytes_to_read]
2706
        cmp     edi, 0  ; hole size >= 2^32
2707
        jne     @f
2708
        cmp     ecx, esi
2709
        jbe     @f
2710
        mov     ecx, esi
2711
    @@:
2712
        add     dword[ebp + XFS.file_offset + 0], ecx
2713
        adc     dword[ebp + XFS.file_offset + 4], 0
2714
        sub     [ebp + XFS.bytes_to_read], ecx
2715
        xor     eax, eax
2716
        mov     edi, [ebp + XFS.buffer_pos]
2717
        rep stosb
2718
        mov     [ebp + XFS.buffer_pos], edi
2719
        pop     edi esi edx eax
2720
        jmp     .node.next_key
2721
  .node.key_found:
2722
        mov     edx, [ebp + XFS.cur_inode_save]
2723
        mov     eax, [ebp + XFS.inodesize]
2724
        sub     eax, xfs_inode.di_u
2725
        cmp     [edx + xfs_inode.di_core.di_forkoff], 0
2726
        je      @f
2727
        movzx   eax, [edx + xfs_inode.di_core.di_forkoff]
2728
        shl     eax, XFS_DIR2_DATA_ALIGN_LOG    ; 3
2729
    @@:
2730
        sub     eax, sizeof.xfs_bmdr_block
2731
        shr     eax, 4  ;log2(sizeof.xfs_bmbt_key + sizeof.xfs_bmdr_ptr)
2732
        mov     edx, [ebx + sizeof.xfs_bmbt_key*eax + 0]        ; hi
2733
        mov     eax, [ebx + sizeof.xfs_bmbt_key*eax + 4]        ; hi
2734
        bswap   edx
2735
        bswap   eax
2736
        stdcall xfs_btree_read, eax, edx, 0
2737
        test    eax, eax
2738
        jnz     .error
2739
        jmp     .node.next_key
2740
        jmp     .quit
2741
 
2742
  .leaf:
6462 pathoswith 2743
 
3913 dunkaist 2744
        jmp     .quit
2745
 
2746
  .error:
2747
        pop     edi esi edx ecx ebx
2748
        movi    eax, ERROR_FS_FAIL
2749
        ret     4
2750
  .quit:
2751
        pop     edi esi edx ecx ebx
2752
        xor     eax, eax
2753
        ret     4
2754
 
2755
 
2756
;----------------------------------------------------------------
2757
; push  nextents
2758
; push  extent_list
2759
; push  file_offset_hi
2760
; push  file_offset_lo
2761
;----------------------------------------------------------------
2762
;xfs_extent_list_read:
2763
;        push    ebx 0 edx esi edi       ; zero means actually_read_bytes
2764
;
2765
;  .quit:
2766
;        pop     edi esi edx ecx ebx
2767
;        xor     eax, eax
2768
;        ret     24
2769
;  .error:
2770
;        pop     edi esi edx ecx ebx
2771
;        ret     24