Subversion Repositories Kolibri OS

Rev

Rev 4850 | Go to most recent revision | Details | Last modification | View Log | RSS feed

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