Subversion Repositories Kolibri OS

Rev

Rev 1065 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2288 clevermous 1
; Copyright (c) 2008-2009, diamond
2
; All rights reserved.
3
;
4
; Redistribution and use in source and binary forms, with or without
5
; modification, are permitted provided that the following conditions are met:
6
;       * Redistributions of source code must retain the above copyright
7
;       notice, this list of conditions and the following disclaimer.
8
;       * Redistributions in binary form must reproduce the above copyright
9
;       notice, this list of conditions and the following disclaimer in the
10
;       documentation and/or other materials provided with the distribution.
11
;       * Neither the name of the  nor the
12
;       names of its contributors may be used to endorse or promote products
13
;       derived from this software without specific prior written permission.
14
;
15
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka  ''AS IS'' AND ANY
16
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
; DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
19
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
;*****************************************************************************
26
 
27
; in: ss:bp = 0:dat
28
; in: es:bx = address to load file
29
; in: ds:si -> ASCIIZ name
30
; in: cx = limit in sectors
31
; out: bx = status: bx=0 - ok, bx=1 - file is too big, only part of file has been loaded, bx=2 - file not found
32
; out: dx:ax = file size (0xFFFFFFFF if file not found)
33
load_file_fat:
34
        mov     eax, [bp + root_clus - dat]
35
        mov     [bp + cur_obj - dat], root_string
36
        push    es
37
        push    bx
38
        push    cx
39
.parse_dir_loop:
40
; convert name to FAT name
41
        push    [bp + cur_obj - dat]
42
        push    ax
43
        mov     [bp + cur_obj - dat], si
44
        push    ss
45
        pop     es
46
; convert ASCIIZ filename to FAT name
47
        mov     di, fat_filename
48
        push    di
49
        mov     cx, 8+3
50
        mov     al, ' '
51
        rep stosb
52
        pop     di
53
        mov     cl, 8   ; 8 symbols per name
54
        mov     bl, 1
55
.nameloop:
56
        lodsb
57
        test    al, al
58
        jz      .namedone
59
        cmp     al, '/'
60
        jz      .namedone
61
        cmp     al, '.'
62
        jz      .namedot
63
        dec     cx
64
        js      .badname
65
        cmp     al, 'a'
66
        jb      @f
67
        cmp     al, 'z'
68
        ja      @f
69
        sub     al, 'a'-'A'
70
@@:
71
        stosb
72
        jmp     .nameloop
73
.namedot:
74
        inc     bx
75
        jp      .badname
76
        add     di, cx
77
        mov     cl, 3
78
        jmp     .nameloop
79
.badname:
80
        mov     si, badname_msg
81
        jmp     find_error_si
82
.namedone:
83
; scan directory
84
        pop     ax      ; eax = cluster of directory
85
                        ; high word of eax is preserved by operations above
86
        push    ds
87
        push    si
88
; read a folder sector-by-sector and scan
89
; first, try to use the cache
90
        push    ss
91
        pop     ds
92
        mov     bx, -2
93
        mov     cx, [bp + rootcache_size - dat]
94
        cmp     [bp + root_clus - dat], eax
95
        jz      .lookcache_root
96
        mov     di, foldcache_mark
97
        xor     bx, bx
98
        mov     cx, [bp + cachelimit - dat]
99
@@:
100
        lea     si, [di+bx]
101
        mov     edx, dword [foldcache_clus+si-foldcache_mark+bx]
102
        cmp     edx, eax
103
        jz      .cacheok
104
        test    edx, edx
105
        jz      .cacheadd       ; the cache has place for new entry
106
        inc     bx
107
        inc     bx
108
        dec     cx
109
        js      @b
110
; the folder is not present in the cache, so add it
111
; the cache is full; find the oldest entry and replace it with the new one
112
        mov     bx, -2
113
        mov     dx, [bp + cachelimit - dat]
114
@@:
115
        inc     bx
116
        inc     bx
117
        cmp     word [di+bx], dx        ; marks have values 0 through [cachelimit]
118
        jnz     @b
119
.cacheadd:
120
        or      word [di+bx], 0xFFFF    ; very big value, it will be changed soon
121
        and     [foldcache_size+di-foldcache_mark+bx], 0        ; no folder items yet
122
        lea     si, [di+bx]
123
        mov     dword [foldcache_clus+si-foldcache_mark+bx], eax
124
.cacheok:
125
; update cache marks
126
        mov     dx, [di+bx]
