Example #1
0
void read_fat(DOS_FS *fs)
{
    int eff_size;
    unsigned long i;
    void *first,*second,*use;
    int first_ok,second_ok;

    eff_size = ((fs->clusters+2)*fs->fat_bits+7)/8;
    first = alloc(eff_size);
    second = alloc(eff_size);
    fs_read(fs->fat_start,eff_size,first);
    fs_read(fs->fat_start+fs->fat_size,eff_size,second);
    use = first;
    if (memcmp(first,second,eff_size) != 0) {
	FAT_ENTRY first_media, second_media;
	get_fat(&first_media,first,0,fs);
	get_fat(&second_media,second,0,fs);
	first_ok = (first_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
	second_ok = (second_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
	if (first_ok && !second_ok) {
	    printf("FATs differ - using first FAT.\n");
	    fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);
	}
	if (!first_ok && second_ok) {
	    printf("FATs differ - using second FAT.\n");
	    fs_write(fs->fat_start,eff_size,use = second);
	}
	if (first_ok && second_ok) {
	    if (interactive) {
		printf("FATs differ but appear to be intact. Use which FAT ?\n"
		  "1) Use first FAT\n2) Use second FAT\n");
		if (get_key("12","?") == '1')
		    fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);
		else fs_write(fs->fat_start,eff_size,use = second);
	    }
	    else {
		printf("FATs differ but appear to be intact. Using first "
		  "FAT.\n");
		fs_write(fs->fat_start+fs->fat_size,eff_size,use = first);
	    }
	}
	if (!first_ok && !second_ok) {
	    printf("Both FATs appear to be corrupt. Giving up.\n");
	    exit(1);
	}
    }
    fs->fat = qalloc(&mem_queue,sizeof(FAT_ENTRY)*(fs->clusters+2));
    for (i = 2; i < fs->clusters+2; i++) get_fat(&fs->fat[i],use,i,fs);
    for (i = 2; i < fs->clusters+2; i++)
	if (fs->fat[i].value >= fs->clusters+2 &&
	    (fs->fat[i].value < FAT_MIN_BAD(fs))) {
	    printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",
		   i-2,fs->fat[i].value,fs->clusters+2-1);
	    set_fat(fs,i,-1);
	}
    free(first);
    free(second);
}
Example #2
0
static int32_t inter_fs_write(
            uint32_t            cid,
            uint16_t            blk,
            uint32_t            offset,
            uint8_t             *pbuf,
            uint32_t            size )
{
    int32_t       rtn;
    uint32_t      i, cnt, c_size;
    uint16_t      a_blk, prevblk, nextblk;
    uint8_t       *p_kbuf;

    if( size == 0 )
    {
        return(DNAND_NO_ERROR);
    }
    if( cid >= DNAND_FS_CLID_NUM )
    {
        return(DNAND_PARAM_ERROR);
    }
    if( ( (blk<DNAND_FS_BLK_DATA_ST)||(blk>=DNAND_FS_BLK_NUM) )&&
        (blk != DNAND_FS_BLK_UNUSE) )
    {
        return(DNAND_MNG_ERROR);
    }

    rtn       = DNAND_NO_ERROR;
    cnt       = (offset+size+DNAND_FS_BLK_SIZE-1)/DNAND_FS_BLK_SIZE;
    a_blk  = alloc_fat();
    if( a_blk >= DNAND_FS_BLK_NUM )
    {
        return(DNAND_NOSPC_ERROR);
    }

    prevblk   = DNAND_FS_BLK_UNUSE;
    p_kbuf    = (uint8_t*)kmalloc(DNAND_FS_BLK_SIZE, GFP_KERNEL);
    if( p_kbuf == NULL )
    {
        return(DNAND_NOMEM_ERROR);
    }

    for( i=0; i<cnt; i++ )
    {
        if( offset >= DNAND_FS_BLK_SIZE )
        {
            if( (blk>=DNAND_FS_BLK_DATA_ST)&&(blk<DNAND_FS_BLK_NUM) )
            {
                offset    -= DNAND_FS_BLK_SIZE;
                prevblk   = blk;
                blk       = get_fat( prevblk );
                continue;
            }
            memset(p_kbuf, 0x00, DNAND_FS_BLK_SIZE);
            rtn           = dnand_blk_write( a_blk, 0, p_kbuf, DNAND_FS_BLK_SIZE );
            offset        -= DNAND_FS_BLK_SIZE;
        }
        else
        {
            if( (offset+size) >= DNAND_FS_BLK_SIZE )
            {
                c_size    = DNAND_FS_BLK_SIZE-offset;
            }
            else
            {
                c_size    = size;
            }

            if( c_size < DNAND_FS_BLK_SIZE )
            {
                if( (blk>=DNAND_FS_BLK_DATA_ST)&&(blk<DNAND_FS_BLK_NUM) )
                {
                    rtn    = dnand_blk_read( blk, 0, p_kbuf, DNAND_FS_BLK_SIZE );
                    if( rtn == DNAND_NO_ERROR )
                    {
                        memcpy( p_kbuf+offset, pbuf, c_size );
                        rtn    = dnand_blk_write( a_blk, 0, p_kbuf, DNAND_FS_BLK_SIZE );
                    }
                }
                else
                {
                    memset( p_kbuf, 0x00, DNAND_FS_BLK_SIZE );
                    memcpy( p_kbuf+offset, pbuf, c_size );
                    rtn    = dnand_blk_write( a_blk, 0, p_kbuf, DNAND_FS_BLK_SIZE );
                }
            }
            else
            {
                rtn    = dnand_blk_write( a_blk, 0, pbuf, c_size );
            }
            offset = 0;
            size   -= c_size;
            pbuf   += c_size;
        }
        if( rtn != DNAND_NO_ERROR )
        {
            break;
        }

        nextblk   = get_fat( blk );
        blk       = nextblk;
        if(  ((nextblk >= DNAND_FS_BLK_DATA_ST)&&(nextblk < DNAND_FS_BLK_NUM)) ||
             (nextblk == DNAND_FS_BLK_EOF) )
        {
            set_fat( a_blk, nextblk );
        }
        else
        {
            set_fat( a_blk, DNAND_FS_BLK_EOF );
        }

        if( (prevblk >= DNAND_FS_BLK_DATA_ST)&&(prevblk < DNAND_FS_BLK_NUM) )
        {
            set_fat( prevblk, a_blk );
        }
        if( i == 0 )
        {
            set_clid( cid, a_blk );
        }
        prevblk   = a_blk;

        if( (i+1) < cnt )
        {
            a_blk     = alloc_fat();
            if( a_blk >= DNAND_FS_BLK_NUM )
            {
                rtn    = DNAND_NOSPC_ERROR;
                break;
            }
        }
    }

    kfree(p_kbuf);
    return(rtn);
}
Example #3
0
/**
 * Build a bookkeeping structure from the partition's FAT table.
 * If the partition has multiple FATs and they don't agree, try to pick a winner,
 * and queue a command to overwrite the loser.
 * One error that is fixed here is a cluster that links to something out of range.
 *
 * @param[inout]    fs      Information about the filesystem
 */
