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.
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>
29 #include "fat_protos.h"
31 #define DEBUG DEBUG_LOCK
35 #define DumpLocks(sb, glob)
37 static void DumpLocks(struct FSSuper
*sb
, struct Globals
*glob
)
39 struct GlobalLock
*gl
;
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
);
57 LONG
TestLock(struct ExtFileLock
*fl
, struct Globals
*glob
)
59 if (fl
== 0 && glob
->sb
== NULL
)
61 if (!glob
->disk_inserted
)
64 return ERROR_NOT_A_DOS_DISK
;
67 if (glob
->sb
== NULL
|| glob
->disk_inhibited
!= 0
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
;
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
;
85 /* If the name is empty, just duplicate the base lock */
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
))
96 return OpLockParent(fl
, lock
, glob
);
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 */
117 else if (fl
->gl
->attr
& ATTR_DIRECTORY
)
118 dir_cluster
= fl
->ioh
.first_cluster
;
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
);
129 InitDirHandle(glob
->sb
, dir_cluster
, &dh
, FALSE
, glob
);
131 /* Look for the entry */
132 if ((err
= GetDirEntryByPath(&dh
, name
, namelen
, &de
, glob
)) != 0)
134 ReleaseDirHandle(&dh
, glob
);
135 D(bug("[fat] couldn't get lock\n"));
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
);
144 err
= LockFile(dh
.ioh
.first_cluster
, de
.index
, access
, lock
, glob
);
146 ReleaseDirHandle(&dh
, glob
);
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
;
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 */
165 ForeachNode(&glob
->sb
->info
->locks
, node
)
167 if (node
->dir_cluster
== dir_cluster
168 && node
->dir_entry
== dir_entry
)
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 */
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
;
203 /* Gotta fish some stuff out of the dir entry too */
204 InitDirHandle(glob
->sb
, dir_cluster
, &dh
, FALSE
, glob
);
205 GetDirEntry(&dh
, dir_entry
, &de
, glob
);
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
, glob
);
215 gl
->name
[0] = (UBYTE
) len
;
216 GetDirEntryLongName(&de
, &(gl
->name
[1]), &len
);
217 gl
->name
[0] = (UBYTE
) len
;
219 GetDirEntryShortName(&de
, &(gl
->shortname
[1]), &len
, glob
);
220 gl
->shortname
[0] = (UBYTE
) len
;
223 ReleaseDirHandle(&dh
, glob
);
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
)
241 D(bug("[fat] searching for notify name '%s'\n",
242 nn
->nr
->nr_FullName
));
244 if (InitDirHandle(glob
->sb
, 0, &dh
, TRUE
, glob
) != 0)
247 if (GetDirEntryByPath(&dh
, nn
->nr
->nr_FullName
,
248 strlen(nn
->nr
->nr_FullName
), &de
, glob
) != 0)
251 if (gl
->dir_cluster
== de
.cluster
252 && gl
->dir_entry
== de
.index
)
254 D(bug("[fat] found and matched to the global lock"
256 gl
->dir_cluster
, gl
->dir_entry
));
264 /* Now set up the file lock */
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
));
280 fl
->do_notify
= FALSE
;
284 ADDTAIL(&gl
->locks
, &fl
->node
);
286 D(bug("[fat] created file lock 0x%08x\n", fl
));
288 DumpLocks(glob
->sb
, glob
);
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
;
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
));
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
;
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
, glob
);
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
,
359 void FreeLock(struct ExtFileLock
*fl
, struct Globals
*glob
)
361 struct NotifyNode
*nn
;
366 D(bug("[fat] freeing lock 0x%08x\n", fl
));
369 SendNotifyByLock(fl
->ioh
.sb
, fl
->gl
);
373 if (IsListEmpty(&fl
->gl
->locks
))
377 ForeachNode(&fl
->sb
->info
->notifies
, nn
)
378 if (nn
->gl
== fl
->gl
)
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
, glob
);
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
);