127
        mov     cx, [foldcache_size+di-foldcache_mark+bx]
128
        mov     di, [bp + cachelimit - dat]
129
        add     di, di
130
.cacheupdate:
131
        cmp     [foldcache_mark+di], dx
132
        adc     [foldcache_mark+di], 0
133
        dec     di
134
        dec     di
135
        jns     .cacheupdate
136
        and     [foldcache_mark+bx], 0
137
; done, bx contains (position in cache)*2
138
.lookcache_root:
139
; bx = (position in cache)*2 for non-root folders; bx = -2 for root folder
140
        ;mov    dx, bx
141
        ;shl    dx, 8
142
        ;add    dx, 0x9200
143
        lea     dx, [bx + 0x92]
144
        xchg    dl, dh
145
        mov     ds, dx
146
        mov     si, fat_filename        ; ss:si -> filename in FAT style
147
        call    fat_scan_for_filename
148
        jz      .lookup_done
149
; cache miss, read folder data from disk
150
; we are reading parent directory, it can result in disk read errors; restore [cur_obj]
151
        mov     di, sp
152
        mov     bx, [bp + cur_obj - dat]
153
        xchg    bx, [ss:di+4]
154
        mov     [bp + cur_obj - dat], bx
155
        mov     bx, cx
156
        add     bx, 0xF
157
        shr     bx, 4
158
        shl     cx, 5
159
        mov     di, cx          ; es:di -> free space in cache entry
160
; external loop: scan clusters
161
.folder_next_cluster:
162
; internal loop: scan sectors in cluster
163
        movzx   ecx, byte [ss:0x320D]   ; BPB_SecPerClus
164
        push    eax
165
; FAT12/16 root - special handling
166
        test    eax, eax
167
        jnz     .folder_notroot
168
        mov     cx, [ss:0x3211]         ; BPB_RootEntCnt
169
        mov     dx, cx
170
        add     cx, 0xF
171
        rcr     cx, 1
172
        shr     cx, 3
173
        mov     eax, [bp + root_start - dat]
174
        jmp     .folder_next_sector
175
.folder_notroot:
176
        mul     ecx
177
        add     eax, [bp + data_start - dat]
178
.folder_next_sector:
179
        sub     dx, 0x10
180
; skip first bx sectors
181
        dec     bx
182
        jns     .folder_skip_sector
183
        push    cx
184
        push    es di
185
        push    0x8000
186
        pop     es
187
        xor     bx, bx
188
        mov     cx, 1
189
        push    es
190
        call    read
191
        jc      ..found_disk_error
192
; copy data to the cache...
193
        pop     ds
194
        pop     di es
195
        cmp     di, 0x2000      ; ...if there is free space, of course
196
        jae     @f
197
        pusha
198
        mov     cx, 0x100
199
        xor     si, si
200
        rep movsw
201
        mov     di, es
202
        shr     di, 8
203
        cmp     di, 0x90
204
        jz      .update_rootcache_size
205
        add     [ss:foldcache_size+di-0x92], 0x10       ; 0x10 new entries in the cache
206
        jmp     .updated_cachesize
207
.update_rootcache_size:
208
        mov     cl, 0x10
209
        cmp     cx, dx
210
        jb      @f
211
        mov     cx, dx
212
@@:
213
        add     [bp + rootcache_size - dat], cx
214
.updated_cachesize:
215
        popa
216
@@:
217
        push    es
218
        mov     cl, 0x10        ; ch=0 at this point
219
        cmp     cx, dx
220
        jb      @f
221
        mov     cx, dx
222
@@:
223
        call    fat_scan_for_filename
224
        pop     es
225
        pop     cx
226
        jz      .lookup_done_pop
227
.folder_skip_sector:
228
        inc     eax
229
        loop    .folder_next_sector
230
        pop     eax     ; eax = current cluster
231
        test    eax, eax
232
        jz      @f
233
        call    [bp + get_next_cluster_ptr - dat]
234
        jc      .folder_next_cluster
235
@@:
236
        stc
237
        push    eax
238
.lookup_done_pop:
239
        pop     eax
240
.lookup_done:
241
        pop     si
242
; CF=1 <=> failed
243
        jnc     .found
244
        pop     ds
245
        pop     [bp + cur_obj - dat]
246
        mov     si, error_not_found
247
        jmp     find_error_si
248
.found:
249
        mov     eax, [di+20-2]
