1/*
2	Copyright 1999-2001, Be Incorporated.   All Rights Reserved.
3	This file may be used under the terms of the Be Sample Code License.
4*/
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <sys/stat.h>
9#include <time.h>
10
11#include <KernelExport.h>
12#include <Drivers.h>
13#include <driver_settings.h>
14
15#include <scsi.h>
16
17#include <fsproto.h>
18#ifndef COMPILE_IN_BEOS
19#include <fs_volume.h>
20#endif
21#include <lock.h>
22#include <cache.h>
23
24#include "dosfs.h"
25#include "attr.h"
26#include "dir.h"
27#include "dlist.h"
28#include "fat.h"
29#include "file.h"
30#include "iter.h"
31#include "util.h"
32#include "vcache.h"
33
34extern const char *build_time, *build_date;
35
36/* debug levels */
37int debug_attr = 0, debug_dir = 0, debug_dlist = 0, debug_dosfs = 0,
38		debug_encodings = 0, debug_fat = 0, debug_file = 0,
39		debug_iter = 0, debug_vcache = 0;
40
41#define DPRINTF(a,b) if (debug_dosfs > (a)) dprintf b
42
43CHECK_MAGIC(vnode,struct vnode,VNODE_MAGIC)
44CHECK_MAGIC(nspace,struct _nspace, NSPACE_MAGIC)
45
46static status_t get_fsinfo(nspace *vol, uint32 *free_count, uint32 *last_allocated);
47
48#if DEBUG
49
50int32 instances = 0;
51
52int debug_dos(int argc, char **argv)
53{
54	int i;
55	for (i=1;i<argc;i++) {
56		nspace *vol = (nspace *)strtoul(argv[i], NULL, 0);
57		if (vol == NULL)
58			continue;
59
60		kprintf("dos nspace @ %p\n", vol);
61		kprintf("magic: %lx\n", vol->magic);
62		kprintf("id: %lx, fd: %x, device: %s, flags %lx\n",
63				vol->id, vol->fd, vol->device, vol->flags);
64		kprintf("bytes/sector = %lx, sectors/cluster = %lx, reserved sectors = %lx\n",
65				vol->bytes_per_sector, vol->sectors_per_cluster,
66				vol->reserved_sectors);
67		kprintf("%lx fats, %lx root entries, %lx total sectors, %lx sectors/fat\n",
68				vol->fat_count, vol->root_entries_count, vol->total_sectors,
69				vol->sectors_per_fat);
70		kprintf("media descriptor %x, fsinfo sector %x, %lx clusters, %lx free\n",
71				vol->media_descriptor, vol->fsinfo_sector, vol->total_clusters,
72				vol->free_clusters);
73		kprintf("%x-bit fat, mirrored %x, active %x\n",
74				vol->fat_bits, vol->fat_mirrored, vol->active_fat);
75		kprintf("root start %lx, %lx root sectors, root vnode @ %p\n",
76				vol->root_start, vol->root_sectors, &(vol->root_vnode));
77		kprintf("label entry %lx, label %s\n", vol->vol_entry, vol->vol_label);
78		kprintf("data start %lx, last allocated %lx\n",
79				vol->data_start, vol->last_allocated);
80		kprintf("last fake vnid %Lx, vnid cache %lx entries @ (%p %p)\n",
81				vol->vcache.cur_vnid, vol->vcache.cache_size,
82				vol->vcache.by_vnid, vol->vcache.by_loc);
83		kprintf("dlist entries: %lx/%lx @ %p\n",
84				vol->dlist.entries, vol->dlist.allocated, vol->dlist.vnid_list);
85	}
86	return B_OK;
87}
88
89int debug_dvnode(int argc, char **argv)
90{
91	int i;
92
93	if (argc < 2) {
94		kprintf("dvnode vnode\n");
95		return B_OK;
96	}
97
98	for (i=1;i<argc;i++) {
99		vnode *n = (vnode *)strtoul(argv[i], NULL, 0);
100		if (!n) continue;
101
102		kprintf("vnode @ %p", n);
103#if TRACK_FILENAME
104		kprintf(" (%s)", n->filename);
105#endif
106		kprintf("\nmagic %lx, vnid %Lx, dir vnid %Lx\n",
107				n->magic, n->vnid, n->dir_vnid);
108		kprintf("iteration %lx, si=%lx, ei=%lx, cluster=%lx\n",
109				n->iteration, n->sindex, n->eindex, n->cluster);
110		kprintf("mode %lx, size %Lx, time %lx\n",
111				n->mode, n->st_size, n->st_time);
112		kprintf("end cluster = %lx\n", n->end_cluster);
113		if (n->mime) kprintf("mime type %s\n", n->mime);
114	}
115
116	return B_OK;
117}
118
119int debug_dc2s(int argc, char **argv)
120{
121	int i;
122	nspace *vol;
123
124	if (argc < 3) {
125		kprintf("dc2s nspace cluster\n");
126		return B_OK;
127	}
128
129	vol = (nspace *)strtoul(argv[1], NULL, 0);
130	if (vol == NULL)
131		return B_OK;
132
133	for (i=2;i<argc;i++) {
134		uint32 cluster = strtoul(argv[i], NULL, 0);
135		kprintf("cluster %lx = block %Lx\n", cluster, vol->data_start +
136				(off_t)(cluster - 2) * vol->sectors_per_cluster);
137	}
138
139	return B_OK;
140}
141
142#endif
143
144static int lock_removable_device(int fd, bool state)
145{
146	return ioctl(fd, B_SCSI_PREVENT_ALLOW, &state, sizeof(state));
147}
148
149static status_t mount_fat_disk(const char *path, nspace_id nsid,
150		const int flags, nspace** newVol, int fs_flags, int op_sync_mode)
151{
152	nspace		*vol = NULL;
153	uint8		buf[512];
154	int			i;
155	device_geometry geo;
156	status_t err;
157
158	*newVol = NULL;
159	if ((vol = (nspace*)calloc(sizeof(nspace), 1)) == NULL) {
160		dprintf("dosfs error: out of memory\n");
161		return ENOMEM;
162	}
163
164	vol->magic = NSPACE_MAGIC;
165	vol->flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME;
166	vol->fs_flags = fs_flags;
167
168	// open read-only for now
169	if ((err = (vol->fd = open(path, O_RDONLY))) < 0) {
170		dprintf("dosfs: unable to open %s (%s)\n", path, strerror(err));
171		goto error0;
172	}
173
174	// get device characteristics
175	if (ioctl(vol->fd, B_GET_GEOMETRY, &geo) < 0) {
176		struct stat st;
177		if ((fstat(vol->fd, &st) >= 0) &&
178		    S_ISREG(st.st_mode)) {
179			/* support mounting disk images */
180			geo.bytes_per_sector = 0x200;
181			geo.sectors_per_track = 1;
182			geo.cylinder_count = st.st_size / 0x200;
183			geo.head_count = 1;
184			geo.read_only = !(st.st_mode & S_IWUSR);
185			geo.removable = true;
186		} else {
187			dprintf("dosfs: error getting device geometry\n");
188			goto error0;
189		}
190	}
191	if ((geo.bytes_per_sector != 0x200) && (geo.bytes_per_sector != 0x400) && (geo.bytes_per_sector != 0x800)) {
192		dprintf("dosfs: unsupported device block size (%lu)\n", geo.bytes_per_sector);
193		goto error0;
194	}
195	if (geo.removable) {
196		DPRINTF(0, ("%s is removable\n", path));
197		vol->flags |= B_FS_IS_REMOVABLE;
198	}
199	if (geo.read_only || (flags & B_MOUNT_READ_ONLY)) {
200		DPRINTF(0, ("%s is read-only\n", path));
201		vol->flags |= B_FS_IS_READONLY;
202	} else {
203		// reopen it with read/write permissions
204		close(vol->fd);
205		if ((err = (vol->fd = open(path, O_RDWR))) < 0) {
206			dprintf("dosfs: unable to open %s (%s)\n", path, strerror(err));
207			goto error0;
208		}
209		if ((vol->flags & B_FS_IS_REMOVABLE) && (vol->fs_flags & FS_FLAGS_LOCK_DOOR))
210			lock_removable_device(vol->fd, true);
211	}
212
213	// see if we need to go into op sync mode
214	vol->fs_flags &= ~FS_FLAGS_OP_SYNC;
215	switch(op_sync_mode) {
216		case 1:
217			if((vol->flags & B_FS_IS_REMOVABLE) == 0) {
218				// we're not removable, so skip op_sync
219				break;
220			}
221		case 2:
222			dprintf("dosfs: mounted with op_sync enabled\n");
223			vol->fs_flags |= FS_FLAGS_OP_SYNC;
224			break;
225		case 0:
226		default:
227			;
228	}
229
230	// read in the boot sector
231	if ((err = read_pos(vol->fd, 0, (void*)buf, 512)) != 512) {
232		dprintf("dosfs: error reading boot sector\n");
233		goto error;
234	}
235
236	// only check boot signature on hard disks to account for broken mtools
237	// behavior
238	if (((buf[0x1fe] != 0x55) || (buf[0x1ff] != 0xaa)) && (buf[0x15] == 0xf8))
239		goto error;
240
241	if (!memcmp(buf+3, "NTFS    ", 8) || !memcmp(buf+3, "HPFS    ", 8)) {
242		dprintf("%4.4s, not FAT\n", buf+3);
243		goto error;
244	}
245
246	// first fill in the universal fields from the bpb
247	vol->bytes_per_sector = read16(buf,0xb);
248	if ((vol->bytes_per_sector != 0x200) && (vol->bytes_per_sector != 0x400) && (vol->bytes_per_sector != 0x800)) {
249		dprintf("dosfs error: unsupported bytes per sector (%lu)\n",
250				vol->bytes_per_sector);
251		goto error;
252	}
253
254	vol->sectors_per_cluster = i = buf[0xd];
255	if ((i != 1) && (i != 2) && (i != 4) && (i != 8) &&
256		(i != 0x10) && (i != 0x20) && (i != 0x40) && (i != 0x80)) {
257		dprintf("dosfs: sectors/cluster = %d\n", i);
258		goto error;
259	}
260
261	vol->reserved_sectors = read16(buf,0xe);
262
263	vol->fat_count = buf[0x10];
264	if ((vol->fat_count == 0) || (vol->fat_count > 8)) {
265		dprintf("dosfs: unreasonable fat count (%lu)\n", vol->fat_count);
266		goto error;
267	}
268
269	vol->media_descriptor = buf[0x15];
270	// check media descriptor versus known types
271	if ((buf[0x15] != 0xF0) && (buf[0x15] < 0xf8)) {
272		dprintf("dosfs error: invalid media descriptor byte\n");
273		goto error;
274	}
275
276	vol->vol_entry = -2;	// for now, assume there is no volume entry
277	memset(vol->vol_label, ' ', 11);
278
279	// now become more discerning citizens
280	vol->sectors_per_fat = read16(buf,0x16);
281	if (vol->sectors_per_fat == 0) {
282		// fat32 land
283		vol->fat_bits = 32;
284		vol->sectors_per_fat = read32(buf,0x24);
285		vol->total_sectors = read32(buf,0x20);
286
287		vol->fsinfo_sector = read16(buf, 0x30);
288		if ((vol->fsinfo_sector != 0xffff) && (vol->fsinfo_sector >= vol->reserved_sectors)) {
289			dprintf("dosfs: fsinfo sector too large (%x)\n", vol->fsinfo_sector);
290			goto error;
291		}
292
293		vol->fat_mirrored = !(buf[0x28] & 0x80);
294		vol->active_fat = (vol->fat_mirrored) ? (buf[0x28] & 0xf) : 0;
295
296		vol->data_start = vol->reserved_sectors + vol->fat_count*vol->sectors_per_fat;
297		vol->total_clusters = (vol->total_sectors - vol->data_start) / vol->sectors_per_cluster;
298
299		vol->root_vnode.cluster = read32(buf,0x2c);
300		if (vol->root_vnode.cluster >= vol->total_clusters) {
301			dprintf("dosfs: root vnode cluster too large (%lx)\n", vol->root_vnode.cluster);
302			goto error;
303		}
304	} else {
305		// fat12 & fat16
306		if (vol->fat_count != 2) {
307			dprintf("dosfs error: claims %ld fat tables\n", vol->fat_count);
308			goto error;
309		}
310
311		vol->root_entries_count = read16(buf,0x11);
312		if (vol->root_entries_count % (vol->bytes_per_sector / 0x20)) {
313			dprintf("dosfs error: invalid number of root entries\n");
314			goto error;
315		}
316
317		vol->fsinfo_sector = 0xffff;
318		vol->total_sectors = read16(buf,0x13); // partition size
319		if (vol->total_sectors == 0)
320			vol->total_sectors = read32(buf,0x20);
321
322		{
323			/*
324			  Zip disks that were formatted at iomega have an incorrect number
325			  of sectors.  They say that they have 196576 sectors but they
326			  really only have 196192.  This check is a work-around for their
327			  brain-deadness.
328			*/
329			unsigned char bogus_zip_data[] = {
330				0x00, 0x02, 0x04, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00,
331				0xf8, 0xc0, 0x00, 0x20, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00
332			};
333
334			if (memcmp(buf+0x0b, bogus_zip_data, sizeof(bogus_zip_data)) == 0 &&
335				vol->total_sectors == 196576 &&
336				((off_t)geo.sectors_per_track *
337				 (off_t)geo.cylinder_count *
338				 (off_t)geo.head_count) == 196192) {
339
340				vol->total_sectors = 196192;
341			}
342		}
343
344
345		if (buf[0x26] == 0x29) {
346			// fill in the volume label
347			if (memcmp(buf+0x2b, "           ", 11)) {
348				memcpy(vol->vol_label, buf+0x2b, 11);
349				vol->vol_entry = -1;
350			}
351		}
352
353		vol->fat_mirrored = true;
354		vol->active_fat = 0;
355
356		vol->root_start = vol->reserved_sectors + vol->fat_count * vol->sectors_per_fat;
357		vol->root_sectors = vol->root_entries_count * 0x20 / vol->bytes_per_sector;
358		vol->root_vnode.cluster = 1;
359		vol->root_vnode.end_cluster = 1;
360		vol->root_vnode.st_size = vol->root_sectors * vol->bytes_per_sector;
361
362		vol->data_start = vol->root_start + vol->root_sectors;
363		vol->total_clusters = (vol->total_sectors - vol->data_start) / vol->sectors_per_cluster;
364
365		// XXX: uncertain about border cases; win32 sdk says cutoffs are at
366		//      at ff6/ff7 (or fff6/fff7), but that doesn't make much sense
367		if (vol->total_clusters > 0xff1)
368			vol->fat_bits = 16;
369		else
370			vol->fat_bits = 12;
371	}
372
373	/* check that the partition is large enough to contain the file system */
374	if (vol->total_sectors > geo.sectors_per_track * geo.cylinder_count *
375			geo.head_count) {
376		dprintf("dosfs: volume extends past end of partition\n");
377		err = B_PARTITION_TOO_SMALL;
378		goto error;
379	}
380
381	// perform sanity checks on the FAT
382
383	// the media descriptor in active FAT should match the one in the BPB
384	if ((err = read_pos(vol->fd, vol->bytes_per_sector*(vol->reserved_sectors + vol->active_fat * vol->sectors_per_fat), (void *)buf, 0x200)) != 0x200) {
385		dprintf("dosfs: error reading FAT\n");
386		goto error;
387	}
388
389	if (buf[0] != vol->media_descriptor) {
390		dprintf("dosfs error: media descriptor mismatch (%x != %x)\n", buf[0], vol->media_descriptor);
391		goto error;
392	}
393
394	if (vol->fat_mirrored) {
395		uint32 i;
396		uint8 buf2[512];
397		for (i=0;i<vol->fat_count;i++) {
398			if (i != vol->active_fat) {
399				DPRINTF(1, ("checking fat #%ld\n", i));
400				buf2[0] = ~buf[0];
401				if ((err = read_pos(vol->fd, vol->bytes_per_sector*(vol->reserved_sectors + vol->sectors_per_fat*i), (void *)buf2, 0x200)) != 0x200) {
402					dprintf("dosfs: error reading FAT %ld\n", i);
403					goto error;
404				}
405
406				if (buf2[0] != vol->media_descriptor) {
407					dprintf("dosfs error: media descriptor mismatch in fat # %ld (%x != %x)\n", i, buf2[0], vol->media_descriptor);
408					goto error;
409				}
410#if 0
411				// checking for exact matches of fats is too
412				// restrictive; allow these to go through in
413				// case the fat is corrupted for some reason
414				if (memcmp(buf, buf2, 0x200)) {
415					dprintf("dosfs error: fat %d doesn't match active fat (%d)\n", i, vol->active_fat);
416					goto error;
417				}
418#endif
419			}
420		}
421	}
422
423	// now we are convinced of the drive's validity
424
425	vol->id = nsid;
426	strncpy(vol->device,path,256);
427
428	// this will be updated later if fsinfo exists
429	vol->last_allocated = 2;
430
431	vol->beos_vnid = INVALID_VNID_BITS_MASK;
432	{
433		void *handle;
434		handle = load_driver_settings("dos");
435		vol->respect_disk_image =
436				get_driver_boolean_parameter(handle, "respect", true, true);
437		unload_driver_settings(handle);
438	}
439
440	// initialize block cache
441	if (init_cache_for_device(vol->fd, (off_t)vol->total_sectors) < 0) {
442		dprintf("error initializing block cache\n");
443		goto error;
444	}
445
446	// as well as the vnode cache
447	if (init_vcache(vol) != B_OK) {
448		dprintf("error initializing vnode cache\n");
449		goto error1;
450	}
451
452	// and the dlist cache
453	if (dlist_init(vol) != B_OK) {
454		dprintf("error initializing dlist cache\n");
455		goto error2;
456	}
457
458	if (vol->flags & B_FS_IS_READONLY)
459		vol->free_clusters = 0;
460	else {
461		uint32 free_count, last_allocated;
462		err = get_fsinfo(vol, &free_count, &last_allocated);
463		if (err >= 0) {
464			if (free_count < vol->total_clusters)
465				vol->free_clusters = free_count;
466			else {
467				dprintf("free cluster count from fsinfo block invalid %lx\n", free_count);
468				err = -1;
469			}
470			if (last_allocated < vol->total_clusters)
471				vol->last_allocated = last_allocated; //update to a closer match
472		}
473		if (err < 0) {
474			if ((err = count_free_clusters(vol)) < 0) {
475				dprintf("error counting free clusters (%s)\n", strerror(err));
476				goto error3;
477			}
478			vol->free_clusters = err;
479		}
480	}
481
482	DPRINTF(0, ("built at %s on %s\n", build_time, build_date));
483	DPRINTF(0, ("mounting %s (id %lx, device %x, media descriptor %x)\n", vol->device, vol->id, vol->fd, vol->media_descriptor));
484	DPRINTF(0, ("%lx bytes/sector, %lx sectors/cluster\n", vol->bytes_per_sector, vol->sectors_per_cluster));
485	DPRINTF(0, ("%lx reserved sectors, %lx total sectors\n", vol->reserved_sectors, vol->total_sectors));
486	DPRINTF(0, ("%lx %d-bit fats, %lx sectors/fat, %lx root entries\n", vol->fat_count, vol->fat_bits, vol->sectors_per_fat, vol->root_entries_count));
487	DPRINTF(0, ("root directory starts at sector %lx (cluster %lx), data at sector %lx\n", vol->root_start, vol->root_vnode.cluster, vol->data_start));
488	DPRINTF(0, ("%lx total clusters, %lx free\n", vol->total_clusters, vol->free_clusters));
489	DPRINTF(0, ("fat mirroring is %s, fs info sector at sector %x\n", (vol->fat_mirrored) ? "on" : "off", vol->fsinfo_sector));
490	DPRINTF(0, ("last allocated cluster = %lx\n", vol->last_allocated));
491
492	if (vol->fat_bits == 32) {
493		// now that the block cache has been initialised, we can figure
494		// out the length of the root directory with count_clusters()
495		vol->root_vnode.st_size = count_clusters(vol, vol->root_vnode.cluster) * vol->bytes_per_sector * vol->sectors_per_cluster;
496		vol->root_vnode.end_cluster = get_nth_fat_entry(vol, vol->root_vnode.cluster, vol->root_vnode.st_size / vol->bytes_per_sector / vol->sectors_per_cluster - 1);
497	}
498
499	// initialize root vnode
500	vol->root_vnode.magic = VNODE_MAGIC;
501	vol->root_vnode.vnid = vol->root_vnode.dir_vnid = GENERATE_DIR_CLUSTER_VNID(vol->root_vnode.cluster,vol->root_vnode.cluster);
502	vol->root_vnode.sindex = vol->root_vnode.eindex = 0xffffffff;
503	vol->root_vnode.mode = FAT_SUBDIR;
504	time(&(vol->root_vnode.st_time));
505	vol->root_vnode.mime = NULL;
506	vol->root_vnode.dirty = false;
507	dlist_add(vol, vol->root_vnode.vnid);
508
509	// find volume label (supercedes any label in the bpb)
510	{
511		struct diri diri;
512		uint8 *buffer;
513		buffer = diri_init(vol, vol->root_vnode.cluster, 0, &diri);
514		for (;buffer;buffer=diri_next_entry(&diri)) {
515			if ((buffer[0x0b] & FAT_VOLUME) && (buffer[0x0b] != 0xf) && (buffer[0] != 0xe5)) {
516				vol->vol_entry = diri.current_index;
517				memcpy(vol->vol_label, buffer, 11);
518				break;
519			}
520		}
521		diri_free(&diri);
522	}
523
524	DPRINTF(0, ("root vnode id = %Lx\n", vol->root_vnode.vnid));
525	DPRINTF(0, ("volume label [%11.11s] (%lx)\n", vol->vol_label, vol->vol_entry));
526
527	// steal a trick from bfs
528	if (!memcmp(vol->vol_label, "__RO__     ", 11)) {
529		vol->flags |= B_FS_IS_READONLY;
530	}
531
532	*newVol = vol;
533	return B_NO_ERROR;
534
535error3:
536	dlist_uninit(vol);
537error2:
538	uninit_vcache(vol);
539error1:
540	remove_cached_device_blocks(vol->fd, NO_WRITES);
541error:
542	if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE) && (vol->fs_flags & FS_FLAGS_LOCK_DOOR))
543		lock_removable_device(vol->fd, false);
544error0:
545	close(vol->fd);
546	free(vol);
547	return (err >= B_NO_ERROR) ? EINVAL : err;
548}
549
550static int dosfs_mount(nspace_id nsid, const char *device, ulong flags, void *parms,
551		size_t len, void **data, vnode_id *vnid)
552{
553	int	result;
554	nspace	*vol;
555	void *handle;
556	int op_sync_mode;
557	int fs_flags = 0;
558
559	handle = load_driver_settings("dos");
560		debug_attr = strtoul(get_driver_parameter(handle, "debug_attr", "0", "0"), NULL, 0);
561		debug_dir = strtoul(get_driver_parameter(handle, "debug_dir", "0", "0"), NULL, 0);
562		debug_dlist = strtoul(get_driver_parameter(handle, "debug_dlist", "0", "0"), NULL, 0);
563		debug_dosfs = strtoul(get_driver_parameter(handle, "debug_dosfs", "0", "0"), NULL, 0);
564		debug_encodings = strtoul(get_driver_parameter(handle, "debug_encodings", "0", "0"), NULL, 0);
565		debug_fat = strtoul(get_driver_parameter(handle, "debug_fat", "0", "0"), NULL, 0);
566		debug_file = strtoul(get_driver_parameter(handle, "debug_file", "0", "0"), NULL, 0);
567		debug_iter = strtoul(get_driver_parameter(handle, "debug_iter", "0", "0"), NULL, 0);
568		debug_vcache = strtoul(get_driver_parameter(handle, "debug_vcache", "0", "0"), NULL, 0);
569
570		op_sync_mode = strtoul(get_driver_parameter(handle, "op_sync_mode", "0", "0"), NULL, 0);
571		if (op_sync_mode < 0 || op_sync_mode > 2) {
572			op_sync_mode = 0;
573		}
574		if (strcasecmp(get_driver_parameter(handle, "lock_device", "true", "true"), "false") == 0) {
575			dprintf("dosfs: mounted with lock_device = false\n");
576		} else {
577			dprintf("dosfs: mounted with lock_device = true\n");
578			fs_flags |= FS_FLAGS_LOCK_DOOR;
579		}
580
581	unload_driver_settings(handle);
582
583	/* parms and len are command line options; dosfs doesn't use any so
584	   we can ignore these arguments */
585	TOUCH(parms); TOUCH(len);
586
587#if __RO__
588	// make it read-only
589	flags |= 1;
590#endif
591
592	if (data == NULL) {
593		dprintf("dosfs_mount passed NULL data pointer\n");
594		return EINVAL;
595	}
596
597	// Try and mount volume as a FAT volume
598	if ((result = mount_fat_disk(device, nsid, flags, &vol, fs_flags, op_sync_mode)) == B_NO_ERROR) {
599		char name[32];
600
601		if (check_nspace_magic(vol, "dosfs_mount")) return EINVAL;
602
603		*vnid = vol->root_vnode.vnid;
604		*data = (void*)vol;
605
606		// You MUST do this. Create the vnode for the root.
607		result = new_vnode(nsid, *vnid, (void*)&(vol->root_vnode));
608		if (result != B_NO_ERROR) {
609			dprintf("error creating new vnode (%s)\n", strerror(result));
610			goto error;
611		}
612		sprintf(name, "fat lock %lx", vol->id);
613		if ((result = new_lock(&(vol->vlock), name)) != 0) {
614			dprintf("error creating lock (%s)\n", strerror(result));
615			goto error;
616		}
617
618#if DEBUG
619		load_driver_symbols("dos");
620
621		if (atomic_add(&instances, 1) == 0) {
622			add_debugger_command("dos", debug_dos, "dump a dos nspace structure");
623			add_debugger_command("dvnode", debug_dvnode, "dump a dos vnode structure");
624			add_debugger_command("dfvnid", debug_dfvnid, "find a vnid in the vnid cache");
625			add_debugger_command("dfloc", debug_dfloc, "find a loc in the vnid cache");
626			add_debugger_command("dc2s", debug_dc2s, "calculate sector for cluster");
627		}
628#endif
629	}
630
631	return result;
632
633error:
634	remove_cached_device_blocks(vol->fd, NO_WRITES);
635	dlist_uninit(vol);
636	uninit_vcache(vol);
637	free(vol);
638	return EINVAL;
639}
640
641static void update_fsinfo(nspace *vol)
642{
643	if ((vol->fat_bits == 32) && (vol->fsinfo_sector != 0xffff) &&
644		((vol->flags & B_FS_IS_READONLY) == false)) {
645		uchar *buffer;
646		if ((buffer = (uchar *)get_block(vol->fd, vol->fsinfo_sector, vol->bytes_per_sector)) != NULL) {
647			if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) {
648				//number of free clusters
649				buffer[0x1e8] = (vol->free_clusters & 0xff);
650				buffer[0x1e9] = ((vol->free_clusters >> 8) & 0xff);
651				buffer[0x1ea] = ((vol->free_clusters >> 16) & 0xff);
652				buffer[0x1eb] = ((vol->free_clusters >> 24) & 0xff);
653				//cluster number of most recently allocated cluster
654				buffer[0x1ec] = (vol->last_allocated & 0xff);
655				buffer[0x1ed] = ((vol->last_allocated >> 8) & 0xff);
656				buffer[0x1ee] = ((vol->last_allocated >> 16) & 0xff);
657				buffer[0x1ef] = ((vol->last_allocated >> 24) & 0xff);
658				mark_blocks_dirty(vol->fd, vol->fsinfo_sector, 1);
659			} else {
660				dprintf("update_fsinfo: fsinfo block has invalid magic number\n");
661			}
662			release_block(vol->fd, vol->fsinfo_sector);
663		} else {
664			dprintf("update_fsinfo: error getting fsinfo sector %x\n", vol->fsinfo_sector);
665		}
666	}
667}
668
669static status_t get_fsinfo(nspace *vol, uint32 *free_count, uint32 *last_allocated)
670{
671	uchar *buffer;
672	int32 result;
673
674	if ((vol->fat_bits != 32) || (vol->fsinfo_sector == 0xffff))
675		return B_ERROR;
676
677	if ((buffer = (uchar *)get_block(vol->fd, vol->fsinfo_sector, vol->bytes_per_sector)) == NULL) {
678		dprintf("get_fsinfo: error getting fsinfo sector %x\n", vol->fsinfo_sector);
679		return EIO;
680	}
681
682	if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) {
683		*free_count = read32(buffer,0x1e8);
684		*last_allocated = read32(buffer,0x1ec);
685		result = B_OK;
686	} else {
687		dprintf("get_fsinfo: fsinfo block has invalid magic number\n");
688		result = B_ERROR;
689	}
690
691	release_block(vol->fd, vol->fsinfo_sector);
692	return result;
693}
694
695static int dosfs_unmount(void *_vol)
696{
697	int result = B_NO_ERROR;
698
699	nspace* vol = (nspace*)_vol;
700
701	LOCK_VOL(vol);
702
703	if (check_nspace_magic(vol, "dosfs_unmount")) {
704		UNLOCK_VOL(vol);
705		return EINVAL;
706	}
707
708	DPRINTF(0, ("dosfs_unmount volume %lx\n", vol->id));
709
710	update_fsinfo(vol);
711	flush_device(vol->fd, 0);
712	remove_cached_device_blocks(vol->fd, ALLOW_WRITES);
713
714#if DEBUG
715	if (atomic_add(&instances, -1) == 1) {
716		remove_debugger_command("dos", debug_dos);
717		remove_debugger_command("dvnode", debug_dvnode);
718		remove_debugger_command("dfvnid", debug_dfvnid);
719		remove_debugger_command("dfloc", debug_dfloc);
720		remove_debugger_command("dc2s", debug_dc2s);
721	}
722#endif
723
724	dlist_uninit(vol);
725	uninit_vcache(vol);
726
727	if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE) && (vol->fs_flags & FS_FLAGS_LOCK_DOOR))
728		lock_removable_device(vol->fd, false);
729	result = close(vol->fd);
730	free_lock(&(vol->vlock));
731	vol->magic = ~VNODE_MAGIC;
732	free(vol);
733
734#if USE_DMALLOC
735	check_mem();
736#endif
737
738	return result;
739}
740
741// dosfs_rfsstat - Fill in fs_info struct for device.
742static int dosfs_rfsstat(void *_vol, struct fs_info * fss)
743{
744	nspace* vol = (nspace*)_vol;
745	int i;
746
747	LOCK_VOL(vol);
748
749	if (check_nspace_magic(vol, "dosfs_rfsstat")) {
750		UNLOCK_VOL(vol);
751		return EINVAL;
752	}
753
754	DPRINTF(1, ("dosfs_rfsstat called\n"));
755
756	// fss->dev and fss->root filled in by kernel
757
758	// File system flags.
759	fss->flags = vol->flags;
760
761	// FS block size.
762	fss->block_size = vol->bytes_per_sector * vol->sectors_per_cluster;
763
764	// IO size - specifies buffer size for file copying
765	fss->io_size = 65536;
766
767	// Total blocks
768	fss->total_blocks = vol->total_clusters;
769
770	// Free blocks
771	fss->free_blocks = vol->free_clusters;
772
773	// Device name.
774	strncpy(fss->device_name, vol->device, sizeof(fss->device_name));
775
776	if (vol->vol_entry > -2)
777		strncpy(fss->volume_name, vol->vol_label, sizeof(fss->volume_name));
778	else
779		strcpy(fss->volume_name, "no name    ");
780
781	// XXX: should sanitize name as well
782	for (i=10;i>0;i--)
783		if (fss->volume_name[i] != ' ')
784			break;
785	fss->volume_name[i+1] = 0;
786	for (;i>=0;i--) {
787		if ((fss->volume_name[i] >= 'A') && (fss->volume_name[i] <= 'Z'))
788			fss->volume_name[i] += 'a' - 'A';
789	}
790
791	// File system name
792	strcpy(fss->fsh_name, "fat");
793
794	UNLOCK_VOL(vol);
795
796	return 0;
797}
798
799static int dosfs_wfsstat(void *_vol, struct fs_info * fss, long mask)
800{
801	int result = B_ERROR;
802	nspace* vol = (nspace*)_vol;
803
804	LOCK_VOL(vol);
805
806	if (check_nspace_magic(vol, "dosfs_wfsstat")) {
807		UNLOCK_VOL(vol);
808		return EINVAL;
809	}
810
811	DPRINTF(0, ("dosfs_wfsstat called\n"));
812
813	/* if it's a r/o file system and not the special hack, then don't allow
814	 * volume renaming */
815	if ((vol->flags & B_FS_IS_READONLY) && memcmp(vol->vol_label, "__RO__     ", 11)) {
816		UNLOCK_VOL(vol);
817		return EROFS;
818	}
819
820	if (mask & WFSSTAT_NAME) {
821		// sanitize name
822		char name[11];
823		int i,j;
824		memset(name, ' ', 11);
825		DPRINTF(1, ("wfsstat: setting name to %s\n", fss->volume_name));
826		for (i=j=0;(i<11)&&(fss->volume_name[j]);j++) {
827			static char acceptable[] = "!#$%&'()-0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`{}~";
828			char c = fss->volume_name[j];
829			if ((c >= 'a') && (c <= 'z')) c += 'A' - 'a';
830			// spaces acceptable in volume names
831			if (strchr(acceptable, c) || (c == ' '))
832				name[i++] = c;
833		}
834		if (i == 0) { // bad name, kiddo
835			result = EINVAL;
836			goto bi;
837		}
838		DPRINTF(1, ("wfsstat: sanitized to [%11.11s]\n", name));
839
840		if (vol->vol_entry == -1) {
841			// stored in the bpb
842			uchar *buffer;
843			if ((buffer = get_block(vol->fd, 0, vol->bytes_per_sector)) == NULL) {
844				result = EIO;
845				goto bi;
846			}
847			if ((buffer[0x26] != 0x29) || memcmp(buffer + 0x2b, vol->vol_label, 11)) {
848				dprintf("dosfs_wfsstat: label mismatch\n");
849				result = B_ERROR;
850			} else {
851				memcpy(buffer + 0x2b, name, 11);
852				mark_blocks_dirty(vol->fd, 0, 1);
853				result = 0;
854			}
855			release_block(vol->fd, 0);
856		} else if (vol->vol_entry >= 0) {
857			struct diri diri;
858			uint8 *buffer;
859			buffer = diri_init(vol, vol->root_vnode.cluster, vol->vol_entry, &diri);
860
861			// check if it is the same as the old volume label
862			if ((buffer == NULL) || (memcmp(buffer, vol->vol_label, 11))) {
863				dprintf("dosfs_wfsstat: label mismatch\n");
864				diri_free(&diri);
865				result = B_ERROR;
866				goto bi;
867			}
868			memcpy(buffer, name, 11);
869			diri_mark_dirty(&diri);
870			diri_free(&diri);
871			result = 0;
872		} else {
873			uint32 index;
874			result = create_volume_label(vol, name, &index);
875			if (result == B_OK) vol->vol_entry = index;
876		}
877
878		if (result == 0)
879			memcpy(vol->vol_label, name, 11);
880	}
881
882	if (vol->fs_flags & FS_FLAGS_OP_SYNC)
883		_dosfs_sync(vol);
884
885bi:	UNLOCK_VOL(vol);
886
887	return result;
888}
889
890static int dosfs_ioctl(void *_vol, void *_node, void *cookie, int code,
891	void *buf, size_t len)
892{
893	status_t result = B_OK;
894	nspace *vol = (nspace *)_vol;
895	vnode *node = (vnode *)_node;
896
897	TOUCH(cookie); TOUCH(buf); TOUCH(len);
898
899	LOCK_VOL(vol);
900
901	if (check_nspace_magic(vol, "dosfs_ioctl") ||
902	    check_vnode_magic(node, "dosfs_ioctl")) {
903		UNLOCK_VOL(vol);
904		return EINVAL;
905	}
906
907	switch (code) {
908		case 10002 : /* return real creation time */
909				if (buf) *(bigtime_t *)buf = node->st_time;
910				break;
911		case 10003 : /* return real last modification time */
912				if (buf) *(bigtime_t *)buf = node->st_time;
913				break;
914
915		case 69666 :
916				result = fragment(vol, buf);
917				break;
918
919		case 100000 :
920			dprintf("built at %s on %s\n", build_time, build_date);
921			dprintf("vol info: %s (device %x, media descriptor %x)\n", vol->device, vol->fd, vol->media_descriptor);
922			dprintf("%lx bytes/sector, %lx sectors/cluster\n", vol->bytes_per_sector, vol->sectors_per_cluster);
923			dprintf("%lx reserved sectors, %lx total sectors\n", vol->reserved_sectors, vol->total_sectors);
924			dprintf("%lx %d-bit fats, %lx sectors/fat, %lx root entries\n", vol->fat_count, vol->fat_bits, vol->sectors_per_fat, vol->root_entries_count);
925			dprintf("root directory starts at sector %lx (cluster %lx), data at sector %lx\n", vol->root_start, vol->root_vnode.cluster, vol->data_start);
926			dprintf("%lx total clusters, %lx free\n", vol->total_clusters, vol->free_clusters);
927			dprintf("fat mirroring is %s, fs info sector at sector %x\n", (vol->fat_mirrored) ? "on" : "off", vol->fsinfo_sector);
928			dprintf("last allocated cluster = %lx\n", vol->last_allocated);
929			dprintf("root vnode id = %Lx\n", vol->root_vnode.vnid);
930			dprintf("volume label [%11.11s]\n", vol->vol_label);
931			break;
932
933		case 100001 :
934			dprintf("vnode id %Lx, dir vnid = %Lx\n", node->vnid, node->dir_vnid);
935			dprintf("si = %lx, ei = %lx\n", node->sindex, node->eindex);
936			dprintf("cluster = %lx (%lx), mode = %lx, size = %Lx\n", node->cluster, vol->data_start + vol->sectors_per_cluster * (node->cluster - 2), node->mode, node->st_size);
937			dprintf("mime = %s\n", node->mime ? node->mime : "(null)");
938			dump_fat_chain(vol, node->cluster);
939			break;
940
941		case 100002 :
942			{struct diri diri;
943			uint8 *buffer;
944			uint32 i;
945			for (i=0,buffer=diri_init(vol,node->cluster, 0, &diri);buffer;buffer=diri_next_entry(&diri),i++) {
946				if (buffer[0] == 0) break;
947				dprintf("entry %lx:\n", i);
948				dump_directory(buffer);
949			}
950			diri_free(&diri);}
951			break;
952
953		case 100003 :
954			dprintf("vcache validation not yet implemented\n");
955#if 0
956			dprintf("validating vcache for %lx\n", vol->id);
957			validate_vcache(vol);
958			dprintf("validation complete for %lx\n", vol->id);
959#endif
960			break;
961
962		case 100004 :
963			dprintf("dumping vcache for %lx\n", vol->id);
964			dump_vcache(vol);
965			break;
966
967		case 100005 :
968			dprintf("dumping dlist for %lx\n", vol->id);
969			dlist_dump(vol);
970			break;
971
972		default :
973			dprintf("dosfs_ioctl: vol %lx, vnode %Lx code = %d\n", vol->id, node->vnid, code);
974			result = EINVAL;
975			break;
976	}
977
978	UNLOCK_VOL(vol);
979
980	return result;
981}
982
983int _dosfs_sync(nspace *vol)
984{
985	if (check_nspace_magic(vol, "dosfs_sync"))
986		return EINVAL;
987
988	update_fsinfo(vol);
989	flush_device(vol->fd, 0);
990
991	return 0;
992}
993
994static int dosfs_sync(void *_vol)
995{
996	nspace *vol = (nspace *)_vol;
997	int err;
998
999	DPRINTF(0, ("dosfs_sync called on volume %lx\n", vol->id));
1000
1001	LOCK_VOL(vol);
1002	err = _dosfs_sync(vol);
1003	UNLOCK_VOL(vol);
1004
1005	return err;
1006}
1007
1008static int dosfs_fsync(void *vol, void *node)
1009{
1010	TOUCH(node);
1011
1012	return dosfs_sync(vol);
1013}
1014
1015vnode_ops fs_entry =  {
1016	&dosfs_read_vnode,
1017	&dosfs_write_vnode,
1018	&dosfs_remove_vnode,
1019	NULL,
1020	&dosfs_walk,
1021	&dosfs_access,
1022	&dosfs_create,
1023	&dosfs_mkdir,
1024	NULL,
1025	NULL,
1026	&dosfs_rename,
1027	&dosfs_unlink,
1028	&dosfs_rmdir,
1029	&dosfs_readlink,
1030	&dosfs_opendir,
1031	&dosfs_closedir,
1032	&dosfs_free_dircookie,
1033	&dosfs_rewinddir,
1034	&dosfs_readdir,
1035	&dosfs_open,
1036	&dosfs_close,
1037	&dosfs_free_cookie,
1038	&dosfs_read,
1039	&dosfs_write,
1040	NULL,
1041	NULL,
1042	&dosfs_ioctl,
1043	NULL,
1044	&dosfs_rstat,
1045	&dosfs_wstat,
1046	&dosfs_fsync,
1047	NULL,
1048	&dosfs_mount,
1049	&dosfs_unmount,
1050	&dosfs_sync,
1051	&dosfs_rfsstat,
1052	&dosfs_wfsstat,
1053	NULL,
1054	NULL,
1055	NULL,
1056	NULL,
1057	NULL,
1058	NULL,
1059	NULL,
1060	NULL,
1061	NULL,
1062	NULL,
1063	NULL,
1064	&dosfs_open_attrdir,
1065	&dosfs_close_attrdir,
1066	&dosfs_free_attrcookie,
1067	&dosfs_rewind_attrdir,
1068	&dosfs_read_attrdir,
1069	&dosfs_write_attr,
1070	&dosfs_read_attr,
1071	NULL,
1072	NULL,
1073	&dosfs_stat_attr,
1074	NULL,
1075	NULL,
1076	NULL,
1077	NULL
1078};
1079
1080int32	api_version = B_CUR_FS_API_VERSION;
1081