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
6
7#include "dosfs.h"
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/stat.h>
13#include <time.h>
14
15#include <KernelExport.h>
16#include <Drivers.h>
17#include <driver_settings.h>
18
19#include <scsi.h>
20
21#include <fs_info.h>
22#include <fs_interface.h>
23#include <fs_cache.h>
24#include <fs_volume.h>
25
26#include "attr.h"
27#include "dir.h"
28#include "dlist.h"
29#include "fat.h"
30#include "file.h"
31#include "iter.h"
32#include "mkdos.h"
33#include "util.h"
34#include "vcache.h"
35
36
37extern const char *build_time, *build_date;
38
39/* debug levels */
40int debug_attr = 0, debug_dir = 0, debug_dlist = 0, debug_dosfs = 0,
41		debug_encodings = 0, debug_fat = 0, debug_file = 0,
42		debug_iter = 0, debug_vcache = 0;
43
44#define DPRINTF(a,b) if (debug_dosfs > (a)) dprintf b
45
46static status_t get_fsinfo(nspace *vol, uint32 *free_count, uint32 *last_allocated);
47
48
49#if DEBUG
50
51int32 instances = 0;
52
53static int
54debug_fat_nspace(int argc, char **argv)
55{
56	int i;
57	for (i = 1; i < argc; i++) {
58		nspace *vol = (nspace *)strtoul(argv[i], NULL, 0);
59		if (vol == NULL)
60			continue;
61
62		kprintf("fat nspace @ %p\n", vol);
63		kprintf("id: %" B_PRIdDEV ", fd: %d, device: %s, flags %" B_PRIu32 "\n",
64			vol->id, vol->fd, vol->device, vol->flags);
65		kprintf("bytes/sector = %" B_PRIu32 ", sectors/cluster = %" B_PRIu32
66			", reserved sectors = %" B_PRIu32 "\n", vol->bytes_per_sector,
67			vol->sectors_per_cluster, vol->reserved_sectors);
68		kprintf("%" B_PRIu32 " fats, %" B_PRIu32 " root entries, %" B_PRIu32
69			" total sectors, %" B_PRIu32 " sectors/fat\n", vol->fat_count,
70			vol->root_entries_count, vol->total_sectors, vol->sectors_per_fat);
71		kprintf("media descriptor %" B_PRIu8 ", fsinfo sector %" B_PRIu16
72			", %" B_PRIu32 " clusters, %" B_PRIu32 " free\n",
73			vol->media_descriptor, vol->fsinfo_sector, vol->total_clusters,
74			vol->free_clusters);
75		kprintf("%" B_PRIu8 "-bit fat, mirrored %s, active %" B_PRIu8 "\n",
76			vol->fat_bits, vol->fat_mirrored ? "yes" : "no", vol->active_fat);
77		kprintf("root start %" B_PRIu8 ", %" B_PRIu8
78			" root sectors, root vnode @ %p\n", vol->root_start,
79			vol->root_sectors, &(vol->root_vnode));
80		kprintf("label entry %" B_PRIu32 ", label %s\n", vol->vol_entry,
81			vol->vol_label);
82		kprintf("data start %" B_PRIu32 ", last allocated %" B_PRIu32 "\n",
83			vol->data_start, vol->last_allocated);
84		kprintf("last fake vnid %" B_PRIdINO ", vnid cache %" B_PRIu32
85			" entries @ (%p %p)\n", vol->vcache.cur_vnid,
86			vol->vcache.cache_size, vol->vcache.by_vnid, vol->vcache.by_loc);
87		kprintf("dlist entries: %" B_PRIu32 "/%" B_PRIu32 " @ %p\n",
88			vol->dlist.entries, vol->dlist.allocated, vol->dlist.vnid_list);
89
90		dump_vcache(vol);
91		dlist_dump(vol);
92	}
93	return B_OK;
94}
95
96
97static int
98debug_dvnode(int argc, char **argv)
99{
100	int i;
101
102	if (argc < 2) {
103		kprintf("dvnode vnode\n");
104		return B_OK;
105	}
106
107	for (i = 1; i < argc; i++) {
108		vnode *n = (vnode *)strtoul(argv[i], NULL, 0);
109		if (!n) continue;
110
111		kprintf("vnode @ %p", n);
112#if TRACK_FILENAME
113		kprintf(" (%s)", n->filename);
114#endif
115		kprintf("\nvnid %" B_PRIdINO ", dir vnid %" B_PRIdINO "\n", n->vnid,
116			n->dir_vnid);
117		kprintf("iteration %" B_PRIu32 ", si=%" B_PRIu32 ", ei=%" B_PRIu32
118			", cluster=%" B_PRIu32 "\n", n->iteration, n->sindex, n->eindex,
119			n->cluster);
120		kprintf("mode %#" B_PRIx32 ", size %" B_PRIdOFF ", time %" B_PRIdTIME
121			", crtime %" B_PRIdTIME "\n", n->mode, n->st_size, n->st_time,
122			n->st_crtim);
123		kprintf("end cluster = %" B_PRIu32 "\n", n->end_cluster);
124		if (n->mime) kprintf("mime type %s\n", n->mime);
125	}
126
127	return B_OK;
128}
129
130
131static int
132debug_dc2s(int argc, char **argv)
133{
134	int i;
135	nspace *vol;
136
137	if (argc < 3) {
138		kprintf("dc2s nspace cluster\n");
139		return B_OK;
140	}
141
142	vol = (nspace *)strtoul(argv[1], NULL, 0);
143	if (vol == NULL)
144		return B_OK;
145
146	for (i=2;i<argc;i++) {
147		uint32 cluster = strtoul(argv[i], NULL, 0);
148		kprintf("cluster %" B_PRIu32 " = block %" B_PRIdOFF "\n", cluster,
149			vol->data_start + (off_t)(cluster - 2) * vol->sectors_per_cluster);
150	}
151
152	return B_OK;
153}
154
155#endif
156
157
158static void
159dosfs_trim_spaces(char *label)
160{
161	uint8 index;
162	for (index = 10; index > 0; index--) {
163		if (label[index] == ' ')
164			label[index] = 0;
165		else
166			break;
167	}
168}
169
170
171static bool
172dosfs_read_label(bool fat32, uint8 *buffer, char *label)
173{
174	uint8 check = fat32 ? 0x42 : 0x29;
175	uint8 offset = fat32 ? 0x47 : 0x2b;
176
177	if (buffer[check] == 0x29
178		&& memcmp(buffer + offset, "           ", 11) != 0) {
179		memcpy(label, buffer + offset, 11);
180		dosfs_trim_spaces(label);
181		return true;
182	}
183
184	return false;
185}
186
187
188static nspace*
189volume_init(int fd, uint8* buf,
190	const int flags, int fs_flags,
191	device_geometry *geo)
192{
193	nspace *vol = NULL;
194	uint8 media_buf[512];
195	int i;
196	status_t err;
197
198	if ((vol = (nspace *)calloc(sizeof(nspace), 1)) == NULL) {
199		dprintf("dosfs error: out of memory\n");
200		return NULL;
201	}
202
203	vol->flags = flags;
204	vol->fs_flags = fs_flags;
205	vol->fd = fd;
206
207	// only check boot signature on hard disks to account for broken mtools
208	// behavior
209	if ((buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) && buf[0x15] == 0xf8)
210		goto error;
211
212	if (!memcmp(buf + 3, "NTFS    ", 8) || !memcmp(buf + 3, "HPFS    ", 8)) {
213		dprintf("dosfs error: %4.4s, not FAT\n", buf + 3);
214		goto error;
215	}
216
217	// first fill in the universal fields from the bpb
218	vol->bytes_per_sector = read16(buf, 0xb);
219	if (vol->bytes_per_sector != 0x200 && vol->bytes_per_sector != 0x400
220		&& vol->bytes_per_sector != 0x800 && vol->bytes_per_sector != 0x1000) {
221		dprintf("dosfs error: unsupported bytes per sector (%" B_PRIu32 ")\n",
222			vol->bytes_per_sector);
223		goto error;
224	}
225
226	vol->sectors_per_cluster = i = buf[0xd];
227	if (i != 1 && i != 2 && i != 4 && i != 8
228		&& i != 0x10 && i != 0x20 && i != 0x40 && i != 0x80) {
229		dprintf("dosfs error: unsupported sectors per cluster (%d)\n", i);
230		goto error;
231	}
232
233	vol->reserved_sectors = read16(buf, 0xe);
234
235	vol->fat_count = buf[0x10];
236	if (vol->fat_count == 0 || vol->fat_count > 8) {
237		dprintf("dosfs error: unreasonable fat count (%" B_PRIu32 ")\n",
238			vol->fat_count);
239		goto error;
240	}
241
242	vol->media_descriptor = buf[0x15];
243	// check media descriptor versus known types
244	if (buf[0x15] != 0xf0 && buf[0x15] < 0xf8) {
245		dprintf("dosfs error: invalid media descriptor byte\n");
246		goto error;
247	}
248
249	vol->vol_entry = -2;	// for now, assume there is no volume entry
250	strcpy(vol->vol_label, "no name");
251
252	// now become more discerning citizens
253	vol->sectors_per_fat = read16(buf, 0x16);
254	if (vol->sectors_per_fat == 0) {
255		// fat32 land
256		vol->fat_bits = 32;
257		vol->sectors_per_fat = read32(buf, 0x24);
258		vol->total_sectors = read32(buf, 0x20);
259
260		vol->fsinfo_sector = read16(buf, 0x30);
261		if (vol->fsinfo_sector != 0xffff
262			&& vol->fsinfo_sector >= vol->reserved_sectors) {
263			dprintf("dosfs error: fsinfo sector too large (0x%x)\n",
264				vol->fsinfo_sector);
265			goto error;
266		}
267
268		vol->fat_mirrored = !(buf[0x28] & 0x80);
269		vol->active_fat = !vol->fat_mirrored ? (buf[0x28] & 0xf) : 0;
270
271		vol->data_start = vol->reserved_sectors + vol->fat_count
272			* vol->sectors_per_fat;
273		vol->total_clusters = (vol->total_sectors - vol->data_start)
274			/ vol->sectors_per_cluster;
275
276		vol->root_vnode.cluster = read32(buf, 0x2c);
277		if (vol->root_vnode.cluster >= vol->total_clusters) {
278			dprintf("dosfs error: root vnode cluster too large (0x%" B_PRIu32
279				")\n", vol->root_vnode.cluster);
280			goto error;
281		}
282
283		if (dosfs_read_label(true, buf, vol->vol_label))
284			vol->vol_entry = -1;
285	} else {
286		// fat12 & fat16
287		if (vol->fat_count != 2) {
288			dprintf("dosfs error: claims %" B_PRIu32 " fat tables\n",
289				vol->fat_count);
290			goto error;
291		}
292
293		vol->root_entries_count = read16(buf, 0x11);
294		if (vol->root_entries_count % (vol->bytes_per_sector / 0x20)) {
295			dprintf("dosfs error: invalid number of root entries\n");
296			goto error;
297		}
298
299		vol->fsinfo_sector = 0xffff;
300		vol->total_sectors = read16(buf, 0x13); // partition size
301		if (vol->total_sectors == 0)
302			vol->total_sectors = read32(buf, 0x20);
303
304		if (geo != NULL) {
305			/*
306				Zip disks that were formatted at iomega have an incorrect number
307				of sectors.  They say that they have 196576 sectors but they
308				really only have 196192.  This check is a work-around for their
309				brain-deadness.
310			*/
311			unsigned char bogus_zip_data[] = {
312				0x00, 0x02, 0x04, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00,
313				0xf8, 0xc0, 0x00, 0x20, 0x00, 0x40, 0x00, 0x20, 0x00, 0x00
314			};
315
316			if (memcmp(buf + 0x0b, bogus_zip_data, sizeof(bogus_zip_data)) == 0
317				&& vol->total_sectors == 196576
318				&& ((off_t)geo->sectors_per_track * (off_t)geo->cylinder_count
319					* (off_t)geo->head_count) == 196192) {
320				vol->total_sectors = 196192;
321			}
322		}
323
324		vol->fat_mirrored = true;
325		vol->active_fat = 0;
326
327		vol->root_start = vol->reserved_sectors + vol->fat_count
328			* vol->sectors_per_fat;
329		vol->root_sectors = vol->root_entries_count * 0x20
330			/ vol->bytes_per_sector;
331		vol->root_vnode.cluster = 1;
332		vol->root_vnode.end_cluster = 1;
333		vol->root_vnode.st_size = vol->root_sectors * vol->bytes_per_sector;
334
335		vol->data_start = vol->root_start + vol->root_sectors;
336		vol->total_clusters = (vol->total_sectors - vol->data_start)
337			/ vol->sectors_per_cluster;
338
339		// XXX: uncertain about border cases; win32 sdk says cutoffs are at
340		//      at ff6/ff7 (or fff6/fff7), but that doesn't make much sense
341		if (vol->total_clusters > 0xff1)
342			vol->fat_bits = 16;
343		else
344			vol->fat_bits = 12;
345
346		if (dosfs_read_label(false, buf, vol->vol_label))
347			vol->vol_entry = -1;
348	}
349
350	// perform sanity checks on the FAT
351
352	// the media descriptor in active FAT should match the one in the BPB
353	if ((err = read_pos(vol->fd, vol->bytes_per_sector * (vol->reserved_sectors
354			+ vol->active_fat * vol->sectors_per_fat),
355			(void *)media_buf, 0x200)) != 0x200) {
356		dprintf("dosfs error: error reading FAT\n");
357		goto error;
358	}
359
360	if (media_buf[0] != vol->media_descriptor) {
361		dprintf("dosfs error: media descriptor mismatch (%x != %x)\n", media_buf[0],
362			vol->media_descriptor);
363		goto error;
364	}
365
366	if (vol->fat_mirrored) {
367		uint32 i;
368		uint8 mirror_media_buf[512];
369		for (i = 0; i < vol->fat_count; i++) {
370			if (i != vol->active_fat) {
371				DPRINTF(1, ("checking fat #%" B_PRIu32 "\n", i));
372				mirror_media_buf[0] = ~media_buf[0];
373				if ((err = read_pos(vol->fd, vol->bytes_per_sector
374						* (vol->reserved_sectors + vol->sectors_per_fat * i),
375						(void *)mirror_media_buf, 0x200)) != 0x200) {
376					dprintf("dosfs error: error reading FAT %" B_PRIu32 "\n",
377						i);
378					goto error;
379				}
380
381				if (mirror_media_buf[0] != vol->media_descriptor) {
382					dprintf("dosfs error: media descriptor mismatch in fat # "
383						"%" B_PRIu32 " (%" B_PRIu8 " != %" B_PRIu8 ")\n", i,
384						mirror_media_buf[0], vol->media_descriptor);
385					goto error;
386				}
387#if 0
388				// checking for exact matches of fats is too
389				// restrictive; allow these to go through in
390				// case the fat is corrupted for some reason
391				if (memcmp(media_buf, mirror_media_buf, 0x200)) {
392					dprintf("dosfs error: fat %d doesn't match active fat "
393						"(%d)\n", i, vol->active_fat);
394					goto error;
395				}
396#endif
397			}
398		}
399	}
400
401	/* check that the partition is large enough to contain the file system */
402	if (geo != NULL
403			&& vol->total_sectors >
404				geo->sectors_per_track * geo->cylinder_count
405				* geo->head_count) {
406		dprintf("dosfs: volume extends past end of partition, mounting read-only\n");
407		vol->flags |= B_FS_IS_READONLY;
408	}
409
410	// now we are convinced of the drive's validity
411
412	// this will be updated later if fsinfo exists
413	vol->last_allocated = 2;
414	vol->beos_vnid = INVALID_VNID_BITS_MASK;
415
416	// initialize block cache
417	vol->fBlockCache = block_cache_create(vol->fd, vol->total_sectors,
418		vol->bytes_per_sector, (vol->flags & B_FS_IS_READONLY) != 0);
419	if (vol->fBlockCache == NULL) {
420		dprintf("dosfs error: error initializing block cache\n");
421		goto error;
422	}
423
424	// find volume label (supercedes any label in the bpb)
425	{
426		struct diri diri;
427		uint8 *buffer;
428		buffer = diri_init(vol, vol->root_vnode.cluster, 0, &diri);
429		for (; buffer; buffer = diri_next_entry(&diri)) {
430			if ((buffer[0x0b] & FAT_VOLUME) && (buffer[0x0b] != 0xf)
431					&& (buffer[0] != 0xe5)) {
432				vol->vol_entry = diri.current_index;
433				memcpy(vol->vol_label, buffer, 11);
434				dosfs_trim_spaces(vol->vol_label);
435				break;
436			}
437		}
438
439		diri_free(&diri);
440	}
441
442	DPRINTF(0, ("root vnode id = %" B_PRIdINO "\n", vol->root_vnode.vnid));
443	DPRINTF(0, ("volume label [%s] (%" B_PRIu32 ")\n", vol->vol_label,
444		vol->vol_entry));
445
446	// steal a trick from bfs
447	if (!memcmp(vol->vol_label, "__RO__     ", 11))
448		vol->flags |= B_FS_IS_READONLY;
449
450	return vol;
451
452error:
453	free(vol);
454	return NULL;
455}
456
457
458static void
459volume_uninit(nspace *vol)
460{
461	block_cache_delete(vol->fBlockCache, false);
462	free(vol);
463}
464
465
466static void
467volume_count_free_cluster(nspace *vol)
468{
469	status_t err;
470
471	if (vol->flags & B_FS_IS_READONLY)
472		vol->free_clusters = 0;
473	else {
474		uint32 free_count, last_allocated;
475		err = get_fsinfo(vol, &free_count, &last_allocated);
476		if (err >= 0) {
477			if (free_count < vol->total_clusters)
478				vol->free_clusters = free_count;
479			else {
480				dprintf("dosfs error: free cluster count from fsinfo block "
481					"invalid %" B_PRIu32 "\n", free_count);
482				err = -1;
483			}
484
485			if (last_allocated < vol->total_clusters)
486				vol->last_allocated = last_allocated; //update to a closer match
487		}
488
489		if (err < 0) {
490			if ((err = count_free_clusters(vol)) < 0) {
491				dprintf("dosfs error: error counting free clusters (%s)\n",
492					strerror(err));
493				return;
494			}
495			vol->free_clusters = err;
496		}
497	}
498}
499
500
501static int
502lock_removable_device(int fd, bool state)
503{
504	return ioctl(fd, B_SCSI_PREVENT_ALLOW, &state, sizeof(state));
505}
506
507
508static status_t
509mount_fat_disk(const char *path, fs_volume *_vol, const int flags,
510	nspace** newVol, int fs_flags, int op_sync_mode)
511{
512	nspace *vol = NULL;
513	uint8 buf[512];
514	device_geometry geo;
515	status_t err;
516	int fd;
517	int vol_flags;
518
519	vol_flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME;
520
521	// open read-only for now
522	if ((err = (fd = open(path, O_RDONLY | O_NOCACHE))) < 0) {
523		dprintf("dosfs error: unable to open %s (%s)\n", path, strerror(err));
524		goto error0;
525	}
526
527	// get device characteristics
528	if (ioctl(fd, B_GET_GEOMETRY, &geo, sizeof(device_geometry)) < 0) {
529		struct stat st;
530		if (fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) {
531			/* support mounting disk images */
532			geo.bytes_per_sector = 0x200;
533			geo.sectors_per_track = 1;
534			geo.cylinder_count = st.st_size / 0x200;
535			geo.head_count = 1;
536			geo.read_only = !(st.st_mode & S_IWUSR);
537			geo.removable = true;
538		} else {
539			dprintf("dosfs error: error getting device geometry\n");
540			goto error1;
541		}
542	}
543
544	if (geo.bytes_per_sector != 0x200 && geo.bytes_per_sector != 0x400
545		&& geo.bytes_per_sector != 0x800 && geo.bytes_per_sector != 0x1000) {
546		dprintf("dosfs error: unsupported device block size (%" B_PRIu32 ")\n",
547			geo.bytes_per_sector);
548		goto error1;
549	}
550
551	if (geo.removable) {
552		DPRINTF(0, ("%s is removable\n", path));
553		vol_flags |= B_FS_IS_REMOVABLE;
554	}
555
556	if (geo.read_only || (flags & B_MOUNT_READ_ONLY)) {
557		DPRINTF(0, ("%s is read-only\n", path));
558		vol_flags |= B_FS_IS_READONLY;
559	} else {
560		// reopen it with read/write permissions
561		close(fd);
562		if ((err = (fd = open(path, O_RDWR | O_NOCACHE))) < 0) {
563			dprintf("dosfs error: unable to open %s (%s)\n", path,
564				strerror(err));
565			goto error0;
566		}
567
568		if ((vol_flags & B_FS_IS_REMOVABLE)
569			&& (fs_flags & FS_FLAGS_LOCK_DOOR))
570			lock_removable_device(fd, true);
571	}
572
573	// see if we need to go into op sync mode
574	fs_flags &= ~FS_FLAGS_OP_SYNC;
575	switch (op_sync_mode) {
576		case 1:
577			if ((vol_flags & B_FS_IS_REMOVABLE) == 0) {
578				// we're not removable, so skip op_sync
579				break;
580			}
581			// supposed to fall through
582
583		case 2:
584			dprintf("dosfs: mounted with op_sync enabled\n");
585			fs_flags |= FS_FLAGS_OP_SYNC;
586			break;
587
588		case 0:
589		default:
590			break;
591	}
592
593	// read in the boot sector
594	if ((err = read_pos(fd, 0, (void *)buf, 512)) != 512) {
595		dprintf("dosfs error: error reading boot sector\n");
596		goto error1;
597	}
598
599	vol = volume_init(fd, buf, vol_flags, fs_flags, &geo);
600	if (vol == NULL) {
601		dprintf("dosfs error: failed to initialize volume\n");
602		err = B_ERROR;
603		goto error1;
604	}
605
606	vol->volume = _vol;
607	vol->id = _vol->id;
608	strncpy(vol->device, path, sizeof(vol->device));
609
610	{
611		void *handle;
612		handle = load_driver_settings("fat");
613		vol->respect_disk_image =
614			get_driver_boolean_parameter(handle, "respect", true, true);
615		unload_driver_settings(handle);
616	}
617
618	// Initialize the vnode cache
619	if (init_vcache(vol) != B_OK) {
620		dprintf("dosfs error: error initializing vnode cache\n");
621		goto error2;
622	}
623
624	// and the dlist cache
625	if (dlist_init(vol) != B_OK) {
626		dprintf("dosfs error: error initializing dlist cache\n");
627		goto error3;
628	}
629
630	volume_count_free_cluster(vol);
631
632	DPRINTF(0, ("built at %s on %s\n", build_time, build_date));
633	DPRINTF(0, ("mounting %s (id %" B_PRIdDEV ", device %u, media descriptor %"
634		B_PRIu8 ")\n", vol->device, vol->id, vol->fd, vol->media_descriptor));
635	DPRINTF(0, ("%" B_PRIu32 " bytes/sector, %" B_PRIu32 " sectors/cluster\n",
636		vol->bytes_per_sector, vol->sectors_per_cluster));
637	DPRINTF(0, ("%" B_PRIu32 " reserved sectors, %" B_PRIu32 " total sectors\n",
638		vol->reserved_sectors, vol->total_sectors));
639	DPRINTF(0, ("%" B_PRIu32 " %" B_PRIu8 "-bit fats, %" B_PRIu32
640		" sectors/fat, %" B_PRIu32 " root entries\n", vol->fat_count,
641		vol->fat_bits, vol->sectors_per_fat, vol->root_entries_count));
642	DPRINTF(0, ("root directory starts at sector %" B_PRIu32 " (cluster %"
643		B_PRIu32 "), data at sector %" B_PRIu32 "\n", vol->root_start,
644		vol->root_vnode.cluster, vol->data_start));
645	DPRINTF(0, ("%" B_PRIu32 " total clusters, %" B_PRIu32 " free\n",
646		vol->total_clusters, vol->free_clusters));
647	DPRINTF(0, ("fat mirroring is %s, fs info sector at sector %" B_PRIu16 "\n",
648		vol->fat_mirrored ? "on" : "off", vol->fsinfo_sector));
649	DPRINTF(0, ("last allocated cluster = %" B_PRIu32 "\n",
650		vol->last_allocated));
651
652	if (vol->fat_bits == 32) {
653		// now that the block cache has been initialised, we can figure
654		// out the length of the root directory with count_clusters()
655		vol->root_vnode.st_size = count_clusters(vol, vol->root_vnode.cluster)
656			* vol->bytes_per_sector * vol->sectors_per_cluster;
657		vol->root_vnode.end_cluster = get_nth_fat_entry(vol,
658			vol->root_vnode.cluster, vol->root_vnode.st_size
659			/ vol->bytes_per_sector / vol->sectors_per_cluster - 1);
660	}
661
662	// initialize root vnode
663	vol->root_vnode.vnid = vol->root_vnode.dir_vnid = GENERATE_DIR_CLUSTER_VNID(
664		vol->root_vnode.cluster, vol->root_vnode.cluster);
665	vol->root_vnode.sindex = vol->root_vnode.eindex = 0xffffffff;
666	vol->root_vnode.mode = FAT_SUBDIR;
667	time(&(vol->root_vnode.st_time));
668	vol->root_vnode.st_crtim = vol->root_vnode.st_time;
669	vol->root_vnode.mime = NULL;
670	vol->root_vnode.dirty = false;
671	dlist_add(vol, vol->root_vnode.vnid);
672
673
674	DPRINTF(0, ("root vnode id = %" B_PRIdINO "\n", vol->root_vnode.vnid));
675	DPRINTF(0, ("volume label [%s] (%" B_PRIu32 ")\n", vol->vol_label,
676		vol->vol_entry));
677
678	// steal a trick from bfs
679	if (!memcmp(vol->vol_label, "__RO__     ", 11))
680		vol->flags |= B_FS_IS_READONLY;
681
682	*newVol = vol;
683	return B_NO_ERROR;
684
685error3:
686	uninit_vcache(vol);
687error2:
688	if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE)
689		&& (vol->fs_flags & FS_FLAGS_LOCK_DOOR)) {
690		lock_removable_device(fd, false);
691	}
692
693	volume_uninit(vol);
694error1:
695	close(fd);
696error0:
697	return err >= B_NO_ERROR ? EINVAL : err;
698}
699
700
701//	#pragma mark - Scanning
702
703
704typedef struct identify_cookie {
705	uint32 bytes_per_sector;
706	uint32 total_sectors;
707	char name[12];
708} identify_cookie;
709
710
711static float
712dosfs_identify_partition(int fd, partition_data *partition, void **_cookie)
713{
714	uint8 buf[512];
715	int i;
716	uint32 bytes_per_sector;
717	uint32 fatCount;
718	uint32 total_sectors;
719	uint32 sectors_per_fat;
720	char name[12];
721	identify_cookie *cookie;
722
723	// read in the boot sector
724	if (read_pos(fd, 0, buf, 512) != 512)
725		return -1;
726
727	// only check boot signature on hard disks to account for broken mtools
728	// behavior
729	if ((buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) && buf[0x15] == 0xf8)
730		return -1;
731	if (!memcmp(buf + 3, "NTFS    ", 8) || !memcmp(buf + 3, "HPFS    ", 8))
732		return -1;
733
734	// first fill in the universal fields from the bpb
735	bytes_per_sector = read16(buf, 0xb);
736	if (bytes_per_sector != 0x200 && bytes_per_sector != 0x400
737		&& bytes_per_sector != 0x800 && bytes_per_sector != 0x1000) {
738		return -1;
739	}
740
741	// must be a power of two
742	i = buf[0xd];
743	if (i != 1 && i != 2 && i != 4 && i != 8 && i != 0x10 && i != 0x20
744		&& i != 0x40 && i != 0x80)
745		return -1;
746
747	fatCount = buf[0x10];
748	if (fatCount == 0 || fatCount > 8)
749		return -1;
750
751	// check media descriptor versus known types
752	if (buf[0x15] != 0xf0 && buf[0x15] < 0xf8)
753		return -1;
754
755	strcpy(name, "no name");
756	sectors_per_fat = read16(buf, 0x16);
757	if (sectors_per_fat == 0) {
758		total_sectors = read32(buf, 0x20);
759		dosfs_read_label(true, buf, name);
760	} else {
761		total_sectors = read16(buf, 0x13);
762			// partition size
763		if (total_sectors == 0)
764			total_sectors = read32(buf, 0x20);
765
766		dosfs_read_label(false, buf, name);
767	}
768
769	// find volume label (supercedes any label in the bpb)
770	{
771		nspace *vol;
772		vol = volume_init(fd, buf, 0, 0, NULL);
773		if (vol != NULL)
774		{
775			strlcpy(name, vol->vol_label, 12);
776			volume_uninit(vol);
777		}
778	}
779
780	cookie = (identify_cookie *)malloc(sizeof(identify_cookie));
781	if (!cookie)
782		return -1;
783
784	cookie->bytes_per_sector = bytes_per_sector;
785	cookie->total_sectors = total_sectors;
786	sanitize_name(name, 12);
787	strlcpy(cookie->name, name, 12);
788	*_cookie = cookie;
789
790	return 0.8f;
791}
792
793
794static status_t
795dosfs_scan_partition(int fd, partition_data *partition, void *_cookie)
796{
797	identify_cookie *cookie = (identify_cookie *)_cookie;
798	partition->status = B_PARTITION_VALID;
799	partition->flags |= B_PARTITION_FILE_SYSTEM;
800	partition->content_size = cookie->total_sectors * cookie->bytes_per_sector;
801	partition->block_size = cookie->bytes_per_sector;
802	partition->content_name = strdup(cookie->name);
803	if (partition->content_name == NULL)
804		return B_NO_MEMORY;
805
806	return B_OK;
807}
808
809
810static void
811dosfs_free_identify_partition_cookie(partition_data *partition, void *_cookie)
812{
813	identify_cookie *cookie = (identify_cookie *)_cookie;
814	free(cookie);
815}
816
817
818//	#pragma mark -
819
820
821static status_t
822dosfs_mount(fs_volume *_vol, const char *device, uint32 flags,
823	const char *args, ino_t *_rootID)
824{
825	int	result;
826	nspace *vol;
827	void *handle;
828	int op_sync_mode = 0;
829	int fs_flags = 0;
830
831	handle = load_driver_settings("fat");
832	if (handle != NULL) {
833		debug_attr = strtoul(get_driver_parameter(handle, "debug_attr", "0", "0"), NULL, 0);
834		debug_dir = strtoul(get_driver_parameter(handle, "debug_dir", "0", "0"), NULL, 0);
835		debug_dlist = strtoul(get_driver_parameter(handle, "debug_dlist", "0", "0"), NULL, 0);
836		debug_dosfs = strtoul(get_driver_parameter(handle, "debug_dosfs", "0", "0"), NULL, 0);
837		debug_encodings = strtoul(get_driver_parameter(handle, "debug_encodings", "0", "0"), NULL, 0);
838		debug_fat = strtoul(get_driver_parameter(handle, "debug_fat", "0", "0"), NULL, 0);
839		debug_file = strtoul(get_driver_parameter(handle, "debug_file", "0", "0"), NULL, 0);
840		debug_iter = strtoul(get_driver_parameter(handle, "debug_iter", "0", "0"), NULL, 0);
841		debug_vcache = strtoul(get_driver_parameter(handle, "debug_vcache", "0", "0"), NULL, 0);
842
843		op_sync_mode = strtoul(get_driver_parameter(handle, "op_sync_mode", "0", "0"), NULL, 0);
844		if (op_sync_mode < 0 || op_sync_mode > 2)
845			op_sync_mode = 0;
846		if (strcasecmp(get_driver_parameter(handle, "lock_device", "true", "true"), "false") == 0) {
847			dprintf("dosfs: mounted with lock_device = false\n");
848		} else {
849			dprintf("dosfs: mounted with lock_device = true\n");
850			fs_flags |= FS_FLAGS_LOCK_DOOR;
851		}
852
853		unload_driver_settings(handle);
854	}
855
856	/* args is a command line option; dosfs doesn't use any so
857	   we can ignore these arguments */
858	TOUCH(args);
859
860#if __RO__
861	// make it read-only
862	flags |= 1;
863#endif
864
865	// Try and mount volume as a FAT volume
866	if ((result = mount_fat_disk(device, _vol, flags, &vol, fs_flags,
867			op_sync_mode)) == B_NO_ERROR) {
868		char name[32];
869
870		*_rootID = vol->root_vnode.vnid;
871		_vol->private_volume = (void *)vol;
872		_vol->ops = &gFATVolumeOps;
873
874		// You MUST do this. Create the vnode for the root.
875		result = publish_vnode(_vol, *_rootID, (void*)&(vol->root_vnode),
876			&gFATVnodeOps, make_mode(vol, &vol->root_vnode), 0);
877		if (result != B_NO_ERROR) {
878			dprintf("error creating new vnode (%s)\n", strerror(result));
879			goto error;
880		}
881		sprintf(name, "fat lock %" B_PRIdDEV, vol->id);
882		recursive_lock_init_etc(&(vol->vlock), name, MUTEX_FLAG_CLONE_NAME);
883
884#if DEBUG
885		if (atomic_add(&instances, 1) == 0) {
886			add_debugger_command("fat", debug_fat_nspace, "dump a fat nspace structure");
887			add_debugger_command("dvnode", debug_dvnode, "dump a fat vnode structure");
888			add_debugger_command("dfvnid", debug_dfvnid, "find a vnid in the vnid cache");
889			add_debugger_command("dfloc", debug_dfloc, "find a loc in the vnid cache");
890			add_debugger_command("dc2s", debug_dc2s, "calculate sector for cluster");
891		}
892#endif
893	}
894
895	return result;
896
897error:
898	block_cache_delete(vol->fBlockCache, false);
899	dlist_uninit(vol);
900	uninit_vcache(vol);
901	free(vol);
902	return EINVAL;
903}
904
905
906static void
907update_fsinfo(nspace *vol)
908{
909	if (vol->fat_bits == 32 && vol->fsinfo_sector != 0xffff
910		&& (vol->flags & B_FS_IS_READONLY) == 0) {
911		uchar *buffer = (uchar *)block_cache_get_writable_etc(vol->fBlockCache,
912				vol->fsinfo_sector, 0, vol->bytes_per_sector, -1);
913		if (buffer != NULL) {
914			if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) {
915				//number of free clusters
916				buffer[0x1e8] = (vol->free_clusters & 0xff);
917				buffer[0x1e9] = ((vol->free_clusters >> 8) & 0xff);
918				buffer[0x1ea] = ((vol->free_clusters >> 16) & 0xff);
919				buffer[0x1eb] = ((vol->free_clusters >> 24) & 0xff);
920				//cluster number of most recently allocated cluster
921				buffer[0x1ec] = (vol->last_allocated & 0xff);
922				buffer[0x1ed] = ((vol->last_allocated >> 8) & 0xff);
923				buffer[0x1ee] = ((vol->last_allocated >> 16) & 0xff);
924				buffer[0x1ef] = ((vol->last_allocated >> 24) & 0xff);
925			} else {
926				dprintf("update_fsinfo: fsinfo block has invalid magic number\n");
927				block_cache_set_dirty(vol->fBlockCache, vol->fsinfo_sector,
928					false, -1);
929			}
930			block_cache_put(vol->fBlockCache, vol->fsinfo_sector);
931		} else {
932			dprintf("update_fsinfo: error getting fsinfo sector %x\n",
933				vol->fsinfo_sector);
934		}
935	}
936}
937
938
939static status_t
940get_fsinfo(nspace *vol, uint32 *free_count, uint32 *last_allocated)
941{
942	uchar *buffer;
943	int32 result;
944
945	if ((vol->fat_bits != 32) || (vol->fsinfo_sector == 0xffff))
946		return B_ERROR;
947
948	if ((buffer = (uchar *)block_cache_get_etc(vol->fBlockCache, vol->fsinfo_sector, 0, vol->bytes_per_sector)) == NULL) {
949		dprintf("get_fsinfo: error getting fsinfo sector %x\n", vol->fsinfo_sector);
950		return EIO;
951	}
952
953	if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) {
954		*free_count = read32(buffer,0x1e8);
955		*last_allocated = read32(buffer,0x1ec);
956		result = B_OK;
957	} else {
958		dprintf("get_fsinfo: fsinfo block has invalid magic number\n");
959		result = B_ERROR;
960	}
961
962	block_cache_put(vol->fBlockCache, vol->fsinfo_sector);
963	return result;
964}
965
966
967static status_t
968dosfs_unmount(fs_volume *_vol)
969{
970	int result = B_NO_ERROR;
971
972	nspace* vol = (nspace*)_vol->private_volume;
973
974	LOCK_VOL(vol);
975
976	DPRINTF(0, ("dosfs_unmount volume %" B_PRIdDEV "\n", vol->id));
977
978	update_fsinfo(vol);
979
980	// Unlike in BeOS, we need to put the reference to our root node ourselves
981	put_vnode(_vol, vol->root_vnode.vnid);
982	block_cache_delete(vol->fBlockCache, true);
983
984#if DEBUG
985	if (atomic_add(&instances, -1) == 1) {
986		remove_debugger_command("fat", debug_fat_nspace);
987		remove_debugger_command("dvnode", debug_dvnode);
988		remove_debugger_command("dfvnid", debug_dfvnid);
989		remove_debugger_command("dfloc", debug_dfloc);
990		remove_debugger_command("dc2s", debug_dc2s);
991	}
992#endif
993
994	dlist_uninit(vol);
995	uninit_vcache(vol);
996
997	if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE) && (vol->fs_flags & FS_FLAGS_LOCK_DOOR))
998		lock_removable_device(vol->fd, false);
999	result = close(vol->fd);
1000	recursive_lock_destroy(&(vol->vlock));
1001	free(vol);
1002
1003#if USE_DMALLOC
1004	check_mem();
1005#endif
1006
1007	return result;
1008}
1009
1010
1011// dosfs_read_fs_stat - Fill in fs_info struct for device.
1012static status_t
1013dosfs_read_fs_stat(fs_volume *_vol, struct fs_info * fss)
1014{
1015	nspace* vol = (nspace*)_vol->private_volume;
1016
1017	LOCK_VOL(vol);
1018
1019	DPRINTF(1, ("dosfs_read_fs_stat called\n"));
1020
1021	// fss->dev and fss->root filled in by kernel
1022
1023	// File system flags.
1024	fss->flags = vol->flags;
1025
1026	// FS block size.
1027	fss->block_size = vol->bytes_per_sector * vol->sectors_per_cluster;
1028
1029	// IO size - specifies buffer size for file copying
1030	fss->io_size = 65536;
1031
1032	// Total blocks
1033	fss->total_blocks = vol->total_clusters;
1034
1035	// Free blocks
1036	fss->free_blocks = vol->free_clusters;
1037
1038	// Device name.
1039	strncpy(fss->device_name, vol->device, sizeof(fss->device_name));
1040
1041	if (vol->vol_entry > -2)
1042		strlcpy(fss->volume_name, vol->vol_label, sizeof(fss->volume_name));
1043	else
1044		strcpy(fss->volume_name, "no name");
1045
1046	sanitize_name(fss->volume_name, 12);
1047
1048	// File system name
1049	strcpy(fss->fsh_name, "fat");
1050
1051	UNLOCK_VOL(vol);
1052
1053	return B_OK;
1054}
1055
1056
1057static status_t
1058dosfs_write_fs_stat(fs_volume *_vol, const struct fs_info * fss, uint32 mask)
1059{
1060	status_t result = B_ERROR;
1061	nspace* vol = (nspace*)_vol->private_volume;
1062
1063	LOCK_VOL(vol);
1064
1065	DPRINTF(0, ("dosfs_write_fs_stat called\n"));
1066
1067	/* if it's a r/o file system and not the special hack, then don't allow
1068	 * volume renaming */
1069	if ((vol->flags & B_FS_IS_READONLY) && memcmp(vol->vol_label, "__RO__     ", 11)) {
1070		UNLOCK_VOL(vol);
1071		return EROFS;
1072	}
1073
1074	if (mask & FS_WRITE_FSINFO_NAME) {
1075		// sanitize name
1076		char name[11];
1077		int i,j;
1078		memset(name, ' ', 11);
1079		DPRINTF(1, ("wfsstat: setting name to %s\n", fss->volume_name));
1080		for (i=j=0;(i<11)&&(fss->volume_name[j]);j++) {
1081			static char acceptable[] = "!#$%&'()-0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`{}~";
1082			char c = fss->volume_name[j];
1083			if ((c >= 'a') && (c <= 'z')) c += 'A' - 'a';
1084			// spaces acceptable in volume names
1085			if (strchr(acceptable, c) || (c == ' '))
1086				name[i++] = c;
1087		}
1088		if (i == 0) { // bad name, kiddo
1089			result = EINVAL;
1090			goto bi;
1091		}
1092		DPRINTF(1, ("wfsstat: sanitized to [%11.11s]\n", name));
1093
1094		if (vol->vol_entry == -1) {
1095			// stored in the bpb
1096			uchar *buffer = block_cache_get_writable_etc(vol->fBlockCache, 0, 0,
1097				vol->bytes_per_sector, -1);
1098			if (buffer == NULL) {
1099				result = EIO;
1100				goto bi;
1101			}
1102			if ((vol->sectors_per_fat == 0 && (buffer[0x42] != 0x29
1103					|| strncmp((const char *)buffer + 0x47, vol->vol_label, 11)
1104						!= 0))
1105				|| (vol->sectors_per_fat != 0 && (buffer[0x26] != 0x29
1106					|| strncmp((const char *)buffer + 0x2b, vol->vol_label, 11)
1107						== 0))) {
1108				dprintf("dosfs_wfsstat: label mismatch\n");
1109				block_cache_set_dirty(vol->fBlockCache, 0, false, -1);
1110				result = B_ERROR;
1111			} else {
1112				memcpy(buffer + 0x2b, name, 11);
1113				result = B_OK;
1114			}
1115			block_cache_put(vol->fBlockCache, 0);
1116		} else if (vol->vol_entry >= 0) {
1117			struct diri diri;
1118			uint8 *buffer;
1119			buffer = diri_init(vol, vol->root_vnode.cluster, vol->vol_entry, &diri);
1120
1121			// check if it is the same as the old volume label
1122			if (buffer == NULL || strncmp((const char *)buffer, vol->vol_label,
1123					11) == 0) {
1124				dprintf("dosfs_wfsstat: label mismatch\n");
1125				diri_free(&diri);
1126				result = B_ERROR;
1127				goto bi;
1128			}
1129
1130			diri_make_writable(&diri);
1131			memcpy(buffer, name, 11);
1132			diri_free(&diri);
1133			result = B_OK;
1134		} else {
1135			uint32 index;
1136			result = create_volume_label(vol, name, &index);
1137			if (result == B_OK) vol->vol_entry = index;
1138		}
1139
1140		if (result == B_OK) {
1141			memcpy(vol->vol_label, name, 11);
1142			dosfs_trim_spaces(vol->vol_label);
1143		}
1144	}
1145
1146	if (vol->fs_flags & FS_FLAGS_OP_SYNC)
1147		_dosfs_sync(vol);
1148
1149bi:	UNLOCK_VOL(vol);
1150
1151	return result;
1152}
1153
1154
1155#if 0
1156static status_t
1157dosfs_ioctl(fs_volume *_vol, fs_vnode *_node, void *cookie, uint32 code,
1158	void *buf, size_t len)
1159{
1160	status_t result = B_OK;
1161	nspace *vol = (nspace *)_vol->private_volume;
1162	vnode *node = (vnode *)_node->private_node;
1163
1164	TOUCH(cookie); TOUCH(len);
1165
1166	LOCK_VOL(vol);
1167
1168	switch (code) {
1169		case 100000 :
1170			dprintf("built at %s on %s\n", build_time, build_date);
1171			dprintf("vol info: %s (device %x, media descriptor %x)\n", vol->device, vol->fd, vol->media_descriptor);
1172			dprintf("%lx bytes/sector, %lx sectors/cluster\n", vol->bytes_per_sector, vol->sectors_per_cluster);
1173			dprintf("%lx reserved sectors, %lx total sectors\n", vol->reserved_sectors, vol->total_sectors);
1174			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);
1175			dprintf("root directory starts at sector %lx (cluster %lx), data at sector %lx\n", vol->root_start, vol->root_vnode.cluster, vol->data_start);
1176			dprintf("%lx total clusters, %lx free\n", vol->total_clusters, vol->free_clusters);
1177			dprintf("fat mirroring is %s, fs info sector at sector %x\n", (vol->fat_mirrored) ? "on" : "off", vol->fsinfo_sector);
1178			dprintf("last allocated cluster = %lx\n", vol->last_allocated);
1179			dprintf("root vnode id = %Lx\n", vol->root_vnode.vnid);
1180			dprintf("volume label [%s]\n", vol->vol_label);
1181			break;
1182
1183		case 100001 :
1184			dprintf("vnode id %Lx, dir vnid = %Lx\n", node->vnid, node->dir_vnid);
1185			dprintf("si = %lx, ei = %lx\n", node->sindex, node->eindex);
1186			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);
1187			dprintf("mime = %s\n", node->mime ? node->mime : "(null)");
1188			dump_fat_chain(vol, node->cluster);
1189			break;
1190
1191		case 100002 :
1192			{struct diri diri;
1193			uint8 *buffer;
1194			uint32 i;
1195			for (i=0,buffer=diri_init(vol,node->cluster, 0, &diri);buffer;buffer=diri_next_entry(&diri),i++) {
1196				if (buffer[0] == 0) break;
1197				dprintf("entry %lx:\n", i);
1198				dump_directory(buffer);
1199			}
1200			diri_free(&diri);}
1201			break;
1202
1203		case 100003 :
1204			dprintf("vcache validation not yet implemented\n");
1205			dprintf("validating vcache for %lx\n", vol->id);
1206			validate_vcache(vol);
1207			dprintf("validation complete for %lx\n", vol->id);
1208			break;
1209
1210		case 100004 :
1211			dprintf("dumping vcache for %lx\n", vol->id);
1212			dump_vcache(vol);
1213			break;
1214
1215		case 100005 :
1216			dprintf("dumping dlist for %lx\n", vol->id);
1217			dlist_dump(vol);
1218			break;
1219
1220		default :
1221			DPRINTF(0, ("dosfs_ioctl: vol %" B_PRIdDEV ", vnode %" B_PRIdINO
1222				" code = %" B_PRIu32 "\n", vol->id, node->vnid, code));
1223			result = B_DEV_INVALID_IOCTL;
1224			break;
1225	}
1226
1227	UNLOCK_VOL(vol);
1228
1229	return result;
1230}
1231#endif
1232
1233
1234status_t
1235_dosfs_sync(nspace *vol)
1236{
1237	update_fsinfo(vol);
1238	block_cache_sync(vol->fBlockCache);
1239
1240	return B_OK;
1241}
1242
1243
1244static status_t
1245dosfs_sync(fs_volume *_vol)
1246{
1247	nspace *vol = (nspace *)_vol->private_volume;
1248	status_t err;
1249
1250	DPRINTF(0, ("dosfs_sync called on volume %" B_PRIdDEV "\n", vol->id));
1251
1252	LOCK_VOL(vol);
1253	err = _dosfs_sync(vol);
1254	UNLOCK_VOL(vol);
1255
1256	return err;
1257}
1258
1259
1260static status_t
1261dosfs_fsync(fs_volume *_vol, fs_vnode *_node)
1262{
1263	nspace *vol = (nspace *)_vol->private_volume;
1264	vnode *node = (vnode *)_node->private_node;
1265	status_t err = B_OK;
1266
1267	LOCK_VOL(vol);
1268
1269	if (node->cache)
1270		err = file_cache_sync(node->cache);
1271
1272	UNLOCK_VOL(vol);
1273	return err;
1274}
1275
1276
1277//	#pragma mark -
1278
1279
1280static uint32
1281dosfs_get_supported_operations(partition_data* partition, uint32 mask)
1282{
1283	dprintf("dosfs_get_supported_operations\n");
1284	// TODO: We should at least check the partition size.
1285	return B_DISK_SYSTEM_SUPPORTS_INITIALIZING
1286		| B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
1287		| B_DISK_SYSTEM_SUPPORTS_WRITING;
1288}
1289
1290
1291//	#pragma mark -
1292
1293
1294static status_t
1295dos_std_ops(int32 op, ...)
1296{
1297	dprintf("dos_std_ops()\n");
1298	switch (op) {
1299		case B_MODULE_INIT:
1300			return B_OK;
1301		case B_MODULE_UNINIT:
1302			return B_OK;
1303
1304		default:
1305			return B_ERROR;
1306	}
1307}
1308
1309
1310fs_volume_ops gFATVolumeOps = {
1311	&dosfs_unmount,
1312	&dosfs_read_fs_stat,
1313	&dosfs_write_fs_stat,
1314	&dosfs_sync,
1315	&dosfs_read_vnode,
1316
1317	/* index directory & index operations */
1318	NULL,	//&fs_open_index_dir,
1319	NULL,	//&fs_close_index_dir,
1320	NULL,	//&fs_free_index_dir_cookie,
1321	NULL,	//&fs_read_index_dir,
1322	NULL,	//&fs_rewind_index_dir,
1323
1324	NULL,	//&fs_create_index,
1325	NULL,	//&fs_remove_index,
1326	NULL,	//&fs_stat_index,
1327
1328	/* query operations */
1329	NULL,	//&fs_open_query,
1330	NULL,	//&fs_close_query,
1331	NULL,	//&fs_free_query_cookie,
1332	NULL,	//&fs_read_query,
1333	NULL,	//&fs_rewind_query,
1334};
1335
1336
1337fs_vnode_ops gFATVnodeOps = {
1338	/* vnode operations */
1339	&dosfs_walk,
1340	&dosfs_get_vnode_name,
1341	&dosfs_release_vnode,
1342	&dosfs_remove_vnode,
1343
1344	/* VM file access */
1345	&dosfs_can_page,
1346	&dosfs_read_pages,
1347	&dosfs_write_pages,
1348
1349	NULL,	// io()
1350	NULL,	// cancel_io()
1351
1352	&dosfs_get_file_map,
1353
1354	NULL,	// fs_ioctl()
1355	NULL,	// fs_set_flags,
1356	NULL,	// fs_select
1357	NULL,	// fs_deselect
1358	&dosfs_fsync,
1359
1360	&dosfs_readlink,
1361	NULL,	// fs_create_symlink,
1362
1363	NULL,	// fs_link,
1364	&dosfs_unlink,
1365	&dosfs_rename,
1366
1367	&dosfs_access,
1368	&dosfs_rstat,
1369	&dosfs_wstat,
1370	NULL,	// fs_preallocate,
1371
1372	/* file operations */
1373	&dosfs_create,
1374	&dosfs_open,
1375	&dosfs_close,
1376	&dosfs_free_cookie,
1377	&dosfs_read,
1378	&dosfs_write,
1379
1380	/* directory operations */
1381	&dosfs_mkdir,
1382	&dosfs_rmdir,
1383	&dosfs_opendir,
1384	&dosfs_closedir,
1385	&dosfs_free_dircookie,
1386	&dosfs_readdir,
1387	&dosfs_rewinddir,
1388
1389	/* attribute directory operations */
1390	&dosfs_open_attrdir,
1391	&dosfs_close_attrdir,
1392	&dosfs_free_attrdir_cookie,
1393	&dosfs_read_attrdir,
1394	&dosfs_rewind_attrdir,
1395
1396	/* attribute operations */
1397	NULL,	// fs_create_attr,
1398	&dosfs_open_attr,
1399	&dosfs_close_attr,
1400	&dosfs_free_attr_cookie,
1401	&dosfs_read_attr,
1402	&dosfs_write_attr,
1403
1404	&dosfs_read_attr_stat,
1405	NULL,	// fs_write_attr_stat,
1406	NULL,	// fs_rename_attr,
1407	NULL,	// fs_remove_attr,
1408};
1409
1410
1411static file_system_module_info sFATFileSystem = {
1412	{
1413		"file_systems/fat" B_CURRENT_FS_API_VERSION,
1414		0,
1415		dos_std_ops,
1416	},
1417
1418	"fat",					// short_name
1419	"FAT32 File System",	// pretty_name
1420
1421	// DDM flags
1422	0
1423//	| B_DISK_SYSTEM_SUPPORTS_CHECKING
1424//	| B_DISK_SYSTEM_SUPPORTS_REPAIRING
1425//	| B_DISK_SYSTEM_SUPPORTS_RESIZING
1426//	| B_DISK_SYSTEM_SUPPORTS_MOVING
1427//	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME
1428//	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS
1429	| B_DISK_SYSTEM_SUPPORTS_INITIALIZING
1430	| B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
1431//	| B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING
1432//	| B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING_WHILE_MOUNTED
1433//	| B_DISK_SYSTEM_SUPPORTS_CHECKING_WHILE_MOUNTED
1434//	| B_DISK_SYSTEM_SUPPORTS_REPAIRING_WHILE_MOUNTED
1435//	| B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED
1436//	| B_DISK_SYSTEM_SUPPORTS_MOVING_WHILE_MOUNTED
1437//	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED
1438//	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED
1439	| B_DISK_SYSTEM_SUPPORTS_WRITING
1440	,
1441
1442	// scanning
1443	dosfs_identify_partition,
1444	dosfs_scan_partition,
1445	dosfs_free_identify_partition_cookie,
1446	NULL,	// free_partition_content_cookie()
1447
1448	&dosfs_mount,
1449
1450	/* capability querying operations */
1451	&dosfs_get_supported_operations,
1452
1453	NULL,	// validate_resize
1454	NULL,	// validate_move
1455	NULL,	// validate_set_content_name
1456	NULL,	// validate_set_content_parameters
1457	NULL,	// validate_initialize,
1458
1459	/* shadow partition modification */
1460	NULL,	// shadow_changed
1461
1462	/* writing */
1463	NULL,	// defragment
1464	NULL,	// repair
1465	NULL,	// resize
1466	NULL,	// move
1467	NULL,	// set_content_name
1468	NULL,	// set_content_parameters
1469	dosfs_initialize,
1470	dosfs_uninitialize
1471};
1472
1473module_info *modules[] = {
1474	(module_info *)&sFATFileSystem,
1475	NULL,
1476};
1477