2 * ntfs.handler - New Technology FileSystem handler
4 * Copyright © 2012 The AROS Development Team
6 * This program is free software; you can redistribute it and/or modify it
7 * under the same terms as AROS itself.
12 #include <aros/macros.h>
13 #include <exec/errors.h>
14 #include <exec/types.h>
16 #include <dos/dosextens.h>
17 #include <dos/filehandler.h>
19 #include <proto/exec.h>
20 #include <proto/dos.h>
21 #include <proto/utility.h>
22 #include <proto/uuid.h>
23 #include <proto/codesets.h>
25 #include <clib/macros.h>
31 #include "ntfs_protos.h"
36 extern struct Globals
*glob
;
38 ULONG
PostProcessMFTRecord(struct FSData
*fs_data
, struct MFTRecordEntry
*record
, int len
, UBYTE
*magic
)
40 UWORD seqarray_len
, seqnum
;
41 UBYTE
*seqarray
, *buf
;
43 buf
= (UBYTE
*)record
;
45 D(bug("[NTFS]: %s(%.4s)\n", __PRETTY_FUNCTION__
, magic
));
47 /* Perform post-read MST fixup by applying the sequence array to acquired blocks */
49 D(bug("[NTFS] %s: FSData @ 0x%p\n", __PRETTY_FUNCTION__
, fs_data
));
50 D(bug("[NTFS] %s: MFTRecordEntry @ 0x%p\n", __PRETTY_FUNCTION__
, record
));
52 if (memcmp(record
->header
.magic
, magic
, 4))
55 bug("[NTFS] %s: record magic mismatch (got '%.4s')\n", __PRETTY_FUNCTION__
, record
->header
.magic
);
57 return ERROR_OBJECT_WRONG_TYPE
;
60 seqarray_len
= AROS_LE2WORD(record
->header
.usa_count
) - 1;
62 if (seqarray_len
!= len
)
64 D(bug("[NTFS] %s: fixup error - sequence array size != record size\n", __PRETTY_FUNCTION__
));
65 return ERROR_NOT_IMPLEMENTED
;
68 seqarray
= (char *)record
+ AROS_LE2WORD(record
->header
.usa_offset
);
69 seqnum
= AROS_LE2WORD(*((UWORD
*)seqarray
));
71 D(bug("[NTFS] %s: update sequence = %u (usa_offset %u)\n", __PRETTY_FUNCTION__
, seqnum
, AROS_LE2WORD(record
->header
.usa_offset
)));
73 while (seqarray_len
> 0)
75 buf
+= fs_data
->sectorsize
;
77 if (AROS_LE2WORD(*((UWORD
*)(buf
- 2))) != seqnum
)
79 D(bug("[NTFS] %s: update sequence mismatch @ 0x%p (%u != %u)\n", __PRETTY_FUNCTION__
, buf
, AROS_LE2WORD(*((UWORD
*)buf
)), seqnum
));
80 return ERROR_NOT_IMPLEMENTED
;
83 *((UWORD
*)(buf
- 2)) = *((UWORD
*)seqarray
);
87 D(bug("[NTFS] %s: record fixup complete\n", __PRETTY_FUNCTION__
));
92 ULONG
PreProcessMFTRecord(struct FSData
*fs_data
, struct MFTRecordEntry
*record
, int len
)
94 D(bug("[NTFS]: %s(MFTRecordEntry @ 0x%p)\n", __PRETTY_FUNCTION__
, record
));
96 /* Perform pre-write MST fixup. set the sequence numbers of blocks */
101 struct MFTAttr
*GetMappingPairPos(UBYTE
*mappos
, int nn
, UQUAD
*val
, int sig
)
106 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__
));
110 pos
+= mask
* (*mappos
);
115 if ((sig
) && (pos
& (mask
>> 1)))
119 return (struct MFTAttr
*)mappos
;
122 IPTR
ReadNTFSRunList(struct NTFSRunLstEntry
* rle
)
126 struct MFTAttr
*mappos
= (struct MFTAttr
*)rle
->mappingpair
;
128 D(bug("[NTFS]: %s(mappos @ 0x%p)\n", __PRETTY_FUNCTION__
, mappos
));
131 len
= (*(UBYTE
*)mappos
& 0xF);
132 offs
= (*(UBYTE
*)mappos
>> 4);
134 D(bug("[NTFS] %s: len = %u\n", __PRETTY_FUNCTION__
, len
));
135 D(bug("[NTFS] %s: offs = %u\n", __PRETTY_FUNCTION__
, offs
));
139 D(bug("[NTFS] %s: !len\n", __PRETTY_FUNCTION__
));
140 if ((rle
->attr
) && (rle
->attr
->flags
& AF_ALST
))
142 D(bug("[NTFS] %s: AF_ALST\n", __PRETTY_FUNCTION__
));
144 mappos
= FindMFTAttrib(rle
->attr
, *(UBYTE
*)rle
->attr
->attr_cur
);
148 D(bug("[NTFS] %s: 'RUN'\n", __PRETTY_FUNCTION__
));
149 if (mappos
->residentflag
== ATTR_RESIDENT_FORM
)
151 D(bug("[NTFS] %s: $DATA should be non-resident\n", __PRETTY_FUNCTION__
));
155 mappos
= (struct MFTAttr
*)(IPTR
)((IPTR
)mappos
+ AROS_LE2WORD(mappos
->data
.non_resident
.mapping_pairs_offset
));
160 D(bug("[NTFS] %s: run list overflow\n", __PRETTY_FUNCTION__
));
163 // current VCN length
164 mappos
= GetMappingPairPos((UBYTE
*)mappos
+ 1, len
, &val
, 0);
165 rle
->curr_vcn
= rle
->next_vcn
;
166 rle
->next_vcn
= rle
->next_vcn
+ val
;
168 D(bug("[NTFS] %s: curr_vcn = %u, next_vcn = %u, val = %u\n", __PRETTY_FUNCTION__
, (unsigned int)rle
->curr_vcn
, (unsigned int)rle
->next_vcn
, (unsigned int)val
));
170 // previous LCN offset
171 mappos
= GetMappingPairPos((UBYTE
*)mappos
, offs
, &val
, 1);
172 rle
->curr_lcn
= rle
->curr_lcn
+ val
;
174 D(bug("[NTFS] %s: curr_lcn = %u\n", __PRETTY_FUNCTION__
, (unsigned int)rle
->curr_lcn
));
177 rle
->flags
|= RLEFLAG_SPARSE
;
179 rle
->flags
&= ~RLEFLAG_SPARSE
;
181 rle
->mappingpair
= (UBYTE
*)mappos
;
186 void FreeMFTAttrib(struct NTFSMFTAttr
*at
)
188 D(bug("[NTFS]: %s(NTFSMFTAttr @ 0x%p)\n", __PRETTY_FUNCTION__
, at
));
190 FreeVec(at
->edat_buf
);
194 FreeMem(at
->emft_buf
, at
->mft
->data
->mft_size
<< SECTORSIZE_SHIFT
);
199 FreeMem(at
->sbuf
, COM_LEN
);
204 IPTR
ReadMFTAttribData(struct NTFSMFTAttr
*at
, struct MFTAttr
*attrentry
, UBYTE
*dest
, UQUAD ofs
, ULONG len
, int cached
)
207 struct NTFSRunLstEntry runlist_entry
, *rle
;
210 bug("[NTFS]: %s(ofs = %u; len = %u)\n", __PRETTY_FUNCTION__
, (IPTR
)ofs
, len
);
212 bug("[NTFS] %s: NTFSMFTAttr @ 0x%p\n", __PRETTY_FUNCTION__
, at
);
213 bug("[NTFS] %s: MFTAttr @ 0x%p, dest @ 0x%p\n", __PRETTY_FUNCTION__
, attrentry
, dest
);
219 memset (&runlist_entry
, 0, sizeof(struct NTFSRunLstEntry
));
220 rle
= &runlist_entry
;
223 if (AROS_LE2LONG(attrentry
->data
.resident
.value_offset
) > AROS_LE2LONG(attrentry
->length
))
225 D(bug("[NTFS] %s: error - corrupt attribute\n", __PRETTY_FUNCTION__
));
229 if (attrentry
->residentflag
== ATTR_RESIDENT_FORM
)
231 D(bug("[NTFS] %s: ATTR_RESIDENT_FORM\n", __PRETTY_FUNCTION__
));
233 if ((ofs
+ len
) > AROS_LE2LONG(attrentry
->data
.resident
.value_length
))
235 D(bug("[NTFS] %s: error - read out of range\n", __PRETTY_FUNCTION__
));
238 CopyMem(attrentry
+ AROS_LE2LONG(attrentry
->data
.resident
.value_offset
) + ofs
, dest
, len
);
242 if (AROS_LE2WORD(attrentry
->attrflags
) & FLAG_COMPRESSED
)
244 rle
->flags
|= RLEFLAG_COMPR
;
248 rle
->flags
&= ~RLEFLAG_COMPR
;
250 rle
->mappingpair
= (UBYTE
*)(IPTR
)((IPTR
)attrentry
+ AROS_LE2WORD(attrentry
->data
.non_resident
.mapping_pairs_offset
));
252 D(bug("[NTFS] %s: mappingpair @ 0x%p\n", __PRETTY_FUNCTION__
, rle
->mappingpair
));
254 if (rle
->flags
& RLEFLAG_COMPR
)
256 D(bug("[NTFS] %s: ## Compressed\n", __PRETTY_FUNCTION__
));
259 D(bug("[NTFS] %s: error - attribute cannot be compressed\n", __PRETTY_FUNCTION__
));
265 if ((ofs
& (~(COM_LEN
- 1))) == at
->save_pos
)
269 n
= COM_LEN
- (ofs
- at
->save_pos
);
273 CopyMem(at
->sbuf
+ ofs
- at
->save_pos
, dest
, n
);
284 at
->sbuf
= AllocMem(COM_LEN
, MEMF_ANY
);
285 if (at
->sbuf
== NULL
)
287 D(bug("[NTFS] %s: error - failed to allocate sbuf\n", __PRETTY_FUNCTION__
));
288 return ERROR_NO_FREE_STORE
;
293 D(vcn
=) rle
->target_vcn
= (ofs
>> COM_LOG_LEN
) * (COM_SEC
/ at
->mft
->data
->cluster_sectors
);
294 rle
->target_vcn
&= ~0xF;
298 rle
->target_vcn
= (ofs
>> SECTORSIZE_SHIFT
) / at
->mft
->data
->cluster_sectors
;
299 D(vcn
= rle
->target_vcn
);
302 rle
->next_vcn
= AROS_LE2QUAD(attrentry
->data
.non_resident
.lowest_vcn
);
305 D(bug("[NTFS] %s: vcn = %u\n", __PRETTY_FUNCTION__
, vcn
));
307 while (rle
->next_vcn
<= rle
->target_vcn
)
309 D(bug("[NTFS] %s: next_vcn = %u, target_vcn = %u\n", __PRETTY_FUNCTION__
, (IPTR
)rle
->next_vcn
, (IPTR
)rle
->target_vcn
));
310 if (ReadNTFSRunList(rle
))
312 D(bug("[NTFS] %s: read_run_list failed\n", __PRETTY_FUNCTION__
));
317 D(bug("[NTFS] %s: next_vcn = %u\n", __PRETTY_FUNCTION__
, (IPTR
)rle
->next_vcn
));
319 if (at
->flags
& AF_GPOS
)
323 D(bug("[NTFS] %s: AF_GPOS\n", __PRETTY_FUNCTION__
));
325 m
= (ofs
>> SECTORSIZE_SHIFT
) % at
->mft
->data
->cluster_sectors
;
328 (rle
->target_vcn
- rle
->curr_vcn
+ rle
->curr_lcn
) * at
->mft
->data
->cluster_sectors
+ m
;
332 (rle
->next_vcn
- rle
->curr_vcn
+ rle
->curr_lcn
) * at
->mft
->data
->cluster_sectors
)
334 if (ReadNTFSRunList(rle
))
336 D(bug("[NTFS] %s: read_run_list failed\n", __PRETTY_FUNCTION__
));
339 st1
= rle
->curr_lcn
* at
->mft
->data
->cluster_sectors
;
341 *((ULONG
*)dest
) = AROS_LONG2LE(st0
);
342 *((ULONG
*)(dest
+ 4)) = AROS_LONG2LE(st1
);
346 if (!(rle
->flags
& RLEFLAG_COMPR
))
348 D(bug("[NTFS] %s: ## Uncompressed\n", __PRETTY_FUNCTION__
));
350 if (!(at
->mft
->data
->cluster_sectors
& 0x1))
352 unsigned int sectbits_shift
= ilog2(at
->mft
->data
->cluster_sectors
);
353 ULONG blocksize
= 1 << (sectbits_shift
+ SECTORSIZE_SHIFT
);
356 UQUAD i
, blockcnt
= ((len
+ ofs
) + blocksize
- 1) >> (sectbits_shift
+ SECTORSIZE_SHIFT
);
359 bug("[NTFS] %s: blockcnt = %u\n", __PRETTY_FUNCTION__
, (IPTR
)blockcnt
);
360 bug("[NTFS] %s: blocksize = %u\n", __PRETTY_FUNCTION__
, blocksize
);
363 for (i
= ofs
>> (sectbits_shift
+ SECTORSIZE_SHIFT
); i
< blockcnt
; i
++)
366 UQUAD blockoff
= ofs
& (blocksize
- 1);
367 UQUAD blockend
= blocksize
;
371 bug("[NTFS] %s: blockoff = %u\n", __PRETTY_FUNCTION__
, (IPTR
)blockoff
);
372 bug("[NTFS] %s: blockend = %u\n", __PRETTY_FUNCTION__
, (IPTR
)blockend
);
375 if (i
>= rle
->next_vcn
)
377 if (ReadNTFSRunList(rle
))
379 D(bug("[NTFS] %s: failed to read run list!\n", __PRETTY_FUNCTION__
));
383 blockstart
= rle
->curr_lcn
;
387 blockstart
= (rle
->flags
& RLEFLAG_SPARSE
) ? 0 : (i
- rle
->curr_vcn
+ rle
->curr_lcn
);
390 blockstart
= blockstart
<< sectbits_shift
;
393 if (i
== (blockcnt
- 1))
395 D(bug("[NTFS] %s: last block.. \n", __PRETTY_FUNCTION__
));
397 blockend
= (len
+ ofs
) & (blocksize
- 1);
399 /* The last portion is exactly blocksize. */
401 blockend
= blocksize
;
405 if (i
== (ofs
>> (sectbits_shift
+ SECTORSIZE_SHIFT
)))
407 D(bug("[NTFS] %s: first block.. \n", __PRETTY_FUNCTION__
));
409 skipfirst
= blockoff
;
410 blockend
-= skipfirst
;
413 /* If the block number is 0 this block is not stored on disk but is zero filled instead. */
416 bug("[NTFS] %s: blockstart = %u\n", __PRETTY_FUNCTION__
, (IPTR
)blockstart
);
417 bug("[NTFS] %s: blockend = %u\n", __PRETTY_FUNCTION__
, (IPTR
)blockend
);
418 bug("[NTFS] %s: skipfirst = %u\n", __PRETTY_FUNCTION__
, (IPTR
)skipfirst
);
423 UQUAD blocknr
, skipblocks
= skipfirst
>> SECTORSIZE_SHIFT
, lastblock
= ((blockend
+ skipfirst
) >> SECTORSIZE_SHIFT
);
424 APTR blockbuf
, bufstart
= buf
;
430 for (blocknr
= skipblocks
; blocknr
< lastblock
; blocknr
++)
432 D(bug("[NTFS] %s: block %u\n", __PRETTY_FUNCTION__
, (IPTR
)blocknr
));
433 if (blocknr
>= (skipfirst
>> SECTORSIZE_SHIFT
))
435 D(bug("[NTFS] %s: reading ..\n", __PRETTY_FUNCTION__
));
437 if ((at
->mft
->cblock
= Cache_GetBlock(at
->mft
->data
->cache
, at
->mft
->data
->first_device_sector
+ blockstart
+ blocknr
, &at
->mft
->cbuf
)) == NULL
)
439 D(bug("[NTFS] %s: read failed\n", __PRETTY_FUNCTION__
));
443 D(bug("[NTFS] %s: cbuf @ 0x%p\n", __PRETTY_FUNCTION__
, at
->mft
->cbuf
));
445 if (blocknr
== (lastblock
- 1) && (blockend
& (at
->mft
->data
->sectorsize
- 1)))
446 copysize
= (blockend
& (at
->mft
->data
->sectorsize
- 1));
448 copysize
= at
->mft
->data
->sectorsize
;
450 if ((blocknr
<< SECTORSIZE_SHIFT
) < skipfirst
)
452 blockbuf
= at
->mft
->cbuf
+ (skipfirst
& (at
->mft
->data
->sectorsize
- 1));
454 copysize
-= (skipfirst
& (at
->mft
->data
->sectorsize
- 1));
458 blockbuf
= at
->mft
->cbuf
;
463 D(bug("[NTFS] %s: copying %u bytes from 0x%p -> 0x%p\n", __PRETTY_FUNCTION__
, copysize
, blockbuf
, bufstart
));
464 CopyMem(blockbuf
, bufstart
, copysize
);
468 Cache_FreeBlock(at
->mft
->data
->cache
, at
->mft
->cblock
);
469 at
->mft
->cblock
= NULL
;
474 memset (buf
, 0, blockend
);
476 buf
+= blocksize
- skipfirst
;
483 /* Warning : TODO - decompress block */
484 D(bug("[NTFS] %s: cannot decompress\n", __PRETTY_FUNCTION__
));
488 IPTR
ReadMFTAttrib(struct NTFSMFTAttr
*at
, UBYTE
*dest
, UQUAD ofs
, ULONG len
, int cached
)
490 struct MFTAttr
*save_cur
;
492 struct MFTAttr
*attrentry
;
495 D(bug("[NTFS]: %s(NTFSMFTAttr @ 0x%p; ofs = %d; len = %d)\n", __PRETTY_FUNCTION__
, at
, (IPTR
)ofs
, len
));
497 save_cur
= at
->attr_cur
;
498 at
->attr_nxt
= at
->attr_cur
;
499 attr
= *(UBYTE
*)at
->attr_nxt
;
500 if (at
->flags
& AF_ALST
)
504 D(bug("[NTFS] %s: AF_ALST\n", __PRETTY_FUNCTION__
));
506 vcn
= ofs
/ (at
->mft
->data
->cluster_sectors
<< SECTORSIZE_SHIFT
);
507 attrentry
= (struct MFTAttr
*)((IPTR
)at
->attr_nxt
+ AROS_LE2WORD(at
->attr_nxt
->length
));
508 while (attrentry
< at
->attr_end
)
510 if (*(UBYTE
*)attrentry
!= attr
)
512 if (AROS_LE2LONG(*((ULONG
*)(attrentry
+ 8))) > vcn
)
514 at
->attr_nxt
= attrentry
;
515 attrentry
= (struct MFTAttr
*)((IPTR
)attrentry
+ AROS_LE2WORD(attrentry
->length
));
518 attrentry
= FindMFTAttrib(at
, attr
);
520 ret
= ReadMFTAttribData(at
, attrentry
, dest
, ofs
, len
, cached
);
523 D(bug("[NTFS] %s: attribute %u not found\n", __PRETTY_FUNCTION__
, attr
));
526 at
->attr_cur
= save_cur
;
530 static IPTR
ReadMFTRecord(struct NTFSMFTEntry
*mft
, UBYTE
*buf
, ULONG mft_id
)
532 D(bug("[NTFS]: %s(%d)\n", __PRETTY_FUNCTION__
, mft_id
));
535 (&mft
->data
->mft
.attr
, buf
, mft_id
* ((UQUAD
) mft
->data
->mft_size
<< SECTORSIZE_SHIFT
),
536 mft
->data
->mft_size
<< SECTORSIZE_SHIFT
, 0))
538 D(bug("[NTFS] %s: failed to read MFT #%d\n", __PRETTY_FUNCTION__
, mft_id
));
541 #if defined(DEBUG_MFT)
545 bug("[NTFS] %s: MFTRecord #%d Dump -:\n", __PRETTY_FUNCTION__
, mft_id
);
546 bug("[NTFS] %s: MFTRecord #%d buf @ 0x%p, size %d x %d", __PRETTY_FUNCTION__
, mft_id
, buf
, mft
->data
->mft_size
, mft
->data
->sectorsize
);
548 for (dumpx
= 0; dumpx
< (mft
->data
->mft_size
* mft
->data
->sectorsize
) ; dumpx
++)
552 bug("\n[NTFS] %s:\t%03x:", __PRETTY_FUNCTION__
, dumpx
);
554 bug(" %02x", ((UBYTE
*)buf
)[dumpx
]);
559 return PostProcessMFTRecord (mft
->data
, (struct MFTRecordEntry
*)buf
, mft
->data
->mft_size
, "FILE");
562 struct MFTAttr
*FindMFTAttrib(struct NTFSMFTAttr
*at
, UBYTE attr
)
564 D(bug("[NTFS]: %s(%u)\n", __PRETTY_FUNCTION__
, attr
));
566 if (at
->flags
& AF_ALST
)
568 D(bug("[NTFS] %s: AF_ALST\n", __PRETTY_FUNCTION__
));
570 while (at
->attr_nxt
< at
->attr_end
)
572 at
->attr_cur
= at
->attr_nxt
;
573 at
->attr_nxt
= (struct MFTAttr
*)((IPTR
)at
->attr_nxt
+ AROS_LE2WORD(at
->attr_cur
->length
));
575 D(bug("[NTFS] %s: attr_cur @ 0x%p, attr_nxt @ 0x%p\n", __PRETTY_FUNCTION__
, at
->attr_cur
, at
->attr_nxt
));
577 if ((*(UBYTE
*)at
->attr_cur
== attr
) || (attr
== 0))
581 D(bug("[NTFS] %s: attr %u found @ 0x%p\n", __PRETTY_FUNCTION__
, attr
, at
->attr_cur
));
583 if (at
->flags
& AF_MMFT
)
585 D(bug("[NTFS] %s: AF_MMFT\n", __PRETTY_FUNCTION__
));
587 if ((at
->mft
->cblock
= Cache_GetBlock(at
->mft
->data
->cache
, at
->mft
->data
->first_device_sector
+ AROS_LE2LONG(*((ULONG
*)(at
->attr_cur
+ 0x10))), &at
->mft
->cbuf
)) == NULL
)
589 D(bug("[NTFS] %s: read failed\n", __PRETTY_FUNCTION__
));
592 CopyMem(at
->mft
->cbuf
, at
->emft_buf
, at
->mft
->data
->sectorsize
);
593 Cache_FreeBlock(at
->mft
->data
->cache
, at
->mft
->cblock
);
594 at
->mft
->cblock
= NULL
;
596 if ((at
->mft
->cblock
= Cache_GetBlock(at
->mft
->data
->cache
, at
->mft
->data
->first_device_sector
+ AROS_LE2LONG(*((ULONG
*)(at
->attr_cur
+ 0x14))), &at
->mft
->cbuf
)) == NULL
)
598 D(bug("[NTFS] %s: read failed\n", __PRETTY_FUNCTION__
));
601 CopyMem(at
->mft
->cbuf
, at
->emft_buf
+ at
->mft
->data
->sectorsize
, at
->mft
->data
->sectorsize
);
602 Cache_FreeBlock(at
->mft
->data
->cache
, at
->mft
->cblock
);
603 at
->mft
->cblock
= NULL
;
605 if (PostProcessMFTRecord
606 (at
->mft
->data
, (struct MFTRecordEntry
*)at
->emft_buf
, at
->mft
->data
->mft_size
,
612 D(bug("[NTFS] %s: !AF_MMFT\n", __PRETTY_FUNCTION__
));
614 if (ReadMFTRecord(at
->mft
, (UBYTE
*)at
->emft_buf
,
615 AROS_LE2LONG(at
->attr_cur
->data
.resident
.value_length
)))
619 new_pos
= &((UBYTE
*)at
->emft_buf
)[AROS_LE2WORD(at
->emft_buf
->data
.resident
.value_offset
)];
620 while ((UBYTE
) *new_pos
!= 0xFF)
623 *(UBYTE
*)at
->attr_cur
)
624 && (AROS_LE2WORD(*((UWORD
*)(new_pos
+ 0xE))) == AROS_LE2WORD(*((UWORD
*)(at
->attr_cur
+ 0x18)))))
626 return (struct MFTAttr
*)new_pos
;
628 new_pos
+= AROS_LE2WORD(*((UWORD
*)(new_pos
+ 4)));
630 D(bug("[NTFS] %s: %u not found in attribute list!\n", __PRETTY_FUNCTION__
, at
->attr_cur
));
637 at
->attr_cur
= at
->attr_nxt
;
639 while (*(UBYTE
*)at
->attr_cur
!= 0xFF)
641 at
->attr_nxt
= (struct MFTAttr
*)((IPTR
)at
->attr_nxt
+ AROS_LE2WORD(at
->attr_cur
->length
));
643 D(bug("[NTFS] %s: attr_cur @ 0x%p, attr_nxt @ 0x%p (offset %u) \n", __PRETTY_FUNCTION__
, at
->attr_cur
, at
->attr_nxt
, AROS_LE2WORD(at
->attr_cur
->length
)));
645 if (*(UBYTE
*)at
->attr_cur
== AT_ATTRIBUTE_LIST
)
646 at
->attr_end
= at
->attr_cur
;
647 if ((*(UBYTE
*)at
->attr_cur
== attr
) || (attr
== 0))
649 D(bug("[NTFS] %s: returning attr_cur @ 0x%p\n", __PRETTY_FUNCTION__
, at
->attr_cur
));
652 at
->attr_cur
= at
->attr_nxt
;
656 struct MFTAttr
*attrentry
;
658 D(bug("[NTFS] %s: attr_end @ 0x%p\n", __PRETTY_FUNCTION__
, at
->attr_end
));
660 at
->emft_buf
= AllocMem(at
->mft
->data
->mft_size
<< SECTORSIZE_SHIFT
, MEMF_ANY
);
661 if (at
->emft_buf
== NULL
)
664 D(bug("[NTFS] %s: emft_buf allocated @ 0x%p\n", __PRETTY_FUNCTION__
, at
->emft_buf
));
666 attrentry
= at
->attr_end
;
668 if (attrentry
->residentflag
== ATTR_NONRESIDENT_FORM
)
672 n
= ((AROS_LE2QUAD(attrentry
->data
.non_resident
.data_size
) + (512 - 1)) & (~(512 - 1)));
673 at
->attr_cur
= at
->attr_end
;
674 at
->edat_buf
= AllocVec(n
, MEMF_ANY
);
678 D(bug("[NTFS] %s: edat_buf allocated @ 0x%p\n", __PRETTY_FUNCTION__
, at
->edat_buf
));
680 if (ReadMFTAttribData(at
, attrentry
, (UBYTE
*)at
->edat_buf
, 0, n
, 0))
682 D(bug("[NTFS] %s: failed to read non-resident attribute list!\n", __PRETTY_FUNCTION__
));
684 at
->attr_nxt
= at
->edat_buf
;
685 /* Note: The extra '(IPTR)' cast here shuts up
686 * gcc warnings on 32-bit architectures
687 * (converting a QUAD to a 32-bit pointer
689 at
->attr_end
= (struct MFTAttr
*)(IPTR
)((IPTR
)at
->edat_buf
+ AROS_LE2QUAD(attrentry
->data
.non_resident
.data_size
));
693 at
->attr_nxt
= (struct MFTAttr
*)((IPTR
)at
->attr_end
+ AROS_LE2WORD(attrentry
->data
.resident
.value_offset
));
694 at
->attr_end
= (struct MFTAttr
*)((IPTR
)at
->attr_end
+ AROS_LE2LONG(attrentry
->length
));
695 D(bug("[NTFS] %s: attr_nxt @ 0x%p, attr_end @ 0x%p\n", __PRETTY_FUNCTION__
, at
->attr_nxt
, at
->attr_end
));
697 at
->flags
|= AF_ALST
;
698 while (at
->attr_nxt
< at
->attr_end
)
700 if ((*(UBYTE
*)at
->attr_nxt
== attr
) || (attr
== 0))
702 at
->attr_nxt
= (struct MFTAttr
*)((IPTR
)at
->attr_nxt
+ AROS_LE2WORD(at
->attr_nxt
->length
));
704 if (at
->attr_nxt
>= at
->attr_end
)
707 if ((at
->flags
& AF_MMFT
) && (attr
== AT_DATA
))
709 D(bug("[NTFS] %s: AT_DATA && AF_MMFT\n", __PRETTY_FUNCTION__
));
711 at
->flags
|= AF_GPOS
;
712 at
->attr_cur
= at
->attr_nxt
;
713 attrentry
= at
->attr_cur
;
714 attrentry
->data
.resident
.value_length
= AROS_LONG2LE(at
->mft
->data
->mft_start
);
715 attrentry
->data
.resident
.value_offset
= AROS_WORD2LE(at
->mft
->data
->mft_start
+ 1);
716 attrentry
= (struct MFTAttr
*)((IPTR
)at
->attr_nxt
+ AROS_LE2WORD(attrentry
->length
));
717 while (attrentry
< at
->attr_end
)
719 if (*(UBYTE
*)attrentry
!= attr
)
722 (at
, (UBYTE
*)(attrentry
+ 0x10),
723 AROS_LE2LONG(attrentry
->data
.resident
.value_length
) * (at
->mft
->data
->mft_size
<< SECTORSIZE_SHIFT
),
724 at
->mft
->data
->mft_size
<< SECTORSIZE_SHIFT
, 0))
726 attrentry
= (struct MFTAttr
*)((IPTR
)attrentry
+ AROS_LE2WORD(attrentry
->length
));
728 at
->attr_nxt
= at
->attr_cur
;
729 at
->flags
&= ~AF_GPOS
;
736 struct MFTAttr
*MapMFTAttrib(struct NTFSMFTAttr
*at
, struct NTFSMFTEntry
*mft
, UBYTE attr
)
738 struct MFTAttr
*attrentry
;
740 D(bug("[NTFS]: %s(%ld)\n", __PRETTY_FUNCTION__
, attr
));
742 INIT_MFTATTRIB(at
, mft
);
743 if ((attrentry
= FindMFTAttrib(at
, attr
)) == NULL
)
746 if ((at
->flags
& AF_ALST
) == 0)
750 if ((attrentry
= FindMFTAttrib(at
, attr
)) == NULL
)
752 if (at
->flags
& AF_ALST
)
756 INIT_MFTATTRIB(at
, mft
);
757 attrentry
= FindMFTAttrib(at
, attr
);
762 IPTR
InitMFTEntry(struct NTFSMFTEntry
*mft
, ULONG mft_id
)
764 struct MFTRecordEntry
*record
;
767 D(bug("[NTFS]: %s(%ld)\n", __PRETTY_FUNCTION__
, mft_id
));
771 if (mft
->buf
!= NULL
)
773 D(bug("[NTFS] %s: NTFSMFTEntry @ 0x%p in use? (mft->buf != NULL)\n", __PRETTY_FUNCTION__
, mft
));
777 mft
->buf
= AllocMem(mft
->data
->mft_size
<< SECTORSIZE_SHIFT
, MEMF_ANY
);
778 if ((record
= (struct MFTRecordEntry
*)mft
->buf
) == NULL
)
780 return ERROR_NO_FREE_STORE
;
783 if (ReadMFTRecord(mft
, mft
->buf
, mft_id
))
785 D(bug("[NTFS] %s: failed to read MFT #%d\n", __PRETTY_FUNCTION__
, mft_id
));
789 flag
= AROS_LE2WORD(record
->flags
);
790 if ((flag
& FILERECORD_SEGMENT_IN_USE
) == 0)
792 D(bug("[NTFS] %s: MFT not in use!\n", __PRETTY_FUNCTION__
));
796 if ((flag
& FILERECORD_NAME_INDEX_PRESENT
) == 0)
798 struct MFTAttr
*attrentry
;
800 attrentry
= MapMFTAttrib(&mft
->attr
, mft
, AT_DATA
);
801 if (attrentry
== NULL
)
803 D(bug("[NTFS] %s: No $DATA in MFT #%d\n", __PRETTY_FUNCTION__
, mft_id
));
807 if (attrentry
->residentflag
== ATTR_RESIDENT_FORM
)
809 mft
->size
= AROS_LE2LONG(*(ULONG
*)((IPTR
)attrentry
+ 0x10));
813 mft
->size
= AROS_LE2QUAD(*(UQUAD
*)((IPTR
)attrentry
+ 0x30));
816 if ((mft
->attr
.flags
& AF_ALST
) == 0)
817 mft
->attr
.attr_end
= 0; /* Don't jump to attribute list */
821 INIT_MFTATTRIB(&mft
->attr
, mft
);
828 ProcessFSEntry(struct NTFSMFTEntry
*diro
, struct DirEntry
*de
, ULONG
**countptr
)
834 D(bug("[NTFS]: %s(NTFSMFTEntry @ 0x%p)\n", __PRETTY_FUNCTION__
, diro
));
839 D(bug("[NTFS] %s: counter @ 0x%p, val = %d\n", __PRETTY_FUNCTION__
, count
, *count
));
846 D(bug("[NTFS] %s: pos = 0x%p\n", __PRETTY_FUNCTION__
, de
->key
->pos
));
849 if (de
->key
->pos
>= de
->key
->indx
+ (diro
->data
->idx_size
<< SECTORSIZE_SHIFT
))
851 D(bug("[NTFS] %s: reached index record buffer end\n", __PRETTY_FUNCTION__
));
856 if (de
->key
->pos
[0xC] & INDEX_ENTRY_END
) /* end of index signature */
858 D(bug("[NTFS] %s: reached index-record end signature\n", __PRETTY_FUNCTION__
));
863 np
= de
->key
->pos
+ 0x50;
864 ns_len
= (UBYTE
) *(np
++);
867 D(bug("[NTFS] %s: np = 0x%p, ns_len = %d (type = %d)\n", __PRETTY_FUNCTION__
, np
, ns_len
, ns_type
));
869 /* ignore DOS namespace files (we want Win32 versions) */
870 if ((ns_len
) && (ns_type
!= 2))
874 if (AROS_LE2WORD(*((UWORD
*)(de
->key
->pos
+ 4))))
876 D(bug("[NTFS] %s: **skipping** [64bit mft number]\n", __PRETTY_FUNCTION__
));
880 D(bug("[NTFS] %s: type = %d\n", __PRETTY_FUNCTION__
, AROS_LE2LONG(*((ULONG
*)(de
->key
->pos
+ 0x48)))));
884 FreeVec(de
->entryname
);
885 de
->entryname
= NULL
;
894 de
->entry
= AllocMem(sizeof (struct NTFSMFTEntry
), MEMF_ANY
|MEMF_CLEAR
);
898 D(bug("[NTFS] %s: failed to allocate NTFSMFTEntry\n", __PRETTY_FUNCTION__
));
899 return ERROR_NO_FREE_STORE
;
902 de
->entry
->data
= diro
->data
;
904 de
->entry
->mftrec_no
= AROS_LE2LONG(*(ULONG
*)de
->key
->pos
);
906 de
->entrytype
= AROS_LE2LONG(*((ULONG
*)(de
->key
->pos
+ 0x48)));
908 if ((de
->entryname
= AllocVec(ns_len
+ 1, MEMF_ANY
)) == NULL
)
909 return ERROR_NO_FREE_STORE
;
911 for (i
= 0; i
< ns_len
; i
++)
913 de
->entryname
[i
] = glob
->from_unicode
[AROS_LE2WORD(*((UWORD
*)(np
+ (i
* 2))))];
915 de
->entryname
[ns_len
] = '\0';
918 bug("[NTFS] %s: ", __PRETTY_FUNCTION__
);
921 bug("[#%d]", *count
);
923 bug(" Label '%s'\n", de
->entryname
);
926 if ((!count
) || ((count
) && (*count
== de
->no
)))
930 de
->key
->pos
+= AROS_LE2WORD(*((UWORD
*)(de
->key
->pos
+ 8)));
935 int bitcount(ULONG n
)
937 register unsigned int tmp
;
938 tmp
= n
- ((n
>> 1) & 033333333333)
939 - ((n
>> 2) & 011111111111);
940 return ((tmp
+ (tmp
>> 3)) & 030707070707) % 63;
943 LONG
ReadBootSector(struct FSData
*fs_data
)
945 struct DosEnvec
*de
= BADDR(glob
->fssm
->fssm_Environ
);
947 ULONG bsize
= de
->de_SizeBlock
* 4;
948 struct NTFSBootSector
*boot
;
949 BOOL invalid
= FALSE
;
952 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__
));
954 boot
= AllocMem(bsize
, MEMF_ANY
);
956 return ERROR_NO_FREE_STORE
;
959 * Read the boot sector. We go direct because we don't have a cache yet,
960 * and can't create one until we know the sector size, which is held in
961 * the boot sector. In practice it doesn't matter - we're going to use
962 * this once and once only.
964 fs_data
->first_device_sector
=
965 de
->de_BlocksPerTrack
* de
->de_Surfaces
* de
->de_LowCyl
;
967 D(bug("[NTFS] %s: trying bootsector at sector %ld (%ld bytes)\n", __PRETTY_FUNCTION__
, fs_data
->first_device_sector
, bsize
));
969 if ((err
= AccessDisk(FALSE
, fs_data
->first_device_sector
, 1, bsize
, (UBYTE
*)boot
)) != 0) {
970 D(bug("[NTFS] %s: failed to read boot block (%ld)\n", __PRETTY_FUNCTION__
, err
));
971 FreeMem(boot
, bsize
);
975 /* check for NTFS signature */
976 if (boot
->oem_name
[0] != 'N' || boot
->oem_name
[1] != 'T' || boot
->oem_name
[2] != 'F' || boot
->oem_name
[3] != 'S')
981 D(bug("[NTFS] %s: invalid NTFS bootsector\n", __PRETTY_FUNCTION__
));
982 FreeMem(boot
, bsize
);
983 return ERROR_NOT_A_DOS_DISK
;
986 D(bug("[NTFS] %s: NTFSBootsector:\n", __PRETTY_FUNCTION__
));
988 fs_data
->sectorsize
= AROS_LE2WORD(boot
->bytes_per_sector
);
989 fs_data
->sectorsize_bits
= ilog2(fs_data
->sectorsize
);
990 D(bug("[NTFS] %s:\tSectorSize = %ld\n", __PRETTY_FUNCTION__
, fs_data
->sectorsize
));
991 D(bug("[NTFS] %s:\tSectorSize Bits = %ld\n", __PRETTY_FUNCTION__
, fs_data
->sectorsize_bits
));
993 fs_data
->cluster_sectors
= boot
->sectors_per_cluster
;
994 fs_data
->clustersize
= fs_data
->sectorsize
* fs_data
->cluster_sectors
;
995 fs_data
->clustersize_bits
= ilog2(fs_data
->clustersize
);
996 fs_data
->cluster_sectors_bits
= fs_data
->clustersize_bits
- fs_data
->sectorsize_bits
;
998 D(bug("[NTFS] %s:\tSectorsPerCluster = %ld\n", __PRETTY_FUNCTION__
, fs_data
->cluster_sectors
));
999 D(bug("[NTFS] %s:\tClusterSize = %ld\n", __PRETTY_FUNCTION__
, fs_data
->clustersize
));
1000 D(bug("[NTFS] %s:\tClusterSize Bits = %ld\n", __PRETTY_FUNCTION__
, fs_data
->clustersize_bits
));
1001 D(bug("[NTFS] %s:\tCluster Sectors Bits = %ld\n", __PRETTY_FUNCTION__
, fs_data
->cluster_sectors_bits
));
1003 fs_data
->total_sectors
= AROS_LE2QUAD(boot
->number_of_sectors
);
1005 D(bug("[NTFS] %s:\tVolumeSize in sectors = %ld\n", __PRETTY_FUNCTION__
, fs_data
->total_sectors
));
1006 D(bug("[NTFS] %s:\t in bytes = %ld\n", __PRETTY_FUNCTION__
, fs_data
->total_sectors
* fs_data
->sectorsize
));
1008 /* Warning : TODO - check the volume /drive can be properly accessed */
1009 if ((fs_data
->first_device_sector
+ fs_data
->total_sectors
- 1 > end
) && (glob
->readcmd
== CMD_READ
))
1011 D(bug("[NTFS] %s: volume is too large\n", __PRETTY_FUNCTION__
));
1012 FreeMem(boot
, bsize
);
1013 return IOERR_BADADDRESS
;
1017 fs_data
->cache
= Cache_CreateCache(64, 64, fs_data
->sectorsize
);
1019 D(bug("[NTFS] %s: allocated cache @ 0x%p (64,64,%d)\n", __PRETTY_FUNCTION__
, fs_data
->cache
, fs_data
->sectorsize
));
1021 if (boot
->clusters_per_mft_record
> 0)
1022 fs_data
->mft_size
= fs_data
->cluster_sectors
* boot
->clusters_per_mft_record
;
1024 fs_data
->mft_size
= 1 << (-boot
->clusters_per_mft_record
- SECTORSIZE_SHIFT
);
1026 D(bug("[NTFS] %s:\tMFTRecordSize = %ld (%ld clusters per record)\n", __PRETTY_FUNCTION__
, fs_data
->mft_size
, boot
->clusters_per_mft_record
));
1028 if (boot
->clusters_per_index_record
> 0)
1029 fs_data
->idx_size
= fs_data
->cluster_sectors
* boot
->clusters_per_index_record
;
1031 fs_data
->idx_size
= 1 << (-boot
->clusters_per_index_record
- SECTORSIZE_SHIFT
);
1033 D(bug("[NTFS] %s:\tIndexRecordSize = %ld (%ld clusters per index)\n", __PRETTY_FUNCTION__
, fs_data
->idx_size
, boot
->clusters_per_index_record
));
1035 fs_data
->mft_start
= AROS_LE2QUAD(boot
->mft_lcn
) * fs_data
->cluster_sectors
;
1037 D(bug("[NTFS] %s:\tMFTStart = %ld\n", __PRETTY_FUNCTION__
, fs_data
->mft_start
));
1039 fs_data
->mft
.buf
= AllocMem(fs_data
->mft_size
* fs_data
->sectorsize
, MEMF_ANY
);
1040 if (!fs_data
->mft
.buf
)
1042 FreeMem(boot
, bsize
);
1043 return ERROR_NO_FREE_STORE
;
1046 /* Warning: todo - UUID stored in LE format- do we need to convert it? */
1047 boot
->volume_serial_number
= AROS_LE2QUAD(boot
->volume_serial_number
);
1048 UUID_Copy((const uuid_t
*)&boot
->volume_serial_number
, (uuid_t
*)&fs_data
->uuid
);
1051 char uuid_str
[UUID_STRLEN
+ 1];
1052 uuid_str
[UUID_STRLEN
] = 0;
1054 /* convert UUID into human-readable format */
1055 UUID_Unparse(&fs_data
->uuid
, uuid_str
);
1057 bug("[NTFS] %s:\tVolumeSerial = %s\n", __PRETTY_FUNCTION__
, uuid_str
);
1060 for (i
= 0; i
< fs_data
->mft_size
; i
++)
1062 if ((fs_data
->mft
.cblock
= Cache_GetBlock(fs_data
->cache
, fs_data
->first_device_sector
+ fs_data
->mft_start
+ i
, &fs_data
->mft
.cbuf
)) == NULL
)
1065 D(bug("[NTFS] %s: failed to read MFT (error:%ld)\n", __PRETTY_FUNCTION__
, err
));
1066 FreeMem(fs_data
->mft
.buf
, fs_data
->mft_size
* fs_data
->sectorsize
);
1067 FreeMem(boot
, bsize
);
1070 CopyMem(fs_data
->mft
.cbuf
, fs_data
->mft
.buf
+ (i
* fs_data
->sectorsize
), fs_data
->sectorsize
);
1071 Cache_FreeBlock(fs_data
->cache
, fs_data
->mft
.cblock
);
1072 fs_data
->mft
.cblock
= NULL
;
1075 #if defined(DEBUG_MFT)
1079 bug("[NTFS] %s: MFTRecord Dump -:\n", __PRETTY_FUNCTION__
);
1080 bug("[NTFS] %s: MFTRecord buf @ 0x%p, size %d x %d", __PRETTY_FUNCTION__
, fs_data
->mft
.buf
, fs_data
->mft_size
, fs_data
->sectorsize
);
1082 for (dumpx
= 0; dumpx
< (fs_data
->mft_size
* fs_data
->sectorsize
) ; dumpx
++)
1084 if ((dumpx
%16) == 0)
1086 bug("\n[NTFS] %s:\t%03x:", __PRETTY_FUNCTION__
, dumpx
);
1088 bug(" %02x", ((UBYTE
*)fs_data
->mft
.buf
)[dumpx
]);
1094 fs_data
->mft
.data
= fs_data
;
1095 if (PostProcessMFTRecord (fs_data
, (struct MFTRecordEntry
*)fs_data
->mft
.buf
, fs_data
->mft_size
, "FILE"))
1097 FreeMem(fs_data
->mft
.buf
, fs_data
->mft_size
* fs_data
->sectorsize
);
1098 FreeMem(boot
, bsize
);
1099 return ERROR_NO_FREE_STORE
;
1102 #if defined(DEBUG_MFT)
1104 bug("[NTFS] %s: MFTRecord Dump (Post Processing) -:\n", __PRETTY_FUNCTION__
);
1105 bug("[NTFS] %s: MFTRecord buf @ 0x%p, size %d x %d", __PRETTY_FUNCTION__
, fs_data
->mft
.buf
, fs_data
->mft_size
, fs_data
->sectorsize
);
1107 for (dumpx
= 0; dumpx
< (fs_data
->mft_size
* fs_data
->sectorsize
) ; dumpx
++)
1109 if ((dumpx
%16) == 0)
1111 bug("\n[NTFS] %s:\t%03x:", __PRETTY_FUNCTION__
, dumpx
);
1113 bug(" %02x", ((UBYTE
*)fs_data
->mft
.buf
)[dumpx
]);
1119 if (!MapMFTAttrib(&fs_data
->mft
.attr
, &fs_data
->mft
, AT_DATA
))
1121 D(bug("[NTFS] %s: no $DATA in MFT\n", __PRETTY_FUNCTION__
));
1122 FreeMem(fs_data
->mft
.buf
, fs_data
->mft_size
* fs_data
->sectorsize
);
1123 FreeMem(boot
, bsize
);
1124 return ERROR_NO_FREE_STORE
;
1127 struct DirHandle dh
;
1128 dh
.ioh
.mft
.buf
= NULL
;
1129 dh
.ioh
.mft
.mftrec_no
= FILE_ROOT
;
1130 InitDirHandle(fs_data
, &dh
, FALSE
);
1132 struct DirEntry dir_entry
;
1133 memset(&dir_entry
, 0, sizeof(struct DirEntry
));
1134 dir_entry
.data
= fs_data
;
1135 while ((err
= GetDirEntry(&dh
, dh
.cur_no
+ 1, &dir_entry
)) == 0)
1137 struct MFTAttr
*attrentry
;
1139 if (strcmp(dir_entry
.entryname
, "$MFT") == 0)
1141 D(bug("[NTFS] %s: ## found $MFT entry\n", __PRETTY_FUNCTION__
));
1143 INIT_MFTATTRIB(&dir_entry
.entry
->attr
, dir_entry
.entry
);
1144 attrentry
= FindMFTAttrib(&dir_entry
.entry
->attr
, AT_STANDARD_INFORMATION
);
1145 if ((attrentry
) && (attrentry
->residentflag
== ATTR_RESIDENT_FORM
) && (AROS_LE2LONG(attrentry
->data
.resident
.value_length
) > 0))
1147 attrentry
= (struct MFTAttr
*)((IPTR
)attrentry
+ AROS_LE2WORD(attrentry
->data
.resident
.value_offset
));
1149 D(bug("[NTFS] %s: nfstime = %d\n", __PRETTY_FUNCTION__
, *(UQUAD
*)attrentry
));
1151 NTFS2DateStamp((UQUAD
*)attrentry
, &fs_data
->volume
.create_time
);
1153 D(bug("[NTFS] %s:\tVolumeDate: %ld days, %ld, minutes, %ld ticks \n", __PRETTY_FUNCTION__
, fs_data
->volume
.create_time
.ds_Days
, fs_data
->volume
.create_time
.ds_Minute
, fs_data
->volume
.create_time
.ds_Tick
));
1156 else if (strcmp(dir_entry
.entryname
, "$Volume") == 0)
1158 D(bug("[NTFS] %s: ## found $Volume label entry\n", __PRETTY_FUNCTION__
));
1160 INIT_MFTATTRIB(&dir_entry
.entry
->attr
, dir_entry
.entry
);
1161 attrentry
= FindMFTAttrib(&dir_entry
.entry
->attr
, AT_VOLUME_NAME
);
1162 if ((attrentry
) && (attrentry
->residentflag
== ATTR_RESIDENT_FORM
) && (AROS_LE2LONG(attrentry
->data
.resident
.value_length
) > 0))
1165 fs_data
->volume
.name
[0] = (UBYTE
)(AROS_LE2LONG(attrentry
->data
.resident
.value_length
) / 2) + 1;
1166 attrentry
= (struct MFTAttr
*)((IPTR
)attrentry
+ AROS_LE2WORD(attrentry
->data
.resident
.value_offset
));
1168 if (fs_data
->volume
.name
[0] > 30)
1169 fs_data
->volume
.name
[0] = 30;
1171 for (i
= 0; i
< fs_data
->volume
.name
[0]; i
++)
1173 fs_data
->volume
.name
[i
+ 1] = glob
->from_unicode
[AROS_LE2WORD(*((UWORD
*)((IPTR
)attrentry
+ (i
* 2))))];
1175 fs_data
->volume
.name
[fs_data
->volume
.name
[0]] = '\0';
1177 D(bug("[NTFS] %s:\tVolumeLabel = '%s'\n", __PRETTY_FUNCTION__
, &fs_data
->volume
.name
[1]));
1180 else if (strcmp(dir_entry
.entryname
, "$Bitmap") == 0)
1182 struct NTFSMFTAttr bitmapatrr
;
1184 int i
, allocated
= 0;
1186 D(bug("[NTFS] %s: ## found $Bitmap entry\n", __PRETTY_FUNCTION__
));
1187 D(bug("[NTFS] %s: ## size = %u\n", __PRETTY_FUNCTION__
, dir_entry
.entry
->size
));
1189 MFTBitmap
= AllocVec(dir_entry
.entry
->size
, MEMF_ANY
);
1191 INIT_MFTATTRIB(&bitmapatrr
, dir_entry
.entry
);
1192 if (MapMFTAttrib (&bitmapatrr
, dir_entry
.entry
, AT_DATA
))
1194 if (ReadMFTAttrib(&bitmapatrr
, MFTBitmap
, 0, dir_entry
.entry
->size
, 0) == 0)
1196 D(bug("[NTFS] %s: read $Bitmap into buffer @ 0x%p\n", __PRETTY_FUNCTION__
, MFTBitmap
));
1197 for (i
= 0; i
< (dir_entry
.entry
->size
/ 4); i
++)
1199 allocated
+= bitcount(*(ULONG
*)(MFTBitmap
+ (i
* 4)));
1201 D(bug("[NTFS] %s: allocated = %u\n", __PRETTY_FUNCTION__
, allocated
));
1202 fs_data
->used_sectors
= allocated
* fs_data
->cluster_sectors
;
1208 if (fs_data
->volume
.name
[0] == '\0')
1210 char tmp
[UUID_STRLEN
+ 1];
1212 UUID_Unparse(&fs_data
->uuid
, tmp
);
1213 for (i
= 0; i
< UUID_STRLEN
; i
++)
1217 tmp
[t
++] = tmp
[i
+ 1];
1223 CopyMem(tmp
, fs_data
->volume
.name
, 30);
1224 fs_data
->volume
.name
[31] = '\0';
1227 bug("[NTFS] %s: successfully detected NTFS Filesystem.\n", __PRETTY_FUNCTION__
);
1229 FreeMem(boot
, bsize
);
1233 void FreeBootSector(struct FSData
*fs_data
)
1235 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__
));
1237 D(bug("[NTFS] %s: removing NTFSBootsector from memory\n", __PRETTY_FUNCTION__
));
1239 Cache_DestroyCache(fs_data
->cache
);