250
        mov     edx, [di+28]
251
        mov     ax, [di+26]     ; get cluster
252
        test    byte [di+11], 10h       ; directory?
253
        pop     ds
254
        pop     [bp + cur_obj - dat]    ; forget old [cur_obj]
255
        jz      .regular_file
256
        cmp     byte [si-1], 0
257
        jnz     .parse_dir_loop
258
..directory_error:
259
        mov     si, directory_string
260
        jmp     find_error_si
261
.regular_file:
262
        cmp     byte [si-1], 0
263
        jz      @f
264
..notdir_error:
265
        mov     si, notdir_string
266
        jmp     find_error_si
267
@@:
268
; ok, we have found a regular file and the caller requested it
269
; parse FAT chunk
270
        push    ss
271
        pop     es
272
        push    ss
273
        pop     ds
274
        mov     di, 0x4005
275
        mov     byte [di-5], 1  ; non-resident attribute
276
        mov     dword [di-4], 1
277
        stosd
278
        pop     cx
279
        push    cx
280
.parsefat:
281
        call    [bp + get_next_cluster_ptr - dat]
282
        jnc     .done
283
        mov     esi, [di-8]
284
        add     esi, [di-4]
285
        cmp     eax, esi
286
        jz      .contc
287
        mov     dword [di], 1
288
        scasd
289
        stosd
290
        jmp     @f
291
.contc:
292
        inc     dword [di-8]
293
@@:
294
        sub     cl, [0x320D]
295
        sbb     ch, 0
296
        ja      .parsefat
297
.done:
298
        xor     eax, eax
299
        stosd
300
        mov     si, 0x4000
301
load_file_common_end:
302
        xor     ecx, ecx
303
        pop     cx
304
        pop     bx
305
        pop     es
306
        mov     [bp + filesize - dat], edx
307
        mov     [bp + sectors_read - dat], ecx
308
        add     edx, 0x1FF
309
        shr     edx, 9
310
        mov     [bp + filesize_sectors - dat], edx
311
        cmp     edx, ecx
312
        seta    al
313
        mov     ah, 0
314
        push    ax
315
        call    read_file_chunk
316
continue_load_common_end:
317
        mov     [bp + cur_chunk_ptr - dat], si
318
        pop     bx
319
        mov     ax, word [bp + filesize - dat]
320
        mov     dx, word [bp + filesize+2 - dat]
321
        jnc     @f
322
        mov     bl, 3   ; read error
323
@@:
324
        ret
325
 
326
continue_load_file:
327
; es:bx -> buffer for output, ecx = cx = number of sectors
328
        mov     si, [bp + cur_chunk_ptr - dat]
329
        push    ecx
330
        add     ecx, [bp + sectors_read - dat]
331
        mov     [bp + sectors_read - dat], ecx
332
        cmp     [bp + filesize_sectors - dat], ecx
333
        pop     ecx
334
        seta    al
335
        mov     ah, 0
336
        push    ax
337
        push    continue_load_common_end
338
        push    ss
339
        pop     ds
340
        cmp     [bp + cur_chunk_resident - dat], ah
341
        jnz     .nonresident
342
.resident:
343
        mov     ax, word [bp + num_sectors - dat]
344
        jmp     read_file_chunk.resident.continue
345
.nonresident:
346
        mov     eax, [bp + cur_cluster - dat]
347
        mov     edx, [bp + num_sectors - dat]
348
        add     eax, [bp + cur_delta - dat]
349
        jmp     read_file_chunk.nonresident.continue
350
 
351
fat_scan_for_filename:
352
; in: ss:si -> 11-bytes FAT name
353
; in: ds:0 -> part of directory data
354
; in: cx = number of entries
355
; out: if found: CF=0, ZF=1, es:di -> directory entry
356
; out: if not found, but continue required: CF=1 and ZF=0
357
; out: if not found and zero item reached: CF=1 and ZF=1
358
        push    ds
359
        pop     es
360
        xor     di, di
361
        push    cx
362
        jcxz    .noent
363
.loop:
364
        cmp     byte [di], 0
365
        jz      .notfound
366
        test    byte [di+11], 8         ; volume label?
367
        jnz     .cont                   ; ignore volume labels
368
        pusha
369
        mov     cx, 11
370
        repz cmps byte [ss:si], byte [es:di]
371
        popa
372
        jz      .done
373
.cont:
374
        add     di, 0x20
375
        loop    .loop
