2 * fat-handler - FAT12/16/32 filesystem handler
4 * Copyright © 2006 Marek Szyprowski
5 * Copyright © 2007-2013 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
37 void DumpLocks(struct FSSuper
*sb
) {
38 struct GlobalLock
*gl
;
41 bug("[fat] global locks:\n");
43 ListLength(&sb
->info
->root_lock
.locks
, count
);
44 bug(" root: %ld references\n", count
);
46 ForeachNode(&sb
->info
->locks
, gl
) {
47 ListLength(&gl
->locks
, count
);
48 bug(" (%ld/%ld) ", gl
->dir_cluster
, gl
->dir_entry
); RawPutChars(&(gl
->name
[1]), gl
->name
[0]);
49 bug(": %ld references\n", count
);
54 LONG
TestLock(struct ExtFileLock
*fl
, struct Globals
*glob
) {
55 if (fl
== 0 && glob
->sb
== NULL
) {
56 if (glob
->disk_inserted
== FALSE
)
59 return ERROR_NOT_A_DOS_DISK
;
62 if (glob
->sb
== NULL
|| glob
->disk_inhibited
|| (fl
&& fl
->fl_Volume
!= MKBADDR(glob
->sb
->doslist
)))
63 return ERROR_DEVICE_NOT_MOUNTED
;
65 if (fl
&& fl
->magic
!= ID_FAT_DISK
)
66 return ERROR_OBJECT_WRONG_TYPE
;
71 LONG
LockFileByName(struct ExtFileLock
*fl
, UBYTE
*name
, LONG namelen
, LONG access
, struct ExtFileLock
**lock
, struct Globals
*glob
) {
72 LONG err
= ERROR_OBJECT_NOT_FOUND
;
77 /* if the name is empty, just duplicate the base lock */
79 return CopyLock(fl
, lock
, glob
);
81 /* if the base lock is a file, the name must either be empty (handled
82 * above) or start with '/' (handled here) */
83 if (fl
!= NULL
&& !(fl
->gl
->attr
& ATTR_DIRECTORY
)) {
86 return OpLockParent(fl
, lock
, glob
);
93 return ERROR_OBJECT_WRONG_TYPE
;
96 /* the . and .. entries are invisible to the user */
97 if (name
[0] == '.' && (namelen
== 1 || (name
[1] == '.' && namelen
== 2))) {
98 D(bug("[fat] not allowing access to '.' or '..' entries\n"));
99 return ERROR_OBJECT_NOT_FOUND
;
102 /* get the first cluster of the directory to look for the file in */
105 else if (fl
->gl
->attr
& ATTR_DIRECTORY
)
106 dir_cluster
= fl
->ioh
.first_cluster
;
108 dir_cluster
= fl
->gl
->dir_cluster
;
110 D(bug("[fat] trying to obtain lock on '"); RawPutChars(name
, namelen
);
111 bug("' in dir at cluster %ld\n", dir_cluster
));
114 InitDirHandle(glob
->sb
, dir_cluster
, &dh
, FALSE
);
116 /* look for the entry */
117 if ((err
= GetDirEntryByPath(&dh
, name
, namelen
, &de
)) != 0) {
118 ReleaseDirHandle(&dh
);
119 D(bug("[fat] couldn't get lock\n"));
123 /* found it, do the locking proper */
124 if (de
.e
.entry
.attr
& ATTR_DIRECTORY
&& FIRST_FILE_CLUSTER(&de
)
125 <= glob
->sb
->rootdir_cluster
)
126 err
= LockRoot(access
, lock
, glob
);
128 err
= LockFile(dh
.ioh
.first_cluster
, de
.index
, access
, lock
, glob
);
130 ReleaseDirHandle(&dh
);
135 LONG
LockFile(ULONG dir_cluster
, ULONG dir_entry
, LONG access
, struct ExtFileLock
**lock
, struct Globals
*glob
) {
136 struct GlobalLock
*node
, *gl
;
137 struct ExtFileLock
*fl
;
142 D(bug("[fat] locking file (%ld/%ld) (%s)\n", dir_cluster
, dir_entry
, access
== SHARED_LOCK
? "shared" : "exclusive"));
144 /* first see if we already have a global lock for this file */
146 ForeachNode(&glob
->sb
->info
->locks
, node
)
147 if (node
->dir_cluster
== dir_cluster
&& node
->dir_entry
== dir_entry
) {
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("[fat] can't obtain exclusive lock on already-locked file\n"));
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
->sb
->info
->mem_pool
,
162 sizeof(struct ExtFileLock
))) == NULL
)
163 return ERROR_NO_FREE_STORE
;
165 /* if we don't have a global lock we need to build one */
167 if ((gl
= AllocVecPooled(glob
->sb
->info
->mem_pool
,
168 sizeof(struct GlobalLock
))) == NULL
) {
169 FreeVecPooled(glob
->sb
->info
->mem_pool
, fl
);
170 return ERROR_NO_FREE_STORE
;
173 gl
->dir_cluster
= dir_cluster
;
174 gl
->dir_entry
= dir_entry
;
177 /* gotta fish some stuff out of the dir entry too */
178 InitDirHandle(glob
->sb
, dir_cluster
, &dh
, FALSE
);
179 GetDirEntry(&dh
, dir_entry
, &de
);
181 gl
->first_cluster
= FIRST_FILE_CLUSTER(&de
);
182 if (gl
->first_cluster
== 0) gl
->first_cluster
= 0xffffffff;
184 gl
->attr
= de
.e
.entry
.attr
;
185 gl
->size
= AROS_LE2LONG(de
.e
.entry
.file_size
);
187 GetDirEntryShortName(&de
, &(gl
->name
[1]), &len
); gl
->name
[0] = (UBYTE
) len
;
188 GetDirEntryLongName(&de
, &(gl
->name
[1]), &len
); gl
->name
[0] = (UBYTE
) len
;
190 GetDirEntryShortName(&de
, &(gl
->shortname
[1]), &len
); gl
->shortname
[0] = (UBYTE
) len
;
193 ReleaseDirHandle(&dh
);
197 ADDTAIL(&glob
->sb
->info
->locks
, gl
);
199 D(bug("[fat] created new global lock\n"));
201 /* look through the notify list. if there's any in there that aren't
202 * currently attached to a global lock, expand them and if they are
203 * for this file, fill them in */
205 struct NotifyNode
*nn
;
207 ForeachNode(&glob
->sb
->info
->notifies
, nn
)
208 if (nn
->gl
== NULL
) {
209 D(bug("[fat] searching for notify name '%s'\n", nn
->nr
->nr_FullName
));
211 if (InitDirHandle(glob
->sb
, 0, &dh
, TRUE
) != 0)
214 if (GetDirEntryByPath(&dh
, nn
->nr
->nr_FullName
, strlen(nn
->nr
->nr_FullName
), &de
) != 0)
217 if (gl
->dir_cluster
== de
.cluster
&& gl
->dir_entry
== de
.index
) {
218 D(bug("[fat] found and matched to the global lock (%ld/%ld)\n", gl
->dir_cluster
, gl
->dir_entry
));
225 /* now setup the file lock */
228 fl
->fl_Access
= access
;
229 fl
->fl_Task
= glob
->ourport
;
230 fl
->fl_Volume
= MKBADDR(glob
->sb
->doslist
);
232 fl
->magic
= ID_FAT_DISK
;
234 fl
->ioh
.sb
= glob
->sb
;
235 fl
->ioh
.first_cluster
= gl
->first_cluster
;
236 fl
->ioh
.block
= NULL
;
237 RESET_HANDLE(&(fl
->ioh
));
241 fl
->do_notify
= FALSE
;
245 ADDTAIL(&gl
->locks
, &fl
->node
);
247 D(bug("[fat] created file lock 0x%08x\n", fl
));
255 LONG
LockRoot(LONG access
, struct ExtFileLock
**lock
, struct Globals
*glob
) {
256 struct ExtFileLock
*fl
;
258 D(bug("[fat] locking root\n"));
260 if (access
== EXCLUSIVE_LOCK
) {
261 D(bug("[fat] can't obtain exclusive lock on the fs root\n"));
262 return ERROR_OBJECT_IN_USE
;
265 if ((fl
= AllocVecPooled(glob
->sb
->info
->mem_pool
,
266 sizeof(struct ExtFileLock
))) == NULL
)
267 return ERROR_NO_FREE_STORE
;
271 fl
->fl_Access
= SHARED_LOCK
;
272 fl
->fl_Task
= glob
->ourport
;
273 fl
->fl_Volume
= MKBADDR(glob
->sb
->doslist
);
275 fl
->magic
= ID_FAT_DISK
;
277 fl
->ioh
.sb
= glob
->sb
;
278 fl
->ioh
.first_cluster
= 0;
279 fl
->ioh
.block
= NULL
;
280 RESET_HANDLE(&(fl
->ioh
));
284 fl
->do_notify
= FALSE
;
286 if (IsListEmpty(&glob
->sb
->info
->root_lock
.locks
))
287 ADDTAIL(&glob
->sb
->info
->locks
, &glob
->sb
->info
->root_lock
);
288 fl
->gl
= &glob
->sb
->info
->root_lock
;
290 ADDTAIL(&glob
->sb
->info
->root_lock
.locks
, &fl
->node
);
292 D(bug("[fat] created root lock 0x%08x\n", fl
));
300 LONG
CopyLock(struct ExtFileLock
*fl
, struct ExtFileLock
**lock
, struct Globals
*glob
) {
301 D(bug("[fat] copying lock\n"));
303 if (fl
== NULL
|| fl
->gl
== &glob
->sb
->info
->root_lock
)
304 return LockRoot(SHARED_LOCK
, lock
, glob
);
306 if (fl
->fl_Access
== EXCLUSIVE_LOCK
) {
307 D(bug("[fat] can't copy exclusive lock\n"));
308 return ERROR_OBJECT_IN_USE
;
311 return LockFile(fl
->gl
->dir_cluster
, fl
->gl
->dir_entry
, SHARED_LOCK
, lock
, glob
);
314 void FreeLock(struct ExtFileLock
*fl
, struct Globals
*glob
) {
315 struct NotifyNode
*nn
;
320 D(bug("[fat] freeing lock 0x%08x\n", fl
));
323 SendNotifyByLock(fl
->ioh
.sb
, fl
->gl
);
327 if (IsListEmpty((struct List
*)&fl
->gl
->locks
)) {
330 ForeachNode(&fl
->sb
->info
->notifies
, nn
)
334 if (fl
->gl
!= &fl
->sb
->info
->root_lock
)
335 FreeVecPooled(glob
->sb
->info
->mem_pool
, fl
->gl
);
337 D(bug("[fat] freed associated global lock\n"));
341 if (fl
->ioh
.block
!= NULL
)
342 Cache_FreeBlock(fl
->sb
->cache
, fl
->ioh
.block
);
344 if (fl
->sb
!= glob
->sb
)
345 AttemptDestroyVolume(fl
->sb
);
347 FreeVecPooled(glob
->sb
->info
->mem_pool
, fl
);