[haiku-commits] r35262 - haiku/trunk/src/add-ons/kernel/file_systems/fat
- From: superstippi@xxxxxx
- To: haiku-commits@xxxxxxxxxxxxx
- Date: Sat, 23 Jan 2010 15:01:05 +0100 (CET)
Author: stippi
Date: 2010-01-23 15:01:04 +0100 (Sat, 23 Jan 2010)
New Revision: 35262
Changeset: http://dev.haiku-os.org/changeset/35262/haiku
Ticket: http://dev.haiku-os.org/ticket/4602
Modified:
haiku/trunk/src/add-ons/kernel/file_systems/fat/dosfs.c
Log:
Applied patch by romain. Through refactoring, the volume name is already
retrieved before a volume is actually mounted and this fixes #4602. I have
applied the patch as is, although it contains some minor coding style
violations,
since these have been there before.
Modified: haiku/trunk/src/add-ons/kernel/file_systems/fat/dosfs.c
===================================================================
--- haiku/trunk/src/add-ons/kernel/file_systems/fat/dosfs.c 2010-01-23
12:50:13 UTC (rev 35261)
+++ haiku/trunk/src/add-ons/kernel/file_systems/fat/dosfs.c 2010-01-23
14:01:04 UTC (rev 35262)
@@ -160,6 +160,7 @@
}
}
+
static bool
dosfs_read_label(bool fat32, uint8 *buffer, char *label)
{
@@ -177,110 +178,25 @@
}
-static int
-lock_removable_device(int fd, bool state)
+static nspace*
+volume_init(int fd, uint8* buf,
+ const int flags, int fs_flags,
+ device_geometry *geo)
{
- return ioctl(fd, B_SCSI_PREVENT_ALLOW, &state, sizeof(state));
-}
-
-
-static status_t
-mount_fat_disk(const char *path, fs_volume *_vol, const int flags,
- nspace** newVol, int fs_flags, int op_sync_mode)
-{
nspace *vol = NULL;
- uint8 buf[512];
+ uint8 media_buf[512];
int i;
- device_geometry geo;
status_t err;
-
- *newVol = NULL;
+
if ((vol = (nspace *)calloc(sizeof(nspace), 1)) == NULL) {
dprintf("dosfs error: out of memory\n");
- return B_NO_MEMORY;
+ return NULL;
}
- vol->flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME;
+ vol->flags = flags;
vol->fs_flags = fs_flags;
+ vol->fd = fd;
- // open read-only for now
- if ((err = (vol->fd = open(path, O_RDONLY | O_NOCACHE))) < 0) {
- dprintf("dosfs error: unable to open %s (%s)\n", path,
strerror(err));
- goto error0;
- }
-
- // get device characteristics
- if (ioctl(vol->fd, B_GET_GEOMETRY, &geo) < 0) {
- struct stat st;
- if (fstat(vol->fd, &st) >= 0 && S_ISREG(st.st_mode)) {
- /* support mounting disk images */
- geo.bytes_per_sector = 0x200;
- geo.sectors_per_track = 1;
- geo.cylinder_count = st.st_size / 0x200;
- geo.head_count = 1;
- geo.read_only = !(st.st_mode & S_IWUSR);
- geo.removable = true;
- } else {
- dprintf("dosfs error: error getting device geometry\n");
- goto error0;
- }
- }
-
- if (geo.bytes_per_sector != 0x200 && geo.bytes_per_sector != 0x400
- && geo.bytes_per_sector != 0x800 && geo.bytes_per_sector !=
0x1000) {
- dprintf("dosfs error: unsupported device block size (%lu)\n",
- geo.bytes_per_sector);
- goto error0;
- }
-
- if (geo.removable) {
- DPRINTF(0, ("%s is removable\n", path));
- vol->flags |= B_FS_IS_REMOVABLE;
- }
-
- if (geo.read_only || (flags & B_MOUNT_READ_ONLY)) {
- DPRINTF(0, ("%s is read-only\n", path));
- vol->flags |= B_FS_IS_READONLY;
- } else {
- // reopen it with read/write permissions
- close(vol->fd);
- if ((err = (vol->fd = open(path, O_RDWR | O_NOCACHE))) < 0) {
- dprintf("dosfs error: unable to open %s (%s)\n", path,
- strerror(err));
- goto error0;
- }
-
- if ((vol->flags & B_FS_IS_REMOVABLE)
- && (vol->fs_flags & FS_FLAGS_LOCK_DOOR))
- lock_removable_device(vol->fd, true);
- }
-
- // see if we need to go into op sync mode
- vol->fs_flags &= ~FS_FLAGS_OP_SYNC;
- switch (op_sync_mode) {
- case 1:
- if ((vol->flags & B_FS_IS_REMOVABLE) == 0) {
- // we're not removable, so skip op_sync
- break;
- }
- // supposed to fall through
-
- case 2:
- dprintf("dosfs: mounted with op_sync enabled\n");
- vol->fs_flags |= FS_FLAGS_OP_SYNC;
- break;
-
- case 0:
- default:
- break;
- }
-
- // read in the boot sector
- if ((err = read_pos(vol->fd, 0, (void *)buf, 512)) != 512) {
- dprintf("dosfs error: error reading boot sector\n");
- goto error;
- }
-
// only check boot signature on hard disks to account for broken mtools
// behavior
if ((buf[0x1fe] != 0x55 || buf[0x1ff] != 0xaa) && buf[0x15] == 0xf8)
@@ -376,22 +292,22 @@
if (vol->total_sectors == 0)
vol->total_sectors = read32(buf, 0x20);
- {
+ if (geo != NULL) {
/*
- Zip disks that were formatted at iomega have an
incorrect number
- of sectors. They say that they have 196576 sectors
but they
- really only have 196192. This check is a work-around
for their
- brain-deadness.
+ Zip disks that were formatted at iomega have an
incorrect number
+ of sectors. They say that they have 196576
sectors but they
+ really only have 196192. This check is a
work-around for their
+ brain-deadness.
*/
unsigned char bogus_zip_data[] = {
0x00, 0x02, 0x04, 0x01, 0x00, 0x02, 0x00, 0x02,
0x00, 0x00,
0xf8, 0xc0, 0x00, 0x20, 0x00, 0x40, 0x00, 0x20,
0x00, 0x00
};
-
+
if (memcmp(buf + 0x0b, bogus_zip_data,
sizeof(bogus_zip_data)) == 0
&& vol->total_sectors == 196576
- && ((off_t)geo.sectors_per_track *
(off_t)geo.cylinder_count
- * (off_t)geo.head_count) == 196192) {
+ && ((off_t)geo->sectors_per_track *
(off_t)geo->cylinder_count
+ * (off_t)geo->head_count) == 196192) {
vol->total_sectors = 196192;
}
}
@@ -422,54 +338,46 @@
vol->vol_entry = -1;
}
- /* check that the partition is large enough to contain the file system
*/
- if (vol->total_sectors > geo.sectors_per_track * geo.cylinder_count
- * geo.head_count) {
- dprintf("dosfs: volume extends past end of partition\n");
- err = B_PARTITION_TOO_SMALL;
- goto error;
- }
-
// perform sanity checks on the FAT
// the media descriptor in active FAT should match the one in the BPB
if ((err = read_pos(vol->fd, vol->bytes_per_sector *
(vol->reserved_sectors
+ vol->active_fat * vol->sectors_per_fat),
- (void *)buf, 0x200)) != 0x200) {
+ (void *)media_buf, 0x200)) != 0x200) {
dprintf("dosfs error: error reading FAT\n");
goto error;
}
- if (buf[0] != vol->media_descriptor) {
- dprintf("dosfs error: media descriptor mismatch (%x != %x)\n",
buf[0],
+ if (media_buf[0] != vol->media_descriptor) {
+ dprintf("dosfs error: media descriptor mismatch (%x != %x)\n",
media_buf[0],
vol->media_descriptor);
goto error;
}
if (vol->fat_mirrored) {
uint32 i;
- uint8 buf2[512];
+ uint8 mirror_media_buf[512];
for (i = 0; i < vol->fat_count; i++) {
if (i != vol->active_fat) {
DPRINTF(1, ("checking fat #%ld\n", i));
- buf2[0] = ~buf[0];
+ mirror_media_buf[0] = ~media_buf[0];
if ((err = read_pos(vol->fd,
vol->bytes_per_sector
* (vol->reserved_sectors +
vol->sectors_per_fat * i),
- (void *)buf2, 0x200)) != 0x200)
{
+ (void *)mirror_media_buf,
0x200)) != 0x200) {
dprintf("dosfs error: error reading FAT
%ld\n", i);
goto error;
}
- if (buf2[0] != vol->media_descriptor) {
+ if (mirror_media_buf[0] !=
vol->media_descriptor) {
dprintf("dosfs error: media descriptor
mismatch in fat # "
- "%ld (%x != %x)\n", i, buf2[0],
vol->media_descriptor);
+ "%ld (%x != %x)\n", i,
mirror_media_buf[0], vol->media_descriptor);
goto error;
}
#if 0
// checking for exact matches of fats is too
// restrictive; allow these to go through in
// case the fat is corrupted for some reason
- if (memcmp(buf, buf2, 0x200)) {
+ if (memcmp(media_buf, mirror_media_buf, 0x200))
{
dprintf("dosfs error: fat %d doesn't
match active fat "
"(%d)\n", i, vol->active_fat);
goto error;
@@ -479,23 +387,12 @@
}
}
+
// now we are convinced of the drive's validity
- vol->volume = _vol;
- vol->id = _vol->id;
- strncpy(vol->device, path, sizeof(vol->device));
-
// this will be updated later if fsinfo exists
vol->last_allocated = 2;
-
vol->beos_vnid = INVALID_VNID_BITS_MASK;
- {
- void *handle;
- handle = load_driver_settings("fat");
- vol->respect_disk_image =
- get_driver_boolean_parameter(handle, "respect",
true, true);
- unload_driver_settings(handle);
- }
// initialize block cache
vol->fBlockCache = block_cache_create(vol->fd, vol->total_sectors,
@@ -505,18 +402,52 @@
goto error;
}
- // as well as the vnode cache
- if (init_vcache(vol) != B_OK) {
- dprintf("dosfs error: error initializing vnode cache\n");
- goto error1;
- }
+ // find volume label (supercedes any label in the bpb)
+ {
+ struct diri diri;
+ uint8 *buffer;
+ buffer = diri_init(vol, vol->root_vnode.cluster, 0, &diri);
+ for (; buffer; buffer = diri_next_entry(&diri)) {
+ if ((buffer[0x0b] & FAT_VOLUME) && (buffer[0x0b] != 0xf)
+ && (buffer[0] != 0xe5)) {
+ vol->vol_entry = diri.current_index;
+ memcpy(vol->vol_label, buffer, 11);
+ dosfs_trim_spaces(vol->vol_label);
+ break;
+ }
+ }
- // and the dlist cache
- if (dlist_init(vol) != B_OK) {
- dprintf("dosfs error: error initializing dlist cache\n");
- goto error2;
+ diri_free(&diri);
}
+ DPRINTF(0, ("root vnode id = %Lx\n", vol->root_vnode.vnid));
+ DPRINTF(0, ("volume label [%s] (%lx)\n", vol->vol_label,
vol->vol_entry));
+
+ // steal a trick from bfs
+ if (!memcmp(vol->vol_label, "__RO__ ", 11))
+ vol->flags |= B_FS_IS_READONLY;
+
+ return vol;
+
+error:
+ free(vol);
+ return NULL;
+}
+
+
+static void
+volume_uninit(nspace *vol)
+{
+ block_cache_delete(vol->fBlockCache, false);
+ free(vol);
+}
+
+
+static void
+volume_count_free_cluster(nspace *vol)
+{
+ status_t err;
+
if (vol->flags & B_FS_IS_READONLY)
vol->free_clusters = 0;
else {
@@ -539,20 +470,164 @@
if ((err = count_free_clusters(vol)) < 0) {
dprintf("dosfs error: error counting free
clusters (%s)\n",
strerror(err));
- goto error3;
+ return;
}
vol->free_clusters = err;
}
}
+}
+
+static int
+lock_removable_device(int fd, bool state)
+{
+ return ioctl(fd, B_SCSI_PREVENT_ALLOW, &state, sizeof(state));
+}
+
+
+static status_t
+mount_fat_disk(const char *path, fs_volume *_vol, const int flags,
+ nspace** newVol, int fs_flags, int op_sync_mode)
+{
+ nspace *vol = NULL;
+ uint8 buf[512];
+ device_geometry geo;
+ status_t err;
+ int fd;
+ int vol_flags;
+
+ vol_flags = B_FS_IS_PERSISTENT | B_FS_HAS_MIME;
+
+ // open read-only for now
+ if ((err = (fd = open(path, O_RDONLY | O_NOCACHE))) < 0) {
+ dprintf("dosfs error: unable to open %s (%s)\n", path,
strerror(err));
+ goto error0;
+ }
+
+ // get device characteristics
+ if (ioctl(fd, B_GET_GEOMETRY, &geo) < 0) {
+ struct stat st;
+ if (fstat(fd, &st) >= 0 && S_ISREG(st.st_mode)) {
+ /* support mounting disk images */
+ geo.bytes_per_sector = 0x200;
+ geo.sectors_per_track = 1;
+ geo.cylinder_count = st.st_size / 0x200;
+ geo.head_count = 1;
+ geo.read_only = !(st.st_mode & S_IWUSR);
+ geo.removable = true;
+ } else {
+ dprintf("dosfs error: error getting device geometry\n");
+ goto error1;
+ }
+ }
+
+ if (geo.bytes_per_sector != 0x200 && geo.bytes_per_sector != 0x400
+ && geo.bytes_per_sector != 0x800 && geo.bytes_per_sector !=
0x1000) {
+ dprintf("dosfs error: unsupported device block size (%lu)\n",
+ geo.bytes_per_sector);
+ goto error1;
+ }
+
+ if (geo.removable) {
+ DPRINTF(0, ("%s is removable\n", path));
+ vol_flags |= B_FS_IS_REMOVABLE;
+ }
+
+ if (geo.read_only || (flags & B_MOUNT_READ_ONLY)) {
+ DPRINTF(0, ("%s is read-only\n", path));
+ vol_flags |= B_FS_IS_READONLY;
+ } else {
+ // reopen it with read/write permissions
+ close(fd);
+ if ((err = (fd = open(path, O_RDWR | O_NOCACHE))) < 0) {
+ dprintf("dosfs error: unable to open %s (%s)\n", path,
+ strerror(err));
+ goto error0;
+ }
+
+ if ((vol_flags & B_FS_IS_REMOVABLE)
+ && (fs_flags & FS_FLAGS_LOCK_DOOR))
+ lock_removable_device(fd, true);
+ }
+
+ // see if we need to go into op sync mode
+ fs_flags &= ~FS_FLAGS_OP_SYNC;
+ switch (op_sync_mode) {
+ case 1:
+ if ((vol_flags & B_FS_IS_REMOVABLE) == 0) {
+ // we're not removable, so skip op_sync
+ break;
+ }
+ // supposed to fall through
+
+ case 2:
+ dprintf("dosfs: mounted with op_sync enabled\n");
+ fs_flags |= FS_FLAGS_OP_SYNC;
+ break;
+
+ case 0:
+ default:
+ break;
+ }
+
+ // read in the boot sector
+ if ((err = read_pos(fd, 0, (void *)buf, 512)) != 512) {
+ dprintf("dosfs error: error reading boot sector\n");
+ goto error1;
+ }
+
+ vol = volume_init(fd, buf, vol_flags, fs_flags, &geo);
+
+ /* check that the partition is large enough to contain the file system
*/
+ if (vol->total_sectors > geo.sectors_per_track * geo.cylinder_count
+ * geo.head_count) {
+ dprintf("dosfs: volume extends past end of partition\n");
+ err = B_PARTITION_TOO_SMALL;
+ goto error2;
+ }
+
+ vol->volume = _vol;
+ vol->id = _vol->id;
+ strncpy(vol->device, path, sizeof(vol->device));
+
+ {
+ void *handle;
+ handle = load_driver_settings("fat");
+ vol->respect_disk_image =
+ get_driver_boolean_parameter(handle, "respect", true,
true);
+ unload_driver_settings(handle);
+ }
+
+ // Initialize the vnode cache
+ if (init_vcache(vol) != B_OK) {
+ dprintf("dosfs error: error initializing vnode cache\n");
+ goto error2;
+ }
+
+ // and the dlist cache
+ if (dlist_init(vol) != B_OK) {
+ dprintf("dosfs error: error initializing dlist cache\n");
+ goto error3;
+ }
+
+ volume_count_free_cluster(vol);
+
DPRINTF(0, ("built at %s on %s\n", build_time, build_date));
- DPRINTF(0, ("mounting %s (id %lx, device %x, media descriptor %x)\n",
vol->device, vol->id, vol->fd, vol->media_descriptor));
- DPRINTF(0, ("%lx bytes/sector, %lx sectors/cluster\n",
vol->bytes_per_sector, vol->sectors_per_cluster));
- DPRINTF(0, ("%lx reserved sectors, %lx total sectors\n",
vol->reserved_sectors, vol->total_sectors));
- 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));
- 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));
- DPRINTF(0, ("%lx total clusters, %lx free\n", vol->total_clusters,
vol->free_clusters));
- DPRINTF(0, ("fat mirroring is %s, fs info sector at sector %x\n",
(vol->fat_mirrored) ? "on" : "off", vol->fsinfo_sector));
+ DPRINTF(0, ("mounting %s (id %lx, device %x, media descriptor %x)\n",
+ vol->device, vol->id, vol->fd,
vol->media_descriptor));
+ DPRINTF(0, ("%lx bytes/sector, %lx sectors/cluster\n",
+ vol->bytes_per_sector,
vol->sectors_per_cluster));
+ DPRINTF(0, ("%lx reserved sectors, %lx total sectors\n",
+ vol->reserved_sectors, vol->total_sectors));
+ 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));
+ 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));
+ DPRINTF(0, ("%lx total clusters, %lx free\n",
+ vol->total_clusters, vol->free_clusters));
+ DPRINTF(0, ("fat mirroring is %s, fs info sector at sector %x\n",
+ (vol->fat_mirrored) ? "on" : "off",
vol->fsinfo_sector));
DPRINTF(0, ("last allocated cluster = %lx\n", vol->last_allocated));
if (vol->fat_bits == 32) {
@@ -575,24 +650,7 @@
vol->root_vnode.dirty = false;
dlist_add(vol, vol->root_vnode.vnid);
- // find volume label (supercedes any label in the bpb)
- {
- struct diri diri;
- uint8 *buffer;
- buffer = diri_init(vol, vol->root_vnode.cluster, 0, &diri);
- for (; buffer; buffer = diri_next_entry(&diri)) {
- if ((buffer[0x0b] & FAT_VOLUME) && (buffer[0x0b] != 0xf)
- && (buffer[0] != 0xe5)) {
- vol->vol_entry = diri.current_index;
- memcpy(vol->vol_label, buffer, 11);
- dosfs_trim_spaces(vol->vol_label);
- break;
- }
- }
- diri_free(&diri);
- }
-
DPRINTF(0, ("root vnode id = %Lx\n", vol->root_vnode.vnid));
DPRINTF(0, ("volume label [%s] (%lx)\n", vol->vol_label,
vol->vol_entry));
@@ -604,19 +662,16 @@
return B_NO_ERROR;
error3:
- dlist_uninit(vol);
+ uninit_vcache(vol);
error2:
- uninit_vcache(vol);
+ volume_uninit(vol);
error1:
- block_cache_delete(vol->fBlockCache, false);
-error:
if (!(vol->flags & B_FS_IS_READONLY) && (vol->flags & B_FS_IS_REMOVABLE)
&& (vol->fs_flags & FS_FLAGS_LOCK_DOOR)) {
- lock_removable_device(vol->fd, false);
+ lock_removable_device(fd, false);
}
+ close(fd);
error0:
- close(vol->fd);
- free(vol);
return err >= B_NO_ERROR ? EINVAL : err;
}
@@ -693,6 +748,17 @@
dosfs_read_label(false, buf, name);
}
+ // find volume label (supercedes any label in the bpb)
+ {
+ nspace *vol;
+ vol = volume_init(fd, buf, 0, 0, NULL);
+ if (vol != NULL)
+ {
+ strlcpy(name, vol->vol_label, 12);
+ volume_uninit(vol);
+ }
+ }
+
cookie = (identify_cookie *)malloc(sizeof(identify_cookie));
if (!cookie)
return -1;
Other related posts:
- » [haiku-commits] r35262 - haiku/trunk/src/add-ons/kernel/file_systems/fat - superstippi