/* * First entry : file entry * Second entry : stream-extension entry * Third entry : first file-name entry * So, the index of first file-name dentry should start from 2.
*/ for (i = ES_IDX_FIRST_FILENAME; i < es.num_entries; i++) { struct exfat_dentry *ep = exfat_get_dentry_cached(&es, i);
/* end of name entry */ if (exfat_get_entry_type(ep) != TYPE_EXTEND) break;
len = exfat_extract_uni_name(ep, uniname);
uni_len += len; if (len != EXFAT_FILE_NAME_LEN || uni_len >= MAX_NAME_LENGTH) break;
uniname += EXFAT_FILE_NAME_LEN;
}
/* name buffer should be allocated before use */
err = exfat_alloc_namebuf(nb); if (err) goto out;
get_new:
mutex_lock(&EXFAT_SB(sb)->s_lock);
if (ei->flags == ALLOC_NO_FAT_CHAIN && cpos >= i_size_read(inode)) goto end_of_dir;
err = exfat_readdir(inode, &cpos, &de); if (err) { /* * At least we tried to read a sector. * Move cpos to next sector position (should be aligned).
*/ if (err == -EIO) {
cpos += 1 << (sb->s_blocksize_bits);
cpos &= ~(sb->s_blocksize - 1);
}
end_of_dir: if (!cpos && fake_offset)
cpos = ITER_POS_FILLED_DOTS;
ctx->pos = cpos;
mutex_unlock(&EXFAT_SB(sb)->s_lock);
out: /* * To improve performance, free namebuf after unlock sb_lock. * If namebuf is not allocated, this function do nothing
*/
exfat_free_namebuf(nb); return err;
}
void exfat_init_ext_entry(struct exfat_entry_set_cache *es, int num_entries, struct exfat_uni_name *p_uniname)
{ int i; unsignedshort *uniname = p_uniname->name; struct exfat_dentry *ep;
ep = exfat_get_dentry_cached(es, ES_IDX_FILE);
ep->dentry.file.num_ext = (unsignedchar)(num_entries - 1);
ep = exfat_get_dentry_cached(es, ES_IDX_STREAM);
ep->dentry.stream.name_len = p_uniname->name_len;
ep->dentry.stream.name_hash = cpu_to_le16(p_uniname->name_hash);
for (i = ES_IDX_FIRST_FILENAME; i < num_entries; i++) {
ep = exfat_get_dentry_cached(es, i);
exfat_init_name_entry(ep, uniname);
uniname += EXFAT_FILE_NAME_LEN;
}
exfat_update_dir_chksum(es);
}
void exfat_remove_entries(struct inode *inode, struct exfat_entry_set_cache *es, int order)
{ int i; struct exfat_dentry *ep;
for (i = order; i < es->num_entries; i++) {
ep = exfat_get_dentry_cached(es, i);
if (exfat_get_entry_type(ep) & TYPE_BENIGN_SEC)
exfat_free_benign_secondary_clusters(inode, ep);
exfat_set_entry_type(ep, TYPE_DELETED);
}
if (order < es->num_entries)
es->modified = true;
}
staticbool exfat_validate_entry(unsignedint type, enum exfat_validate_dentry_mode *mode)
{ if (type == TYPE_UNUSED || type == TYPE_DELETED) returnfalse;
switch (*mode) { case ES_MODE_GET_FILE_ENTRY: if (type != TYPE_STREAM) returnfalse;
*mode = ES_MODE_GET_STRM_ENTRY; break; case ES_MODE_GET_STRM_ENTRY: if (type != TYPE_EXTEND) returnfalse;
*mode = ES_MODE_GET_NAME_ENTRY; break; case ES_MODE_GET_NAME_ENTRY: if (type & TYPE_BENIGN_SEC)
*mode = ES_MODE_GET_BENIGN_SEC_ENTRY; elseif (type != TYPE_EXTEND) returnfalse; break; case ES_MODE_GET_BENIGN_SEC_ENTRY: /* Assume unreconized benign secondary entry */ if (!(type & TYPE_BENIGN_SEC)) returnfalse; break; default: returnfalse;
}
returntrue;
}
struct exfat_dentry *exfat_get_dentry_cached( struct exfat_entry_set_cache *es, int num)
{ int off = es->start_off + num * DENTRY_SIZE; struct buffer_head *bh = es->bh[EXFAT_B_TO_BLK(off, es->sb)]; char *p = bh->b_data + EXFAT_BLK_OFFSET(off, es->sb);
return (struct exfat_dentry *)p;
}
/* * Returns a set of dentries. * * Note It provides a direct pointer to bh->data via exfat_get_dentry_cached(). * User should call exfat_get_dentry_set() after setting 'modified' to apply * changes made in this entry set to the real device. * * in: * sb+p_dir+entry: indicates a file/dir * num_entries: specifies how many dentries should be included. * It will be set to es->num_entries if it is not 0. * If num_entries is 0, es->num_entries will be obtained * from the first dentry. * out: * es: pointer of entry set on success. * return: * 0 on success * -error code on failure
*/ staticint __exfat_get_dentry_set(struct exfat_entry_set_cache *es, struct super_block *sb, struct exfat_chain *p_dir, int entry, unsignedint num_entries)
{ int ret, i, num_bh; unsignedint off;
sector_t sec; struct exfat_sb_info *sbi = EXFAT_SB(sb); struct buffer_head *bh;
if (p_dir->dir == DIR_DELETED) {
exfat_err(sb, "access to deleted dentry"); return -EIO;
}
ret = exfat_find_location(sb, p_dir, entry, &sec, &off); if (ret) return ret;
for (i = 1; i < num_bh; i++) { /* get the next sector */ if (exfat_is_last_sector_in_cluster(sbi, sec)) { unsignedint clu = exfat_sector_to_cluster(sbi, sec);
staticint exfat_validate_empty_dentry_set(struct exfat_entry_set_cache *es)
{ struct exfat_dentry *ep; struct buffer_head *bh; int i, off; bool unused_hit = false;
/* * ONLY UNUSED OR DELETED DENTRIES ARE ALLOWED: * Although it violates the specification for a deleted entry to * follow an unused entry, some exFAT implementations could work * like this. Therefore, to improve compatibility, let's allow it.
*/ for (i = 0; i < es->num_entries; i++) {
ep = exfat_get_dentry_cached(es, i); if (ep->type == EXFAT_UNUSED) {
unused_hit = true;
} elseif (!IS_EXFAT_DELETED(ep->type)) { if (unused_hit) goto err_used_follow_unused;
i++; goto count_skip_entries;
}
}
return 0;
err_used_follow_unused:
off = es->start_off + (i << DENTRY_SIZE_BITS);
bh = es->bh[EXFAT_B_TO_BLK(off, es->sb)];
exfat_fs_error(es->sb, "in sector %lld, dentry %d should be unused, but 0x%x",
bh->b_blocknr, off >> DENTRY_SIZE_BITS, ep->type);
return -EIO;
count_skip_entries:
es->num_entries = EXFAT_B_TO_DEN(EXFAT_BLK_TO_B(es->num_bh, es->sb) - es->start_off); for (; i < es->num_entries; i++) {
ep = exfat_get_dentry_cached(es, i); if (IS_EXFAT_DELETED(ep->type)) break;
}
return i;
}
/* * Get an empty dentry set. * * in: * sb+p_dir+entry: indicates the empty dentry location * num_entries: specifies how many empty dentries should be included. * out: * es: pointer of empty dentry set on success. * return: * 0 : on success * >0 : the dentries are not empty, the return value is the number of * dentries to be skipped for the next lookup. * <0 : on failure
*/ int exfat_get_empty_dentry_set(struct exfat_entry_set_cache *es, struct super_block *sb, struct exfat_chain *p_dir, int entry, unsignedint num_entries)
{ int ret;
ret = __exfat_get_dentry_set(es, sb, p_dir, entry, num_entries); if (ret < 0) return ret;
ret = exfat_validate_empty_dentry_set(es); if (ret)
exfat_put_dentry_set(es, false);
if (entry_type &
(TYPE_CRITICAL_SEC | TYPE_BENIGN_SEC)) { if (step == DIRENT_STEP_SECD) { if (++order == num_ext) goto found; continue;
}
}
step = DIRENT_STEP_FILE;
}
if (clu.flags == ALLOC_NO_FAT_CHAIN) { if (--clu.size > 0)
clu.dir++; else
clu.dir = EXFAT_EOF_CLUSTER;
} else { if (exfat_get_next_cluster(sb, &clu.dir)) return -EIO;
/* break if the cluster chain includes a loop */ if (unlikely(++clu_count > EXFAT_DATA_CLUSTER_COUNT(sbi))) goto not_found;
}
}
not_found: /* * We started at not 0 index,so we should try to find target * from 0 index to the index we started at.
*/ if (!rewind && end_eidx) {
rewind = 1;
dentry = 0;
clu.dir = p_dir->dir; goto rewind;
}
/* * set the EXFAT_EOF_CLUSTER flag to avoid search * from the beginning again when allocated a new cluster
*/ if (ei->hint_femp.eidx == EXFAT_HINT_NONE) {
ei->hint_femp.cur.dir = EXFAT_EOF_CLUSTER;
ei->hint_femp.eidx = p_dir->size * dentries_per_clu;
ei->hint_femp.count = 0;
}
int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir)
{ int i, count = 0; int dentries_per_clu; unsignedint entry_type; unsignedint clu_count = 0; struct exfat_chain clu; struct exfat_dentry *ep; struct exfat_sb_info *sbi = EXFAT_SB(sb); struct buffer_head *bh;
dentries_per_clu = sbi->dentries_per_clu;
exfat_chain_dup(&clu, p_dir);
while (clu.dir != EXFAT_EOF_CLUSTER) { for (i = 0; i < dentries_per_clu; i++) {
ep = exfat_get_dentry(sb, &clu, i, &bh); if (!ep) return -EIO;
entry_type = exfat_get_entry_type(ep);
brelse(bh);
if (entry_type == TYPE_UNUSED) return count; if (entry_type != TYPE_DIR) continue;
count++;
}
if (clu.flags == ALLOC_NO_FAT_CHAIN) { if (--clu.size > 0)
clu.dir++; else
clu.dir = EXFAT_EOF_CLUSTER;
} else { if (exfat_get_next_cluster(sb, &(clu.dir))) return -EIO;
if (unlikely(++clu_count > sbi->used_clusters)) {
exfat_fs_error(sb, "FAT or bitmap is corrupted"); return -EIO;
}
}
}
return count;
}
Messung V0.5
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.17Bemerkung:
Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.