/*! shrink directory to the size needed errors here are neither likely nor problematic w95 doesn't seem to do this, so it's possible to create a really large directory that consumes all available space! */ status_t compact_directory(nspace *vol, vnode *dir) { uint32 last = 0; struct diri diri; status_t error = B_ERROR; /* quiet warning */ DPRINTF(0, ("compacting directory with vnode id %Lx\n", dir->vnid)); // root directory can't shrink in fat12 and fat16 if (IS_FIXED_ROOT(dir->cluster)) return 0; if (diri_init(vol, dir->cluster, 0, &diri) == NULL) { dprintf("compact_directory: cannot open dir at cluster (%lx)\n", dir->cluster); return EIO; } while (diri.current_block) { char filename[512]; struct _dirent_info_ info; error = _next_dirent_(&diri, &info, filename, 512); if (error == B_OK) { // don't compact away volume labels in the root dir if (!(info.mode & FAT_VOLUME) || (dir->vnid != vol->root_vnode.vnid)) last = diri.current_index; } else if (error == ENOENT) { uint32 clusters = (last + vol->bytes_per_sector / 0x20 * vol->sectors_per_cluster - 1) / (vol->bytes_per_sector / 0x20) / vol->sectors_per_cluster; error = 0; // special case for fat32 root directory; we don't want // it to disappear if (clusters == 0) clusters = 1; if (clusters * vol->bytes_per_sector * vol->sectors_per_cluster < dir->st_size) { DPRINTF(0, ("shrinking directory to %lx clusters\n", clusters)); error = set_fat_chain_length(vol, dir, clusters); dir->st_size = clusters*vol->bytes_per_sector*vol->sectors_per_cluster; dir->iteration++; } break; } else { dprintf("compact_directory: unknown error from _next_dirent_ (%s)\n", strerror(error)); break; } } diri_free(&diri); return error; }
static off_t _csi_to_block_(struct csi *csi) { // presumes the caller has already called _validate_cs_ on the argument ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0); if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) return EINVAL; if (IS_FIXED_ROOT(csi->cluster)) return csi->vol->root_start + csi->sector; return csi->vol->data_start + (off_t)(csi->cluster - 2)* csi->vol->sectors_per_cluster + csi->sector; }
static int _validate_cs_(nspace *vol, uint32 cluster, uint32 sector) { if (sector < 0) return -1; if ((vol->fat_bits != 32) && IS_FIXED_ROOT(cluster)) { // fat12 or fat16 root if (sector >= vol->root_sectors) return -1; return 0; } if (sector >= vol->sectors_per_cluster) return -1; if (!IS_DATA_CLUSTER(cluster)) return -1; return 0; }
int iter_csi(struct csi *csi, int sectors) { if (csi->sector == 0xffff) // check if already at end of chain return -1; if (sectors < 0) return EINVAL; if (sectors == 0) return 0; if (IS_FIXED_ROOT(csi->cluster)) { csi->sector += sectors; if (csi->sector < csi->vol->root_sectors) return 0; } else { csi->sector += sectors; if (csi->sector < csi->vol->sectors_per_cluster) return 0; csi->cluster = get_nth_fat_entry(csi->vol, csi->cluster, csi->sector / csi->vol->sectors_per_cluster); if ((int32)csi->cluster < 0) { csi->sector = 0xffff; return csi->cluster; } if (vIS_DATA_CLUSTER(csi->vol,csi->cluster)) { csi->sector %= csi->vol->sectors_per_cluster; return 0; } } csi->sector = 0xffff; return -1; }