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/types.h>
15 #include <proto/exec.h>
16 #include <proto/dos.h>
23 #include "ntfs_protos.h"
27 LONG
InitDirHandle(struct FSData
*fs_data
, struct DirHandle
*dh
, BOOL reuse
)
29 struct MFTAttr
*curattr
;
34 D(bug("[NTFS]: %s(%u)\n", __PRETTY_FUNCTION__
, dh
->ioh
.mft
.mftrec_no
));
36 /* dh may or may not be initialised when this is called. if it is, then it
37 * probably has a valid cache block that we need to free, but we wouldn't
38 * know. we test the superblock pointer to figure out if it's valid or
40 if (reuse
&& (dh
->ioh
.data
== fs_data
)) {
41 D(bug("[NTFS] %s: re-using directory handle\n", __PRETTY_FUNCTION__
));
42 if (dh
->ioh
.mft
.cblock
!= NULL
) {
43 Cache_FreeBlock(fs_data
->cache
, dh
->ioh
.mft
.cblock
);
44 dh
->ioh
.mft
.cblock
= NULL
;
48 dh
->ioh
.data
= fs_data
;
49 dh
->ioh
.mft
.cblock
= NULL
;
54 dh
->ioh
.mft
.data
= fs_data
;
55 dh
->ioh
.first_cluster
= dh
->ioh
.mft
.mftrec_no
* fs_data
->mft_size
;
57 InitMFTEntry(&dh
->ioh
.mft
, dh
->ioh
.mft
.mftrec_no
);
59 INIT_MFTATTRIB(&dh
->ioh
.mft
.attr
, &dh
->ioh
.mft
);
63 if ((curattr
= FindMFTAttrib(&dh
->ioh
.mft
.attr
, AT_INDEX_ROOT
)) == NULL
)
65 D(bug("[NTFS] %s: no $INDEX_ROOT found!\n", __PRETTY_FUNCTION__
));
69 if ((curattr
->residentflag
!= ATTR_RESIDENT_FORM
) ||
70 (curattr
->attrname_length
!= 4) ||
71 (AROS_LE2WORD(curattr
->attrname_offset
) != 0x18) ||
72 (AROS_LE2LONG(*((ULONG
*)((IPTR
)curattr
+ 0x18))) != 0x00490024) ||
73 (AROS_LE2LONG(*((ULONG
*)((IPTR
)curattr
+ 0x1c))) != 0x00300033))
77 curattr
= (struct MFTAttr
*)((IPTR
)curattr
+ AROS_LE2WORD(curattr
->data
.resident
.value_offset
));
78 if (*(UBYTE
*)curattr
!= 0x30) /* Not filename index */
85 dh
->idx_root
= (UBYTE
*)curattr
+ 0x10;
86 dh
->idx_root
+= AROS_LE2WORD(*(UWORD
*)(dh
->idx_root
));
88 D(bug("[NTFS] %s: idx_root @ 0x%p\n", __PRETTY_FUNCTION__
, dh
->idx_root
));
90 dh
->ioh
.bitmap
= NULL
;
91 dh
->ioh
.bitmap_len
= 0;
93 FreeMFTAttrib(&dh
->ioh
.mft
.attr
);
94 INIT_MFTATTRIB(&dh
->ioh
.mft
.attr
, &dh
->ioh
.mft
);
95 while ((curattr
= FindMFTAttrib(&dh
->ioh
.mft
.attr
, AT_BITMAP
)) != NULL
)
99 ofs
= ((UBYTE
*)curattr
)[0xA];
100 if ((curattr
->attrname_length
== 4) &&
101 (AROS_LE2LONG(*((ULONG
*)((IPTR
)curattr
+ ofs
))) == 0x00490024) &&
102 (AROS_LE2LONG(*((ULONG
*)((IPTR
)curattr
+ ofs
+ 4))) == 0x00300033)) /* "$I30" */
104 int is_resident
= (curattr
->residentflag
== ATTR_RESIDENT_FORM
);
106 bitmap_len
= (is_resident
) ? AROS_LE2LONG(curattr
->data
.resident
.value_length
) : AROS_LE2QUAD(curattr
->data
.non_resident
.data_size
);
108 D(bug("[NTFS] %s: bitmap_len = %d\n", __PRETTY_FUNCTION__
, bitmap_len
));
110 if ((bmp
= AllocVec(bitmap_len
, MEMF_ANY
)) == NULL
)
115 CopyMem((UBYTE
*) ((IPTR
)curattr
+ AROS_LE2WORD(curattr
->data
.resident
.value_offset
)), bmp
, bitmap_len
);
116 dh
->ioh
.bitmap_len
= bitmap_len
;
120 if (ReadMFTAttribData(&dh
->ioh
.mft
.attr
, curattr
, bmp
, 0, bitmap_len
, 0))
122 D(bug("[NTFS] %s: failed to read $BITMAP\n", __PRETTY_FUNCTION__
));
125 dh
->ioh
.bitmap_len
= AROS_LE2LONG(*((ULONG
*)(curattr
+ 0x30)));
128 dh
->ioh
.bitmap
= (UBYTE
*) bmp
;
133 FreeMFTAttrib(&dh
->ioh
.mft
.attr
);
134 INIT_MFTATTRIB(&dh
->idx_attr
, &dh
->ioh
.mft
);
135 curattr
= MapMFTAttrib (&dh
->idx_attr
, &dh
->ioh
.mft
, AT_INDEX_ALLOCATION
);
136 while (curattr
!= NULL
)
138 if ((curattr
->residentflag
== ATTR_NONRESIDENT_FORM
) &&
139 (curattr
->attrname_length
== 4) &&
140 (AROS_LE2WORD(curattr
->attrname_offset
) == 0x40) &&
141 (AROS_LE2LONG(*((ULONG
*)((IPTR
)curattr
+ 0x40))) == 0x00490024) &&
142 (AROS_LE2LONG(*((ULONG
*)((IPTR
)curattr
+ 0x44))) == 0x00300033)) /* "$I30" */
144 curattr
= FindMFTAttrib(&dh
->idx_attr
, AT_INDEX_ALLOCATION
);
147 if ((!curattr
) && (dh
->ioh
.bitmap
))
149 D(bug("[NTFS] %s: $BITMAP without $INDEX_ALLOCATION\n", __PRETTY_FUNCTION__
));
153 D(bug("[NTFS] %s: initialised dir handle\n", __PRETTY_FUNCTION__
));
160 LONG
ReleaseDirHandle(struct DirHandle
*dh
)
162 D(bug("[NTFS] %s: releasing dir handle (cluster %ld)\n", __PRETTY_FUNCTION__
, dh
->ioh
.first_cluster
));
166 if (dh
->ioh
.mft
.buf
!= NULL
)
168 FreeMem(dh
->ioh
.mft
.buf
, dh
->ioh
.data
->mft_size
<< SECTORSIZE_SHIFT
);
169 dh
->ioh
.mft
.buf
= NULL
;
171 dh
->ioh
.bitmap
= NULL
;
177 LONG
GetDirEntry(struct DirHandle
*dh
, ULONG no
, struct DirEntry
*de
)
179 ULONG
*count
= &dh
->cur_no
;
182 D(bug("[NTFS]: %s(dh @ 0x%p, de @ 0x%p, no #%ld)\n", __PRETTY_FUNCTION__
, dh
, de
, no
));
184 /* setup the return object */
185 de
->data
= dh
->ioh
.data
;
187 de
->cluster
= dh
->ioh
.first_cluster
;
191 de
->key
= AllocMem(sizeof(struct Index_Key
), MEMF_ANY
|MEMF_CLEAR
);
193 de
->key
->indx
= dh
->ioh
.mft
.buf
;
194 de
->key
->pos
= dh
->idx_root
;
197 if (de
->key
->indx
== dh
->ioh
.mft
.buf
)
199 while (de
->key
->pos
!= NULL
)
201 ret
= ProcessFSEntry(&dh
->ioh
.mft
, de
, &count
);
202 if (de
->key
->pos
!= NULL
) de
->key
->pos
+= AROS_LE2WORD(*((UWORD
*)(de
->key
->pos
+ 8)));
206 de
->key
->indx
= NULL
;
209 if (de
->key
->bitmap
== NULL
)
210 de
->key
->bitmap
= dh
->ioh
.bitmap
;
212 if (de
->key
->bitmap
!= NULL
)
216 if (de
->key
->indx
== NULL
)
217 de
->key
->indx
= AllocMem(dh
->ioh
.data
->idx_size
<< SECTORSIZE_SHIFT
, MEMF_ANY
);
219 if (de
->key
->indx
== NULL
)
229 for (; i
< (dh
->ioh
.bitmap_len
* 8); i
++)
233 if (*de
->key
->bitmap
& de
->key
->v
)
235 if ((de
->key
->pos
) && (de
->key
->pos
< de
->key
->indx
+ (dh
->ioh
.data
->idx_size
<< SECTORSIZE_SHIFT
)))
236 de
->key
->pos
+= AROS_LE2WORD(*((UWORD
*)(de
->key
->pos
+ 8)));
239 D(bug("[NTFS] %s: key @ 0x%p [index #%u @ 0x%p - 0x%p]\n", __PRETTY_FUNCTION__
, de
->key
, (IPTR
)i
, de
->key
->indx
, de
->key
->indx
+ (dh
->ioh
.data
->idx_size
<< SECTORSIZE_SHIFT
)));
242 (&dh
->idx_attr
, de
->key
->indx
, i
* (dh
->ioh
.data
->idx_size
<< SECTORSIZE_SHIFT
),
243 (dh
->ioh
.data
->idx_size
<< SECTORSIZE_SHIFT
), 0))
244 || (PostProcessMFTRecord(dh
->ioh
.data
, (struct MFTRecordEntry
*)de
->key
->indx
, dh
->ioh
.data
->idx_size
, "INDX")))
246 de
->key
->pos
= &de
->key
->indx
[0x18 + AROS_LE2WORD(*((UWORD
*)(de
->key
->indx
+ 0x18)))];
248 ret
= ProcessFSEntry(&dh
->ioh
.mft
, de
, &count
);
253 if (de
->key
->v
>= 0x100)
259 D(bug("[NTFS] %s: Reached End\n", __PRETTY_FUNCTION__
));
263 de
->key
->bitmap
= dh
->ioh
.bitmap
;
269 if (de
->entry
->buf
!= NULL
)
271 FreeMem(de
->entry
->buf
, dh
->ioh
.data
->mft_size
<< SECTORSIZE_SHIFT
);
272 de
->entry
->buf
= NULL
;
274 InitMFTEntry(de
->entry
, de
->entry
->mftrec_no
);
276 D(bug("[NTFS] %s: entry initialised\n", __PRETTY_FUNCTION__
));
279 return ret
? ERROR_OBJECT_NOT_FOUND
: 0;
282 LONG
GetNextDirEntry(struct DirHandle
*dh
, struct DirEntry
*de
, BOOL skipsys
)
286 D(bug("[NTFS] %s: looking for next entry after #%ld\n", __PRETTY_FUNCTION__
, dh
->cur_no
));
288 while ((err
= GetDirEntry(dh
, dh
->cur_no
+ 1, de
)) == 0) {
289 if (dh
->ioh
.first_cluster
== (FILE_ROOT
* dh
->ioh
.data
->mft_size
))
291 D(bug("[NTFS] %s: in ROOT dir\n", __PRETTY_FUNCTION__
));
294 if ((de
->entryname
[0] == '.' && de
->entryname
[1] == '\0'))
296 D(bug("[NTFS] %s: skipping special entry '.'\n", __PRETTY_FUNCTION__
));
299 else if (de
->entryname
[0] == '$')
302 (de
->entryname
[1] == 'B' && de
->entryname
[2] == 'a' && de
->entryname
[3] == 'd' && de
->entryname
[4] == 'C' && de
->entryname
[5] == 'l' && de
->entryname
[6] == 'u' && de
->entryname
[7] == 's' && de
->entryname
[8] == '\0') ||
304 (de
->entryname
[1] == 'A' && de
->entryname
[2] == 't' && de
->entryname
[3] == 't' && de
->entryname
[4] == 'r' && de
->entryname
[5] == 'D' && de
->entryname
[6] == 'e' && de
->entryname
[7] == 'f' && de
->entryname
[8] == '\0') ||
306 (de
->entryname
[1] == 'B' && de
->entryname
[2] == 'i' && de
->entryname
[3] == 't' && de
->entryname
[4] == 'm' && de
->entryname
[5] == 'a' && de
->entryname
[6] == 'p' && de
->entryname
[7] == '\0') ||
308 (de
->entryname
[1] == 'B' && de
->entryname
[2] == 'o' && de
->entryname
[3] == 'o' && de
->entryname
[4] == 't' && de
->entryname
[5] == '\0') ||
310 (de
->entryname
[1] == 'E' && de
->entryname
[2] == 'x' && de
->entryname
[3] == 't' && de
->entryname
[4] == 'e' && de
->entryname
[5] == 'n' && de
->entryname
[6] == 'd' && de
->entryname
[7] == '\0') ||
312 (de
->entryname
[1] == 'L' && de
->entryname
[2] == 'o' && de
->entryname
[3] == 'g' && de
->entryname
[4] == 'F' && de
->entryname
[5] == 'i' && de
->entryname
[6] == 'l' && de
->entryname
[7] == 'e' && de
->entryname
[8] == '\0') ||
314 (de
->entryname
[1] == 'M' && de
->entryname
[2] == 'F' && de
->entryname
[3] == 'T' && de
->entryname
[4] == '\0') ||
316 (de
->entryname
[1] == 'M' && de
->entryname
[2] == 'F' && de
->entryname
[3] == 'T' && de
->entryname
[4] == 'M' && de
->entryname
[5] == 'i' && de
->entryname
[6] == 'r' && de
->entryname
[7] == 'r' && de
->entryname
[8] == '\0') ||
318 (de
->entryname
[1] == 'S' && de
->entryname
[2] == 'e' && de
->entryname
[3] == 'c' && de
->entryname
[4] == 'u' && de
->entryname
[5] == 'r' && de
->entryname
[6] == 'e' && de
->entryname
[7] == '\0') ||
320 (de
->entryname
[1] == 'U' && de
->entryname
[2] == 'p' && de
->entryname
[3] == 'C' && de
->entryname
[4] == 'a' && de
->entryname
[5] == 's' && de
->entryname
[6] == 'e' && de
->entryname
[7] == '\0') ||
322 (de
->entryname
[1] == 'V' && de
->entryname
[2] == 'o' && de
->entryname
[3] == 'l' && de
->entryname
[4] == 'u' && de
->entryname
[5] == 'm' && de
->entryname
[6] == 'e' && de
->entryname
[7] == '\0')
326 D(bug("[NTFS] %s: skipping special entry '%s'\n", __PRETTY_FUNCTION__
, de
->entryname
));
332 if (de
->entryname
[0] == '$' && de
->entryname
[1] == 'R' && de
->entryname
[2] == 'e' && de
->entryname
[3] == 'c' && de
->entryname
[4] == 'y' && de
->entryname
[5] == 'c' && de
->entryname
[6] == 'l' && de
->entryname
[7] == 'e' && de
->entryname
[8] == '.' && de
->entryname
[9] == 'B' && de
->entryname
[10] == 'i' && de
->entryname
[11] == 'n' && de
->entryname
[12] == '\0')
335 char *fixedname
= AllocVec(strlen(de
->entryname
), MEMF_ANY
|MEMF_CLEAR
);
336 CopyMem(de
->entryname
+ 1, fixedname
, strlen(de
->entryname
) - 1);
337 FreeVec(de
->entryname
);
338 de
->entryname
= fixedname
;
342 D(bug("[NTFS] %s: returning entry #%u\n", __PRETTY_FUNCTION__
, dh
->cur_no
));
350 LONG
GetParentDir(struct DirHandle
*dh
, struct DirEntry
*de
)
353 struct NTFSMFTAttr dirattr
;
354 struct DirHandle parentdh
;
355 struct MFTAttr
*attrentry
;
357 D(bug("[NTFS]: %s(dh @ 0x%p)\n", __PRETTY_FUNCTION__
, dh
));
359 // if we're already at the root, then we can't go any further
360 if (dh
->ioh
.first_cluster
== (dh
->ioh
.data
->mft_start
* dh
->ioh
.data
->mft_size
))
362 D(bug("[NTFS] %s: trying to go up past the root, so entry not found\n", __PRETTY_FUNCTION__
));
363 return ERROR_OBJECT_NOT_FOUND
;
366 D(bug("[NTFS] %s: finding parent of directory MFT #%u\n", __PRETTY_FUNCTION__
, (IPTR
)dh
->ioh
.mft
.mftrec_no
));
368 // InitDirHandle(dh->ioh.data, dh, TRUE);
369 if (dh
->parent_mft
== 0)
371 INIT_MFTATTRIB(&dirattr
, &dh
->ioh
.mft
);
372 attrentry
= FindMFTAttrib(&dirattr
, AT_FILENAME
);
373 attrentry
= (struct MFTAttr
*)((IPTR
)attrentry
+ AROS_LE2WORD(attrentry
->data
.resident
.value_offset
));
376 parentdh
.ioh
.mft
.mftrec_no
= *(UQUAD
*)((IPTR
)attrentry
) & MFTREF_MASK
;
379 parentdh
.ioh
.mft
.mftrec_no
= dh
->parent_mft
;
380 if (parentdh
.ioh
.mft
.mftrec_no
== 0x2)
381 parentdh
.ioh
.mft
.mftrec_no
= FILE_ROOT
;
383 de
->cluster
= parentdh
.ioh
.first_cluster
= parentdh
.ioh
.mft
.mftrec_no
* glob
->data
->mft_size
;
385 D(bug("[NTFS] %s: parent_mft = %u [%u]\n", __PRETTY_FUNCTION__
, (IPTR
)(parentdh
.ioh
.first_cluster
/ glob
->data
->mft_size
), (IPTR
)parentdh
.ioh
.mft
.mftrec_no
));
386 parentdh
.ioh
.mft
.buf
= NULL
;
387 InitDirHandle(dh
->ioh
.data
, &parentdh
, TRUE
);
389 if ((parentdh
.ioh
.mft
.mftrec_no
!= 0x2) && (parentdh
.ioh
.mft
.mftrec_no
!= FILE_ROOT
))
391 INIT_MFTATTRIB(&dirattr
, &parentdh
.ioh
.mft
);
392 attrentry
= FindMFTAttrib(&dirattr
, AT_FILENAME
);
393 attrentry
= (struct MFTAttr
*)((IPTR
)attrentry
+ AROS_LE2WORD(attrentry
->data
.resident
.value_offset
));
396 parentdh
.ioh
.mft
.mftrec_no
= *(UQUAD
*)((IPTR
)attrentry
) & MFTREF_MASK
;
397 if (parentdh
.ioh
.mft
.mftrec_no
== 0x2)
398 parentdh
.ioh
.mft
.mftrec_no
= FILE_ROOT
;
399 parentdh
.ioh
.first_cluster
= parentdh
.ioh
.mft
.mftrec_no
* glob
->data
->mft_size
;
401 D(bug("[NTFS] %s: grandparent_mft = %u [%u]\n", __PRETTY_FUNCTION__
, (IPTR
)(parentdh
.ioh
.first_cluster
/ glob
->data
->mft_size
), (IPTR
)parentdh
.ioh
.mft
.mftrec_no
));
402 ReleaseDirHandle(&parentdh
);
403 InitDirHandle(dh
->ioh
.data
, &parentdh
, TRUE
);
405 err
= GetDirEntryByCluster(&parentdh
, de
->cluster
, de
);
409 de
->entry
->mftrec_no
= parentdh
.ioh
.mft
.mftrec_no
;
410 de
->entrytype
= ATTR_DIRECTORY
;
416 LONG
GetDirEntryByCluster(struct DirHandle
*dh
, UQUAD cluster
, struct DirEntry
*de
)
420 D(bug("[NTFS] %s: looking for dir entry with first cluster %lu\n", __PRETTY_FUNCTION__
, cluster
));
422 // start at the start
425 // loop through the entries until we find a match
426 while ((err
= GetNextDirEntry(dh
, de
, FALSE
)) == 0)
428 if (cluster
== (de
->entry
->mftrec_no
* glob
->data
->mft_size
))
430 D(bug("[NTFS] %s: matched starting cluster at entry %ld, returning\n", __PRETTY_FUNCTION__
, de
->no
));
435 D(bug("[NTFS] %s: dir entry with first cluster %lu not found\n", __PRETTY_FUNCTION__
, cluster
));
439 LONG
GetDirEntryByName(struct DirHandle
*dh
, STRPTR name
, ULONG namelen
, struct DirEntry
*de
)
443 D(bug("[NTFS]: %s('", __PRETTY_FUNCTION__
); RawPutChars(name
, namelen
) ; bug("')\n"));
445 // loop through the entries until we find a match
446 while ((err
= GetNextDirEntry(dh
, de
, FALSE
)) == 0)
448 if ((strnicmp((char *) name
, de
->entryname
, namelen
) == 0) &&
449 (strlen(de
->entryname
) == namelen
))
451 D(bug("[NTFS] %s: matched name '%s' at entry %ld, returning\n", __PRETTY_FUNCTION__
, de
->entryname
, de
->no
));
459 LONG
GetDirEntryByPath(struct DirHandle
*dh
, STRPTR path
, ULONG pathlen
, struct DirEntry
*de
)
464 D(bug("[NTFS]: %s('", __PRETTY_FUNCTION__
); RawPutChars(path
, pathlen
); bug("')\n"));
466 // if it starts with a volume specifier (or just a :), remove it and get
467 // us back to the root dir
468 for (i
= 0; i
< pathlen
; i
++)
472 D(bug("[NTFS] %s: path has volume specifier, moving to the root dir\n", __PRETTY_FUNCTION__
));
477 dh
->ioh
.mft
.mftrec_no
= FILE_ROOT
;
479 ReleaseDirHandle(dh
);
480 InitDirHandle(dh
->ioh
.data
, dh
, TRUE
);
482 /* If we were called with simply ":" as the name we will return
483 immediately after this, so we prepare a fictional direntry for
485 Note that we fill only fields which are actually used in our handler */
486 de
->no
= -1; /* WARNING! Dummy index */
487 de
->entrytype
= ATTR_DIRECTORY
;
493 D(bug("[NTFS] %s: looking for entry '", __PRETTY_FUNCTION__
); RawPutChars(path
, pathlen
); bug("'\n"));
495 // get back to the start of the dir
498 /* each time around the loop we find one dir/file in the full path */
501 /* zoom forward and find the first dir separator */
502 for (len
= 0; (len
< pathlen
) && (path
[len
] != '/') && (path
[len
] != '\0'); len
++);
504 D(bug("[NTFS] %s: remaining path is '", __PRETTY_FUNCTION__
); RawPutChars(path
, pathlen
);
505 bug("' (%d bytes), current chunk is '", pathlen
); RawPutChars(path
, (len
== 0) ? 1 : len
);
506 bug("' (%d bytes)\n", (len
== 0) ? 1 : len
));
508 /* if the first character is a /, then we have to go up a level */
511 /* get the parent dir, and bale if we've gone past it (i.e. we are
513 if ((err
= GetParentDir(dh
, de
)) != 0)
516 /* otherwise, we want to search the current directory for this name */
518 if ((err
= GetDirEntryByName(dh
, path
, len
, de
)) != 0)
519 return ERROR_OBJECT_NOT_FOUND
;
520 D(bug("[NTFS] %s: #%d\n", __PRETTY_FUNCTION__
, de
->no
));
523 /* move up the buffer */
527 /* a / here is either the path separator or the directory we just went
528 * up. either way, we have to ignore it */
529 if (pathlen
> 0 && path
[0] == '/')
537 D(bug("[NTFS] %s: next part.. (%u bytes)\n", __PRETTY_FUNCTION__
, pathlen
));
538 /* more to do, so this entry had better be a directory */
539 if (!(de
->entrytype
& ATTR_DIRECTORY
))
541 D(bug("[NTFS] %s: '%.*s' is not a directory, so can't go any further\n", __PRETTY_FUNCTION__
, len
, path
));
542 return ERROR_OBJECT_WRONG_TYPE
;
547 if ((de
->key
->indx
) && (de
->key
->indx
!= dh
->ioh
.mft
.buf
))
549 D(bug("[NTFS] %s: freeing old key indx buffer @ 0x%p\n", __PRETTY_FUNCTION__
, de
->key
->indx
));
550 FreeMem(de
->key
->indx
, dh
->ioh
.data
->idx_size
<< SECTORSIZE_SHIFT
);
551 de
->key
->indx
= NULL
;
553 D(bug("[NTFS] %s: freeing old key @ 0x%p\n", __PRETTY_FUNCTION__
, de
->key
));
554 FreeMem(de
->key
, sizeof(struct Index_Key
));
557 dh
->ioh
.mft
.mftrec_no
= de
->entry
->mftrec_no
;
558 ReleaseDirHandle(dh
);
559 InitDirHandle(dh
->ioh
.data
, dh
, TRUE
);
563 /* nothing left, so we've found it */
564 D(bug("[NTFS] %s: found the entry, returning it\n", __PRETTY_FUNCTION__
));
568 LONG
UpdateDirEntry(struct DirEntry
*de
)
570 // struct DirHandle dh;
574 D(bug("[NTFS] %s: writing dir entry %ld in dir starting at cluster %ld\n", __PRETTY_FUNCTION__
, de
->no
, de
->cluster
));
576 #if defined(NTFS_READONLY)
577 err
= ERROR_DISK_WRITE_PROTECTED
;
579 InitDirHandle(glob
->data
, &dh
, FALSE
);
581 // err = WriteFileChunk(&(dh.ioh), de->pos, sizeof(struct FATDirEntry), (UBYTE *) &(de->e.entry), &nwritten);
584 D(bug("[NTFS] %s: dir entry update failed\n", __PRETTY_FUNCTION__
));
585 ReleaseDirHandle(&dh
);
589 ReleaseDirHandle(&dh
);
595 #define fs_data glob->data
597 LONG
FillFIB (struct ExtFileLock
*fl
, struct FileInfoBlock
*fib
) {
598 struct GlobalLock
*gl
= (fl
!= NULL
? fl
->gl
: &fs_data
->info
->root_lock
);
602 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__
));
604 if (gl
== &fs_data
->info
->root_lock
) {
605 D(bug("[NTFS] %s:\t\ttype: root directory\n", __PRETTY_FUNCTION__
));
606 fib
->fib_DirEntryType
= ST_ROOT
;
608 else if ((fl
->entry
== NULL
) || (fl
->entry
&& fl
->entry
->entrytype
& ATTR_DIRECTORY
)) {
609 D(bug("[NTFS] %s:\t\ttype: directory\n", __PRETTY_FUNCTION__
));
610 fib
->fib_DirEntryType
= ST_USERDIR
;
613 D(bug("[NTFS] %s:\t\ttype: file\n", __PRETTY_FUNCTION__
));
614 fib
->fib_DirEntryType
= ST_FILE
;
617 D(bug("[NTFS] %s:\t\tsize: %llu\n", __PRETTY_FUNCTION__
, gl
->size
));
619 /* Mark >32bit sizes so that software knows to use the 64bit packets to get the file size */
620 if (fl
->entry
&& fl
->entry
->entry
)
622 if (fl
->entry
->entry
->size
>= 0x7FFFFFFF)
623 fib
->fib_Size
= 0x7FFFFFFF;
625 fib
->fib_Size
= fl
->entry
->entry
->size
;
639 /* Warning: TODO - technically if the $data is resident it doesnt take any space (since its embeded in the mft record) */
640 fib
->fib_NumBlocks
= gl
->size
/ (fs_data
->mft_size
<< SECTORSIZE_SHIFT
);
641 if (fib
->fib_NumBlocks
<< SECTORSIZE_SHIFT
!= gl
->size
)
642 fib
->fib_NumBlocks
+= 1;
644 fib
->fib_EntryType
= fib
->fib_DirEntryType
;
646 if (fib
->fib_DirEntryType
== ST_ROOT
)
647 CopyMem(&fs_data
->volume
.create_time
, &fib
->fib_Date
, sizeof(struct DateStamp
));
649 struct MFTAttr
*attrentry
;
650 struct NTFSMFTAttr
*mftattr
, dirattr
;
651 struct NTFSMFTEntry
*mft
;
654 if (!(fl
->entry
->entry
))
656 D(bug("[NTFS] %s:\t\tNO MFT ENTRY\n", __PRETTY_FUNCTION__
));
659 mftattr
= &fl
->entry
->entry
->attr
;
660 mft
= fl
->entry
->entry
;
665 mft
= &fl
->dir
->ioh
.mft
;
667 D(bug("[NTFS] %s:\t\tNTFSMFTEntry @ 0x%p, NTFSMFTAttr @ 0x%p\n", __PRETTY_FUNCTION__
, mft
, mftattr
));
669 INIT_MFTATTRIB(mftattr
, mft
);
670 attrentry
= FindMFTAttrib(mftattr
, AT_STANDARD_INFORMATION
);
671 attrentry
= (struct MFTAttr
*)((IPTR
)attrentry
+ AROS_LE2WORD(attrentry
->data
.resident
.value_offset
));
673 D(bug("[NTFS] %s: nfstime = %d\n", __PRETTY_FUNCTION__
, *((UQUAD
*)(attrentry
+ 8))));
675 NTFS2DateStamp((UQUAD
*)((IPTR
)attrentry
+ 8), &fib
->fib_Date
);
677 D(bug("[NTFS] %s:\t Date: days %ld minutes %ld ticks %ld\n", __PRETTY_FUNCTION__
, fib
->fib_Date
.ds_Days
, fib
->fib_Date
.ds_Minute
, fib
->fib_Date
.ds_Tick
));
680 len
= gl
->name
[0] <= 106 ? gl
->name
[0] : 106;
681 CopyMem(gl
->name
, fib
->fib_FileName
, len
+ 1);
682 fib
->fib_FileName
[len
+ 1] = '\0';
683 D(bug("[NTFS] %s:\t\tname (len %ld) %s\n", __PRETTY_FUNCTION__
, len
, fib
->fib_FileName
+ 1));
685 fib
->fib_Protection
= 0;
686 if (gl
->attr
& ATTR_READ_ONLY
) fib
->fib_Protection
|= (FIBF_DELETE
| FIBF_WRITE
);
687 if (gl
->attr
& ATTR_ARCHIVE
) fib
->fib_Protection
|= FIBF_ARCHIVE
;
689 fib
->fib_Comment
[0] = 0;