Subversion Repositories Kolibri OS

Rev

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

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