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 <KernelExport.h> 6 7#include <fsproto.h> 8#include <lock.h> 9#include <cache.h> 10 11#include "iter.h" 12#include "dosfs.h" 13#include "fat.h" 14#include "util.h" 15 16#define DPRINTF(a,b) if (debug_iter > (a)) dprintf b 17 18CHECK_MAGIC(diri,struct diri,DIRI_MAGIC) 19 20static int _validate_cs_(nspace *vol, uint32 cluster, uint32 sector) 21{ 22 if (sector < 0) return -1; 23 24 if ((vol->fat_bits != 32) && IS_FIXED_ROOT(cluster)) { // fat12 or fat16 root 25 if (sector >= vol->root_sectors) 26 return -1; 27 return 0; 28 } 29 30 if (sector >= vol->sectors_per_cluster) return -1; 31 32 if (!IS_DATA_CLUSTER(cluster)) return -1; 33 34 return 0; 35} 36 37static off_t _csi_to_block_(struct csi *csi) 38{ 39 // presumes the caller has already called _validate_cs_ on the argument 40 ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0); 41 if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) 42 return EINVAL; 43 44 if (IS_FIXED_ROOT(csi->cluster)) 45 return csi->vol->root_start + csi->sector; 46 47 return csi->vol->data_start + 48 (off_t)(csi->cluster - 2)* csi->vol->sectors_per_cluster + 49 csi->sector; 50} 51 52int init_csi(nspace *vol, uint32 cluster, uint32 sector, struct csi *csi) 53{ 54 int ret; 55 if ((ret = _validate_cs_(vol,cluster,sector)) != 0) 56 return ret; 57 58 csi->vol = vol; csi->cluster = cluster; csi->sector = sector; 59 60 return 0; 61} 62 63int iter_csi(struct csi *csi, int sectors) 64{ 65 if (csi->sector == 0xffff) // check if already at end of chain 66 return -1; 67 68 if (sectors < 0) 69 return EINVAL; 70 71 if (sectors == 0) 72 return 0; 73 74 if (IS_FIXED_ROOT(csi->cluster)) { 75 csi->sector += sectors; 76 if (csi->sector < csi->vol->root_sectors) 77 return 0; 78 } else { 79 csi->sector += sectors; 80 if (csi->sector < csi->vol->sectors_per_cluster) 81 return 0; 82 csi->cluster = get_nth_fat_entry(csi->vol, csi->cluster, csi->sector / csi->vol->sectors_per_cluster); 83 84 if ((int32)csi->cluster < 0) { 85 csi->sector = 0xffff; 86 return csi->cluster; 87 } 88 89 if (vIS_DATA_CLUSTER(csi->vol,csi->cluster)) { 90 csi->sector %= csi->vol->sectors_per_cluster; 91 return 0; 92 } 93 } 94 95 csi->sector = 0xffff; 96 97 return -1; 98} 99 100uint8 *csi_get_block(struct csi *csi) 101{ 102 if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) 103 return NULL; 104 105 return get_block(csi->vol->fd, _csi_to_block_(csi), csi->vol->bytes_per_sector); 106} 107 108status_t csi_release_block(struct csi *csi) 109{ 110 status_t err; 111 112 if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) 113 return EINVAL; 114 115 err = release_block(csi->vol->fd, _csi_to_block_(csi)); 116 ASSERT(err == B_OK); 117 return err; 118} 119 120status_t csi_mark_block_dirty(struct csi *csi) 121{ 122 status_t err; 123 124 ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0); 125 if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) 126 return EINVAL; 127 128 err = mark_blocks_dirty(csi->vol->fd, _csi_to_block_(csi), 1); 129 ASSERT(err == B_OK); 130 return err; 131} 132 133/* XXX: not the most efficient implementation, but it gets the job done */ 134status_t csi_read_blocks(struct csi *csi, uint8 *buffer, ssize_t len) 135{ 136 struct csi old_csi; 137 uint32 sectors; 138 off_t block; 139 status_t err; 140 141 ASSERT(len >= csi->vol->bytes_per_sector); 142 143 if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) 144 return EINVAL; 145 146 sectors = 1; 147 block = _csi_to_block_(csi); 148 149 while (1) { 150 old_csi = *csi; 151 err = iter_csi(csi, 1); 152 if (len < (sectors + 1) * csi->vol->bytes_per_sector) 153 break; 154 if ((err < B_OK) || (block + sectors != _csi_to_block_(csi))) 155 break; 156 sectors++; 157 } 158 159 err = cached_read(csi->vol->fd, block, buffer, sectors, csi->vol->bytes_per_sector); 160 if (err < B_OK) 161 return err; 162 163 *csi = old_csi; 164 165 return sectors * csi->vol->bytes_per_sector; 166} 167 168status_t csi_write_blocks(struct csi *csi, uint8 *buffer, ssize_t len) 169{ 170 struct csi old_csi; 171 uint32 sectors; 172 off_t block; 173 status_t err; 174 175 ASSERT(len >= csi->vol->bytes_per_sector); 176 177 ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0); 178 if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) 179 return EINVAL; 180 181 sectors = 1; 182 block = _csi_to_block_(csi); 183 184 while (1) { 185 old_csi = *csi; 186 err = iter_csi(csi, 1); 187 if (len < (sectors + 1) * csi->vol->bytes_per_sector) 188 break; 189 if ((err < B_OK) || (block + sectors != _csi_to_block_(csi))) 190 break; 191 sectors++; 192 } 193 194 err = cached_write(csi->vol->fd, block, buffer, sectors, csi->vol->bytes_per_sector); 195 if (err < B_OK) 196 return err; 197 198 /* return the last state of the iterator because that's what dosfs_write 199 * expects. this lets it meaningfully cache the state even when it's 200 * writing to the end of the file. */ 201 *csi = old_csi; 202 203 return sectors * csi->vol->bytes_per_sector; 204} 205 206status_t csi_write_block(struct csi *csi, uint8 *buffer) 207{ 208 ASSERT(_validate_cs_(csi->vol, csi->cluster, csi->sector) == 0); 209 if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) 210 return EINVAL; 211 212 return cached_write(csi->vol->fd, _csi_to_block_(csi), buffer, 1, csi->vol->bytes_per_sector); 213} 214 215static void _diri_release_current_block_(struct diri *diri) 216{ 217 ASSERT(diri->current_block); 218 if (diri->current_block == NULL) 219 return; 220 csi_release_block(&(diri->csi)); 221 diri->current_block = NULL; 222} 223 224uint8 *diri_init(nspace *vol, uint32 cluster, uint32 index, struct diri *diri) 225{ 226 diri->magic = DIRI_MAGIC; 227 diri->current_block = NULL; 228 229 if (cluster >= vol->total_clusters + 2) 230 return NULL; 231 232 if (init_csi(vol,cluster,0,&(diri->csi)) != 0) 233 return NULL; 234 235 diri->starting_cluster = cluster; 236 diri->current_index = index; 237 if (index >= vol->bytes_per_sector / 0x20) { 238 if (iter_csi(&(diri->csi), diri->current_index / (vol->bytes_per_sector / 0x20)) != 0) 239 return NULL; 240 } 241 242 // get current sector 243 diri->current_block = csi_get_block(&(diri->csi)); 244 245 if (diri->current_block == NULL) 246 return NULL; 247 248 return diri->current_block + (diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20))*0x20; 249} 250 251int diri_free(struct diri *diri) 252{ 253 if (check_diri_magic(diri, "diri_free")) return EINVAL; 254 255 diri->magic = ~DIRI_MAGIC; // trash magic number 256 257 if (diri->current_block) 258 _diri_release_current_block_(diri); 259 260 return 0; 261} 262 263uint8 *diri_current_entry(struct diri *diri) 264{ 265 if (check_diri_magic(diri, "diri_current_entry")) return NULL; 266 267 if (diri->current_block == NULL) 268 return NULL; 269 270 return diri->current_block + (diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20))*0x20; 271} 272 273uint8 *diri_next_entry(struct diri *diri) 274{ 275 if (check_diri_magic(diri, "diri_next_entry")) return NULL; 276 277 if (diri->current_block == NULL) 278 return NULL; 279 280 if ((++diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20)) == 0) { 281 _diri_release_current_block_(diri); 282 if (iter_csi(&(diri->csi), 1) != 0) 283 return NULL; 284 diri->current_block = csi_get_block(&(diri->csi)); 285 if (diri->current_block == NULL) 286 return NULL; 287 } 288 289 return diri->current_block + (diri->current_index % (diri->csi.vol->bytes_per_sector / 0x20))*0x20; 290} 291 292uint8 *diri_rewind(struct diri *diri) 293{ 294 if (check_diri_magic(diri, "diri_rewind")) return NULL; 295 296 if (diri->current_index > (diri->csi.vol->bytes_per_sector / 0x20 - 1)) { 297 if (diri->current_block) 298 _diri_release_current_block_(diri); 299 if (init_csi(diri->csi.vol, diri->starting_cluster, 0, &(diri->csi)) != 0) 300 return NULL; 301 diri->current_block = csi_get_block(&(diri->csi)); 302 } 303 diri->current_index = 0; 304 return diri->current_block; 305} 306 307void diri_mark_dirty(struct diri *diri) 308{ 309 csi_mark_block_dirty(&(diri->csi)); 310} 311