static long fat_fallocate(struct file *file, int mode, loff_t offset, loff_t len) { int err = 0; struct inode *inode = file->f_mapping->host; int cluster, nr_cluster, fclus, dclus, free_bytes, nr_bytes; struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); if (mode & ~FALLOC_FL_KEEP_SIZE) return -EOPNOTSUPP; if ((offset + len) <= MSDOS_I(inode)->mmu_private) { fat_msg(sb, KERN_ERR, "fat_fallocate():Blocks already allocated"); return -EINVAL; } if ((mode & FALLOC_FL_KEEP_SIZE)) { if (inode->i_size > 0) { err = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus); if (err < 0) { fat_msg(sb, KERN_ERR, "fat_fallocate():fat_get_cluster() error"); return err; } free_bytes = ((fclus+1) << sbi->cluster_bits) - (inode->i_size); nr_bytes = (offset + len - inode->i_size) - free_bytes; } else nr_bytes = (offset + len - inode->i_size); nr_cluster = (nr_bytes + (sbi->cluster_size - 1)) >> sbi->cluster_bits; mutex_lock(&inode->i_mutex); while (nr_cluster-- > 0) { err = fat_alloc_clusters(inode, &cluster, 1); if (err) { fat_msg(sb, KERN_ERR, "fat_fallocate():fat_alloc_clusters() error"); goto error; } err = fat_chain_add(inode, cluster, 1); if (err) { fat_free_clusters(inode, cluster); goto error; } } err = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus); if (err < 0) { fat_msg(sb, KERN_ERR, "fat_fallocate():fat_get_cluster() error"); goto error; } MSDOS_I(inode)->mmu_private = (fclus + 1) << sbi->cluster_bits; } else {
/* * Desc: Return the size of a directory file in bytes * */ static int fat_calc_dir_size(struct inode *inode) { struct fat_sb_info *sbi = MSDOS_SB(inode->i_sb); int ret, fclus, dclus; inode->i_size = 0; if (MSDOS_I(inode)->i_start == 0) return 0; ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus); if (ret < 0) return ret; inode->i_size = (fclus + 1) << sbi->cluster_bits; return 0; }
/** Walk the cluster chain. * * @param bs Buffer holding the boot sector for the file. * @param service_id Service ID of the device with the file. * @param firstc First cluster to start the walk with. * @param lastc If non-NULL, output argument hodling the last cluster * number visited. * @param numc If non-NULL, output argument holding the number of * clusters seen during the walk. * @param max_clusters Maximum number of clusters to visit. * * @return EOK on success or a negative error code. */ int fat_cluster_walk(fat_bs_t *bs, service_id_t service_id, fat_cluster_t firstc, fat_cluster_t *lastc, uint32_t *numc, uint32_t max_clusters) { uint32_t clusters = 0; fat_cluster_t clst = firstc, clst_last1 = FAT_CLST_LAST1(bs); fat_cluster_t clst_bad = FAT_CLST_BAD(bs); int rc; if (firstc == FAT_CLST_RES0) { /* No space allocated to the file. */ if (lastc) *lastc = firstc; if (numc) *numc = 0; return EOK; } while (clst < clst_last1 && clusters < max_clusters) { assert(clst >= FAT_CLST_FIRST); if (lastc) *lastc = clst; /* remember the last cluster number */ /* read FAT1 */ rc = fat_get_cluster(bs, service_id, FAT1, clst, &clst); if (rc != EOK) return rc; assert(clst != clst_bad); clusters++; } if (lastc && clst < clst_last1) *lastc = clst; if (numc) *numc = clusters; return EOK; }
/* Free all clusters after the skip'th cluster. */ static int fat_free(struct inode *inode, int skip) { struct super_block *sb = inode->i_sb; int err, wait, free_start, i_start, i_logstart; if (MSDOS_I(inode)->i_start == 0) return 0; fat_cache_inval_inode(inode); wait = IS_DIRSYNC(inode); i_start = free_start = MSDOS_I(inode)->i_start; i_logstart = MSDOS_I(inode)->i_logstart; /* First, we write the new file size. */ if (!skip) { MSDOS_I(inode)->i_start = 0; MSDOS_I(inode)->i_logstart = 0; } MSDOS_I(inode)->i_attrs |= ATTR_ARCH; inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; if (wait) { err = fat_sync_inode(inode); if (err) { MSDOS_I(inode)->i_start = i_start; MSDOS_I(inode)->i_logstart = i_logstart; return err; } } else mark_inode_dirty(inode); /* Write a new EOF, and get the remaining cluster chain for freeing. */ if (skip) { struct fat_entry fatent; int ret, fclus, dclus; ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus); if (ret < 0) return ret; else if (ret == FAT_ENT_EOF) return 0; fatent_init(&fatent); ret = fat_ent_read(inode, &fatent, dclus); if (ret == FAT_ENT_EOF) { fatent_brelse(&fatent); return 0; } else if (ret == FAT_ENT_FREE) { fat_fs_panic(sb, "%s: invalid cluster chain (i_pos %lld)", __FUNCTION__, MSDOS_I(inode)->i_pos); ret = -EIO; } else if (ret > 0) { err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait); if (err) ret = err; } fatent_brelse(&fatent); if (ret < 0) return ret; free_start = ret; } inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9); /* Freeing the remained cluster chain */ return fat_free_clusters(inode, free_start); }