Commit 974083ab authored by Hirofumi Ogawa's avatar Hirofumi Ogawa Committed by Linus Torvalds

[PATCH] fat_access cleanup (4/11)

This removes dirty raw_scan_*(), and rewrites fat_scan() and
fat_subdirs() to use fat_get_entry() instead.
parent 83bb8e18
......@@ -501,6 +501,7 @@ static int fat_read_root(struct inode *inode)
struct msdos_sb_info *sbi = MSDOS_SB(sb);
int error;
MSDOS_I(inode)->file_cluster = MSDOS_I(inode)->disk_cluster = 0;
MSDOS_I(inode)->i_pos = 0;
inode->i_uid = sbi->options.fs_uid;
inode->i_gid = sbi->options.fs_gid;
......
......@@ -326,230 +326,61 @@ int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
return 0;
}
/*
* Now an ugly part: this set of directory scan routines works on clusters
* rather than on inodes and sectors. They are necessary to locate the '..'
* directory "inode". raw_scan_sector operates in four modes:
*
* name number ino action
* -------- -------- -------- -------------------------------------------------
* non-NULL - X Find an entry with that name
* NULL non-NULL non-NULL Find an entry whose data starts at *number
* NULL non-NULL NULL Count subdirectories in *number. (*)
* NULL NULL non-NULL Find an empty entry
*
* (*) The return code should be ignored. It DOES NOT indicate success or
* failure. *number has to be initialized to zero.
*
* - = not used, X = a value is returned unless NULL
*
* If res_bh is non-NULL, the buffer is not deallocated but returned to the
* caller on success. res_de is set accordingly.
*
* If cont is non-zero, raw_found continues with the entry after the one
* res_bh/res_de point to.
*/
#define RSS_NAME /* search for name */ \
done = !strncmp(data[entry].name,name,MSDOS_NAME) && \
!(data[entry].attr & ATTR_VOLUME);
#define RSS_START /* search for start cluster */ \
done = !IS_FREE(data[entry].name) \
&& ( \
( \
(sbi->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \
) \
| CF_LE_W(data[entry].start) \
) == *number;
#define RSS_FREE /* search for free entry */ \
{ \
done = IS_FREE(data[entry].name); \
}
#define RSS_COUNT /* count subdirectories */ \
{ \
done = 0; \
if (!IS_FREE(data[entry].name) && (data[entry].attr & ATTR_DIR)) \
(*number)++; \
}
static int raw_scan_sector(struct super_block *sb, sector_t sector,
const char *name, int *number, loff_t *i_pos,
struct buffer_head **res_bh,
struct msdos_dir_entry **res_de)
{
struct msdos_sb_info *sbi = MSDOS_SB(sb);
struct buffer_head *bh;
struct msdos_dir_entry *data;
int entry,start,done;
if (!(bh = sb_bread(sb, sector)))
return -EIO;
data = (struct msdos_dir_entry *) bh->b_data;
for (entry = 0; entry < sbi->dir_per_block; entry++) {
/* RSS_COUNT: if (data[entry].name == name) done=true else done=false. */
if (name) {
RSS_NAME
} else {
if (!i_pos) RSS_COUNT
else {
if (number) RSS_START
else RSS_FREE
}
}
if (done) {
if (i_pos) {
*i_pos = ((loff_t)sector << sbi->dir_per_block_bits) + entry;
}
start = CF_LE_W(data[entry].start);
if (sbi->fat_bits == 32)
start |= (CF_LE_W(data[entry].starthi) << 16);
if (!res_bh)
brelse(bh);
else {
*res_bh = bh;
*res_de = &data[entry];
}
return start;
}
}
brelse(bh);
return -ENOENT;
}
/*
* raw_scan_root performs raw_scan_sector on the root directory until the
* requested entry is found or the end of the directory is reached.
*/
static int raw_scan_root(struct super_block *sb, const char *name,
int *number, loff_t *i_pos,
struct buffer_head **res_bh,
struct msdos_dir_entry **res_de)
static int fat_get_short_entry(struct inode *dir, loff_t *pos,
struct buffer_head **bh,
struct msdos_dir_entry **de, loff_t *i_pos)
{
int count,cluster;
for (count = 0;
count < MSDOS_SB(sb)->dir_entries / MSDOS_SB(sb)->dir_per_block;
count++) {
cluster = raw_scan_sector(sb, MSDOS_SB(sb)->dir_start + count,
name, number, i_pos, res_bh, res_de);
if (cluster >= 0)
return cluster;
}
return -ENOENT;
}
/*
* raw_scan_nonroot performs raw_scan_sector on a non-root directory until the
* requested entry is found or the end of the directory is reached.
*/
struct super_block *sb = dir->i_sb;
static int raw_scan_nonroot(struct super_block *sb, int start, const char *name,
int *number, loff_t *i_pos,
struct buffer_head **res_bh,
struct msdos_dir_entry **res_de)
{
struct msdos_sb_info *sbi = MSDOS_SB(sb);
int count, cluster;
unsigned long dir_size = 0;
sector_t sector;
#ifdef DEBUG
printk("raw_scan_nonroot: start=%d\n",start);
#endif
do {
for (count = 0; count < sbi->cluster_size; count++) {
sector = ((sector_t)start - 2) * sbi->cluster_size
+ count + sbi->data_start;
cluster = raw_scan_sector(sb, sector, name, number,
i_pos, res_bh, res_de);
if (cluster >= 0)
return cluster;
}
dir_size += 1 << sbi->cluster_bits;
if (dir_size > FAT_MAX_DIR_SIZE) {
fat_fs_panic(sb, "Directory %d: "
while (fat_get_entry(dir, pos, bh, de, i_pos) >= 0) {
if (*pos >= FAT_MAX_DIR_SIZE) {
fat_fs_panic(sb, "Directory %llu: "
"exceeded the maximum size of directory",
start);
break;
}
start = fat_access(sb, start, -1);
if (start < 0)
return start;
else if (start == FAT_ENT_FREE) {
fat_fs_panic(sb, "%s: invalid cluster chain",
__FUNCTION__);
break;
MSDOS_I(dir)->i_pos);
return -EIO;
}
#ifdef DEBUG
printk("next start: %d\n",start);
#endif
} while (start != FAT_ENT_EOF);
/* free entry or long name entry or volume label */
if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME))
return 0;
}
return -ENOENT;
}
/*
* raw_scan performs raw_scan_sector on any sector.
*
* NOTE: raw_scan must not be used on a directory that is is the process of
* being created.
*/
static int raw_scan(struct super_block *sb, int start, const char *name,
loff_t *i_pos, struct buffer_head **res_bh,
struct msdos_dir_entry **res_de)
{
if (start)
return raw_scan_nonroot(sb,start,name,NULL,i_pos,res_bh,res_de);
else
return raw_scan_root(sb,name,NULL,i_pos,res_bh,res_de);
}
/*
* fat_subdirs counts the number of sub-directories of dir. It can be run
* on directories being created.
*/
int fat_subdirs(struct inode *dir)
{
struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
int number;
number = 0;
if ((dir->i_ino == MSDOS_ROOT_INO) && (sbi->fat_bits != 32))
raw_scan_root(dir->i_sb, NULL, &number, NULL, NULL, NULL);
else {
if ((dir->i_ino != MSDOS_ROOT_INO) && !MSDOS_I(dir)->i_start)
return 0; /* in mkdir */
else {
raw_scan_nonroot(dir->i_sb, MSDOS_I(dir)->i_start,
NULL, &number, NULL, NULL, NULL);
}
struct buffer_head *bh;
struct msdos_dir_entry *de;
loff_t cpos, i_pos;
int count = 0;
bh = NULL;
cpos = 0;
while (fat_get_short_entry(dir, &cpos, &bh, &de, &i_pos) >= 0) {
if (de->attr & ATTR_DIR)
count++;
}
return number;
brelse(bh);
return count;
}
/*
* Scans a directory for a given file (name points to its formatted name) or
* for an empty directory slot (name is NULL). Returns an error code or zero.
* Scans a directory for a given file (name points to its formatted name).
* Returns an error code or zero.
*/
int fat_scan(struct inode *dir, const char *name, struct buffer_head **res_bh,
struct msdos_dir_entry **res_de, loff_t *i_pos)
int fat_scan(struct inode *dir, const char *name, struct buffer_head **bh,
struct msdos_dir_entry **de, loff_t *i_pos)
{
int res;
loff_t cpos;
res = raw_scan(dir->i_sb, MSDOS_I(dir)->i_start, name, i_pos,
res_bh, res_de);
return (res < 0) ? res : 0;
*bh = NULL;
cpos = 0;
while (fat_get_short_entry(dir, &cpos, bh, de, i_pos) >= 0) {
if (!strncmp((*de)->name, name, MSDOS_NAME))
return 0;
}
return -ENOENT;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment