Change gfx.hidd API -:
[AROS.git] / workbench / fs / ntfs / ntfs.c
blobfe0682e1404c327d802f371589a015a4e2d8c0f5
1 /*
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.
9 * $Id $
12 #include <aros/macros.h>
13 #include <exec/errors.h>
14 #include <exec/types.h>
15 #include <dos/dos.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>
27 #include <string.h>
28 #include <ctype.h>
30 #include "ntfs_fs.h"
31 #include "ntfs_protos.h"
33 //#define DEBUG_MFT
34 #include "debug.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;
76 seqarray += 2;
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);
84 seqarray_len--;
87 D(bug("[NTFS] %s: record fixup complete\n", __PRETTY_FUNCTION__));
89 return 0;
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 */
98 return 0;
101 struct MFTAttr *GetMappingPairPos(UBYTE *mappos, int nn, UQUAD *val, int sig)
103 UQUAD pos = 0;
104 UQUAD mask = 1;
106 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__));
108 while (nn--)
110 pos += mask * (*mappos);
111 mappos += 1;
112 mask <<= 8;
115 if ((sig) && (pos & (mask >> 1)))
116 pos -= mask;
118 *val = pos;
119 return (struct MFTAttr *)mappos;
122 IPTR ReadNTFSRunList(struct NTFSRunLstEntry * rle)
124 int len, offs;
125 UQUAD val;
126 struct MFTAttr *mappos = (struct MFTAttr *)rle->mappingpair;
128 D(bug("[NTFS]: %s(mappos @ 0x%p)\n", __PRETTY_FUNCTION__, mappos));
130 retry:
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));
137 if (!len)
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);
146 if (mappos)
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__));
152 return ~0;
155 mappos = (struct MFTAttr *)(IPTR)((IPTR)mappos + AROS_LE2WORD(mappos->data.non_resident.mapping_pairs_offset));
156 rle->curr_lcn = 0;
157 goto retry;
160 D(bug("[NTFS] %s: run list overflow\n", __PRETTY_FUNCTION__));
161 return ~0;
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));
176 if (val == 0)
177 rle->flags |= RLEFLAG_SPARSE;
178 else
179 rle->flags &= ~RLEFLAG_SPARSE;
181 rle->mappingpair = (UBYTE *)mappos;
183 return 0;
186 void FreeMFTAttrib(struct NTFSMFTAttr *at)
188 D(bug("[NTFS]: %s(NTFSMFTAttr @ 0x%p)\n", __PRETTY_FUNCTION__, at));
190 FreeVec(at->edat_buf);
191 at->edat_buf = NULL;
192 if (at->emft_buf)
194 FreeMem(at->emft_buf, at->mft->data->mft_size << SECTORSIZE_SHIFT);
195 at->emft_buf = NULL;
197 if (at->sbuf)
199 FreeMem(at->sbuf, COM_LEN);
200 at->sbuf = NULL;
204 IPTR ReadMFTAttribData(struct NTFSMFTAttr *at, struct MFTAttr *attrentry, UBYTE *dest, UQUAD ofs, ULONG len, int cached)
206 D(UQUAD vcn);
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);
216 if (len == 0)
217 return 0;
219 memset (&runlist_entry, 0, sizeof(struct NTFSRunLstEntry));
220 rle = &runlist_entry;
221 rle->attr = at;
223 if (AROS_LE2LONG(attrentry->data.resident.value_offset) > AROS_LE2LONG(attrentry->length))
225 D(bug("[NTFS] %s: error - corrupt attribute\n", __PRETTY_FUNCTION__));
226 return ~0;
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__));
236 return ~0;
238 CopyMem(attrentry + AROS_LE2LONG(attrentry->data.resident.value_offset) + ofs, dest, len);
239 return 0;
242 if (AROS_LE2WORD(attrentry->attrflags) & FLAG_COMPRESSED)
244 rle->flags |= RLEFLAG_COMPR;
246 else
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__));
257 if (!cached)
259 D(bug("[NTFS] %s: error - attribute cannot be compressed\n", __PRETTY_FUNCTION__));
260 return ~0;
263 if (at->sbuf)
265 if ((ofs & (~(COM_LEN - 1))) == at->save_pos)
267 UQUAD n;
269 n = COM_LEN - (ofs - at->save_pos);
270 if (n > len)
271 n = len;
273 CopyMem(at->sbuf + ofs - at->save_pos, dest, n);
274 if (n == len)
275 return 0;
277 dest += n;
278 len -= n;
279 ofs += n;
282 else
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;
290 at->save_pos = 1;
293 D(vcn =) rle->target_vcn = (ofs >> COM_LOG_LEN) * (COM_SEC / at->mft->data->cluster_sectors);
294 rle->target_vcn &= ~0xF;
296 else
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);
303 rle->curr_lcn = 0;
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__));
313 return ~0;
317 D(bug("[NTFS] %s: next_vcn = %u\n", __PRETTY_FUNCTION__, (IPTR)rle->next_vcn));
319 if (at->flags & AF_GPOS)
321 UQUAD st0, st1, m;
323 D(bug("[NTFS] %s: AF_GPOS\n", __PRETTY_FUNCTION__));
325 m = (ofs >> SECTORSIZE_SHIFT) % at->mft->data->cluster_sectors;
327 st0 =
328 (rle->target_vcn - rle->curr_vcn + rle->curr_lcn) * at->mft->data->cluster_sectors + m;
329 st1 = st0 + 1;
331 if (st1 ==
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__));
337 return ~0;
339 st1 = rle->curr_lcn * at->mft->data->cluster_sectors;
341 *((ULONG *)dest) = AROS_LONG2LE(st0);
342 *((ULONG *)(dest + 4)) = AROS_LONG2LE(st1);
343 return 0;
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);
354 UBYTE *buf = dest;
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++)
365 UQUAD blockstart;
366 UQUAD blockoff = ofs & (blocksize - 1);
367 UQUAD blockend = blocksize;
368 UQUAD skipfirst = 0;
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__));
380 return -1;
383 blockstart = rle->curr_lcn;
385 else
387 blockstart = (rle->flags & RLEFLAG_SPARSE) ? 0 : (i - rle->curr_vcn + rle->curr_lcn);
390 blockstart = blockstart << sectbits_shift;
392 /* Last block. */
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. */
400 if (! blockend)
401 blockend = blocksize;
404 /* First block. */
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);
421 if (blockstart)
423 UQUAD blocknr, skipblocks = skipfirst >> SECTORSIZE_SHIFT, lastblock = ((blockend + skipfirst) >> SECTORSIZE_SHIFT);
424 APTR blockbuf, bufstart = buf;
425 IPTR copysize;
427 if (lastblock == 0)
428 lastblock = 1;
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__));
440 return IoErr();
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));
447 else
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));
456 else
458 blockbuf = at->mft->cbuf;
461 if (copysize > 0)
463 D(bug("[NTFS] %s: copying %u bytes from 0x%p -> 0x%p\n", __PRETTY_FUNCTION__, copysize, blockbuf, bufstart));
464 CopyMem(blockbuf, bufstart, copysize);
466 bufstart +=copysize;
468 Cache_FreeBlock(at->mft->data->cache, at->mft->cblock);
469 at->mft->cblock = NULL;
473 else
474 memset (buf, 0, blockend);
476 buf += blocksize - skipfirst;
480 return 0;
483 /* Warning : TODO - decompress block */
484 D(bug("[NTFS] %s: cannot decompress\n", __PRETTY_FUNCTION__));
485 return ~0;
488 IPTR ReadMFTAttrib(struct NTFSMFTAttr *at, UBYTE *dest, UQUAD ofs, ULONG len, int cached)
490 struct MFTAttr *save_cur;
491 UBYTE attr;
492 struct MFTAttr *attrentry;
493 IPTR ret;
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)
502 UQUAD vcn;
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)
511 break;
512 if (AROS_LE2LONG(*((ULONG *)(attrentry + 8))) > vcn)
513 break;
514 at->attr_nxt = attrentry;
515 attrentry = (struct MFTAttr *)((IPTR)attrentry + AROS_LE2WORD(attrentry->length));
518 attrentry = FindMFTAttrib(at, attr);
519 if (attrentry)
520 ret = ReadMFTAttribData(at, attrentry, dest, ofs, len, cached);
521 else
523 D(bug("[NTFS] %s: attribute %u not found\n", __PRETTY_FUNCTION__, attr));
524 ret = ~0;
526 at->attr_cur = save_cur;
527 return ret;
530 static IPTR ReadMFTRecord(struct NTFSMFTEntry *mft, UBYTE *buf, ULONG mft_id)
532 D(bug("[NTFS]: %s(%d)\n", __PRETTY_FUNCTION__, mft_id));
534 if (ReadMFTAttrib
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));
539 return ~0;
541 #if defined(DEBUG_MFT)
543 int dumpx;
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 ++)
550 if ((dumpx%16) == 0)
552 bug("\n[NTFS] %s:\t%03x:", __PRETTY_FUNCTION__, dumpx);
554 bug(" %02x", ((UBYTE*)buf)[dumpx]);
556 bug("\n");
558 #endif
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__));
569 retry:
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))
579 UBYTE *new_pos;
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__));
590 return NULL;
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__));
599 return NULL;
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,
607 "FILE"))
608 return NULL;
610 else
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)))
616 return NULL;
619 new_pos = &((UBYTE *)at->emft_buf)[AROS_LE2WORD(at->emft_buf->data.resident.value_offset)];
620 while ((UBYTE) *new_pos != 0xFF)
622 if ((*new_pos ==
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));
631 return NULL;
634 return NULL;
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));
650 return at->attr_cur;
652 at->attr_cur = at->attr_nxt;
654 if (at->attr_end)
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)
662 return 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)
670 int n;
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);
675 if (!at->edat_buf)
676 return NULL;
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));
691 else
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))
701 break;
702 at->attr_nxt = (struct MFTAttr *)((IPTR)at->attr_nxt + AROS_LE2WORD(at->attr_nxt->length));
704 if (at->attr_nxt >= at->attr_end)
705 return NULL;
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)
720 break;
721 if (ReadMFTAttrib
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))
725 return NULL;
726 attrentry = (struct MFTAttr *)((IPTR)attrentry + AROS_LE2WORD(attrentry->length));
728 at->attr_nxt = at->attr_cur;
729 at->flags &= ~AF_GPOS;
731 goto retry;
733 return NULL;
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)
744 return NULL;
746 if ((at->flags & AF_ALST) == 0)
748 while (1)
750 if ((attrentry = FindMFTAttrib(at, attr)) == NULL)
751 break;
752 if (at->flags & AF_ALST)
753 return attrentry;
755 FreeMFTAttrib(at);
756 INIT_MFTATTRIB(at, mft);
757 attrentry = FindMFTAttrib(at, attr);
759 return attrentry;
762 IPTR InitMFTEntry(struct NTFSMFTEntry *mft, ULONG mft_id)
764 struct MFTRecordEntry *record;
765 unsigned short flag;
767 D(bug("[NTFS]: %s(%ld)\n", __PRETTY_FUNCTION__, mft_id));
769 mft->buf_filled = 1;
771 if (mft->buf != NULL)
773 D(bug("[NTFS] %s: NTFSMFTEntry @ 0x%p in use? (mft->buf != NULL)\n", __PRETTY_FUNCTION__, mft));
774 return ~0;
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));
786 return ~0;
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__));
793 return ~0;
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));
804 return ~0;
807 if (attrentry->residentflag == ATTR_RESIDENT_FORM)
809 mft->size = AROS_LE2LONG(*(ULONG *)((IPTR)attrentry + 0x10));
811 else
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 */
819 else
821 INIT_MFTATTRIB(&mft->attr, mft);
824 return 0;
827 LONG
828 ProcessFSEntry(struct NTFSMFTEntry *diro, struct DirEntry *de, ULONG **countptr)
830 ULONG *count = NULL;
831 UBYTE *np;
832 int ns_len;
834 D(bug("[NTFS]: %s(NTFSMFTEntry @ 0x%p)\n", __PRETTY_FUNCTION__, diro));
836 if (countptr)
838 count = *countptr;
839 D(bug("[NTFS] %s: counter @ 0x%p, val = %d\n", __PRETTY_FUNCTION__, count, *count));
842 while (1)
844 UBYTE ns_type;
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__));
852 de->key->pos = 0;
853 return 0;
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__));
859 de->key->pos = 0;
860 return 0;
863 np = de->key->pos + 0x50;
864 ns_len = (UBYTE) *(np++);
865 ns_type = *(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))
872 int i;
874 if (AROS_LE2WORD(*((UWORD *)(de->key->pos + 4))))
876 D(bug("[NTFS] %s: **skipping** [64bit mft number]\n", __PRETTY_FUNCTION__));
877 return 0;
880 D(bug("[NTFS] %s: type = %d\n", __PRETTY_FUNCTION__, AROS_LE2LONG(*((ULONG *)(de->key->pos + 0x48)))));
882 if (de)
884 FreeVec(de->entryname);
885 de->entryname = NULL;
888 if (de && de->data)
890 if (count)
891 *count += 1;
893 if (!de->entry)
894 de->entry = AllocMem(sizeof (struct NTFSMFTEntry), MEMF_ANY|MEMF_CLEAR);
896 if (!de->entry)
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__);
919 if (count)
921 bug("[#%d]", *count);
923 bug(" Label '%s'\n", de->entryname);
926 if ((!count) || ((count) && (*count == de->no)))
927 return 1;
930 de->key->pos += AROS_LE2WORD(*((UWORD *)(de->key->pos + 8)));
932 return 0;
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);
946 LONG err;
947 ULONG bsize = de->de_SizeBlock * 4;
948 struct NTFSBootSector *boot;
949 BOOL invalid = FALSE;
950 int i;
952 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__));
954 boot = AllocMem(bsize, MEMF_ANY);
955 if (!boot)
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);
972 return err;
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')
977 invalid = TRUE;
979 if (invalid)
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));
1007 #if (0)
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;
1015 #endif
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;
1023 else
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;
1030 else
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)
1064 err = IoErr();
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);
1068 return err;
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)
1077 int dumpx;
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]);
1090 bug("\n");
1092 #endif
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]);
1115 bug("\n");
1117 #endif
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))
1164 int i;
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;
1183 UBYTE *MFTBitmap;
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];
1211 int t = 0;
1212 UUID_Unparse(&fs_data->uuid, tmp);
1213 for (i = 0; i < UUID_STRLEN; i++)
1215 if (tmp[i] == '-')
1217 tmp[t++] = tmp[i + 1];
1218 i ++;
1220 else
1221 t++;
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);
1230 return 0;
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);