r25972@plastic: rob | 2007-04-15 01:04:52 +1000
[cake.git] / workbench / fs / fat / disk.c
blob474494a9fa462dee4a4bff87810d4409f2f7ea49
1 /*
2 * fat.handler - FAT12/16/32 filesystem handler
4 * Copyright © 2006 Marek Szyprowski
5 * Copyright © 2007 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 USE_INLINE_STDARG
15 #include <exec/types.h>
16 #include <exec/execbase.h>
17 #include <exec/libraries.h>
18 #include <exec/errors.h>
20 #include <dos/dos.h>
21 #include <dos/dosextens.h>
22 #include <dos/dostags.h>
23 #include <dos/filehandler.h>
24 #include <devices/trackdisk.h>
25 #include <devices/inputevent.h>
27 #include <proto/exec.h>
28 #include <proto/dos.h>
30 #include <string.h> /* for memset() */
32 #include "fat_fs.h"
33 #include "fat_protos.h"
35 #ifndef ID_BUSY
36 #define ID_BUSY 0x42555359
37 #endif
40 void FillDiskInfo (struct InfoData *id) {
41 struct DosEnvec *de = BADDR(glob->fssm->fssm_Environ);
43 id->id_NumSoftErrors = 0;
44 id->id_UnitNumber = glob->fssm->fssm_Unit;
45 id->id_DiskState = ID_VALIDATED;
47 if (glob->sb) {
48 CountFreeClusters(glob->sb);
50 id->id_NumBlocks = glob->sb->total_sectors;
51 id->id_NumBlocksUsed = glob->sb->total_sectors - ((glob->sb->free_clusters * glob->sb->clustersize) >> glob->sb->sectorsize_bits);
52 id->id_BytesPerBlock = glob->sb->sectorsize;
54 id->id_DiskType = (glob->sb->type == 12) ? ID_FAT12_DISK :
55 (glob->sb->type == 16) ? ID_FAT16_DISK :
56 (glob->sb->type == 32) ? ID_FAT32_DISK :
57 ID_FAT12_DISK;
59 id->id_VolumeNode = MKBADDR(glob->sb->doslist);
60 id->id_InUse = glob->sb->doslist->dol_misc.dol_volume.dol_LockList ? DOSTRUE : DOSFALSE;
63 else {
64 id->id_NumBlocks = de->de_Surfaces * de->de_BlocksPerTrack * (de->de_HighCyl+1 - de->de_LowCyl) / de->de_SectorPerBlock;
65 id->id_NumBlocksUsed = id->id_NumBlocks;
66 id->id_BytesPerBlock = de->de_SizeBlock << 2;
68 id->id_DiskState = ID_VALIDATED;
70 if (glob->disk_inhibited)
71 id->id_DiskType = ID_BUSY;
72 else if (glob->disk_inserted)
73 id->id_DiskType = ID_NOT_REALLY_DOS; //ID_UNREADABLE_DISK;
74 else
75 id->id_DiskType = ID_NO_DISK_PRESENT;
77 id->id_VolumeNode = NULL;
78 id->id_InUse = DOSFALSE;
82 LONG InitDevice(struct FileSysStartupMsg *fssm, LONG blocksize) {
83 glob->blocksize = blocksize;
84 glob->cache = cache_new(64, 256, blocksize, 0);
86 return 0;
89 void SendVolumePacket(struct DosList *vol, ULONG action) {
90 struct DosPacket *dospacket;
92 dospacket = AllocDosObject(DOS_STDPKT, TAG_DONE);
93 dospacket->dp_Type = ACTION_DISK_CHANGE;
94 dospacket->dp_Arg1 = ID_FAT_DISK;
95 dospacket->dp_Arg2 = (ULONG) vol;
96 dospacket->dp_Arg3 = action;
97 dospacket->dp_Port = NULL;
99 PutMsg(glob->ourport, dospacket->dp_Link);
102 void DoDiskInsert(void) {
103 struct FSSuper *sb;
105 if (glob->sb == NULL && (sb = AllocVecPooled(glob->mempool, sizeof(struct FSSuper)))) {
106 memset(sb, 0, sizeof(struct FSSuper));
108 if (ReadFATSuper(sb) == 0) {
109 LONG found = FALSE;
111 if (glob->sblist) {
112 struct FSSuper *ptr = glob->sblist, *prev = NULL;
114 while (ptr != NULL) {
115 if (CompareFATSuper(sb, ptr) == 0)
116 break;
118 prev = ptr;
119 ptr = ptr->next;
122 if (ptr) {
123 kprintf("\tFound FAT FS Super Block in spare list, freeing obsolete old one\n");
125 sb->doslist = ptr->doslist;
126 ptr->doslist = NULL;
127 sb->doslist->dol_Name = (BSTR)MKBADDR(&sb->volume.name);
129 if (prev)
130 prev->next = ptr->next;
131 else
132 glob->sblist = ptr->next;
134 FreeFATSuper(ptr);
135 FreeVecPooled(glob->mempool, ptr);
137 found = TRUE;
141 if (!found) {
142 struct DosList *newvol;
144 kprintf("\tCreating new volume.\n");
146 if ((newvol = AllocVecPooled(glob->mempool, sizeof(struct DosList)))) {
147 newvol->dol_Next = NULL;
148 newvol->dol_Type = DLT_VOLUME;
149 newvol->dol_Task = glob->ourport;
150 newvol->dol_Lock = NULL;
152 CopyMem(&sb->volume.create_time, &newvol->dol_misc.dol_volume.dol_VolumeDate, sizeof(struct DateStamp));
154 newvol->dol_misc.dol_volume.dol_LockList = NULL;
156 newvol->dol_misc.dol_volume.dol_DiskType = (sb->type == 12) ? ID_FAT12_DISK :
157 (sb->type == 16) ? ID_FAT16_DISK :
158 (sb->type == 32) ? ID_FAT32_DISK :
159 ID_FAT12_DISK;
161 #ifdef AROS_FAST_BPTR
162 /* ReadFATSuper() sets a null byte * after the string, so
163 * this should be fine */
164 newvol->dol_Name = (BSTR)MKBADDR(&(sb->volume.name[1]));
165 #else
166 newvol->dol_Name = (BSTR)MKBADDR(&sb->volume.name);
167 #endif
169 sb->doslist = newvol;
171 SendVolumePacket(newvol, ACTION_VOLUME_ADD);
175 else
176 SendEvent(IECLASS_DISKINSERTED);
178 glob->sb = sb;
180 kprintf("\tDisk successfully initialised\n");
182 return;
185 FreeVecPooled(glob->mempool, sb);
188 SendEvent(IECLASS_DISKINSERTED);
190 return;
193 void DoDiskRemove(void) {
195 if (glob->sb) {
196 struct FSSuper *sb = glob->sb;
198 glob->sb = NULL;
200 if (sb->doslist->dol_misc.dol_volume.dol_LockList == NULL) { /* check if the device can be removed */
201 kprintf("\tRemoving disk completely\n");
203 SendVolumePacket(sb->doslist, ACTION_VOLUME_REMOVE);
205 sb->doslist = NULL;
206 FreeFATSuper(sb);
207 FreeVecPooled(glob->mempool, sb);
209 else {
210 sb->next = glob->sblist;
211 glob->sblist = sb;
213 kprintf("\tMoved in-memory super block to spare list. Waiting for locks to be freed\n");
215 SendEvent(IECLASS_DISKREMOVED);
220 void ProcessDiskChange(void) {
221 kprintf("\nGot disk change request\n");
223 if (glob->disk_inhibited) {
224 kprintf("Disk is inhibited, ignoring disk change\n");
225 return;
228 glob->diskioreq->iotd_Req.io_Command = TD_CHANGESTATE;
229 glob->diskioreq->iotd_Req.io_Data = NULL;
230 glob->diskioreq->iotd_Req.io_Length = 0;
231 glob->diskioreq->iotd_Req.io_Flags = IOF_QUICK;
232 DoIO((struct IORequest*) glob->diskioreq);
234 if (glob->diskioreq->iotd_Req.io_Error == 0 && glob->diskioreq->iotd_Req.io_Actual == 0) {
235 /* Disk has been inserted. */
236 kprintf("\tDisk has been inserted\n");
237 glob->disk_inserted = TRUE;
238 DoDiskInsert();
240 else {
241 /* Disk has been removed. */
242 kprintf("\tDisk has been removed\n");
243 glob->disk_inserted = FALSE;
244 DoDiskRemove();
247 kprintf("Done\n");