void read_fat(DOS_FS * fs)
{
    int eff_size;
    unsigned long i;
    void *first, *second = NULL;
    int first_ok, second_ok;
    unsigned long total_num_clusters;

    /* Clean up from previous pass */
    if (fs->fat)
	free(fs->fat);
    if (fs->cluster_owner)
	free(fs->cluster_owner);
    fs->fat = NULL;
    fs->cluster_owner = NULL;

    total_num_clusters = fs->clusters + 2UL;
    eff_size = (total_num_clusters * fs->fat_bits + 7) / 8ULL;
    first = alloc(eff_size);
    fs_read(fs->fat_start, eff_size, first);
    if (fs->nfats > 1) {
	second = alloc(eff_size);
	fs_read(fs->fat_start + fs->fat_size, eff_size, second);
    }
    if (second && memcmp(first, second, eff_size) != 0) {
	FAT_ENTRY first_media, second_media;
	get_fat(&first_media, first, 0, fs);
	get_fat(&second_media, second, 0, fs);
	first_ok = (first_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
	second_ok = (second_media.value & FAT_EXTD(fs)) == FAT_EXTD(fs);
	if (first_ok && !second_ok) {
	    printf("FATs differ - using first FAT.\n");
	    fs_write(fs->fat_start + fs->fat_size, eff_size, first);
	}
	if (!first_ok && second_ok) {
	    printf("FATs differ - using second FAT.\n");
	    fs_write(fs->fat_start, eff_size, second);
	    memcpy(first, second, eff_size);
	}
	if (first_ok && second_ok) {
	    if (interactive) {
		printf("FATs differ but appear to be intact. Use which FAT ?\n"
		       "1) Use first FAT\n2) Use second FAT\n");
		if (get_key("12", "?") == '1') {
		    fs_write(fs->fat_start + fs->fat_size, eff_size, first);
		} else {
		    fs_write(fs->fat_start, eff_size, second);
		    memcpy(first, second, eff_size);
		}
	    } else {
		printf("FATs differ but appear to be intact. Using first "
		       "FAT.\n");
		fs_write(fs->fat_start + fs->fat_size, eff_size, first);
	    }
	}
	if (!first_ok && !second_ok) {
	    printf("Both FATs appear to be corrupt. Giving up.\n");
	    exit(1);
	}
    }
    if (second) {
	free(second);
    }
    fs->fat = (unsigned char *)first;

    fs->cluster_owner = alloc(total_num_clusters * sizeof(DOS_FILE *));
    memset(fs->cluster_owner, 0, (total_num_clusters * sizeof(DOS_FILE *)));

    /* Truncate any cluster chains that link to something out of range */
    for (i = 2; i < fs->clusters + 2; i++) {
	FAT_ENTRY curEntry;
	get_fat(&curEntry, fs->fat, i, fs);
	if (curEntry.value == 1) {
	    printf("Cluster %ld out of range (1). Setting to EOF.\n", i - 2);
	    set_fat(fs, i, -1);
	}
	if (curEntry.value >= fs->clusters + 2 &&
	    (curEntry.value < FAT_MIN_BAD(fs))) {
	    printf("Cluster %ld out of range (%ld > %ld). Setting to EOF.\n",
		   i - 2, curEntry.value, fs->clusters + 2 - 1);
	    set_fat(fs, i, -1);
	}
    }
}