Subversion Repositories Kolibri OS

Rev

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

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