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 #define AROS_ALMOST_COMPATIBLE
14 #include <aros/macros.h>
15 #include <exec/types.h>
16 #include <exec/execbase.h>
17 #include <exec/memory.h>
18 #include <dos/dosextens.h>
19 #include <dos/filehandler.h>
21 #include <proto/exec.h>
22 #include <proto/dos.h>
23 #include <proto/utility.h>
28 #include "ntfs_protos.h"
34 #define DumpLocks(fs_data)
36 void DumpLocks(struct FSData
*fs_data
)
38 struct GlobalLock
*gl
;
41 bug("[NTFS] %s: global locks-:\n", __PRETTY_FUNCTION__
);
43 ListLength(&fs_data
->info
->root_lock
.locks
, count
);
44 bug("[NTFS] %s:\troot: %ld references\n", __PRETTY_FUNCTION__
, count
);
46 ForeachNode(&fs_data
->info
->locks
, gl
) {
47 ListLength(&gl
->locks
, count
);
48 bug("[NTFS] %s:\t (%ld/%ld) ", __PRETTY_FUNCTION__
, gl
->dir_cluster
/ glob
->data
->mft_size
, gl
->dir_entry
); RawPutChars(&(gl
->name
[1]), gl
->name
[0]);
49 bug(": %ld references\n", count
);
54 LONG
TestLock(struct ExtFileLock
*fl
)
56 if (fl
== 0 && glob
->data
== NULL
) {
57 if (glob
->disk_inserted
== FALSE
)
60 return ERROR_NOT_A_DOS_DISK
;
63 if (glob
->data
== NULL
|| glob
->disk_inhibited
|| (fl
&& fl
->fl_Volume
!= MKBADDR(glob
->data
->doslist
)))
64 return ERROR_DEVICE_NOT_MOUNTED
;
66 if (fl
&& fl
->magic
!= ID_NTFS_DISK
)
67 return ERROR_OBJECT_WRONG_TYPE
;
72 LONG
LockFileByName(struct ExtFileLock
*fl
, UBYTE
*name
, LONG namelen
, LONG access
, struct ExtFileLock
**lock
)
74 LONG err
= ERROR_OBJECT_NOT_FOUND
;
75 struct DirHandle dirh
;
76 struct DirHandle
*dh
= &dirh
;
79 D(bug("[NTFS] %s('", __PRETTY_FUNCTION__
); RawPutChars(name
, namelen
); bug("')\n"));
81 D(bug("[NTFS] %s: fs_data @ 0x%p\n", __PRETTY_FUNCTION__
, glob
->data
));
83 /* if the name is empty, just duplicate the base lock */
85 return CopyLock(fl
, lock
);
87 /* if the base lock is a file, the name must either be empty (handled
88 * above) or start with '/' (handled here) */
89 if (fl
!= NULL
&& !(fl
->gl
->attr
& ATTR_DIRECTORY
)) {
92 return OpLockParent(fl
, lock
);
99 return ERROR_OBJECT_WRONG_TYPE
;
102 dh
->ioh
.mft
.buf
= NULL
;
107 dh
->ioh
.mft
.mftrec_no
= FILE_ROOT
;
111 dh
->ioh
.mft
.mftrec_no
= fl
->dir
->ioh
.mft
.mftrec_no
;
113 InitDirHandle(glob
->data
, dh
, FALSE
);
115 D(bug("[NTFS] %s: looking in directory MFT #%u\n", __PRETTY_FUNCTION__
, (IPTR
)dh
->ioh
.mft
.mftrec_no
));
117 memset(&de
, 0, sizeof(struct DirEntry
));
119 /* look for the entry */
120 if ((err
= GetDirEntryByPath(dh
, name
, namelen
, &de
)) != 0) {
121 D(bug("[NTFS] %s: couldn't get lock\n", __PRETTY_FUNCTION__
));
125 ReleaseDirHandle(dh
);
127 /* found it, do the locking proper */
128 if (de
.entrytype
& ATTR_DIRECTORY
&& !de
.entry
)
129 err
= LockRoot(access
, lock
);
131 err
= LockFile(&de
, access
, lock
);
136 LONG
LockFile(struct DirEntry
*de
, LONG access
, struct ExtFileLock
**lock
)
138 struct GlobalLock
*node
, *gl
;
139 struct ExtFileLock
*fl
;
141 D(bug("[NTFS]: %s(entry @ 0x%p) (%s)\n", __PRETTY_FUNCTION__
, de
, access
== SHARED_LOCK
? "shared" : "exclusive"));
143 /* first see if we already have a global lock for this file */
145 ForeachNode(&glob
->data
->info
->locks
, node
)
146 if (node
->dir_cluster
== de
->cluster
&& node
->dir_entry
== de
->no
) {
147 D(bug("[NTFS] %s: using GlobalLock @ 0x%p\n", __PRETTY_FUNCTION__
, node
));
152 /* if we do and we're trying for an exclusive lock, then bail out */
153 if (gl
!= NULL
&& access
== EXCLUSIVE_LOCK
) {
154 D(bug("[NTFS] %s: can't obtain exclusive lock on already-locked file\n", __PRETTY_FUNCTION__
));
155 return ERROR_OBJECT_IN_USE
;
158 /* allocate space for the lock. we do this first so that we don't go to
159 * all the effort of setting up the global lock only to have to discard it
160 * if the filelock allocation fails */
161 if ((fl
= _AllocVecPooled(glob
->data
->info
->mem_pool
,
162 sizeof(struct ExtFileLock
))) == NULL
)
163 return ERROR_NO_FREE_STORE
;
165 if ((fl
->dir
= _AllocVecPooled(glob
->data
->info
->mem_pool
,
166 sizeof(struct DirHandle
))) == NULL
)
167 return ERROR_NO_FREE_STORE
;
169 memset(fl
->dir
, 0, sizeof(struct DirHandle
));
171 if ((fl
->entry
= _AllocVecPooled(glob
->data
->info
->mem_pool
,
172 sizeof(struct DirEntry
))) == NULL
)
173 return ERROR_NO_FREE_STORE
;
175 memset(fl
->entry
, 0, sizeof(struct DirEntry
));
177 fl
->data
= glob
->data
;
179 fl
->dir
->ioh
.mft
.mftrec_no
= de
->cluster
/ glob
->data
->mft_size
;
180 InitDirHandle(glob
->data
, fl
->dir
, FALSE
);
182 fl
->entry
->data
= de
->data
; /* filesystem data */
183 fl
->entry
->entryname
= AllocVec(strlen(de
->entryname
) + 1, MEMF_ANY
|MEMF_CLEAR
);
184 CopyMem(de
->entryname
, fl
->entry
->entryname
, strlen(de
->entryname
));
185 fl
->entry
->entrytype
= de
->entrytype
;
187 fl
->entry
->no
= de
->no
;
189 if ((fl
->entry
->entry
= de
->entry
) == NULL
)
191 GetDirEntry(fl
->dir
, de
->no
, fl
->entry
);
195 fl
->entry
->cluster
= de
->cluster
;
197 /* if we don't have a global lock we need to build one */
199 if ((gl
= _AllocVecPooled(glob
->data
->info
->mem_pool
,
200 sizeof(struct GlobalLock
))) == NULL
) {
201 _FreeVecPooled(glob
->data
->info
->mem_pool
, fl
);
202 return ERROR_NO_FREE_STORE
;
205 gl
->dir_cluster
= fl
->entry
->cluster
;
206 gl
->dir_entry
= fl
->entry
->no
;
209 gl
->first_cluster
= fl
->entry
->entry
->mftrec_no
* glob
->data
->mft_size
;
211 gl
->attr
= fl
->entry
->entrytype
;
212 if (fl
->entry
->entry
)
213 gl
->size
= fl
->entry
->entry
->size
;
215 gl
->name
[0] = strlen(fl
->entry
->entryname
) + 1;
216 CopyMem(fl
->entry
->entryname
, &gl
->name
[1], gl
->name
[0]);
220 ADDTAIL(&glob
->data
->info
->locks
, gl
);
222 D(bug("[NTFS] %s: created new global lock for '%s'\n", __PRETTY_FUNCTION__
, &gl
->name
[1]));
224 /* TODO : look through the notify list. if there's any in there that aren't
225 * currently attached to a global lock, expand them and if they are
226 * for this file, fill them in */
229 /* now setup the file lock */
231 fl
->fl_Access
= access
;
232 fl
->fl_Task
= glob
->ourport
;
233 fl
->fl_Volume
= MKBADDR(glob
->data
->doslist
);
235 fl
->magic
= ID_NTFS_DISK
;
239 fl
->do_notify
= FALSE
;
242 ADDTAIL(&gl
->locks
, &fl
->node
);
244 D(bug("[NTFS] %s: created file lock @ 0x%08x\n", __PRETTY_FUNCTION__
, fl
));
246 DumpLocks(glob
->data
);
252 LONG
LockRoot(LONG access
, struct ExtFileLock
**lock
)
254 struct ExtFileLock
*fl
;
256 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__
));
258 if (access
== EXCLUSIVE_LOCK
) {
259 D(bug("[NTFS] %s: EXCLUSIVE_LOCK\n", __PRETTY_FUNCTION__
));
260 return ERROR_OBJECT_IN_USE
;
263 if ((fl
= _AllocVecPooled(glob
->data
->info
->mem_pool
,
264 sizeof(struct ExtFileLock
))) == NULL
)
265 return ERROR_NO_FREE_STORE
;
267 if ((fl
->dir
= _AllocVecPooled(glob
->data
->info
->mem_pool
,
268 sizeof(struct DirHandle
))) == NULL
)
269 return ERROR_NO_FREE_STORE
;
271 memset(fl
->dir
, 0, sizeof(struct DirHandle
));
273 if ((fl
->entry
= _AllocVecPooled(glob
->data
->info
->mem_pool
,
274 sizeof(struct DirEntry
))) == NULL
)
275 return ERROR_NO_FREE_STORE
;
277 memset(fl
->entry
, 0, sizeof(struct DirEntry
));
281 fl
->fl_Access
= SHARED_LOCK
;
282 fl
->fl_Task
= glob
->ourport
;
283 fl
->fl_Volume
= MKBADDR(glob
->data
->doslist
);
285 fl
->magic
= ID_NTFS_DISK
;
287 fl
->dir
->ioh
.mft
.data
= glob
->data
;
289 fl
->dir
->ioh
.mft
.mftrec_no
= FILE_ROOT
;
290 InitDirHandle(glob
->data
, fl
->dir
, FALSE
);
294 fl
->do_notify
= FALSE
;
296 if (IsListEmpty(&glob
->data
->info
->root_lock
.locks
))
297 ADDTAIL(&glob
->data
->info
->locks
, &glob
->data
->info
->root_lock
);
298 fl
->gl
= &glob
->data
->info
->root_lock
;
299 fl
->data
= glob
->data
;
300 ADDTAIL(&glob
->data
->info
->root_lock
.locks
, &fl
->node
);
302 D(bug("[NTFS] %s: created root lock 0x%08x\n", __PRETTY_FUNCTION__
, fl
));
304 DumpLocks(glob
->data
);
310 LONG
CopyLock(struct ExtFileLock
*fl
, struct ExtFileLock
**lock
)
315 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__
));
317 if (fl
== NULL
|| (fl
->gl
== &glob
->data
->info
->root_lock
))
318 return LockRoot(SHARED_LOCK
, lock
);
320 if (fl
->fl_Access
== EXCLUSIVE_LOCK
) {
321 D(bug("[NTFS] %s: EXCLUSIVE_LOCK\n", __PRETTY_FUNCTION__
));
322 return ERROR_OBJECT_IN_USE
;
325 D(bug("[NTFS] %s: copying lock (dir %ld; entry %ld)\n", __PRETTY_FUNCTION__
, fl
->gl
->dir_cluster
/ glob
->data
->mft_size
, fl
->gl
->dir_entry
));
327 memset(&de
, 0, sizeof(struct DirEntry
));
331 de
.cluster
= fl
->dir
->ioh
.first_cluster
;
332 de
.no
= fl
->entry
->no
;
337 dh
.ioh
.mft
.mftrec_no
= fl
->gl
->dir_cluster
/ glob
->data
->mft_size
;
338 dh
.ioh
.mft
.buf
= NULL
;
339 InitDirHandle(glob
->data
, &dh
, FALSE
);
340 GetDirEntry(&dh
, fl
->gl
->dir_entry
, &de
);
342 if ((ret
= LockFile(&de
, SHARED_LOCK
, lock
)) == 0)
345 if (fl
->gl
->attr
& ATTR_DIRECTORY
)
351 if ((fl
->entry
->key
->indx
) && (fl
->entry
->key
->indx
!=fl
->dir
->ioh
.mft
.buf
))
353 D(bug("[NTFS] %s: freeing old key indx buffer @ 0x%p\n", __PRETTY_FUNCTION__
, fl
->entry
->key
->indx
));
354 FreeMem(fl
->entry
->key
->indx
, glob
->data
->idx_size
<< SECTORSIZE_SHIFT
);
355 fl
->entry
->key
->indx
= NULL
;
357 D(bug("[NTFS] %s: freeing old key @ 0x%p\n", __PRETTY_FUNCTION__
, fl
->entry
->key
));
358 FreeMem(fl
->entry
->key
, sizeof(struct Index_Key
));
359 fl
->entry
->key
= NULL
;
363 fl
->dir
->parent_mft
= fl
->dir
->ioh
.mft
.mftrec_no
;
364 fl
->dir
->ioh
.mft
.mftrec_no
= fl
->gl
->first_cluster
/ glob
->data
->mft_size
;
365 ReleaseDirHandle(fl
->dir
);
366 InitDirHandle(glob
->data
, fl
->dir
, FALSE
);
372 void FreeLock(struct ExtFileLock
*fl
)
374 struct NotifyNode
*nn
;
376 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__
));
381 D(bug("[NTFS] %s: lock @ 0x%08x\n", __PRETTY_FUNCTION__
, fl
));
384 SendNotifyByLock(fl
->dir
->ioh
.data
, fl
->gl
);
388 if (IsListEmpty(&fl
->gl
->locks
))
392 ForeachNode(&fl
->data
->info
->notifies
, nn
)
396 if (fl
->gl
!= &fl
->data
->info
->root_lock
)
397 _FreeVecPooled(glob
->data
->info
->mem_pool
, fl
->gl
);
399 D(bug("[NTFS] %s: freed associated global lock\n", __PRETTY_FUNCTION__
));
404 if (fl
->entry
!= NULL
)
406 FreeVec(fl
->entry
->entryname
);
407 fl
->entry
->entryname
= NULL
;
409 if (fl
->entry
->entry
!= NULL
)
411 if (fl
->entry
->entry
->cblock
!= NULL
)
413 Cache_FreeBlock(fl
->data
->cache
, fl
->entry
->entry
->cblock
);
414 fl
->entry
->entry
->cblock
= NULL
;
416 if (fl
->entry
->entry
->buf
!= NULL
)
418 FreeMem(fl
->entry
->entry
->buf
, glob
->data
->mft_size
<< SECTORSIZE_SHIFT
);
419 fl
->entry
->entry
->buf
= NULL
;
422 FreeMem(fl
->entry
->entry
, sizeof (struct NTFSMFTEntry
));
423 fl
->entry
->entry
= NULL
;
425 if (fl
->entry
->key
!= NULL
)
427 if ((fl
->entry
->key
->indx
!= NULL
) && (fl
->entry
->key
->indx
!= fl
->dir
->ioh
.mft
.buf
))
429 D(bug("[NTFS] %s: freeing old key indx buffer @ 0x%p\n", __PRETTY_FUNCTION__
, fl
->entry
->key
->indx
));
430 FreeMem(fl
->entry
->key
->indx
, glob
->data
->idx_size
<< SECTORSIZE_SHIFT
);
431 fl
->entry
->key
->indx
= NULL
;
433 D(bug("[NTFS] %s: freeing old key @ 0x%p\n", __PRETTY_FUNCTION__
, fl
->entry
->key
));
434 FreeMem(fl
->entry
->key
, sizeof(struct Index_Key
));
435 fl
->entry
->key
= NULL
;
437 _FreeVecPooled(glob
->data
->info
->mem_pool
, fl
->entry
);
443 if (fl
->dir
->ioh
.mft
.cblock
!= NULL
)
445 Cache_FreeBlock(fl
->data
->cache
, fl
->dir
->ioh
.mft
.cblock
);
446 fl
->dir
->ioh
.mft
.cblock
= NULL
;
448 if (fl
->dir
->ioh
.mft
.buf
)
450 FreeMem(fl
->dir
->ioh
.mft
.buf
, glob
->data
->mft_size
<< SECTORSIZE_SHIFT
);
451 fl
->dir
->ioh
.mft
.buf
= NULL
;
454 if (!(fl
->dir
->ioh
.bitmap
))
456 FreeVec(fl
->dir
->ioh
.bitmap
);
457 fl
->dir
->ioh
.bitmap
= NULL
;
459 _FreeVecPooled(glob
->data
->info
->mem_pool
, fl
->dir
);
463 if (fl
->data
!= glob
->data
)
464 AttemptDestroyVolume(fl
->data
);
466 _FreeVecPooled(glob
->data
->info
->mem_pool
, fl
);