Implemented MUIM_Family_GetChild in the Group class (i.e. redirect to Family
[AROS.git] / workbench / fs / ntfs / ops.c
blob387f1d4cf4e403aea1fed0fb0f8f609a26cd4d84
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 #define AROS_ALMOST_COMPATIBLE
14 #include <aros/macros.h>
15 #include <exec/types.h>
16 #include <dos/dos.h>
17 #include <dos/notify.h>
18 #include <proto/exec.h>
20 #include <dos/dosextens.h>
21 #include <dos/filehandler.h>
23 #include "ntfs_fs.h"
24 #include "ntfs_protos.h"
25 #include "support.h"
27 #include "debug.h"
29 LONG OpLockFile(struct ExtFileLock *dirlock, UBYTE *name, ULONG namelen, LONG access, struct ExtFileLock **filelock)
31 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__));
33 // if they passed in a name, go searching for it
34 if (namelen != 0)
35 return LockFileByName(dirlock, name, namelen, access, filelock);
37 // otherwise the empty filename, just make a copy
38 else if (dirlock != NULL)
39 return CopyLock(dirlock, filelock);
41 // null dir lock means they want the root
42 else
43 return LockRoot(access, filelock);
46 void OpUnlockFile(struct ExtFileLock *lock)
48 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__));
50 if (lock != NULL)
51 FreeLock(lock);
54 LONG OpCopyLock(struct ExtFileLock *lock, struct ExtFileLock **copy)
56 D(bug("[NTFS]: %s(lock @ 0x%p)\n", __PRETTY_FUNCTION__, lock));
58 if (lock != NULL)
59 return CopyLock(lock, copy);
60 else
61 return LockRoot(SHARED_LOCK, copy);
64 LONG OpLockParent(struct ExtFileLock *lock, struct ExtFileLock **parent)
66 LONG err;
67 struct DirEntry de;
68 struct DirHandle dh;
69 struct NTFSMFTAttr dirattr;
70 struct MFTAttr *attrentry;
72 D(bug("[NTFS]: %s(lock @ 0x%p)\n", __PRETTY_FUNCTION__, lock));
75 // the root has no parent, but as a special case we have to return success
76 // with the zero lock
77 if (lock == NULL || lock->gl == &glob->data->info->root_lock) {
78 *parent = NULL;
79 return 0;
82 // if we're in the root directory, then the root is our parent
83 if (lock->gl->dir_cluster == glob->data->info->root_lock.dir_cluster)
84 return LockRoot(SHARED_LOCK, parent);
86 memset(&de, 0, sizeof(struct DirEntry));
87 memset(&dh, 0, sizeof(struct DirHandle));
89 // get the parent dir
90 if (lock->gl->attr & ATTR_DIRECTORY)
92 dh.ioh.mft.mftrec_no = lock->dir->ioh.mft.mftrec_no;
93 InitDirHandle(glob->data, &dh, FALSE);
95 if ((err = GetDirEntryByPath(&dh, "/", 1, &de)) != 0) {
96 return err;
99 else
101 dh.ioh.mft.mftrec_no = lock->gl->dir_cluster / glob->data->mft_size;
102 InitDirHandle(glob->data, &dh, FALSE);
104 INIT_MFTATTRIB(&dirattr, &dh.ioh.mft);
105 attrentry = FindMFTAttrib(&dirattr, AT_FILENAME);
106 attrentry = (struct MFTAttr *)((IPTR)attrentry + AROS_LE2WORD(attrentry->data.resident.value_offset));
108 // take us up
109 dh.ioh.mft.mftrec_no = AROS_LE2QUAD(*(UQUAD *)((IPTR)attrentry)) & MFTREF_MASK;
110 if (dh.ioh.mft.mftrec_no == 0x2)
111 dh.ioh.mft.mftrec_no = FILE_ROOT;
112 dh.ioh.first_cluster = dh.ioh.mft.mftrec_no * glob->data->mft_size;
113 D(bug("[NTFS] %s: parent_mft = %u [%u]\n", __PRETTY_FUNCTION__, (IPTR)(dh.ioh.first_cluster / glob->data->mft_size), (IPTR)dh.ioh.mft.mftrec_no));
114 ReleaseDirHandle(&dh);
115 InitDirHandle(dh.ioh.data, &dh, TRUE);
117 if ((err = GetDirEntryByCluster(&dh, lock->gl->dir_cluster, &de)) != 0) {
118 return err;
122 D(bug("[NTFS] %s: found parent!\n", __PRETTY_FUNCTION__));
124 err = LockFile(&de, SHARED_LOCK, parent);
126 return err;
130 * obtains a lock on the named file under the given dir. this is the service
131 * routine for DOS Open() (ie FINDINPUT/FINDOUTPUT/FINDUPDATE) and as such may
132 * only return a lock on a file, never on a dir.
134 LONG OpOpenFile(struct ExtFileLock *dirlock, UBYTE *name, ULONG namelen, LONG action, struct ExtFileLock **filelock)
136 LONG err;
137 struct ExtFileLock *lock;
139 D(bug("[NTFS]: %s('", __PRETTY_FUNCTION__); RawPutChars(name, namelen); bug("')\n"));
140 D(bug("[NTFS] %s: action = %s\n", __PRETTY_FUNCTION__,
141 action == ACTION_FINDINPUT ? "FINDINPUT" :
142 action == ACTION_FINDOUTPUT ? "FINDOUTPUT" :
143 action == ACTION_FINDUPDATE ? "FINDUPDATE" : "[unknown]"));
145 // no filename means they're trying to open whatever dirlock is (which
146 // despite the name may not actually be a dir). since there's already an
147 // extant lock, it's never going to be possible to get an exclusive lock,
148 // so this will only work for FINDINPUT (read-only)
149 if (namelen == 0) {
150 D(bug("[NTFS] %s: trying to copy passed dir lock\n", __PRETTY_FUNCTION__));
152 if (action != ACTION_FINDINPUT) {
153 D(bug("[NTFS] %s: can't copy lock for write (exclusive)\n", __PRETTY_FUNCTION__));
154 return ERROR_OBJECT_IN_USE;
157 // dirs can't be opened
158 if (dirlock == NULL || dirlock->gl->attr & ATTR_DIRECTORY) {
159 D(bug("[NTFS] %s: dir lock is a directory, which can't be opened\n", __PRETTY_FUNCTION__));
160 return ERROR_OBJECT_WRONG_TYPE;
163 // it's a file, just copy the lock
164 return CopyLock(dirlock, filelock);
167 // lock the file
168 err = LockFileByName(dirlock, name, namelen, action == ACTION_FINDINPUT ? SHARED_LOCK : EXCLUSIVE_LOCK, &lock);
170 // found it
171 if (err == 0) {
172 D(bug("[NTFS] %s: found existing file\n", __PRETTY_FUNCTION__));
174 // can't open directories
175 if (lock->gl->attr & ATTR_DIRECTORY) {
176 D(bug("[NTFS] %s: it's a directory, can't open it\n", __PRETTY_FUNCTION__));
177 FreeLock(lock);
178 return ERROR_OBJECT_WRONG_TYPE;
181 // INPUT/UPDATE use the file as/is
182 if (action != ACTION_FINDOUTPUT) {
183 D(bug("[NTFS] %s: returning the lock\n", __PRETTY_FUNCTION__));
184 *filelock = lock;
185 return 0;
188 // whereas OUTPUT truncates it
189 D(bug("[NTFS] %s: handling FINDOUTPUT, so truncating the file\n", __PRETTY_FUNCTION__));
191 if (lock->gl->attr & ATTR_READ_ONLY) {
192 D(bug("[NTFS] %s: file is write protected, doing nothing\n", __PRETTY_FUNCTION__));
193 FreeLock(lock);
194 return ERROR_WRITE_PROTECTED;
197 // update the dir entry to make the file empty
198 UpdateDirEntry(lock->entry);
200 D(bug("[NTFS] %s: set first cluster and size to 0 in directory entry\n", __PRETTY_FUNCTION__));
202 // free the clusters
203 lock->gl->first_cluster = lock->dir->ioh.first_cluster = 0xffffffff;
204 RESET_HANDLE(&lock->dir->ioh);
205 lock->gl->size = 0;
207 D(bug("[NTFS] %s: file truncated, returning the lock\n", __PRETTY_FUNCTION__));
209 // file is empty, go
210 *filelock = lock;
212 return 0;
215 // any error other than "not found" should be taken as-is
216 if (err != ERROR_OBJECT_NOT_FOUND)
217 return err;
219 // not found. for INPUT we bail out
220 if (action == ACTION_FINDINPUT) {
221 D(bug("[NTFS] %s: file not found, and not creating it\n", __PRETTY_FUNCTION__));
222 return ERROR_OBJECT_NOT_FOUND;
225 D(bug("[NTFS] %s: trying to create '", __PRETTY_FUNCTION__); RawPutChars(name, namelen); bug("'\n"));
227 if (err == 0) {
228 (*filelock)->do_notify = TRUE;
229 D(bug("[NTFS] %s: returning lock on new file\n", __PRETTY_FUNCTION__));
232 return err;
235 /* find the named file in the directory referenced by dirlock, and delete it.
236 * if the file is a directory, it will only be deleted if it's empty */
237 LONG OpDeleteFile(struct ExtFileLock *dirlock, UBYTE *name, ULONG namelen)
239 LONG err = 0;
241 D(bug("[NTFS]: %s('", __PRETTY_FUNCTION__); RawPutChars(name, namelen); bug("')\n"));
243 #if defined(NTFS_READONLY)
244 err = ERROR_DISK_WRITE_PROTECTED;
245 #else
247 #endif
249 return err;
252 LONG OpRenameFile(struct ExtFileLock *sdirlock, UBYTE *sname, ULONG snamelen, struct ExtFileLock *ddirlock, UBYTE *dname, ULONG dnamelen)
254 LONG err = 0;
256 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__));
258 #if defined(NTFS_READONLY)
259 err = ERROR_DISK_WRITE_PROTECTED;
260 #else
262 #endif
264 return err;
267 LONG OpCreateDir(struct ExtFileLock *dirlock, UBYTE *name, ULONG namelen, struct ExtFileLock **newdirlock)
269 LONG err = 0;
271 D(bug("[NTFS]: %s('", __PRETTY_FUNCTION__); RawPutChars(name, namelen); bug("')\n"));
273 #if defined(NTFS_READONLY)
274 err = ERROR_DISK_WRITE_PROTECTED;
275 #else
277 #endif
279 return err;
282 LONG OpRead(struct ExtFileLock *lock, UBYTE *data, UQUAD want, UQUAD *read)
284 LONG err = 0;
285 struct NTFSMFTAttr dataatrr;
286 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__));
287 D(bug("[NTFS] %s: %u bytes, pos %u\n", __PRETTY_FUNCTION__, (IPTR)want, (IPTR)lock->pos));
289 if (want == 0)
290 return 0;
292 if (want + lock->pos > lock->gl->size) {
293 want = lock->gl->size - lock->pos;
294 D(bug("[NTFS] %s: full read would take us past end-of-file, adjusted want to %u bytes\n", __PRETTY_FUNCTION__, (IPTR)want));
297 INIT_MFTATTRIB(&dataatrr, lock->entry->entry);
298 if (MapMFTAttrib (&dataatrr, lock->entry->entry, AT_DATA))
300 if (ReadMFTAttrib(&dataatrr, data, lock->pos, want, 0) == 0)
302 *read = want;
303 lock->pos = lock->pos + want;
304 D(bug("[NTFS] %s: read %u bytes, new file pos is %u\n", __PRETTY_FUNCTION__, (IPTR)want, (IPTR)lock->pos));
307 return err;
310 LONG OpWrite(struct ExtFileLock *lock, UBYTE *data, UQUAD want, UQUAD *written)
312 LONG err = 0;
314 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__));
315 #if defined(NTFS_READONLY)
316 err = ERROR_DISK_WRITE_PROTECTED;
317 #else
318 D(bug("[NTFS] %s: %u bytes, pos %u\n", __PRETTY_FUNCTION__, (IPTR)want, (IPTR)lock->pos));
319 #endif
321 return err;
324 LONG OpSetFileSize(struct ExtFileLock *lock, UQUAD offset, LONG offsetfrom, UQUAD *newsize)
326 LONG err = 0;
328 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__));
329 #if defined(NTFS_READONLY)
330 err = ERROR_DISK_WRITE_PROTECTED;
331 #else
333 #endif
334 return err;
337 LONG OpSetProtect(struct ExtFileLock *dirlock, UBYTE *name, ULONG namelen, ULONG prot)
339 LONG err = 0;
341 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__));
342 #if defined(NTFS_READONLY)
343 err = ERROR_DISK_WRITE_PROTECTED;
344 #else
346 #endif
347 return err;
350 LONG OpSetDate(struct ExtFileLock *dirlock, UBYTE *name, ULONG namelen, struct DateStamp *ds)
352 LONG err = 0;
354 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__));
355 #if defined(NTFS_READONLY)
356 err = ERROR_DISK_WRITE_PROTECTED;
357 #else
359 #endif
360 return err;
363 LONG OpAddNotify(struct NotifyRequest *nr)
365 LONG err;
366 struct DirHandle dh;
367 struct DirEntry de;
368 struct GlobalLock *gl = NULL, *tmp;
369 struct NotifyNode *nn;
370 BOOL exists = FALSE;
372 D(bug("[NTFS]: %s('%s')\n", __PRETTY_FUNCTION__, nr->nr_FullName));
374 // if the request is for the volume root, then we just link to the root lock
375 if (nr->nr_FullName[strlen(nr->nr_FullName)-1] == ':')
377 D(bug("[NTFS] %s: adding notify for root dir\n", __PRETTY_FUNCTION__));
378 gl = &glob->data->info->root_lock;
380 else {
381 dh.ioh.mft.mftrec_no = FILE_ROOT;
382 dh.ioh.mft.buf = NULL;
383 if ((err = InitDirHandle(glob->data, &dh, FALSE)) != 0)
384 return err;
386 memset(&de, 0, sizeof(struct DirEntry));
388 // look for the entry
389 err = GetDirEntryByPath(&dh, nr->nr_FullName, strlen(nr->nr_FullName), &de);
390 if (err != 0 && err != ERROR_OBJECT_NOT_FOUND)
391 return err;
393 // if it was found, then it might be open. try to find the global lock
394 if (err == 0) {
395 exists = TRUE;
397 D(bug("[NTFS] %s: file exists (%ld/%ld), looking for global lock\n", __PRETTY_FUNCTION__, de.cluster, de.no));
399 ForeachNode(&glob->data->info->locks, tmp)
400 if (tmp->dir_cluster == de.cluster && tmp->dir_entry == de.no) {
401 gl = tmp;
403 D(bug("[NTFS] %s: global lock 0x%0x\n", __PRETTY_FUNCTION__, gl));
405 break;
409 else {
410 exists = FALSE;
412 D(bug("[NTFS] %s: file doesn't exist\n", __PRETTY_FUNCTION__));
416 if (gl == NULL)
418 D(bug("[NTFS] %s: file not currently locked\n", __PRETTY_FUNCTION__));
421 // allocate space for the notify node
422 if ((nn = _AllocVecPooled(glob->data->info->mem_pool,
423 sizeof(struct NotifyNode))) == NULL)
424 return ERROR_NO_FREE_STORE;
426 // plug the bits in
427 nn->gl = gl;
428 nn->nr = nr;
430 // add to the list
431 ADDTAIL(&glob->data->info->notifies, nn);
433 // tell them that the file exists if they wanted to know
434 if (exists && nr->nr_Flags & NRF_NOTIFY_INITIAL)
435 SendNotify(nr);
437 D(bug("[NTFS] %s: notifying for '%s'\n", __PRETTY_FUNCTION__, nr->nr_FullName));
439 return 0;
442 LONG OpRemoveNotify(struct NotifyRequest *nr)
444 struct FSData *fs_data;
445 struct NotifyNode *nn, *nn2;
447 D(bug("[NTFS]: %s('%s')\n", __PRETTY_FUNCTION__, nr->nr_FullName));
449 /* search inserted volume for the request */
450 if (glob->data != NULL) {
451 ForeachNodeSafe(&glob->data->info->notifies, nn, nn2) {
452 if (nn->nr == nr) {
453 D(bug("[NTFS] %s: found notify request in list, removing it\n", __PRETTY_FUNCTION__));
454 REMOVE(nn);
455 _FreeVecPooled(glob->data->info->mem_pool, nn);
456 return 0;
461 /* search offline volumes for the request */
462 ForeachNode(&glob->sblist, fs_data) {
463 ForeachNodeSafe(&fs_data->info->notifies, nn, nn2) {
464 if (nn->nr == nr) {
465 D(bug("[NTFS] %s: found notify request in list, removing it\n", __PRETTY_FUNCTION__));
466 REMOVE(nn);
467 _FreeVecPooled(fs_data->info->mem_pool, nn);
468 AttemptDestroyVolume(fs_data);
469 return 0;
474 D(bug("[NTFS] %s: not found, doing nothing\n", __PRETTY_FUNCTION__));
476 return 0;