Tabs to spaces; more consistent and conventional formatting.
[AROS.git] / rom / filesys / fat / lock.c
bloba511d1026efecbbc973731c96171b2f1463c71ca
1 /*
2 * fat-handler - FAT12/16/32 filesystem handler
4 * Copyright © 2006 Marek Szyprowski
5 * Copyright © 2007-2015 The AROS Development Team
7 * This program is free software; you can redistribute it and/or modify it
8 * under the same terms as AROS itself.
10 * $Id$
13 #define AROS_ALMOST_COMPATIBLE
15 #include <aros/macros.h>
16 #include <exec/types.h>
17 #include <exec/execbase.h>
18 #include <exec/memory.h>
19 #include <dos/dosextens.h>
20 #include <dos/filehandler.h>
22 #include <proto/exec.h>
23 #include <proto/dos.h>
24 #include <proto/utility.h>
26 #include <string.h>
28 #include "fat_fs.h"
29 #include "fat_protos.h"
31 #define DEBUG DEBUG_LOCK
32 #include "debug.h"
34 #if DEBUG == 0
35 #define DumpLocks(sb)
36 #else
37 void DumpLocks(struct FSSuper *sb)
39 struct GlobalLock *gl;
40 ULONG count;
42 bug("[fat] global locks:\n");
44 ListLength(&sb->info->root_lock.locks, count);
45 bug(" root: %ld references\n", count);
47 ForeachNode(&sb->info->locks, gl)
49 ListLength(&gl->locks, count);
50 bug(" (%ld/%ld) ", gl->dir_cluster, gl->dir_entry);
51 RawPutChars(&(gl->name[1]), gl->name[0]);
52 bug(": %ld references\n", count);
55 #endif
57 LONG TestLock(struct ExtFileLock *fl, struct Globals *glob)
59 if (fl == 0 && glob->sb == NULL)
61 if (glob->disk_inserted == FALSE)
62 return ERROR_NO_DISK;
63 else
64 return ERROR_NOT_A_DOS_DISK;
67 if (glob->sb == NULL || glob->disk_inhibited
68 || (fl && fl->fl_Volume != MKBADDR(glob->sb->doslist)))
69 return ERROR_DEVICE_NOT_MOUNTED;
71 if (fl && fl->magic != ID_FAT_DISK)
72 return ERROR_OBJECT_WRONG_TYPE;
74 return 0;
77 LONG LockFileByName(struct ExtFileLock *fl, UBYTE *name, LONG namelen,
78 LONG access, struct ExtFileLock **lock, struct Globals *glob)
80 LONG err = ERROR_OBJECT_NOT_FOUND;
81 struct DirHandle dh;
82 struct DirEntry de;
83 ULONG dir_cluster;
85 /* if the name is empty, just duplicate the base lock */
86 if (namelen == 0)
87 return CopyLock(fl, lock, glob);
89 /* if the base lock is a file, the name must either be empty (handled
90 * above) or start with '/' (handled here) */
91 if (fl != NULL && !(fl->gl->attr & ATTR_DIRECTORY))
93 if (name[0] == '/')
95 if (namelen == 1)
96 return OpLockParent(fl, lock, glob);
97 else
99 name++;
100 namelen--;
103 else
104 return ERROR_OBJECT_WRONG_TYPE;
107 /* the . and .. entries are invisible to the user */
108 if (name[0] == '.' && (namelen == 1 || (name[1] == '.' && namelen == 2)))
110 D(bug("[fat] not allowing access to '.' or '..' entries\n"));
111 return ERROR_OBJECT_NOT_FOUND;
114 /* get the first cluster of the directory to look for the file in */
115 if (fl == NULL)
116 dir_cluster = 0;
117 else if (fl->gl->attr & ATTR_DIRECTORY)
118 dir_cluster = fl->ioh.first_cluster;
119 else
120 dir_cluster = fl->gl->dir_cluster;
123 bug("[fat] trying to obtain lock on '");
124 RawPutChars(name, namelen);
125 bug("' in dir at cluster %ld\n", dir_cluster);
128 /* open the dir */
129 InitDirHandle(glob->sb, dir_cluster, &dh, FALSE);
131 /* look for the entry */
132 if ((err = GetDirEntryByPath(&dh, name, namelen, &de)) != 0)
134 ReleaseDirHandle(&dh);
135 D(bug("[fat] couldn't get lock\n"));
136 return err;
139 /* found it, do the locking proper */
140 if (de.e.entry.attr & ATTR_DIRECTORY && FIRST_FILE_CLUSTER(&de)
141 <= glob->sb->rootdir_cluster)
142 err = LockRoot(access, lock, glob);
143 else
144 err = LockFile(dh.ioh.first_cluster, de.index, access, lock, glob);
146 ReleaseDirHandle(&dh);
148 return err;
151 LONG LockFile(ULONG dir_cluster, ULONG dir_entry, LONG access,
152 struct ExtFileLock **lock, struct Globals *glob)
154 struct GlobalLock *node, *gl;
155 struct ExtFileLock *fl;
156 struct DirHandle dh;
157 struct DirEntry de;
158 ULONG len;
160 D(bug("[fat] locking file (%ld/%ld) (%s)\n", dir_cluster, dir_entry,
161 access == SHARED_LOCK ? "shared" : "exclusive"));
163 /* first see if we already have a global lock for this file */
164 gl = NULL;
165 ForeachNode(&glob->sb->info->locks, node)
167 if (node->dir_cluster == dir_cluster
168 && node->dir_entry == dir_entry)
170 gl = node;
171 break;
175 /* if we do and we're trying for an exclusive lock, then bail out */
176 if (gl != NULL && access == EXCLUSIVE_LOCK)
178 D(bug("[fat] can't obtain exclusive lock on already-locked file\n"));
179 return ERROR_OBJECT_IN_USE;
182 /* allocate space for the lock. we do this first so that we don't go to
183 * all the effort of setting up the global lock only to have to discard it
184 * if the filelock allocation fails */
185 if ((fl = AllocVecPooled(glob->sb->info->mem_pool,
186 sizeof(struct ExtFileLock))) == NULL)
187 return ERROR_NO_FREE_STORE;
189 /* if we don't have a global lock we need to build one */
190 if (gl == NULL)
192 if ((gl = AllocVecPooled(glob->sb->info->mem_pool,
193 sizeof(struct GlobalLock))) == NULL)
195 FreeVecPooled(glob->sb->info->mem_pool, fl);
196 return ERROR_NO_FREE_STORE;
199 gl->dir_cluster = dir_cluster;
200 gl->dir_entry = dir_entry;
201 gl->access = access;
203 /* gotta fish some stuff out of the dir entry too */
204 InitDirHandle(glob->sb, dir_cluster, &dh, FALSE);
205 GetDirEntry(&dh, dir_entry, &de);
207 gl->first_cluster = FIRST_FILE_CLUSTER(&de);
208 if (gl->first_cluster == 0)
209 gl->first_cluster = 0xffffffff;
211 gl->attr = de.e.entry.attr;
212 gl->size = AROS_LE2LONG(de.e.entry.file_size);
214 GetDirEntryShortName(&de, &(gl->name[1]), &len);
215 gl->name[0] = (UBYTE) len;
216 GetDirEntryLongName(&de, &(gl->name[1]), &len);
217 gl->name[0] = (UBYTE) len;
218 #if DEBUG_NAMES
219 GetDirEntryShortName(&de, &(gl->shortname[1]), &len);
220 gl->shortname[0] = (UBYTE) len;
221 #endif
223 ReleaseDirHandle(&dh);
225 NEWLIST(&gl->locks);
227 ADDTAIL(&glob->sb->info->locks, gl);
229 D(bug("[fat] created new global lock\n"));
231 /* look through the notify list. if there's any in there that aren't
232 * currently attached to a global lock, expand them and if they are
233 * for this file, fill them in */
235 struct NotifyNode *nn;
237 ForeachNode(&glob->sb->info->notifies, nn)
239 if (nn->gl == NULL)
241 D(bug("[fat] searching for notify name '%s'\n",
242 nn->nr->nr_FullName));
244 if (InitDirHandle(glob->sb, 0, &dh, TRUE) != 0)
245 continue;
247 if (GetDirEntryByPath(&dh, nn->nr->nr_FullName,
248 strlen(nn->nr->nr_FullName), &de) != 0)
249 continue;
251 if (gl->dir_cluster == de.cluster
252 && gl->dir_entry == de.index)
254 D(bug("[fat] found and matched to the global lock"
255 " (%ld/%ld)\n",
256 gl->dir_cluster, gl->dir_entry));
257 nn->gl = gl;
264 /* now set up the file lock */
265 fl->fl_Link = BNULL;
266 fl->fl_Key = 0;
267 fl->fl_Access = access;
268 fl->fl_Task = glob->ourport;
269 fl->fl_Volume = MKBADDR(glob->sb->doslist);
271 fl->magic = ID_FAT_DISK;
273 fl->ioh.sb = glob->sb;
274 fl->ioh.first_cluster = gl->first_cluster;
275 fl->ioh.block = NULL;
276 RESET_HANDLE(&(fl->ioh));
278 fl->pos = 0;
280 fl->do_notify = FALSE;
282 fl->gl = gl;
283 fl->sb = glob->sb;
284 ADDTAIL(&gl->locks, &fl->node);
286 D(bug("[fat] created file lock 0x%08x\n", fl));
288 DumpLocks(glob->sb);
290 *lock = fl;
291 return 0;
294 LONG LockRoot(LONG access, struct ExtFileLock **lock, struct Globals *glob)
296 struct ExtFileLock *fl;
298 D(bug("[fat] locking root\n"));
300 if (access == EXCLUSIVE_LOCK)
302 D(bug("[fat] can't obtain exclusive lock on the fs root\n"));
303 return ERROR_OBJECT_IN_USE;
306 if ((fl = AllocVecPooled(glob->sb->info->mem_pool,
307 sizeof(struct ExtFileLock))) == NULL)
308 return ERROR_NO_FREE_STORE;
310 fl->fl_Link = BNULL;
311 fl->fl_Key = 0;
312 fl->fl_Access = SHARED_LOCK;
313 fl->fl_Task = glob->ourport;
314 fl->fl_Volume = MKBADDR(glob->sb->doslist);
316 fl->magic = ID_FAT_DISK;
318 fl->ioh.sb = glob->sb;
319 fl->ioh.first_cluster = 0;
320 fl->ioh.block = NULL;
321 RESET_HANDLE(&(fl->ioh));
323 fl->pos = 0;
325 fl->do_notify = FALSE;
327 if (IsListEmpty(&glob->sb->info->root_lock.locks))
328 ADDTAIL(&glob->sb->info->locks, &glob->sb->info->root_lock);
329 fl->gl = &glob->sb->info->root_lock;
330 fl->sb = glob->sb;
331 ADDTAIL(&glob->sb->info->root_lock.locks, &fl->node);
333 D(bug("[fat] created root lock 0x%08x\n", fl));
335 DumpLocks(glob->sb);
337 *lock = fl;
338 return 0;
341 LONG CopyLock(struct ExtFileLock *fl, struct ExtFileLock **lock,
342 struct Globals *glob)
344 D(bug("[fat] copying lock\n"));
346 if (fl == NULL || fl->gl == &glob->sb->info->root_lock)
347 return LockRoot(SHARED_LOCK, lock, glob);
349 if (fl->fl_Access == EXCLUSIVE_LOCK)
351 D(bug("[fat] can't copy exclusive lock\n"));
352 return ERROR_OBJECT_IN_USE;
355 return LockFile(fl->gl->dir_cluster, fl->gl->dir_entry, SHARED_LOCK,
356 lock, glob);
359 void FreeLock(struct ExtFileLock *fl, struct Globals *glob)
361 struct NotifyNode *nn;
363 if (fl == NULL)
364 return;
366 D(bug("[fat] freeing lock 0x%08x\n", fl));
368 if (fl->do_notify)
369 SendNotifyByLock(fl->ioh.sb, fl->gl);
371 REMOVE(&fl->node);
373 if (IsListEmpty((struct List *)&fl->gl->locks))
375 REMOVE(fl->gl);
377 ForeachNode(&fl->sb->info->notifies, nn)
378 if (nn->gl == fl->gl)
379 nn->gl = NULL;
381 if (fl->gl != &fl->sb->info->root_lock)
382 FreeVecPooled(glob->sb->info->mem_pool, fl->gl);
384 D(bug("[fat] freed associated global lock\n"));
387 DumpLocks(fl->sb);
388 if (fl->ioh.block != NULL)
389 Cache_FreeBlock(fl->sb->cache, fl->ioh.block);
391 if (fl->sb != glob->sb)
392 AttemptDestroyVolume(fl->sb);
394 FreeVecPooled(glob->sb->info->mem_pool, fl);