Test initialisation of MUIA_List_AdjustWidth and MUIA_List_AdjustHeight, and
[AROS.git] / workbench / fs / ntfs / direntry.c
blobea68e9af489ab5aa6eaebe72487edc8f67282cf8
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/types.h>
14 #include <dos/dos.h>
15 #include <proto/exec.h>
16 #include <proto/dos.h>
18 #include <string.h>
20 #include "cache.h"
22 #include "ntfs_fs.h"
23 #include "ntfs_protos.h"
25 #include "debug.h"
27 LONG InitDirHandle(struct FSData *fs_data, struct DirHandle *dh, BOOL reuse)
29 struct MFTAttr *curattr;
30 UBYTE *bmp;
31 UQUAD bitmap_len;
32 LONG ret = 0;
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
39 * not */
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;
47 else {
48 dh->ioh.data = fs_data;
49 dh->ioh.mft.cblock = NULL;
52 RESET_DIRHANDLE(dh);
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);
61 while(1)
63 if ((curattr = FindMFTAttrib(&dh->ioh.mft.attr, AT_INDEX_ROOT)) == NULL)
65 D(bug("[NTFS] %s: no $INDEX_ROOT found!\n", __PRETTY_FUNCTION__));
66 goto done;
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))
75 continue;
77 curattr = (struct MFTAttr *)((IPTR)curattr + AROS_LE2WORD(curattr->data.resident.value_offset));
78 if (*(UBYTE *)curattr != 0x30) /* Not filename index */
80 continue;
82 break;
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)
97 int ofs;
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)
111 goto done;
113 if (is_resident)
115 CopyMem((UBYTE *) ((IPTR)curattr + AROS_LE2WORD(curattr->data.resident.value_offset)), bmp, bitmap_len);
116 dh->ioh.bitmap_len = bitmap_len;
118 else
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__));
123 goto done;
125 dh->ioh.bitmap_len = AROS_LE2LONG(*((ULONG *)(curattr + 0x30)));
128 dh->ioh.bitmap = (UBYTE *) bmp;
129 break;
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" */
143 break;
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__));
150 goto done;
153 D(bug("[NTFS] %s: initialised dir handle\n", __PRETTY_FUNCTION__));
155 done:
157 return ret;
160 LONG ReleaseDirHandle(struct DirHandle *dh)
162 D(bug("[NTFS] %s: releasing dir handle (cluster %ld)\n", __PRETTY_FUNCTION__, dh->ioh.first_cluster));
164 RESET_DIRHANDLE(dh);
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;
172 dh->idx_root = NULL;
174 return 0;
177 LONG GetDirEntry(struct DirHandle *dh, ULONG no, struct DirEntry *de)
179 ULONG *count = &dh->cur_no;
180 LONG ret = ~0;
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;
186 de->no = no;
187 de->cluster = dh->ioh.first_cluster;
189 if (de->key == NULL)
191 de->key = AllocMem(sizeof(struct Index_Key), MEMF_ANY|MEMF_CLEAR);
192 dh->cur_no = -1;
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)));
203 if (ret)
204 goto done;
206 de->key->indx = NULL;
209 if (de->key->bitmap == NULL)
210 de->key->bitmap = dh->ioh.bitmap;
212 if (de->key->bitmap != NULL)
214 UQUAD i;
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)
220 goto done;
222 if (de->key->i == 0)
224 de->key->v = 1;
227 i = de->key->i;
229 for (; i < (dh->ioh.bitmap_len * 8); i++)
231 de->key->i = 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)));
237 else
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)));
241 if ((ReadMFTAttrib
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")))
245 goto done;
246 de->key->pos = &de->key->indx[0x18 + AROS_LE2WORD(*((UWORD *)(de->key->indx + 0x18)))];
248 ret = ProcessFSEntry(&dh->ioh.mft, de, &count);
249 if (ret)
250 goto done;
252 de->key->v <<= 1;
253 if (de->key->v >= 0x100)
255 de->key->v = 1;
256 de->key->bitmap++;
259 D(bug("[NTFS] %s: Reached End\n", __PRETTY_FUNCTION__));
261 ret = ~0;
262 de->key->i = 0;
263 de->key->bitmap = dh->ioh.bitmap;
265 done:
266 if (ret == 1)
268 ret = 0;
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)
284 LONG err;
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__));
292 if (skipsys)
294 if ((de->entryname[0] == '.' && de->entryname[1] == '\0'))
296 D(bug("[NTFS] %s: skipping special entry '.'\n", __PRETTY_FUNCTION__));
297 continue;
299 else if (de->entryname[0] == '$')
301 if (
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') ||
303 // $BadClus
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') ||
305 // $AttrDef
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') ||
307 // $Bitmap
308 (de->entryname[1] == 'B' && de->entryname[2] == 'o' && de->entryname[3] == 'o' && de->entryname[4] == 't' && de->entryname[5] == '\0') ||
309 // $Boot
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') ||
311 // $Extend
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') ||
313 // $LogFile
314 (de->entryname[1] == 'M' && de->entryname[2] == 'F' && de->entryname[3] == 'T' && de->entryname[4] == '\0') ||
315 // $MFT
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') ||
317 // $MFTMirr
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') ||
319 // $Secure
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') ||
321 // $UpCase
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')
323 // $Volume
326 D(bug("[NTFS] %s: skipping special entry '%s'\n", __PRETTY_FUNCTION__, de->entryname));
327 continue;
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')
333 // $Recycle.Bin
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));
344 return 0;
347 return err;
350 LONG GetParentDir(struct DirHandle *dh, struct DirEntry *de)
352 LONG err = 0;
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));
375 // take us up
376 parentdh.ioh.mft.mftrec_no = *(UQUAD *)((IPTR)attrentry) & MFTREF_MASK;
378 else
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));
395 // take us up
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);
407 else
409 de->entry->mftrec_no = parentdh.ioh.mft.mftrec_no;
410 de->entrytype = ATTR_DIRECTORY;
411 de->no = -1;
413 return err;
416 LONG GetDirEntryByCluster(struct DirHandle *dh, UQUAD cluster, struct DirEntry *de)
418 LONG err = 0;
420 D(bug("[NTFS] %s: looking for dir entry with first cluster %lu\n", __PRETTY_FUNCTION__, cluster));
422 // start at the start
423 RESET_DIRHANDLE(dh);
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));
431 break;
435 D(bug("[NTFS] %s: dir entry with first cluster %lu not found\n", __PRETTY_FUNCTION__, cluster));
436 return err;
439 LONG GetDirEntryByName(struct DirHandle *dh, STRPTR name, ULONG namelen, struct DirEntry *de)
441 LONG err;
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));
452 break;
456 return err;
459 LONG GetDirEntryByPath(struct DirHandle *dh, STRPTR path, ULONG pathlen, struct DirEntry *de)
461 LONG err;
462 ULONG len, i;
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++)
470 if (path[i] == ':')
472 D(bug("[NTFS] %s: path has volume specifier, moving to the root dir\n", __PRETTY_FUNCTION__));
474 pathlen -= (i+1);
475 path = &path[i+1];
477 dh->ioh.mft.mftrec_no = FILE_ROOT;
478 if (dh->ioh.mft.buf)
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
484 such a case.
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;
489 break;
493 D(bug("[NTFS] %s: looking for entry '", __PRETTY_FUNCTION__); RawPutChars(path, pathlen); bug("'\n"));
495 // get back to the start of the dir
496 RESET_DIRHANDLE(dh);
498 /* each time around the loop we find one dir/file in the full path */
499 while (pathlen > 0)
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 */
509 if (path[0] == '/')
511 /* get the parent dir, and bale if we've gone past it (i.e. we are
512 * the root) */
513 if ((err = GetParentDir(dh, de)) != 0)
514 return err;
516 /* otherwise, we want to search the current directory for this name */
517 else {
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 */
524 path += len;
525 pathlen -= len;
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] == '/')
531 path++;
532 pathlen--;
535 if (pathlen > 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;
545 if (de->key)
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));
555 de->key = NULL;
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__));
565 return 0;
568 LONG UpdateDirEntry(struct DirEntry *de)
570 // struct DirHandle dh;
571 LONG err = 0;
572 // ULONG nwritten;
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;
578 #else
579 InitDirHandle(glob->data, &dh, FALSE);
581 // err = WriteFileChunk(&(dh.ioh), de->pos, sizeof(struct FATDirEntry), (UBYTE *) &(de->e.entry), &nwritten);
582 if (err != 0)
584 D(bug("[NTFS] %s: dir entry update failed\n", __PRETTY_FUNCTION__));
585 ReleaseDirHandle(&dh);
586 return err;
589 ReleaseDirHandle(&dh);
591 #endif
592 return err;
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);
599 LONG result = 0;
600 int len;
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;
612 else {
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;
624 else
625 fib->fib_Size = fl->entry->entry->size;
627 else
629 if (fl->entry)
633 else
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));
648 else {
649 struct MFTAttr *attrentry;
650 struct NTFSMFTAttr *mftattr, dirattr;
651 struct NTFSMFTEntry *mft;
652 if (fl->entry)
654 if (!(fl->entry->entry))
656 D(bug("[NTFS] %s:\t\tNO MFT ENTRY\n", __PRETTY_FUNCTION__));
657 return result;
659 mftattr = &fl->entry->entry->attr;
660 mft = fl->entry->entry;
662 else
664 mftattr = &dirattr;
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;
691 return result;