376
.noent:
377
        inc     cx      ; clear ZF flag
378
.notfound:
379
        stc
380
.done:
381
        pop     cx
382
        ret
383
 
384
fat12_get_next_cluster:
385
; in: ax = cluster (high word of eax is zero)
386
; out: if there is next cluster: CF=1, ax = next cluster
387
; out: if there is no next cluster: CF=0
388
        push    si
389
        push    ds
390
        push    0x6000
391
        pop     ds
392
        mov     si, ax
393
        shr     si, 1
394
        add     si, ax
395
        test    al, 1
396
        lodsw
397
        jz      @f
398
        shr     ax, 4
399
@@:
400
        and     ax, 0xFFF
401
        cmp     ax, 0xFF7
402
        pop     ds si
403
        ret
404
 
405
fat16_get_next_cluster:
406
; in: ax = cluster (high word of eax is zero)
407
; out: if there is next cluster: CF=1, ax = next cluster
408
; out: if there is no next cluster: CF=0
409
; each sector contains 200h bytes = 100h FAT entries
410
; so ah = # of sector, al = offset in sector
411
        push    si
412
        mov     si, ax
413
        shr     si, 8
414
; calculate segment for this sector of FAT table
415
; base for FAT table is 6000:0000, so the sector #si has to be loaded to (60000 + 200*si)
416
; segment = 6000 + 20*si, offset = 0
417
        push    es
418
        push    si
419
        shl     si, 5
420
        add     si, 0x6000
421
        mov     es, si
422
        pop     si
423
        cmp     byte [ss:0x3400+si], 0  ; sector already loaded?
424
        jnz     .noread
425
; load corresponding sector, try all FATs if disk read error detected
426
        pusha
427
        movzx   di, byte [ss:0x3210]    ; BPB_NumFATs
428
        xor     bx, bx
429
        mov     ax, [ss:0x320E]         ; BPB_RsvdSecCnt
430
        xor     dx, dx
431
        add     ax, si
432
        adc     dx, bx
433
@@:
434
        push    es
435
        push    dx ax
436
        pop     eax
437
        mov     cx, 1   ; read 1 sector
438
        call    read
439
        pop     es
440
        jnc     @f
441
        add     ax, [ss:0x3216]         ; BPB_FATSz16
442
        adc     dx, bx
443
        dec     di
444
        jnz     @b
445
..found_disk_error:
446
        mov     si, disk_error_msg
447
        jmp     find_error_si
448
@@:
449
        popa
450
.noread:
451
        mov     si, ax
452
        and     si, 0xFF
453
        add     si, si
454
        mov     ax, [es:si]
455
        pop     es
456
        cmp     ax, 0xFFF7
457
        pop     si
458
        ret
459
 
460
fat32_get_next_cluster:
461
; in: eax = cluster
462
; out: if there is next cluster: CF=1, eax = next cluster
463
; out: if there is no next cluster: CF=0
464
        push    di
465
        push    ax
466
        shr     eax, 7
467
; eax = FAT sector number; look in cache
468
        push    si
469
        mov     si, cache1head
470
        call    cache_lookup
471
        pop     si
472
        jnc     .noread
473
; read FAT, try all FATs if disk read error detected
474
        push    es
475
        pushad
476
        movzx   edx, word [ss:0x320E]   ; BPB_RsvdSecCnt
477
        add     eax, edx
478
        movzx   si, byte [ss:0x3210]    ; BPB_NumFATs
479
@@:
480
        lea     cx, [di - 0x3400 + (0x6000 shr (9-3))]
481
        shl     cx, 9-3
482
        mov     es, cx
483
        xor     bx, bx
484
        mov     cx, 1
485
        call    read
486
        jnc     @f
487
        add     eax, [ss:0x3224]        ; BPB_FATSz32
488
        dec     si
489
        jnz     @b
490
        jmp     ..found_disk_error
491
@@:
492
        popad
493
        pop     es
494
.noread:
495
; get requested item
496
        lea     ax, [di - 0x3400 + (0x6000 shr (9-3))]
497
        pop     di
498
        and     di, 0x7F
499
        shl     di, 2
500
        shl     ax, 9-3
501
        push    ds
502
        mov     ds, ax
503
        and     byte [di+3], 0x0F
504
        mov     eax, [di]
505
        pop     ds
506
        pop     di
507
        ;and    eax, 0x0FFFFFFF
508
        cmp     eax, 0x0FFFFFF7
509
        ret