Added -Wno-pointer-sign to reduce number of warnings when building AHI.
[AROS.git] / workbench / fs / ntfs / lock.c
blobd0b42f36904b33b9efcc64d9a3aff5b5905188e5
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 <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>
25 #include <string.h>
27 #include "ntfs_fs.h"
28 #include "ntfs_protos.h"
29 #include "support.h"
31 #include "debug.h"
33 #if DEBUG == 0
34 #define DumpLocks(fs_data)
35 #else
36 void DumpLocks(struct FSData *fs_data)
38 struct GlobalLock *gl;
39 ULONG count;
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);
52 #endif
54 LONG TestLock(struct ExtFileLock *fl)
56 if (fl == 0 && glob->data == NULL) {
57 if (glob->disk_inserted == FALSE)
58 return ERROR_NO_DISK;
59 else
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;
69 return 0;
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;
77 struct DirEntry de;
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 */
84 if (namelen == 0)
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)) {
90 if (name[0] == '/') {
91 if (namelen == 1)
92 return OpLockParent(fl, lock);
93 else {
94 name++;
95 namelen--;
98 else
99 return ERROR_OBJECT_WRONG_TYPE;
102 dh->ioh.mft.buf = NULL;
104 /* open the dir */
105 if (fl == NULL)
107 dh->ioh.mft.mftrec_no = FILE_ROOT;
109 else
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__));
122 return err;
125 ReleaseDirHandle(dh);
127 /* found it, do the locking proper */
128 if (de.entrytype & ATTR_DIRECTORY && !de.entry)
129 err = LockRoot(access, lock);
130 else
131 err = LockFile(&de, access, lock);
133 return err;
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 */
144 gl = NULL;
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));
148 gl = node;
149 break;
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);
193 de->entry = NULL;
195 fl->entry->cluster = de->cluster;
197 /* if we don't have a global lock we need to build one */
198 if (gl == NULL) {
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;
207 gl->access = access;
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]);
218 NEWLIST(&gl->locks);
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 */
230 fl->fl_Link = BNULL;
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;
237 fl->pos = 0;
239 fl->do_notify = FALSE;
241 fl->gl = gl;
242 ADDTAIL(&gl->locks, &fl->node);
244 D(bug("[NTFS] %s: created file lock @ 0x%08x\n", __PRETTY_FUNCTION__, fl));
246 DumpLocks(glob->data);
248 *lock = fl;
249 return 0;
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));
279 fl->fl_Link = BNULL;
280 fl->fl_Key = 0;
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);
292 fl->pos = 0;
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);
306 *lock = fl;
307 return 0;
310 LONG CopyLock(struct ExtFileLock *fl, struct ExtFileLock **lock)
312 struct DirEntry de;
313 LONG ret;
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));
329 if (fl->entry)
331 de.cluster = fl->dir->ioh.first_cluster;
332 de.no = fl->entry->no;
334 else
336 struct DirHandle dh;
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)
344 fl = *lock;
345 if (fl->gl->attr & ATTR_DIRECTORY)
347 if (fl->entry)
349 if (fl->entry->key)
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;
361 fl->entry = 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);
369 return ret;
372 void FreeLock(struct ExtFileLock *fl)
374 struct NotifyNode *nn;
376 D(bug("[NTFS]: %s()\n", __PRETTY_FUNCTION__));
378 if (fl == NULL)
379 return;
381 D(bug("[NTFS] %s: lock @ 0x%08x\n", __PRETTY_FUNCTION__, fl));
383 if (fl->do_notify)
384 SendNotifyByLock(fl->dir->ioh.data, fl->gl);
386 REMOVE(&fl->node);
388 if (IsListEmpty((struct List *)&fl->gl->locks))
390 REMOVE(fl->gl);
392 ForeachNode(&fl->data->info->notifies, nn)
393 if(nn->gl == fl->gl)
394 nn->gl = NULL;
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__));
402 DumpLocks(fl->data);
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);
438 fl->entry = NULL;
441 if (fl->dir)
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);
460 fl->dir = NULL;
463 if (fl->data != glob->data)
464 AttemptDestroyVolume(fl->data);
466 _FreeVecPooled(glob->data->info->mem_pool, fl);