Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
9
fs/udf/Makefile
Normal file
9
fs/udf/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# Makefile for the linux udf-filesystem routines.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_UDF_FS) += udf.o
|
||||
|
||||
udf-objs := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \
|
||||
partition.o super.o truncate.o symlink.o fsync.o \
|
||||
crc.o directory.o misc.o udftime.o unicode.o
|
||||
953
fs/udf/balloc.c
Normal file
953
fs/udf/balloc.c
Normal file
@@ -0,0 +1,953 @@
|
||||
/*
|
||||
* balloc.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Block allocation handling routines for the OSTA-UDF(tm) filesystem.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*
|
||||
* (C) 1999-2001 Ben Fennema
|
||||
* (C) 1999 Stelias Computing Inc
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
* 02/24/99 blf Created.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include "udf_i.h"
|
||||
#include "udf_sb.h"
|
||||
|
||||
#define udf_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
|
||||
#define udf_set_bit(nr,addr) ext2_set_bit(nr,addr)
|
||||
#define udf_test_bit(nr, addr) ext2_test_bit(nr, addr)
|
||||
#define udf_find_first_one_bit(addr, size) find_first_one_bit(addr, size)
|
||||
#define udf_find_next_one_bit(addr, size, offset) find_next_one_bit(addr, size, offset)
|
||||
|
||||
#define leBPL_to_cpup(x) leNUM_to_cpup(BITS_PER_LONG, x)
|
||||
#define leNUM_to_cpup(x,y) xleNUM_to_cpup(x,y)
|
||||
#define xleNUM_to_cpup(x,y) (le ## x ## _to_cpup(y))
|
||||
#define uintBPL_t uint(BITS_PER_LONG)
|
||||
#define uint(x) xuint(x)
|
||||
#define xuint(x) __le ## x
|
||||
|
||||
static inline int find_next_one_bit (void * addr, int size, int offset)
|
||||
{
|
||||
uintBPL_t * p = ((uintBPL_t *) addr) + (offset / BITS_PER_LONG);
|
||||
int result = offset & ~(BITS_PER_LONG-1);
|
||||
unsigned long tmp;
|
||||
|
||||
if (offset >= size)
|
||||
return size;
|
||||
size -= result;
|
||||
offset &= (BITS_PER_LONG-1);
|
||||
if (offset)
|
||||
{
|
||||
tmp = leBPL_to_cpup(p++);
|
||||
tmp &= ~0UL << offset;
|
||||
if (size < BITS_PER_LONG)
|
||||
goto found_first;
|
||||
if (tmp)
|
||||
goto found_middle;
|
||||
size -= BITS_PER_LONG;
|
||||
result += BITS_PER_LONG;
|
||||
}
|
||||
while (size & ~(BITS_PER_LONG-1))
|
||||
{
|
||||
if ((tmp = leBPL_to_cpup(p++)))
|
||||
goto found_middle;
|
||||
result += BITS_PER_LONG;
|
||||
size -= BITS_PER_LONG;
|
||||
}
|
||||
if (!size)
|
||||
return result;
|
||||
tmp = leBPL_to_cpup(p);
|
||||
found_first:
|
||||
tmp &= ~0UL >> (BITS_PER_LONG-size);
|
||||
found_middle:
|
||||
return result + ffz(~tmp);
|
||||
}
|
||||
|
||||
#define find_first_one_bit(addr, size)\
|
||||
find_next_one_bit((addr), (size), 0)
|
||||
|
||||
static int read_block_bitmap(struct super_block * sb,
|
||||
struct udf_bitmap *bitmap, unsigned int block, unsigned long bitmap_nr)
|
||||
{
|
||||
struct buffer_head *bh = NULL;
|
||||
int retval = 0;
|
||||
kernel_lb_addr loc;
|
||||
|
||||
loc.logicalBlockNum = bitmap->s_extPosition;
|
||||
loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
|
||||
|
||||
bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block));
|
||||
if (!bh)
|
||||
{
|
||||
retval = -EIO;
|
||||
}
|
||||
bitmap->s_block_bitmap[bitmap_nr] = bh;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int __load_block_bitmap(struct super_block * sb,
|
||||
struct udf_bitmap *bitmap, unsigned int block_group)
|
||||
{
|
||||
int retval = 0;
|
||||
int nr_groups = bitmap->s_nr_groups;
|
||||
|
||||
if (block_group >= nr_groups)
|
||||
{
|
||||
udf_debug("block_group (%d) > nr_groups (%d)\n", block_group, nr_groups);
|
||||
}
|
||||
|
||||
if (bitmap->s_block_bitmap[block_group])
|
||||
return block_group;
|
||||
else
|
||||
{
|
||||
retval = read_block_bitmap(sb, bitmap, block_group, block_group);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
return block_group;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int load_block_bitmap(struct super_block * sb,
|
||||
struct udf_bitmap *bitmap, unsigned int block_group)
|
||||
{
|
||||
int slot;
|
||||
|
||||
slot = __load_block_bitmap(sb, bitmap, block_group);
|
||||
|
||||
if (slot < 0)
|
||||
return slot;
|
||||
|
||||
if (!bitmap->s_block_bitmap[slot])
|
||||
return -EIO;
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
static void udf_bitmap_free_blocks(struct super_block * sb,
|
||||
struct inode * inode,
|
||||
struct udf_bitmap *bitmap,
|
||||
kernel_lb_addr bloc, uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
struct buffer_head * bh = NULL;
|
||||
unsigned long block;
|
||||
unsigned long block_group;
|
||||
unsigned long bit;
|
||||
unsigned long i;
|
||||
int bitmap_nr;
|
||||
unsigned long overflow;
|
||||
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
if (bloc.logicalBlockNum < 0 ||
|
||||
(bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
|
||||
{
|
||||
udf_debug("%d < %d || %d + %d > %d\n",
|
||||
bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
|
||||
UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
block = bloc.logicalBlockNum + offset + (sizeof(struct spaceBitmapDesc) << 3);
|
||||
|
||||
do_more:
|
||||
overflow = 0;
|
||||
block_group = block >> (sb->s_blocksize_bits + 3);
|
||||
bit = block % (sb->s_blocksize << 3);
|
||||
|
||||
/*
|
||||
* Check to see if we are freeing blocks across a group boundary.
|
||||
*/
|
||||
if (bit + count > (sb->s_blocksize << 3))
|
||||
{
|
||||
overflow = bit + count - (sb->s_blocksize << 3);
|
||||
count -= overflow;
|
||||
}
|
||||
bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
|
||||
if (bitmap_nr < 0)
|
||||
goto error_return;
|
||||
|
||||
bh = bitmap->s_block_bitmap[bitmap_nr];
|
||||
for (i=0; i < count; i++)
|
||||
{
|
||||
if (udf_set_bit(bit + i, bh->b_data))
|
||||
{
|
||||
udf_debug("bit %ld already set\n", bit + i);
|
||||
udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inode)
|
||||
DQUOT_FREE_BLOCK(inode, 1);
|
||||
if (UDF_SB_LVIDBH(sb))
|
||||
{
|
||||
UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
|
||||
cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
mark_buffer_dirty(bh);
|
||||
if (overflow)
|
||||
{
|
||||
block += count;
|
||||
count = overflow;
|
||||
goto do_more;
|
||||
}
|
||||
error_return:
|
||||
sb->s_dirt = 1;
|
||||
if (UDF_SB_LVIDBH(sb))
|
||||
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
static int udf_bitmap_prealloc_blocks(struct super_block * sb,
|
||||
struct inode * inode,
|
||||
struct udf_bitmap *bitmap, uint16_t partition, uint32_t first_block,
|
||||
uint32_t block_count)
|
||||
{
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
int alloc_count = 0;
|
||||
int bit, block, block_group, group_start;
|
||||
int nr_groups, bitmap_nr;
|
||||
struct buffer_head *bh;
|
||||
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
|
||||
goto out;
|
||||
|
||||
if (first_block + block_count > UDF_SB_PARTLEN(sb, partition))
|
||||
block_count = UDF_SB_PARTLEN(sb, partition) - first_block;
|
||||
|
||||
repeat:
|
||||
nr_groups = (UDF_SB_PARTLEN(sb, partition) +
|
||||
(sizeof(struct spaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
|
||||
block = first_block + (sizeof(struct spaceBitmapDesc) << 3);
|
||||
block_group = block >> (sb->s_blocksize_bits + 3);
|
||||
group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc);
|
||||
|
||||
bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
|
||||
if (bitmap_nr < 0)
|
||||
goto out;
|
||||
bh = bitmap->s_block_bitmap[bitmap_nr];
|
||||
|
||||
bit = block % (sb->s_blocksize << 3);
|
||||
|
||||
while (bit < (sb->s_blocksize << 3) && block_count > 0)
|
||||
{
|
||||
if (!udf_test_bit(bit, bh->b_data))
|
||||
goto out;
|
||||
else if (DQUOT_PREALLOC_BLOCK(inode, 1))
|
||||
goto out;
|
||||
else if (!udf_clear_bit(bit, bh->b_data))
|
||||
{
|
||||
udf_debug("bit already cleared for block %d\n", bit);
|
||||
DQUOT_FREE_BLOCK(inode, 1);
|
||||
goto out;
|
||||
}
|
||||
block_count --;
|
||||
alloc_count ++;
|
||||
bit ++;
|
||||
block ++;
|
||||
}
|
||||
mark_buffer_dirty(bh);
|
||||
if (block_count > 0)
|
||||
goto repeat;
|
||||
out:
|
||||
if (UDF_SB_LVIDBH(sb))
|
||||
{
|
||||
UDF_SB_LVID(sb)->freeSpaceTable[partition] =
|
||||
cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
|
||||
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
|
||||
}
|
||||
sb->s_dirt = 1;
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
return alloc_count;
|
||||
}
|
||||
|
||||
static int udf_bitmap_new_block(struct super_block * sb,
|
||||
struct inode * inode,
|
||||
struct udf_bitmap *bitmap, uint16_t partition, uint32_t goal, int *err)
|
||||
{
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
int newbit, bit=0, block, block_group, group_start;
|
||||
int end_goal, nr_groups, bitmap_nr, i;
|
||||
struct buffer_head *bh = NULL;
|
||||
char *ptr;
|
||||
int newblock = 0;
|
||||
|
||||
*err = -ENOSPC;
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
|
||||
repeat:
|
||||
if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition))
|
||||
goal = 0;
|
||||
|
||||
nr_groups = bitmap->s_nr_groups;
|
||||
block = goal + (sizeof(struct spaceBitmapDesc) << 3);
|
||||
block_group = block >> (sb->s_blocksize_bits + 3);
|
||||
group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc);
|
||||
|
||||
bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
|
||||
if (bitmap_nr < 0)
|
||||
goto error_return;
|
||||
bh = bitmap->s_block_bitmap[bitmap_nr];
|
||||
ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
|
||||
|
||||
if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
|
||||
{
|
||||
bit = block % (sb->s_blocksize << 3);
|
||||
|
||||
if (udf_test_bit(bit, bh->b_data))
|
||||
{
|
||||
goto got_block;
|
||||
}
|
||||
end_goal = (bit + 63) & ~63;
|
||||
bit = udf_find_next_one_bit(bh->b_data, end_goal, bit);
|
||||
if (bit < end_goal)
|
||||
goto got_block;
|
||||
ptr = memscan((char *)bh->b_data + (bit >> 3), 0xFF, sb->s_blocksize - ((bit + 7) >> 3));
|
||||
newbit = (ptr - ((char *)bh->b_data)) << 3;
|
||||
if (newbit < sb->s_blocksize << 3)
|
||||
{
|
||||
bit = newbit;
|
||||
goto search_back;
|
||||
}
|
||||
newbit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, bit);
|
||||
if (newbit < sb->s_blocksize << 3)
|
||||
{
|
||||
bit = newbit;
|
||||
goto got_block;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<(nr_groups*2); i++)
|
||||
{
|
||||
block_group ++;
|
||||
if (block_group >= nr_groups)
|
||||
block_group = 0;
|
||||
group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc);
|
||||
|
||||
bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
|
||||
if (bitmap_nr < 0)
|
||||
goto error_return;
|
||||
bh = bitmap->s_block_bitmap[bitmap_nr];
|
||||
if (i < nr_groups)
|
||||
{
|
||||
ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
|
||||
if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
|
||||
{
|
||||
bit = (ptr - ((char *)bh->b_data)) << 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = udf_find_next_one_bit((char *)bh->b_data, sb->s_blocksize << 3, group_start << 3);
|
||||
if (bit < sb->s_blocksize << 3)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= (nr_groups*2))
|
||||
{
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
return newblock;
|
||||
}
|
||||
if (bit < sb->s_blocksize << 3)
|
||||
goto search_back;
|
||||
else
|
||||
bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, group_start << 3);
|
||||
if (bit >= sb->s_blocksize << 3)
|
||||
{
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
search_back:
|
||||
for (i=0; i<7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--);
|
||||
|
||||
got_block:
|
||||
|
||||
/*
|
||||
* Check quota for allocation of this block.
|
||||
*/
|
||||
if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
|
||||
{
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
*err = -EDQUOT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
|
||||
(sizeof(struct spaceBitmapDesc) << 3);
|
||||
|
||||
if (!udf_clear_bit(bit, bh->b_data))
|
||||
{
|
||||
udf_debug("bit already cleared for block %d\n", bit);
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
mark_buffer_dirty(bh);
|
||||
|
||||
if (UDF_SB_LVIDBH(sb))
|
||||
{
|
||||
UDF_SB_LVID(sb)->freeSpaceTable[partition] =
|
||||
cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
|
||||
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
|
||||
}
|
||||
sb->s_dirt = 1;
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
*err = 0;
|
||||
return newblock;
|
||||
|
||||
error_return:
|
||||
*err = -EIO;
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void udf_table_free_blocks(struct super_block * sb,
|
||||
struct inode * inode,
|
||||
struct inode * table,
|
||||
kernel_lb_addr bloc, uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
uint32_t start, end;
|
||||
uint32_t nextoffset, oextoffset, elen;
|
||||
kernel_lb_addr nbloc, obloc, eloc;
|
||||
struct buffer_head *obh, *nbh;
|
||||
int8_t etype;
|
||||
int i;
|
||||
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
if (bloc.logicalBlockNum < 0 ||
|
||||
(bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
|
||||
{
|
||||
udf_debug("%d < %d || %d + %d > %d\n",
|
||||
bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
|
||||
UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/* We do this up front - There are some error conditions that could occure,
|
||||
but.. oh well */
|
||||
if (inode)
|
||||
DQUOT_FREE_BLOCK(inode, count);
|
||||
if (UDF_SB_LVIDBH(sb))
|
||||
{
|
||||
UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
|
||||
cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+count);
|
||||
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
|
||||
}
|
||||
|
||||
start = bloc.logicalBlockNum + offset;
|
||||
end = bloc.logicalBlockNum + offset + count - 1;
|
||||
|
||||
oextoffset = nextoffset = sizeof(struct unallocSpaceEntry);
|
||||
elen = 0;
|
||||
obloc = nbloc = UDF_I_LOCATION(table);
|
||||
|
||||
obh = nbh = NULL;
|
||||
|
||||
while (count && (etype =
|
||||
udf_next_aext(table, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
|
||||
{
|
||||
if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) ==
|
||||
start))
|
||||
{
|
||||
if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits))
|
||||
{
|
||||
count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
|
||||
start += ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
|
||||
elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
|
||||
}
|
||||
else
|
||||
{
|
||||
elen = (etype << 30) |
|
||||
(elen + (count << sb->s_blocksize_bits));
|
||||
start += count;
|
||||
count = 0;
|
||||
}
|
||||
udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1);
|
||||
}
|
||||
else if (eloc.logicalBlockNum == (end + 1))
|
||||
{
|
||||
if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits))
|
||||
{
|
||||
count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
|
||||
end -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
|
||||
eloc.logicalBlockNum -=
|
||||
((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
|
||||
elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
|
||||
}
|
||||
else
|
||||
{
|
||||
eloc.logicalBlockNum = start;
|
||||
elen = (etype << 30) |
|
||||
(elen + (count << sb->s_blocksize_bits));
|
||||
end -= count;
|
||||
count = 0;
|
||||
}
|
||||
udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1);
|
||||
}
|
||||
|
||||
if (nbh != obh)
|
||||
{
|
||||
i = -1;
|
||||
obloc = nbloc;
|
||||
udf_release_data(obh);
|
||||
atomic_inc(&nbh->b_count);
|
||||
obh = nbh;
|
||||
oextoffset = 0;
|
||||
}
|
||||
else
|
||||
oextoffset = nextoffset;
|
||||
}
|
||||
|
||||
if (count)
|
||||
{
|
||||
/* NOTE: we CANNOT use udf_add_aext here, as it can try to allocate
|
||||
a new block, and since we hold the super block lock already
|
||||
very bad things would happen :)
|
||||
|
||||
We copy the behavior of udf_add_aext, but instead of
|
||||
trying to allocate a new block close to the existing one,
|
||||
we just steal a block from the extent we are trying to add.
|
||||
|
||||
It would be nice if the blocks were close together, but it
|
||||
isn't required.
|
||||
*/
|
||||
|
||||
int adsize;
|
||||
short_ad *sad = NULL;
|
||||
long_ad *lad = NULL;
|
||||
struct allocExtDesc *aed;
|
||||
|
||||
eloc.logicalBlockNum = start;
|
||||
elen = EXT_RECORDED_ALLOCATED |
|
||||
(count << sb->s_blocksize_bits);
|
||||
|
||||
if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT)
|
||||
adsize = sizeof(short_ad);
|
||||
else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG)
|
||||
adsize = sizeof(long_ad);
|
||||
else
|
||||
{
|
||||
udf_release_data(obh);
|
||||
udf_release_data(nbh);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
if (nextoffset + (2 * adsize) > sb->s_blocksize)
|
||||
{
|
||||
char *sptr, *dptr;
|
||||
int loffset;
|
||||
|
||||
udf_release_data(obh);
|
||||
obh = nbh;
|
||||
obloc = nbloc;
|
||||
oextoffset = nextoffset;
|
||||
|
||||
/* Steal a block from the extent being free'd */
|
||||
nbloc.logicalBlockNum = eloc.logicalBlockNum;
|
||||
eloc.logicalBlockNum ++;
|
||||
elen -= sb->s_blocksize;
|
||||
|
||||
if (!(nbh = udf_tread(sb,
|
||||
udf_get_lb_pblock(sb, nbloc, 0))))
|
||||
{
|
||||
udf_release_data(obh);
|
||||
goto error_return;
|
||||
}
|
||||
aed = (struct allocExtDesc *)(nbh->b_data);
|
||||
aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
|
||||
if (nextoffset + adsize > sb->s_blocksize)
|
||||
{
|
||||
loffset = nextoffset;
|
||||
aed->lengthAllocDescs = cpu_to_le32(adsize);
|
||||
sptr = UDF_I_DATA(inode) + nextoffset -
|
||||
udf_file_entry_alloc_offset(inode) +
|
||||
UDF_I_LENEATTR(inode) - adsize;
|
||||
dptr = nbh->b_data + sizeof(struct allocExtDesc);
|
||||
memcpy(dptr, sptr, adsize);
|
||||
nextoffset = sizeof(struct allocExtDesc) + adsize;
|
||||
}
|
||||
else
|
||||
{
|
||||
loffset = nextoffset + adsize;
|
||||
aed->lengthAllocDescs = cpu_to_le32(0);
|
||||
sptr = (obh)->b_data + nextoffset;
|
||||
nextoffset = sizeof(struct allocExtDesc);
|
||||
|
||||
if (obh)
|
||||
{
|
||||
aed = (struct allocExtDesc *)(obh)->b_data;
|
||||
aed->lengthAllocDescs =
|
||||
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
UDF_I_LENALLOC(table) += adsize;
|
||||
mark_inode_dirty(table);
|
||||
}
|
||||
}
|
||||
if (UDF_SB_UDFREV(sb) >= 0x0200)
|
||||
udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
|
||||
nbloc.logicalBlockNum, sizeof(tag));
|
||||
else
|
||||
udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
|
||||
nbloc.logicalBlockNum, sizeof(tag));
|
||||
switch (UDF_I_ALLOCTYPE(table))
|
||||
{
|
||||
case ICBTAG_FLAG_AD_SHORT:
|
||||
{
|
||||
sad = (short_ad *)sptr;
|
||||
sad->extLength = cpu_to_le32(
|
||||
EXT_NEXT_EXTENT_ALLOCDECS |
|
||||
sb->s_blocksize);
|
||||
sad->extPosition = cpu_to_le32(nbloc.logicalBlockNum);
|
||||
break;
|
||||
}
|
||||
case ICBTAG_FLAG_AD_LONG:
|
||||
{
|
||||
lad = (long_ad *)sptr;
|
||||
lad->extLength = cpu_to_le32(
|
||||
EXT_NEXT_EXTENT_ALLOCDECS |
|
||||
sb->s_blocksize);
|
||||
lad->extLocation = cpu_to_lelb(nbloc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (obh)
|
||||
{
|
||||
udf_update_tag(obh->b_data, loffset);
|
||||
mark_buffer_dirty(obh);
|
||||
}
|
||||
else
|
||||
mark_inode_dirty(table);
|
||||
}
|
||||
|
||||
if (elen) /* It's possible that stealing the block emptied the extent */
|
||||
{
|
||||
udf_write_aext(table, nbloc, &nextoffset, eloc, elen, nbh, 1);
|
||||
|
||||
if (!nbh)
|
||||
{
|
||||
UDF_I_LENALLOC(table) += adsize;
|
||||
mark_inode_dirty(table);
|
||||
}
|
||||
else
|
||||
{
|
||||
aed = (struct allocExtDesc *)nbh->b_data;
|
||||
aed->lengthAllocDescs =
|
||||
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
|
||||
udf_update_tag(nbh->b_data, nextoffset);
|
||||
mark_buffer_dirty(nbh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
udf_release_data(nbh);
|
||||
udf_release_data(obh);
|
||||
|
||||
error_return:
|
||||
sb->s_dirt = 1;
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
static int udf_table_prealloc_blocks(struct super_block * sb,
|
||||
struct inode * inode,
|
||||
struct inode *table, uint16_t partition, uint32_t first_block,
|
||||
uint32_t block_count)
|
||||
{
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
int alloc_count = 0;
|
||||
uint32_t extoffset, elen, adsize;
|
||||
kernel_lb_addr bloc, eloc;
|
||||
struct buffer_head *bh;
|
||||
int8_t etype = -1;
|
||||
|
||||
if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
|
||||
return 0;
|
||||
|
||||
if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT)
|
||||
adsize = sizeof(short_ad);
|
||||
else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG)
|
||||
adsize = sizeof(long_ad);
|
||||
else
|
||||
return 0;
|
||||
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
extoffset = sizeof(struct unallocSpaceEntry);
|
||||
bloc = UDF_I_LOCATION(table);
|
||||
|
||||
bh = NULL;
|
||||
eloc.logicalBlockNum = 0xFFFFFFFF;
|
||||
|
||||
while (first_block != eloc.logicalBlockNum && (etype =
|
||||
udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
|
||||
{
|
||||
udf_debug("eloc=%d, elen=%d, first_block=%d\n",
|
||||
eloc.logicalBlockNum, elen, first_block);
|
||||
; /* empty loop body */
|
||||
}
|
||||
|
||||
if (first_block == eloc.logicalBlockNum)
|
||||
{
|
||||
extoffset -= adsize;
|
||||
|
||||
alloc_count = (elen >> sb->s_blocksize_bits);
|
||||
if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count))
|
||||
alloc_count = 0;
|
||||
else if (alloc_count > block_count)
|
||||
{
|
||||
alloc_count = block_count;
|
||||
eloc.logicalBlockNum += alloc_count;
|
||||
elen -= (alloc_count << sb->s_blocksize_bits);
|
||||
udf_write_aext(table, bloc, &extoffset, eloc, (etype << 30) | elen, bh, 1);
|
||||
}
|
||||
else
|
||||
udf_delete_aext(table, bloc, extoffset, eloc, (etype << 30) | elen, bh);
|
||||
}
|
||||
else
|
||||
alloc_count = 0;
|
||||
|
||||
udf_release_data(bh);
|
||||
|
||||
if (alloc_count && UDF_SB_LVIDBH(sb))
|
||||
{
|
||||
UDF_SB_LVID(sb)->freeSpaceTable[partition] =
|
||||
cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
|
||||
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
|
||||
sb->s_dirt = 1;
|
||||
}
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
return alloc_count;
|
||||
}
|
||||
|
||||
static int udf_table_new_block(struct super_block * sb,
|
||||
struct inode * inode,
|
||||
struct inode *table, uint16_t partition, uint32_t goal, int *err)
|
||||
{
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF;
|
||||
uint32_t newblock = 0, adsize;
|
||||
uint32_t extoffset, goal_extoffset, elen, goal_elen = 0;
|
||||
kernel_lb_addr bloc, goal_bloc, eloc, goal_eloc;
|
||||
struct buffer_head *bh, *goal_bh;
|
||||
int8_t etype;
|
||||
|
||||
*err = -ENOSPC;
|
||||
|
||||
if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT)
|
||||
adsize = sizeof(short_ad);
|
||||
else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG)
|
||||
adsize = sizeof(long_ad);
|
||||
else
|
||||
return newblock;
|
||||
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition))
|
||||
goal = 0;
|
||||
|
||||
/* We search for the closest matching block to goal. If we find a exact hit,
|
||||
we stop. Otherwise we keep going till we run out of extents.
|
||||
We store the buffer_head, bloc, and extoffset of the current closest
|
||||
match and use that when we are done.
|
||||
*/
|
||||
|
||||
extoffset = sizeof(struct unallocSpaceEntry);
|
||||
bloc = UDF_I_LOCATION(table);
|
||||
|
||||
goal_bh = bh = NULL;
|
||||
|
||||
while (spread && (etype =
|
||||
udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
|
||||
{
|
||||
if (goal >= eloc.logicalBlockNum)
|
||||
{
|
||||
if (goal < eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits))
|
||||
nspread = 0;
|
||||
else
|
||||
nspread = goal - eloc.logicalBlockNum -
|
||||
(elen >> sb->s_blocksize_bits);
|
||||
}
|
||||
else
|
||||
nspread = eloc.logicalBlockNum - goal;
|
||||
|
||||
if (nspread < spread)
|
||||
{
|
||||
spread = nspread;
|
||||
if (goal_bh != bh)
|
||||
{
|
||||
udf_release_data(goal_bh);
|
||||
goal_bh = bh;
|
||||
atomic_inc(&goal_bh->b_count);
|
||||
}
|
||||
goal_bloc = bloc;
|
||||
goal_extoffset = extoffset - adsize;
|
||||
goal_eloc = eloc;
|
||||
goal_elen = (etype << 30) | elen;
|
||||
}
|
||||
}
|
||||
|
||||
udf_release_data(bh);
|
||||
|
||||
if (spread == 0xFFFFFFFF)
|
||||
{
|
||||
udf_release_data(goal_bh);
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Only allocate blocks from the beginning of the extent.
|
||||
That way, we only delete (empty) extents, never have to insert an
|
||||
extent because of splitting */
|
||||
/* This works, but very poorly.... */
|
||||
|
||||
newblock = goal_eloc.logicalBlockNum;
|
||||
goal_eloc.logicalBlockNum ++;
|
||||
goal_elen -= sb->s_blocksize;
|
||||
|
||||
if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
|
||||
{
|
||||
udf_release_data(goal_bh);
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
*err = -EDQUOT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (goal_elen)
|
||||
udf_write_aext(table, goal_bloc, &goal_extoffset, goal_eloc, goal_elen, goal_bh, 1);
|
||||
else
|
||||
udf_delete_aext(table, goal_bloc, goal_extoffset, goal_eloc, goal_elen, goal_bh);
|
||||
udf_release_data(goal_bh);
|
||||
|
||||
if (UDF_SB_LVIDBH(sb))
|
||||
{
|
||||
UDF_SB_LVID(sb)->freeSpaceTable[partition] =
|
||||
cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
|
||||
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
|
||||
}
|
||||
|
||||
sb->s_dirt = 1;
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
*err = 0;
|
||||
return newblock;
|
||||
}
|
||||
|
||||
inline void udf_free_blocks(struct super_block * sb,
|
||||
struct inode * inode,
|
||||
kernel_lb_addr bloc, uint32_t offset, uint32_t count)
|
||||
{
|
||||
uint16_t partition = bloc.partitionReferenceNum;
|
||||
|
||||
if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
|
||||
{
|
||||
return udf_bitmap_free_blocks(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
|
||||
bloc, offset, count);
|
||||
}
|
||||
else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
|
||||
{
|
||||
return udf_table_free_blocks(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
|
||||
bloc, offset, count);
|
||||
}
|
||||
else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
|
||||
{
|
||||
return udf_bitmap_free_blocks(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
|
||||
bloc, offset, count);
|
||||
}
|
||||
else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
|
||||
{
|
||||
return udf_table_free_blocks(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
|
||||
bloc, offset, count);
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
inline int udf_prealloc_blocks(struct super_block * sb,
|
||||
struct inode * inode,
|
||||
uint16_t partition, uint32_t first_block, uint32_t block_count)
|
||||
{
|
||||
if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
|
||||
{
|
||||
return udf_bitmap_prealloc_blocks(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
|
||||
partition, first_block, block_count);
|
||||
}
|
||||
else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
|
||||
{
|
||||
return udf_table_prealloc_blocks(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
|
||||
partition, first_block, block_count);
|
||||
}
|
||||
else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
|
||||
{
|
||||
return udf_bitmap_prealloc_blocks(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
|
||||
partition, first_block, block_count);
|
||||
}
|
||||
else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
|
||||
{
|
||||
return udf_table_prealloc_blocks(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
|
||||
partition, first_block, block_count);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int udf_new_block(struct super_block * sb,
|
||||
struct inode * inode,
|
||||
uint16_t partition, uint32_t goal, int *err)
|
||||
{
|
||||
if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
|
||||
{
|
||||
return udf_bitmap_new_block(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
|
||||
partition, goal, err);
|
||||
}
|
||||
else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
|
||||
{
|
||||
return udf_table_new_block(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
|
||||
partition, goal, err);
|
||||
}
|
||||
else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
|
||||
{
|
||||
return udf_bitmap_new_block(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
|
||||
partition, goal, err);
|
||||
}
|
||||
else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
|
||||
{
|
||||
return udf_table_new_block(sb, inode,
|
||||
UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
|
||||
partition, goal, err);
|
||||
}
|
||||
else
|
||||
{
|
||||
*err = -EIO;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
173
fs/udf/crc.c
Normal file
173
fs/udf/crc.c
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* crc.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Routines to generate, calculate, and test a 16-bit CRC.
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories
|
||||
* and Ned W. Rhodes of Software Systems Group. It has been published in
|
||||
* "Design and Validation of Computer Protocols", Prentice Hall,
|
||||
* Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4.
|
||||
*
|
||||
* Copyright is held by AT&T.
|
||||
*
|
||||
* AT&T gives permission for the free use of the CRC source code.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
|
||||
static uint16_t crc_table[256] = {
|
||||
0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U,
|
||||
0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU,
|
||||
0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U,
|
||||
0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU,
|
||||
0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U,
|
||||
0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU,
|
||||
0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U,
|
||||
0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU,
|
||||
0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U,
|
||||
0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU,
|
||||
0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U,
|
||||
0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU,
|
||||
0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U,
|
||||
0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U,
|
||||
0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U,
|
||||
0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U,
|
||||
0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU,
|
||||
0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U,
|
||||
0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU,
|
||||
0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U,
|
||||
0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU,
|
||||
0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U,
|
||||
0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU,
|
||||
0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U,
|
||||
0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU,
|
||||
0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U,
|
||||
0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU,
|
||||
0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U,
|
||||
0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U,
|
||||
0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U,
|
||||
0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U,
|
||||
0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U
|
||||
};
|
||||
|
||||
/*
|
||||
* udf_crc
|
||||
*
|
||||
* PURPOSE
|
||||
* Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial.
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
|
||||
* The polynomial used is: x^16 + x^12 + x^15 + 1
|
||||
*
|
||||
* PRE-CONDITIONS
|
||||
* data Pointer to the data block.
|
||||
* size Size of the data block.
|
||||
*
|
||||
* POST-CONDITIONS
|
||||
* <return> CRC of the data block.
|
||||
*
|
||||
* HISTORY
|
||||
* July 21, 1997 - Andrew E. Mileski
|
||||
* Adapted from OSTA-UDF(tm) 1.50 standard.
|
||||
*/
|
||||
uint16_t
|
||||
udf_crc(uint8_t *data, uint32_t size, uint16_t crc)
|
||||
{
|
||||
while (size--)
|
||||
crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
#if defined(TEST)
|
||||
|
||||
/*
|
||||
* PURPOSE
|
||||
* Test udf_crc()
|
||||
*
|
||||
* HISTORY
|
||||
* July 21, 1997 - Andrew E. Mileski
|
||||
* Adapted from OSTA-UDF(tm) 1.50 standard.
|
||||
*/
|
||||
|
||||
unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U };
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned short x;
|
||||
|
||||
x = udf_crc16(bytes, sizeof bytes);
|
||||
printf("udf_crc16: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* defined(TEST) */
|
||||
|
||||
/****************************************************************************/
|
||||
#if defined(GENERATE)
|
||||
|
||||
/*
|
||||
* PURPOSE
|
||||
* Generate a table for fast 16-bit CRC calculations (any polynomial).
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The ITU-T V.41 polynomial is 010041.
|
||||
*
|
||||
* HISTORY
|
||||
* July 21, 1997 - Andrew E. Mileski
|
||||
* Adapted from OSTA-UDF(tm) 1.50 standard.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned long crc, poly;
|
||||
int n, i;
|
||||
|
||||
/* Get the polynomial */
|
||||
sscanf(argv[1], "%lo", &poly);
|
||||
if (poly & 0xffff0000U){
|
||||
fprintf(stderr, "polynomial is too large\en");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("/* CRC 0%o */\n", poly);
|
||||
|
||||
/* Create a table */
|
||||
printf("static unsigned short crc_table[256] = {\n");
|
||||
for (n = 0; n < 256; n++){
|
||||
if (n % 8 == 0)
|
||||
printf("\t");
|
||||
crc = n << 8;
|
||||
for (i = 0; i < 8; i++){
|
||||
if(crc & 0x8000U)
|
||||
crc = (crc << 1) ^ poly;
|
||||
else
|
||||
crc <<= 1;
|
||||
crc &= 0xFFFFU;
|
||||
}
|
||||
if (n == 255)
|
||||
printf("0x%04xU ", crc);
|
||||
else
|
||||
printf("0x%04xU, ", crc);
|
||||
if(n % 8 == 7)
|
||||
printf("\n");
|
||||
}
|
||||
printf("};\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* defined(GENERATE) */
|
||||
263
fs/udf/dir.c
Normal file
263
fs/udf/dir.c
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* dir.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Directory handling routines for the OSTA-UDF(tm) filesystem.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*
|
||||
* (C) 1998-2004 Ben Fennema
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
* 10/05/98 dgb Split directory operations into its own file
|
||||
* Implemented directory reads via do_udf_readdir
|
||||
* 10/06/98 Made directory operations work!
|
||||
* 11/17/98 Rewrote directory to support ICBTAG_FLAG_AD_LONG
|
||||
* 11/25/98 blf Rewrote directory handling (readdir+lookup) to support reading
|
||||
* across blocks.
|
||||
* 12/12/98 Split out the lookup code to namei.c. bulk of directory
|
||||
* code now in directory.c:udf_fileident_read.
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
#include "udf_i.h"
|
||||
#include "udf_sb.h"
|
||||
|
||||
/* Prototypes for file operations */
|
||||
static int udf_readdir(struct file *, void *, filldir_t);
|
||||
static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *);
|
||||
|
||||
/* readdir and lookup functions */
|
||||
|
||||
const struct file_operations udf_dir_operations = {
|
||||
.read = generic_read_dir,
|
||||
.readdir = udf_readdir,
|
||||
.ioctl = udf_ioctl,
|
||||
.fsync = udf_fsync_file,
|
||||
};
|
||||
|
||||
/*
|
||||
* udf_readdir
|
||||
*
|
||||
* PURPOSE
|
||||
* Read a directory entry.
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Optional - sys_getdents() will return -ENOTDIR if this routine is not
|
||||
* available.
|
||||
*
|
||||
* Refer to sys_getdents() in fs/readdir.c
|
||||
* sys_getdents() -> .
|
||||
*
|
||||
* PRE-CONDITIONS
|
||||
* filp Pointer to directory file.
|
||||
* buf Pointer to directory entry buffer.
|
||||
* filldir Pointer to filldir function.
|
||||
*
|
||||
* POST-CONDITIONS
|
||||
* <return> >=0 on success.
|
||||
*
|
||||
* HISTORY
|
||||
* July 1, 1997 - Andrew E. Mileski
|
||||
* Written, tested, and released.
|
||||
*/
|
||||
|
||||
int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||
{
|
||||
struct inode *dir = filp->f_path.dentry->d_inode;
|
||||
int result;
|
||||
|
||||
lock_kernel();
|
||||
|
||||
if ( filp->f_pos == 0 )
|
||||
{
|
||||
if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0)
|
||||
{
|
||||
unlock_kernel();
|
||||
return 0;
|
||||
}
|
||||
filp->f_pos ++;
|
||||
}
|
||||
|
||||
result = do_udf_readdir(dir, filp, filldir, dirent);
|
||||
unlock_kernel();
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *dirent)
|
||||
{
|
||||
struct udf_fileident_bh fibh;
|
||||
struct fileIdentDesc *fi=NULL;
|
||||
struct fileIdentDesc cfi;
|
||||
int block, iblock;
|
||||
loff_t nf_pos = filp->f_pos - 1;
|
||||
int flen;
|
||||
char fname[UDF_NAME_LEN];
|
||||
char *nameptr;
|
||||
uint16_t liu;
|
||||
uint8_t lfi;
|
||||
loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
|
||||
struct buffer_head * bh = NULL, * tmp, * bha[16];
|
||||
kernel_lb_addr bloc, eloc;
|
||||
uint32_t extoffset, elen, offset;
|
||||
int i, num;
|
||||
unsigned int dt_type;
|
||||
|
||||
if (nf_pos >= size)
|
||||
return 0;
|
||||
|
||||
if (nf_pos == 0)
|
||||
nf_pos = (udf_ext0_offset(dir) >> 2);
|
||||
|
||||
fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
|
||||
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
|
||||
fibh.sbh = fibh.ebh = NULL;
|
||||
else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
|
||||
&bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
|
||||
{
|
||||
offset >>= dir->i_sb->s_blocksize_bits;
|
||||
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
|
||||
if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
|
||||
{
|
||||
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
|
||||
extoffset -= sizeof(short_ad);
|
||||
else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
|
||||
extoffset -= sizeof(long_ad);
|
||||
}
|
||||
else
|
||||
offset = 0;
|
||||
|
||||
if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
|
||||
{
|
||||
udf_release_data(bh);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
|
||||
{
|
||||
i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
|
||||
if (i+offset > (elen >> dir->i_sb->s_blocksize_bits))
|
||||
i = (elen >> dir->i_sb->s_blocksize_bits)-offset;
|
||||
for (num=0; i>0; i--)
|
||||
{
|
||||
block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i);
|
||||
tmp = udf_tgetblk(dir->i_sb, block);
|
||||
if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
|
||||
bha[num++] = tmp;
|
||||
else
|
||||
brelse(tmp);
|
||||
}
|
||||
if (num)
|
||||
{
|
||||
ll_rw_block(READA, num, bha);
|
||||
for (i=0; i<num; i++)
|
||||
brelse(bha[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
udf_release_data(bh);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
while ( nf_pos < size )
|
||||
{
|
||||
filp->f_pos = nf_pos + 1;
|
||||
|
||||
fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
|
||||
|
||||
if (!fi)
|
||||
{
|
||||
if (fibh.sbh != fibh.ebh)
|
||||
udf_release_data(fibh.ebh);
|
||||
udf_release_data(fibh.sbh);
|
||||
udf_release_data(bh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
liu = le16_to_cpu(cfi.lengthOfImpUse);
|
||||
lfi = cfi.lengthFileIdent;
|
||||
|
||||
if (fibh.sbh == fibh.ebh)
|
||||
nameptr = fi->fileIdent + liu;
|
||||
else
|
||||
{
|
||||
int poffset; /* Unpaded ending offset */
|
||||
|
||||
poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi;
|
||||
|
||||
if (poffset >= lfi)
|
||||
nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
|
||||
else
|
||||
{
|
||||
nameptr = fname;
|
||||
memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
|
||||
memcpy(nameptr + lfi - poffset, fibh.ebh->b_data, poffset);
|
||||
}
|
||||
}
|
||||
|
||||
if ( (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
|
||||
{
|
||||
if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) )
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( (cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 )
|
||||
{
|
||||
if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) )
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( cfi.fileCharacteristics & FID_FILE_CHAR_PARENT )
|
||||
{
|
||||
iblock = parent_ino(filp->f_path.dentry);
|
||||
flen = 2;
|
||||
memcpy(fname, "..", flen);
|
||||
dt_type = DT_DIR;
|
||||
}
|
||||
else
|
||||
{
|
||||
kernel_lb_addr tloc = lelb_to_cpu(cfi.icb.extLocation);
|
||||
|
||||
iblock = udf_get_lb_pblock(dir->i_sb, tloc, 0);
|
||||
flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
|
||||
dt_type = DT_UNKNOWN;
|
||||
}
|
||||
|
||||
if (flen)
|
||||
{
|
||||
if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0)
|
||||
{
|
||||
if (fibh.sbh != fibh.ebh)
|
||||
udf_release_data(fibh.ebh);
|
||||
udf_release_data(fibh.sbh);
|
||||
udf_release_data(bh);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
filp->f_pos = nf_pos + 1;
|
||||
|
||||
if (fibh.sbh != fibh.ebh)
|
||||
udf_release_data(fibh.ebh);
|
||||
udf_release_data(fibh.sbh);
|
||||
udf_release_data(bh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
338
fs/udf/directory.c
Normal file
338
fs/udf/directory.c
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
* directory.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Directory related functions
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
#include "udf_i.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
#if 0
|
||||
static uint8_t *
|
||||
udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
|
||||
kernel_lb_addr fe_loc, int *pos, int *offset,
|
||||
struct buffer_head **bh, int *error)
|
||||
{
|
||||
int loffset = *offset;
|
||||
int block;
|
||||
uint8_t *ad;
|
||||
int remainder;
|
||||
|
||||
*error = 0;
|
||||
|
||||
ad = (uint8_t *)(*bh)->b_data + *offset;
|
||||
*offset += ad_size;
|
||||
|
||||
if (!ad)
|
||||
{
|
||||
udf_release_data(*bh);
|
||||
*error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (*offset == dir->i_sb->s_blocksize)
|
||||
{
|
||||
udf_release_data(*bh);
|
||||
block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
|
||||
if (!block)
|
||||
return NULL;
|
||||
if (!(*bh = udf_tread(dir->i_sb, block)))
|
||||
return NULL;
|
||||
}
|
||||
else if (*offset > dir->i_sb->s_blocksize)
|
||||
{
|
||||
ad = tmpad;
|
||||
|
||||
remainder = dir->i_sb->s_blocksize - loffset;
|
||||
memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder);
|
||||
|
||||
udf_release_data(*bh);
|
||||
block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
|
||||
if (!block)
|
||||
return NULL;
|
||||
if (!((*bh) = udf_tread(dir->i_sb, block)))
|
||||
return NULL;
|
||||
|
||||
memcpy((uint8_t *)ad + remainder, (*bh)->b_data, ad_size - remainder);
|
||||
*offset = ad_size - remainder;
|
||||
}
|
||||
return ad;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct fileIdentDesc *
|
||||
udf_fileident_read(struct inode *dir, loff_t *nf_pos,
|
||||
struct udf_fileident_bh *fibh,
|
||||
struct fileIdentDesc *cfi,
|
||||
kernel_lb_addr *bloc, uint32_t *extoffset,
|
||||
kernel_lb_addr *eloc, uint32_t *elen,
|
||||
uint32_t *offset, struct buffer_head **bh)
|
||||
{
|
||||
struct fileIdentDesc *fi;
|
||||
int i, num, block;
|
||||
struct buffer_head * tmp, * bha[16];
|
||||
|
||||
fibh->soffset = fibh->eoffset;
|
||||
|
||||
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
|
||||
{
|
||||
fi = udf_get_fileident(UDF_I_DATA(dir) -
|
||||
(UDF_I_EFE(dir) ?
|
||||
sizeof(struct extendedFileEntry) :
|
||||
sizeof(struct fileEntry)),
|
||||
dir->i_sb->s_blocksize, &(fibh->eoffset));
|
||||
|
||||
if (!fi)
|
||||
return NULL;
|
||||
|
||||
*nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
|
||||
|
||||
memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
|
||||
|
||||
return fi;
|
||||
}
|
||||
|
||||
if (fibh->eoffset == dir->i_sb->s_blocksize)
|
||||
{
|
||||
int lextoffset = *extoffset;
|
||||
|
||||
if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) !=
|
||||
(EXT_RECORDED_ALLOCATED >> 30))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
|
||||
|
||||
(*offset) ++;
|
||||
|
||||
if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
|
||||
*offset = 0;
|
||||
else
|
||||
*extoffset = lextoffset;
|
||||
|
||||
udf_release_data(fibh->sbh);
|
||||
if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
|
||||
return NULL;
|
||||
fibh->soffset = fibh->eoffset = 0;
|
||||
|
||||
if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
|
||||
{
|
||||
i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
|
||||
if (i+*offset > (*elen >> dir->i_sb->s_blocksize_bits))
|
||||
i = (*elen >> dir->i_sb->s_blocksize_bits)-*offset;
|
||||
for (num=0; i>0; i--)
|
||||
{
|
||||
block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset+i);
|
||||
tmp = udf_tgetblk(dir->i_sb, block);
|
||||
if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
|
||||
bha[num++] = tmp;
|
||||
else
|
||||
brelse(tmp);
|
||||
}
|
||||
if (num)
|
||||
{
|
||||
ll_rw_block(READA, num, bha);
|
||||
for (i=0; i<num; i++)
|
||||
brelse(bha[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fibh->sbh != fibh->ebh)
|
||||
{
|
||||
udf_release_data(fibh->sbh);
|
||||
fibh->sbh = fibh->ebh;
|
||||
}
|
||||
|
||||
fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
|
||||
&(fibh->eoffset));
|
||||
|
||||
if (!fi)
|
||||
return NULL;
|
||||
|
||||
*nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
|
||||
|
||||
if (fibh->eoffset <= dir->i_sb->s_blocksize)
|
||||
{
|
||||
memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
|
||||
}
|
||||
else if (fibh->eoffset > dir->i_sb->s_blocksize)
|
||||
{
|
||||
int lextoffset = *extoffset;
|
||||
|
||||
if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) !=
|
||||
(EXT_RECORDED_ALLOCATED >> 30))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
|
||||
|
||||
(*offset) ++;
|
||||
|
||||
if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
|
||||
*offset = 0;
|
||||
else
|
||||
*extoffset = lextoffset;
|
||||
|
||||
fibh->soffset -= dir->i_sb->s_blocksize;
|
||||
fibh->eoffset -= dir->i_sb->s_blocksize;
|
||||
|
||||
if (!(fibh->ebh = udf_tread(dir->i_sb, block)))
|
||||
return NULL;
|
||||
|
||||
if (sizeof(struct fileIdentDesc) > - fibh->soffset)
|
||||
{
|
||||
int fi_len;
|
||||
|
||||
memcpy((uint8_t *)cfi, (uint8_t *)fi, - fibh->soffset);
|
||||
memcpy((uint8_t *)cfi - fibh->soffset, fibh->ebh->b_data,
|
||||
sizeof(struct fileIdentDesc) + fibh->soffset);
|
||||
|
||||
fi_len = (sizeof(struct fileIdentDesc) + cfi->lengthFileIdent +
|
||||
le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
|
||||
|
||||
*nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2);
|
||||
fibh->eoffset = fibh->soffset + fi_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
|
||||
}
|
||||
}
|
||||
return fi;
|
||||
}
|
||||
|
||||
struct fileIdentDesc *
|
||||
udf_get_fileident(void * buffer, int bufsize, int * offset)
|
||||
{
|
||||
struct fileIdentDesc *fi;
|
||||
int lengthThisIdent;
|
||||
uint8_t * ptr;
|
||||
int padlen;
|
||||
|
||||
if ( (!buffer) || (!offset) ) {
|
||||
udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = buffer;
|
||||
|
||||
if ( (*offset > 0) && (*offset < bufsize) ) {
|
||||
ptr += *offset;
|
||||
}
|
||||
fi=(struct fileIdentDesc *)ptr;
|
||||
if (le16_to_cpu(fi->descTag.tagIdent) != TAG_IDENT_FID)
|
||||
{
|
||||
udf_debug("0x%x != TAG_IDENT_FID\n",
|
||||
le16_to_cpu(fi->descTag.tagIdent));
|
||||
udf_debug("offset: %u sizeof: %lu bufsize: %u\n",
|
||||
*offset, (unsigned long)sizeof(struct fileIdentDesc), bufsize);
|
||||
return NULL;
|
||||
}
|
||||
if ( (*offset + sizeof(struct fileIdentDesc)) > bufsize )
|
||||
{
|
||||
lengthThisIdent = sizeof(struct fileIdentDesc);
|
||||
}
|
||||
else
|
||||
lengthThisIdent = sizeof(struct fileIdentDesc) +
|
||||
fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
|
||||
|
||||
/* we need to figure padding, too! */
|
||||
padlen = lengthThisIdent % UDF_NAME_PAD;
|
||||
if (padlen)
|
||||
lengthThisIdent += (UDF_NAME_PAD - padlen);
|
||||
*offset = *offset + lengthThisIdent;
|
||||
|
||||
return fi;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static extent_ad *
|
||||
udf_get_fileextent(void * buffer, int bufsize, int * offset)
|
||||
{
|
||||
extent_ad * ext;
|
||||
struct fileEntry *fe;
|
||||
uint8_t * ptr;
|
||||
|
||||
if ( (!buffer) || (!offset) )
|
||||
{
|
||||
printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fe = (struct fileEntry *)buffer;
|
||||
|
||||
if ( le16_to_cpu(fe->descTag.tagIdent) != TAG_IDENT_FE )
|
||||
{
|
||||
udf_debug("0x%x != TAG_IDENT_FE\n",
|
||||
le16_to_cpu(fe->descTag.tagIdent));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr=(uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr);
|
||||
|
||||
if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) )
|
||||
{
|
||||
ptr += *offset;
|
||||
}
|
||||
|
||||
ext = (extent_ad *)ptr;
|
||||
|
||||
*offset = *offset + sizeof(extent_ad);
|
||||
return ext;
|
||||
}
|
||||
#endif
|
||||
|
||||
short_ad *
|
||||
udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc)
|
||||
{
|
||||
short_ad *sa;
|
||||
|
||||
if ( (!ptr) || (!offset) )
|
||||
{
|
||||
printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset) )
|
||||
return NULL;
|
||||
else if ((sa = (short_ad *)ptr)->extLength == 0)
|
||||
return NULL;
|
||||
|
||||
if (inc)
|
||||
*offset += sizeof(short_ad);
|
||||
return sa;
|
||||
}
|
||||
|
||||
long_ad *
|
||||
udf_get_filelongad(uint8_t *ptr, int maxoffset, int * offset, int inc)
|
||||
{
|
||||
long_ad *la;
|
||||
|
||||
if ( (!ptr) || (!offset) )
|
||||
{
|
||||
printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( (*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset) )
|
||||
return NULL;
|
||||
else if ((la = (long_ad *)ptr)->extLength == 0)
|
||||
return NULL;
|
||||
|
||||
if (inc)
|
||||
*offset += sizeof(long_ad);
|
||||
return la;
|
||||
}
|
||||
864
fs/udf/ecma_167.h
Normal file
864
fs/udf/ecma_167.h
Normal file
@@ -0,0 +1,864 @@
|
||||
/*
|
||||
* ecma_167.h
|
||||
*
|
||||
* This file is based on ECMA-167 3rd edition (June 1997)
|
||||
* http://www.ecma.ch
|
||||
*
|
||||
* Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifndef _ECMA_167_H
|
||||
#define _ECMA_167_H 1
|
||||
|
||||
/* Character set specification (ECMA 167r3 1/7.2.1) */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t charSetType;
|
||||
uint8_t charSetInfo[63];
|
||||
} __attribute__ ((packed)) charspec;
|
||||
|
||||
/* Character Set Type (ECMA 167r3 1/7.2.1.1) */
|
||||
#define CHARSPEC_TYPE_CS0 0x00 /* (1/7.2.2) */
|
||||
#define CHARSPEC_TYPE_CS1 0x01 /* (1/7.2.3) */
|
||||
#define CHARSPEC_TYPE_CS2 0x02 /* (1/7.2.4) */
|
||||
#define CHARSPEC_TYPE_CS3 0x03 /* (1/7.2.5) */
|
||||
#define CHARSPEC_TYPE_CS4 0x04 /* (1/7.2.6) */
|
||||
#define CHARSPEC_TYPE_CS5 0x05 /* (1/7.2.7) */
|
||||
#define CHARSPEC_TYPE_CS6 0x06 /* (1/7.2.8) */
|
||||
#define CHARSPEC_TYPE_CS7 0x07 /* (1/7.2.9) */
|
||||
#define CHARSPEC_TYPE_CS8 0x08 /* (1/7.2.10) */
|
||||
|
||||
typedef uint8_t dstring;
|
||||
|
||||
/* Timestamp (ECMA 167r3 1/7.3) */
|
||||
typedef struct
|
||||
{
|
||||
__le16 typeAndTimezone;
|
||||
__le16 year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t centiseconds;
|
||||
uint8_t hundredsOfMicroseconds;
|
||||
uint8_t microseconds;
|
||||
} __attribute__ ((packed)) timestamp;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t typeAndTimezone;
|
||||
int16_t year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t centiseconds;
|
||||
uint8_t hundredsOfMicroseconds;
|
||||
uint8_t microseconds;
|
||||
} __attribute__ ((packed)) kernel_timestamp;
|
||||
|
||||
/* Type and Time Zone (ECMA 167r3 1/7.3.1) */
|
||||
#define TIMESTAMP_TYPE_MASK 0xF000
|
||||
#define TIMESTAMP_TYPE_CUT 0x0000
|
||||
#define TIMESTAMP_TYPE_LOCAL 0x1000
|
||||
#define TIMESTAMP_TYPE_AGREEMENT 0x2000
|
||||
#define TIMESTAMP_TIMEZONE_MASK 0x0FFF
|
||||
|
||||
/* Entity identifier (ECMA 167r3 1/7.4) */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t flags;
|
||||
uint8_t ident[23];
|
||||
uint8_t identSuffix[8];
|
||||
} __attribute__ ((packed)) regid;
|
||||
|
||||
/* Flags (ECMA 167r3 1/7.4.1) */
|
||||
#define ENTITYID_FLAGS_DIRTY 0x00
|
||||
#define ENTITYID_FLAGS_PROTECTED 0x01
|
||||
|
||||
/* Volume Structure Descriptor (ECMA 167r3 2/9.1) */
|
||||
#define VSD_STD_ID_LEN 5
|
||||
struct volStructDesc
|
||||
{
|
||||
uint8_t structType;
|
||||
uint8_t stdIdent[VSD_STD_ID_LEN];
|
||||
uint8_t structVersion;
|
||||
uint8_t structData[2041];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Standard Identifier (EMCA 167r2 2/9.1.2) */
|
||||
#define VSD_STD_ID_NSR02 "NSR02" /* (3/9.1) */
|
||||
|
||||
/* Standard Identifier (ECMA 167r3 2/9.1.2) */
|
||||
#define VSD_STD_ID_BEA01 "BEA01" /* (2/9.2) */
|
||||
#define VSD_STD_ID_BOOT2 "BOOT2" /* (2/9.4) */
|
||||
#define VSD_STD_ID_CD001 "CD001" /* (ECMA-119) */
|
||||
#define VSD_STD_ID_CDW02 "CDW02" /* (ECMA-168) */
|
||||
#define VSD_STD_ID_NSR03 "NSR03" /* (3/9.1) */
|
||||
#define VSD_STD_ID_TEA01 "TEA01" /* (2/9.3) */
|
||||
|
||||
/* Beginning Extended Area Descriptor (ECMA 167r3 2/9.2) */
|
||||
struct beginningExtendedAreaDesc
|
||||
{
|
||||
uint8_t structType;
|
||||
uint8_t stdIdent[VSD_STD_ID_LEN];
|
||||
uint8_t structVersion;
|
||||
uint8_t structData[2041];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Terminating Extended Area Descriptor (ECMA 167r3 2/9.3) */
|
||||
struct terminatingExtendedAreaDesc
|
||||
{
|
||||
uint8_t structType;
|
||||
uint8_t stdIdent[VSD_STD_ID_LEN];
|
||||
uint8_t structVersion;
|
||||
uint8_t structData[2041];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Boot Descriptor (ECMA 167r3 2/9.4) */
|
||||
struct bootDesc
|
||||
{
|
||||
uint8_t structType;
|
||||
uint8_t stdIdent[VSD_STD_ID_LEN];
|
||||
uint8_t structVersion;
|
||||
uint8_t reserved1;
|
||||
regid archType;
|
||||
regid bootIdent;
|
||||
__le32 bootExtLocation;
|
||||
__le32 bootExtLength;
|
||||
__le64 loadAddress;
|
||||
__le64 startAddress;
|
||||
timestamp descCreationDateAndTime;
|
||||
__le16 flags;
|
||||
uint8_t reserved2[32];
|
||||
uint8_t bootUse[1906];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Flags (ECMA 167r3 2/9.4.12) */
|
||||
#define BOOT_FLAGS_ERASE 0x01
|
||||
|
||||
/* Extent Descriptor (ECMA 167r3 3/7.1) */
|
||||
typedef struct
|
||||
{
|
||||
__le32 extLength;
|
||||
__le32 extLocation;
|
||||
} __attribute__ ((packed)) extent_ad;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t extLength;
|
||||
uint32_t extLocation;
|
||||
} kernel_extent_ad;
|
||||
|
||||
/* Descriptor Tag (ECMA 167r3 3/7.2) */
|
||||
typedef struct
|
||||
{
|
||||
__le16 tagIdent;
|
||||
__le16 descVersion;
|
||||
uint8_t tagChecksum;
|
||||
uint8_t reserved;
|
||||
__le16 tagSerialNum;
|
||||
__le16 descCRC;
|
||||
__le16 descCRCLength;
|
||||
__le32 tagLocation;
|
||||
} __attribute__ ((packed)) tag;
|
||||
|
||||
/* Tag Identifier (ECMA 167r3 3/7.2.1) */
|
||||
#define TAG_IDENT_PVD 0x0001
|
||||
#define TAG_IDENT_AVDP 0x0002
|
||||
#define TAG_IDENT_VDP 0x0003
|
||||
#define TAG_IDENT_IUVD 0x0004
|
||||
#define TAG_IDENT_PD 0x0005
|
||||
#define TAG_IDENT_LVD 0x0006
|
||||
#define TAG_IDENT_USD 0x0007
|
||||
#define TAG_IDENT_TD 0x0008
|
||||
#define TAG_IDENT_LVID 0x0009
|
||||
|
||||
/* NSR Descriptor (ECMA 167r3 3/9.1) */
|
||||
struct NSRDesc
|
||||
{
|
||||
uint8_t structType;
|
||||
uint8_t stdIdent[VSD_STD_ID_LEN];
|
||||
uint8_t structVersion;
|
||||
uint8_t reserved;
|
||||
uint8_t structData[2040];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Primary Volume Descriptor (ECMA 167r3 3/10.1) */
|
||||
struct primaryVolDesc
|
||||
{
|
||||
tag descTag;
|
||||
__le32 volDescSeqNum;
|
||||
__le32 primaryVolDescNum;
|
||||
dstring volIdent[32];
|
||||
__le16 volSeqNum;
|
||||
__le16 maxVolSeqNum;
|
||||
__le16 interchangeLvl;
|
||||
__le16 maxInterchangeLvl;
|
||||
__le32 charSetList;
|
||||
__le32 maxCharSetList;
|
||||
dstring volSetIdent[128];
|
||||
charspec descCharSet;
|
||||
charspec explanatoryCharSet;
|
||||
extent_ad volAbstract;
|
||||
extent_ad volCopyright;
|
||||
regid appIdent;
|
||||
timestamp recordingDateAndTime;
|
||||
regid impIdent;
|
||||
uint8_t impUse[64];
|
||||
__le32 predecessorVolDescSeqLocation;
|
||||
__le16 flags;
|
||||
uint8_t reserved[22];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Flags (ECMA 167r3 3/10.1.21) */
|
||||
#define PVD_FLAGS_VSID_COMMON 0x0001
|
||||
|
||||
/* Anchor Volume Descriptor Pointer (ECMA 167r3 3/10.2) */
|
||||
struct anchorVolDescPtr
|
||||
{
|
||||
tag descTag;
|
||||
extent_ad mainVolDescSeqExt;
|
||||
extent_ad reserveVolDescSeqExt;
|
||||
uint8_t reserved[480];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Volume Descriptor Pointer (ECMA 167r3 3/10.3) */
|
||||
struct volDescPtr
|
||||
{
|
||||
tag descTag;
|
||||
__le32 volDescSeqNum;
|
||||
extent_ad nextVolDescSeqExt;
|
||||
uint8_t reserved[484];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) */
|
||||
struct impUseVolDesc
|
||||
{
|
||||
tag descTag;
|
||||
__le32 volDescSeqNum;
|
||||
regid impIdent;
|
||||
uint8_t impUse[460];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Partition Descriptor (ECMA 167r3 3/10.5) */
|
||||
struct partitionDesc
|
||||
{
|
||||
tag descTag;
|
||||
__le32 volDescSeqNum;
|
||||
__le16 partitionFlags;
|
||||
__le16 partitionNumber;
|
||||
regid partitionContents;
|
||||
uint8_t partitionContentsUse[128];
|
||||
__le32 accessType;
|
||||
__le32 partitionStartingLocation;
|
||||
__le32 partitionLength;
|
||||
regid impIdent;
|
||||
uint8_t impUse[128];
|
||||
uint8_t reserved[156];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Partition Flags (ECMA 167r3 3/10.5.3) */
|
||||
#define PD_PARTITION_FLAGS_ALLOC 0x0001
|
||||
|
||||
/* Partition Contents (ECMA 167r2 3/10.5.3) */
|
||||
#define PD_PARTITION_CONTENTS_NSR02 "+NSR02"
|
||||
|
||||
/* Partition Contents (ECMA 167r3 3/10.5.5) */
|
||||
#define PD_PARTITION_CONTENTS_FDC01 "+FDC01"
|
||||
#define PD_PARTITION_CONTENTS_CD001 "+CD001"
|
||||
#define PD_PARTITION_CONTENTS_CDW02 "+CDW02"
|
||||
#define PD_PARTITION_CONTENTS_NSR03 "+NSR03"
|
||||
|
||||
/* Access Type (ECMA 167r3 3/10.5.7) */
|
||||
#define PD_ACCESS_TYPE_NONE 0x00000000
|
||||
#define PD_ACCESS_TYPE_READ_ONLY 0x00000001
|
||||
#define PD_ACCESS_TYPE_WRITE_ONCE 0x00000002
|
||||
#define PD_ACCESS_TYPE_REWRITABLE 0x00000003
|
||||
#define PD_ACCESS_TYPE_OVERWRITABLE 0x00000004
|
||||
|
||||
/* Logical Volume Descriptor (ECMA 167r3 3/10.6) */
|
||||
struct logicalVolDesc
|
||||
{
|
||||
tag descTag;
|
||||
__le32 volDescSeqNum;
|
||||
charspec descCharSet;
|
||||
dstring logicalVolIdent[128];
|
||||
__le32 logicalBlockSize;
|
||||
regid domainIdent;
|
||||
uint8_t logicalVolContentsUse[16];
|
||||
__le32 mapTableLength;
|
||||
__le32 numPartitionMaps;
|
||||
regid impIdent;
|
||||
uint8_t impUse[128];
|
||||
extent_ad integritySeqExt;
|
||||
uint8_t partitionMaps[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Generic Partition Map (ECMA 167r3 3/10.7.1) */
|
||||
struct genericPartitionMap
|
||||
{
|
||||
uint8_t partitionMapType;
|
||||
uint8_t partitionMapLength;
|
||||
uint8_t partitionMapping[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Partition Map Type (ECMA 167r3 3/10.7.1.1) */
|
||||
#define GP_PARTITION_MAP_TYPE_UNDEF 0x00
|
||||
#define GP_PARTIITON_MAP_TYPE_1 0x01
|
||||
#define GP_PARTITION_MAP_TYPE_2 0x02
|
||||
|
||||
/* Type 1 Partition Map (ECMA 167r3 3/10.7.2) */
|
||||
struct genericPartitionMap1
|
||||
{
|
||||
uint8_t partitionMapType;
|
||||
uint8_t partitionMapLength;
|
||||
__le16 volSeqNum;
|
||||
__le16 partitionNum;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Type 2 Partition Map (ECMA 167r3 3/10.7.3) */
|
||||
struct genericPartitionMap2
|
||||
{
|
||||
uint8_t partitionMapType;
|
||||
uint8_t partitionMapLength;
|
||||
uint8_t partitionIdent[62];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Unallocated Space Descriptor (ECMA 167r3 3/10.8) */
|
||||
struct unallocSpaceDesc
|
||||
{
|
||||
tag descTag;
|
||||
__le32 volDescSeqNum;
|
||||
__le32 numAllocDescs;
|
||||
extent_ad allocDescs[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Terminating Descriptor (ECMA 167r3 3/10.9) */
|
||||
struct terminatingDesc
|
||||
{
|
||||
tag descTag;
|
||||
uint8_t reserved[496];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) */
|
||||
struct logicalVolIntegrityDesc
|
||||
{
|
||||
tag descTag;
|
||||
timestamp recordingDateAndTime;
|
||||
__le32 integrityType;
|
||||
extent_ad nextIntegrityExt;
|
||||
uint8_t logicalVolContentsUse[32];
|
||||
__le32 numOfPartitions;
|
||||
__le32 lengthOfImpUse;
|
||||
__le32 freeSpaceTable[0];
|
||||
__le32 sizeTable[0];
|
||||
uint8_t impUse[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Integrity Type (ECMA 167r3 3/10.10.3) */
|
||||
#define LVID_INTEGRITY_TYPE_OPEN 0x00000000
|
||||
#define LVID_INTEGRITY_TYPE_CLOSE 0x00000001
|
||||
|
||||
/* Recorded Address (ECMA 167r3 4/7.1) */
|
||||
typedef struct
|
||||
{
|
||||
__le32 logicalBlockNum;
|
||||
__le16 partitionReferenceNum;
|
||||
} __attribute__ ((packed)) lb_addr;
|
||||
|
||||
/* ... and its in-core analog */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t logicalBlockNum;
|
||||
uint16_t partitionReferenceNum;
|
||||
} kernel_lb_addr;
|
||||
|
||||
/* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
|
||||
typedef struct
|
||||
{
|
||||
__le32 extLength;
|
||||
__le32 extPosition;
|
||||
} __attribute__ ((packed)) short_ad;
|
||||
|
||||
/* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */
|
||||
typedef struct
|
||||
{
|
||||
__le32 extLength;
|
||||
lb_addr extLocation;
|
||||
uint8_t impUse[6];
|
||||
} __attribute__ ((packed)) long_ad;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t extLength;
|
||||
kernel_lb_addr extLocation;
|
||||
uint8_t impUse[6];
|
||||
} kernel_long_ad;
|
||||
|
||||
/* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */
|
||||
typedef struct
|
||||
{
|
||||
__le32 extLength;
|
||||
__le32 recordedLength;
|
||||
__le32 informationLength;
|
||||
lb_addr extLocation;
|
||||
} __attribute__ ((packed)) ext_ad;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t extLength;
|
||||
uint32_t recordedLength;
|
||||
uint32_t informationLength;
|
||||
kernel_lb_addr extLocation;
|
||||
} kernel_ext_ad;
|
||||
|
||||
/* Descriptor Tag (ECMA 167r3 4/7.2 - See 3/7.2) */
|
||||
|
||||
/* Tag Identifier (ECMA 167r3 4/7.2.1) */
|
||||
#define TAG_IDENT_FSD 0x0100
|
||||
#define TAG_IDENT_FID 0x0101
|
||||
#define TAG_IDENT_AED 0x0102
|
||||
#define TAG_IDENT_IE 0x0103
|
||||
#define TAG_IDENT_TE 0x0104
|
||||
#define TAG_IDENT_FE 0x0105
|
||||
#define TAG_IDENT_EAHD 0x0106
|
||||
#define TAG_IDENT_USE 0x0107
|
||||
#define TAG_IDENT_SBD 0x0108
|
||||
#define TAG_IDENT_PIE 0x0109
|
||||
#define TAG_IDENT_EFE 0x010A
|
||||
|
||||
/* File Set Descriptor (ECMA 167r3 4/14.1) */
|
||||
struct fileSetDesc
|
||||
{
|
||||
tag descTag;
|
||||
timestamp recordingDateAndTime;
|
||||
__le16 interchangeLvl;
|
||||
__le16 maxInterchangeLvl;
|
||||
__le32 charSetList;
|
||||
__le32 maxCharSetList;
|
||||
__le32 fileSetNum;
|
||||
__le32 fileSetDescNum;
|
||||
charspec logicalVolIdentCharSet;
|
||||
dstring logicalVolIdent[128];
|
||||
charspec fileSetCharSet;
|
||||
dstring fileSetIdent[32];
|
||||
dstring copyrightFileIdent[32];
|
||||
dstring abstractFileIdent[32];
|
||||
long_ad rootDirectoryICB;
|
||||
regid domainIdent;
|
||||
long_ad nextExt;
|
||||
long_ad streamDirectoryICB;
|
||||
uint8_t reserved[32];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Partition Header Descriptor (ECMA 167r3 4/14.3) */
|
||||
struct partitionHeaderDesc
|
||||
{
|
||||
short_ad unallocSpaceTable;
|
||||
short_ad unallocSpaceBitmap;
|
||||
short_ad partitionIntegrityTable;
|
||||
short_ad freedSpaceTable;
|
||||
short_ad freedSpaceBitmap;
|
||||
uint8_t reserved[88];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* File Identifier Descriptor (ECMA 167r3 4/14.4) */
|
||||
struct fileIdentDesc
|
||||
{
|
||||
tag descTag;
|
||||
__le16 fileVersionNum;
|
||||
uint8_t fileCharacteristics;
|
||||
uint8_t lengthFileIdent;
|
||||
long_ad icb;
|
||||
__le16 lengthOfImpUse;
|
||||
uint8_t impUse[0];
|
||||
uint8_t fileIdent[0];
|
||||
uint8_t padding[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* File Characteristics (ECMA 167r3 4/14.4.3) */
|
||||
#define FID_FILE_CHAR_HIDDEN 0x01
|
||||
#define FID_FILE_CHAR_DIRECTORY 0x02
|
||||
#define FID_FILE_CHAR_DELETED 0x04
|
||||
#define FID_FILE_CHAR_PARENT 0x08
|
||||
#define FID_FILE_CHAR_METADATA 0x10
|
||||
|
||||
/* Allocation Ext Descriptor (ECMA 167r3 4/14.5) */
|
||||
struct allocExtDesc
|
||||
{
|
||||
tag descTag;
|
||||
__le32 previousAllocExtLocation;
|
||||
__le32 lengthAllocDescs;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* ICB Tag (ECMA 167r3 4/14.6) */
|
||||
typedef struct
|
||||
{
|
||||
__le32 priorRecordedNumDirectEntries;
|
||||
__le16 strategyType;
|
||||
__le16 strategyParameter;
|
||||
__le16 numEntries;
|
||||
uint8_t reserved;
|
||||
uint8_t fileType;
|
||||
lb_addr parentICBLocation;
|
||||
__le16 flags;
|
||||
} __attribute__ ((packed)) icbtag;
|
||||
|
||||
/* Strategy Type (ECMA 167r3 4/14.6.2) */
|
||||
#define ICBTAG_STRATEGY_TYPE_UNDEF 0x0000
|
||||
#define ICBTAG_STRATEGY_TYPE_1 0x0001
|
||||
#define ICBTAG_STRATEGY_TYPE_2 0x0002
|
||||
#define ICBTAG_STRATEGY_TYPE_3 0x0003
|
||||
#define ICBTAG_STRATEGY_TYPE_4 0x0004
|
||||
|
||||
/* File Type (ECMA 167r3 4/14.6.6) */
|
||||
#define ICBTAG_FILE_TYPE_UNDEF 0x00
|
||||
#define ICBTAG_FILE_TYPE_USE 0x01
|
||||
#define ICBTAG_FILE_TYPE_PIE 0x02
|
||||
#define ICBTAG_FILE_TYPE_IE 0x03
|
||||
#define ICBTAG_FILE_TYPE_DIRECTORY 0x04
|
||||
#define ICBTAG_FILE_TYPE_REGULAR 0x05
|
||||
#define ICBTAG_FILE_TYPE_BLOCK 0x06
|
||||
#define ICBTAG_FILE_TYPE_CHAR 0x07
|
||||
#define ICBTAG_FILE_TYPE_EA 0x08
|
||||
#define ICBTAG_FILE_TYPE_FIFO 0x09
|
||||
#define ICBTAG_FILE_TYPE_SOCKET 0x0A
|
||||
#define ICBTAG_FILE_TYPE_TE 0x0B
|
||||
#define ICBTAG_FILE_TYPE_SYMLINK 0x0C
|
||||
#define ICBTAG_FILE_TYPE_STREAMDIR 0x0D
|
||||
|
||||
/* Flags (ECMA 167r3 4/14.6.8) */
|
||||
#define ICBTAG_FLAG_AD_MASK 0x0007
|
||||
#define ICBTAG_FLAG_AD_SHORT 0x0000
|
||||
#define ICBTAG_FLAG_AD_LONG 0x0001
|
||||
#define ICBTAG_FLAG_AD_EXTENDED 0x0002
|
||||
#define ICBTAG_FLAG_AD_IN_ICB 0x0003
|
||||
#define ICBTAG_FLAG_SORTED 0x0008
|
||||
#define ICBTAG_FLAG_NONRELOCATABLE 0x0010
|
||||
#define ICBTAG_FLAG_ARCHIVE 0x0020
|
||||
#define ICBTAG_FLAG_SETUID 0x0040
|
||||
#define ICBTAG_FLAG_SETGID 0x0080
|
||||
#define ICBTAG_FLAG_STICKY 0x0100
|
||||
#define ICBTAG_FLAG_CONTIGUOUS 0x0200
|
||||
#define ICBTAG_FLAG_SYSTEM 0x0400
|
||||
#define ICBTAG_FLAG_TRANSFORMED 0x0800
|
||||
#define ICBTAG_FLAG_MULTIVERSIONS 0x1000
|
||||
#define ICBTAG_FLAG_STREAM 0x2000
|
||||
|
||||
/* Indirect Entry (ECMA 167r3 4/14.7) */
|
||||
struct indirectEntry
|
||||
{
|
||||
tag descTag;
|
||||
icbtag icbTag;
|
||||
long_ad indirectICB;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Terminal Entry (ECMA 167r3 4/14.8) */
|
||||
struct terminalEntry
|
||||
{
|
||||
tag descTag;
|
||||
icbtag icbTag;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* File Entry (ECMA 167r3 4/14.9) */
|
||||
struct fileEntry
|
||||
{
|
||||
tag descTag;
|
||||
icbtag icbTag;
|
||||
__le32 uid;
|
||||
__le32 gid;
|
||||
__le32 permissions;
|
||||
__le16 fileLinkCount;
|
||||
uint8_t recordFormat;
|
||||
uint8_t recordDisplayAttr;
|
||||
__le32 recordLength;
|
||||
__le64 informationLength;
|
||||
__le64 logicalBlocksRecorded;
|
||||
timestamp accessTime;
|
||||
timestamp modificationTime;
|
||||
timestamp attrTime;
|
||||
__le32 checkpoint;
|
||||
long_ad extendedAttrICB;
|
||||
regid impIdent;
|
||||
__le64 uniqueID;
|
||||
__le32 lengthExtendedAttr;
|
||||
__le32 lengthAllocDescs;
|
||||
uint8_t extendedAttr[0];
|
||||
uint8_t allocDescs[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Permissions (ECMA 167r3 4/14.9.5) */
|
||||
#define FE_PERM_O_EXEC 0x00000001U
|
||||
#define FE_PERM_O_WRITE 0x00000002U
|
||||
#define FE_PERM_O_READ 0x00000004U
|
||||
#define FE_PERM_O_CHATTR 0x00000008U
|
||||
#define FE_PERM_O_DELETE 0x00000010U
|
||||
#define FE_PERM_G_EXEC 0x00000020U
|
||||
#define FE_PERM_G_WRITE 0x00000040U
|
||||
#define FE_PERM_G_READ 0x00000080U
|
||||
#define FE_PERM_G_CHATTR 0x00000100U
|
||||
#define FE_PERM_G_DELETE 0x00000200U
|
||||
#define FE_PERM_U_EXEC 0x00000400U
|
||||
#define FE_PERM_U_WRITE 0x00000800U
|
||||
#define FE_PERM_U_READ 0x00001000U
|
||||
#define FE_PERM_U_CHATTR 0x00002000U
|
||||
#define FE_PERM_U_DELETE 0x00004000U
|
||||
|
||||
/* Record Format (ECMA 167r3 4/14.9.7) */
|
||||
#define FE_RECORD_FMT_UNDEF 0x00
|
||||
#define FE_RECORD_FMT_FIXED_PAD 0x01
|
||||
#define FE_RECORD_FMT_FIXED 0x02
|
||||
#define FE_RECORD_FMT_VARIABLE8 0x03
|
||||
#define FE_RECORD_FMT_VARIABLE16 0x04
|
||||
#define FE_RECORD_FMT_VARIABLE16_MSB 0x05
|
||||
#define FE_RECORD_FMT_VARIABLE32 0x06
|
||||
#define FE_RECORD_FMT_PRINT 0x07
|
||||
#define FE_RECORD_FMT_LF 0x08
|
||||
#define FE_RECORD_FMT_CR 0x09
|
||||
#define FE_RECORD_FMT_CRLF 0x0A
|
||||
#define FE_RECORD_FMT_LFCR 0x0B
|
||||
|
||||
/* Record Display Attributes (ECMA 167r3 4/14.9.8) */
|
||||
#define FE_RECORD_DISPLAY_ATTR_UNDEF 0x00
|
||||
#define FE_RECORD_DISPLAY_ATTR_1 0x01
|
||||
#define FE_RECORD_DISPLAY_ATTR_2 0x02
|
||||
#define FE_RECORD_DISPLAY_ATTR_3 0x03
|
||||
|
||||
/* Extended Attribute Header Descriptor (ECMA 167r3 4/14.10.1) */
|
||||
struct extendedAttrHeaderDesc
|
||||
{
|
||||
tag descTag;
|
||||
__le32 impAttrLocation;
|
||||
__le32 appAttrLocation;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Generic Format (ECMA 167r3 4/14.10.2) */
|
||||
struct genericFormat
|
||||
{
|
||||
__le32 attrType;
|
||||
uint8_t attrSubtype;
|
||||
uint8_t reserved[3];
|
||||
__le32 attrLength;
|
||||
uint8_t attrData[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Character Set Information (ECMA 167r3 4/14.10.3) */
|
||||
struct charSetInfo
|
||||
{
|
||||
__le32 attrType;
|
||||
uint8_t attrSubtype;
|
||||
uint8_t reserved[3];
|
||||
__le32 attrLength;
|
||||
__le32 escapeSeqLength;
|
||||
uint8_t charSetType;
|
||||
uint8_t escapeSeq[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Alternate Permissions (ECMA 167r3 4/14.10.4) */
|
||||
struct altPerms
|
||||
{
|
||||
__le32 attrType;
|
||||
uint8_t attrSubtype;
|
||||
uint8_t reserved[3];
|
||||
__le32 attrLength;
|
||||
__le16 ownerIdent;
|
||||
__le16 groupIdent;
|
||||
__le16 permission;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* File Times Extended Attribute (ECMA 167r3 4/14.10.5) */
|
||||
struct fileTimesExtAttr
|
||||
{
|
||||
__le32 attrType;
|
||||
uint8_t attrSubtype;
|
||||
uint8_t reserved[3];
|
||||
__le32 attrLength;
|
||||
__le32 dataLength;
|
||||
__le32 fileTimeExistence;
|
||||
uint8_t fileTimes;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* FileTimeExistence (ECMA 167r3 4/14.10.5.6) */
|
||||
#define FTE_CREATION 0x00000001
|
||||
#define FTE_DELETION 0x00000004
|
||||
#define FTE_EFFECTIVE 0x00000008
|
||||
#define FTE_BACKUP 0x00000002
|
||||
|
||||
/* Information Times Extended Attribute (ECMA 167r3 4/14.10.6) */
|
||||
struct infoTimesExtAttr
|
||||
{
|
||||
__le32 attrType;
|
||||
uint8_t attrSubtype;
|
||||
uint8_t reserved[3];
|
||||
__le32 attrLength;
|
||||
__le32 dataLength;
|
||||
__le32 infoTimeExistence;
|
||||
uint8_t infoTimes[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Device Specification (ECMA 167r3 4/14.10.7) */
|
||||
struct deviceSpec
|
||||
{
|
||||
__le32 attrType;
|
||||
uint8_t attrSubtype;
|
||||
uint8_t reserved[3];
|
||||
__le32 attrLength;
|
||||
__le32 impUseLength;
|
||||
__le32 majorDeviceIdent;
|
||||
__le32 minorDeviceIdent;
|
||||
uint8_t impUse[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Implementation Use Extended Attr (ECMA 167r3 4/14.10.8) */
|
||||
struct impUseExtAttr
|
||||
{
|
||||
__le32 attrType;
|
||||
uint8_t attrSubtype;
|
||||
uint8_t reserved[3];
|
||||
__le32 attrLength;
|
||||
__le32 impUseLength;
|
||||
regid impIdent;
|
||||
uint8_t impUse[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Application Use Extended Attribute (ECMA 167r3 4/14.10.9) */
|
||||
struct appUseExtAttr
|
||||
{
|
||||
__le32 attrType;
|
||||
uint8_t attrSubtype;
|
||||
uint8_t reserved[3];
|
||||
__le32 attrLength;
|
||||
__le32 appUseLength;
|
||||
regid appIdent;
|
||||
uint8_t appUse[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define EXTATTR_CHAR_SET 1
|
||||
#define EXTATTR_ALT_PERMS 3
|
||||
#define EXTATTR_FILE_TIMES 5
|
||||
#define EXTATTR_INFO_TIMES 6
|
||||
#define EXTATTR_DEV_SPEC 12
|
||||
#define EXTATTR_IMP_USE 2048
|
||||
#define EXTATTR_APP_USE 65536
|
||||
|
||||
|
||||
/* Unallocated Space Entry (ECMA 167r3 4/14.11) */
|
||||
struct unallocSpaceEntry
|
||||
{
|
||||
tag descTag;
|
||||
icbtag icbTag;
|
||||
__le32 lengthAllocDescs;
|
||||
uint8_t allocDescs[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Space Bitmap Descriptor (ECMA 167r3 4/14.12) */
|
||||
struct spaceBitmapDesc
|
||||
{
|
||||
tag descTag;
|
||||
__le32 numOfBits;
|
||||
__le32 numOfBytes;
|
||||
uint8_t bitmap[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Partition Integrity Entry (ECMA 167r3 4/14.13) */
|
||||
struct partitionIntegrityEntry
|
||||
{
|
||||
tag descTag;
|
||||
icbtag icbTag;
|
||||
timestamp recordingDateAndTime;
|
||||
uint8_t integrityType;
|
||||
uint8_t reserved[175];
|
||||
regid impIdent;
|
||||
uint8_t impUse[256];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
|
||||
|
||||
/* Extent Length (ECMA 167r3 4/14.14.1.1) */
|
||||
#define EXT_RECORDED_ALLOCATED 0x00000000
|
||||
#define EXT_NOT_RECORDED_ALLOCATED 0x40000000
|
||||
#define EXT_NOT_RECORDED_NOT_ALLOCATED 0x80000000
|
||||
#define EXT_NEXT_EXTENT_ALLOCDECS 0xC0000000
|
||||
|
||||
/* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */
|
||||
|
||||
/* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */
|
||||
|
||||
/* Logical Volume Header Descriptor (ECMA 167r3 4/14.15) */
|
||||
struct logicalVolHeaderDesc
|
||||
{
|
||||
__le64 uniqueID;
|
||||
uint8_t reserved[24];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Path Component (ECMA 167r3 4/14.16.1) */
|
||||
struct pathComponent
|
||||
{
|
||||
uint8_t componentType;
|
||||
uint8_t lengthComponentIdent;
|
||||
__le16 componentFileVersionNum;
|
||||
dstring componentIdent[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* File Entry (ECMA 167r3 4/14.17) */
|
||||
struct extendedFileEntry
|
||||
{
|
||||
tag descTag;
|
||||
icbtag icbTag;
|
||||
__le32 uid;
|
||||
__le32 gid;
|
||||
__le32 permissions;
|
||||
__le16 fileLinkCount;
|
||||
uint8_t recordFormat;
|
||||
uint8_t recordDisplayAttr;
|
||||
__le32 recordLength;
|
||||
__le64 informationLength;
|
||||
__le64 objectSize;
|
||||
__le64 logicalBlocksRecorded;
|
||||
timestamp accessTime;
|
||||
timestamp modificationTime;
|
||||
timestamp createTime;
|
||||
timestamp attrTime;
|
||||
__le32 checkpoint;
|
||||
__le32 reserved;
|
||||
long_ad extendedAttrICB;
|
||||
long_ad streamDirectoryICB;
|
||||
regid impIdent;
|
||||
__le64 uniqueID;
|
||||
__le32 lengthExtendedAttr;
|
||||
__le32 lengthAllocDescs;
|
||||
uint8_t extendedAttr[0];
|
||||
uint8_t allocDescs[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif /* _ECMA_167_H */
|
||||
268
fs/udf/file.c
Normal file
268
fs/udf/file.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* file.c
|
||||
*
|
||||
* PURPOSE
|
||||
* File handling routines for the OSTA-UDF(tm) filesystem.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*
|
||||
* (C) 1998-1999 Dave Boynton
|
||||
* (C) 1998-2004 Ben Fennema
|
||||
* (C) 1999-2000 Stelias Computing Inc
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
* 10/02/98 dgb Attempt to integrate into udf.o
|
||||
* 10/07/98 Switched to using generic_readpage, etc., like isofs
|
||||
* And it works!
|
||||
* 12/06/98 blf Added udf_file_read. uses generic_file_read for all cases but
|
||||
* ICBTAG_FLAG_AD_IN_ICB.
|
||||
* 04/06/99 64 bit file handling on 32 bit systems taken from ext2 file.c
|
||||
* 05/12/99 Preliminary file write support
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
#include <linux/fs.h>
|
||||
#include <linux/udf_fs.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h> /* memset */
|
||||
#include <linux/capability.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
#include "udf_i.h"
|
||||
#include "udf_sb.h"
|
||||
|
||||
static int udf_adinicb_readpage(struct file *file, struct page * page)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
char *kaddr;
|
||||
|
||||
BUG_ON(!PageLocked(page));
|
||||
|
||||
kaddr = kmap(page);
|
||||
memset(kaddr, 0, PAGE_CACHE_SIZE);
|
||||
memcpy(kaddr, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), inode->i_size);
|
||||
flush_dcache_page(page);
|
||||
SetPageUptodate(page);
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int udf_adinicb_writepage(struct page *page, struct writeback_control *wbc)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
char *kaddr;
|
||||
|
||||
BUG_ON(!PageLocked(page));
|
||||
|
||||
kaddr = kmap(page);
|
||||
memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), kaddr, inode->i_size);
|
||||
mark_inode_dirty(inode);
|
||||
SetPageUptodate(page);
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int udf_adinicb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
|
||||
{
|
||||
kmap(page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int udf_adinicb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
char *kaddr = page_address(page);
|
||||
|
||||
memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset,
|
||||
kaddr + offset, to - offset);
|
||||
mark_inode_dirty(inode);
|
||||
SetPageUptodate(page);
|
||||
kunmap(page);
|
||||
/* only one page here */
|
||||
if (to > inode->i_size)
|
||||
inode->i_size = to;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct address_space_operations udf_adinicb_aops = {
|
||||
.readpage = udf_adinicb_readpage,
|
||||
.writepage = udf_adinicb_writepage,
|
||||
.sync_page = block_sync_page,
|
||||
.prepare_write = udf_adinicb_prepare_write,
|
||||
.commit_write = udf_adinicb_commit_write,
|
||||
};
|
||||
|
||||
static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t ppos)
|
||||
{
|
||||
ssize_t retval;
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
int err, pos;
|
||||
size_t count = iocb->ki_left;
|
||||
|
||||
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
|
||||
{
|
||||
if (file->f_flags & O_APPEND)
|
||||
pos = inode->i_size;
|
||||
else
|
||||
pos = ppos;
|
||||
|
||||
if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
|
||||
pos + count))
|
||||
{
|
||||
udf_expand_file_adinicb(inode, pos + count, &err);
|
||||
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
|
||||
{
|
||||
udf_debug("udf_expand_adinicb: err=%d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pos + count > inode->i_size)
|
||||
UDF_I_LENALLOC(inode) = pos + count;
|
||||
else
|
||||
UDF_I_LENALLOC(inode) = inode->i_size;
|
||||
}
|
||||
}
|
||||
|
||||
retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
|
||||
|
||||
if (retval > 0)
|
||||
mark_inode_dirty(inode);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* udf_ioctl
|
||||
*
|
||||
* PURPOSE
|
||||
* Issue an ioctl.
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Optional - sys_ioctl() will return -ENOTTY if this routine is not
|
||||
* available, and the ioctl cannot be handled without filesystem help.
|
||||
*
|
||||
* sys_ioctl() handles these ioctls that apply only to regular files:
|
||||
* FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD
|
||||
* These ioctls are also handled by sys_ioctl():
|
||||
* FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC
|
||||
* All other ioctls are passed to the filesystem.
|
||||
*
|
||||
* Refer to sys_ioctl() in fs/ioctl.c
|
||||
* sys_ioctl() -> .
|
||||
*
|
||||
* PRE-CONDITIONS
|
||||
* inode Pointer to inode that ioctl was issued on.
|
||||
* filp Pointer to file that ioctl was issued on.
|
||||
* cmd The ioctl command.
|
||||
* arg The ioctl argument [can be interpreted as a
|
||||
* user-space pointer if desired].
|
||||
*
|
||||
* POST-CONDITIONS
|
||||
* <return> Success (>=0) or an error code (<=0) that
|
||||
* sys_ioctl() will return.
|
||||
*
|
||||
* HISTORY
|
||||
* July 1, 1997 - Andrew E. Mileski
|
||||
* Written, tested, and released.
|
||||
*/
|
||||
int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int result = -EINVAL;
|
||||
|
||||
if ( file_permission(filp, MAY_READ) != 0 )
|
||||
{
|
||||
udf_debug("no permission to access inode %lu\n",
|
||||
inode->i_ino);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if ( !arg )
|
||||
{
|
||||
udf_debug("invalid argument to udf_ioctl\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case UDF_GETVOLIDENT:
|
||||
return copy_to_user((char __user *)arg,
|
||||
UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0;
|
||||
case UDF_RELOCATE_BLOCKS:
|
||||
{
|
||||
long old, new;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
|
||||
if (get_user(old, (long __user *)arg)) return -EFAULT;
|
||||
if ((result = udf_relocate_blocks(inode->i_sb,
|
||||
old, &new)) == 0)
|
||||
result = put_user(new, (long __user *)arg);
|
||||
|
||||
return result;
|
||||
}
|
||||
case UDF_GETEASIZE:
|
||||
result = put_user(UDF_I_LENEATTR(inode), (int __user *)arg);
|
||||
break;
|
||||
|
||||
case UDF_GETEABLOCK:
|
||||
result = copy_to_user((char __user *)arg, UDF_I_DATA(inode),
|
||||
UDF_I_LENEATTR(inode)) ? -EFAULT : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* udf_release_file
|
||||
*
|
||||
* PURPOSE
|
||||
* Called when all references to the file are closed
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Discard prealloced blocks
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
*/
|
||||
static int udf_release_file(struct inode * inode, struct file * filp)
|
||||
{
|
||||
if (filp->f_mode & FMODE_WRITE)
|
||||
{
|
||||
lock_kernel();
|
||||
udf_discard_prealloc(inode);
|
||||
unlock_kernel();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations udf_file_operations = {
|
||||
.read = do_sync_read,
|
||||
.aio_read = generic_file_aio_read,
|
||||
.ioctl = udf_ioctl,
|
||||
.open = generic_file_open,
|
||||
.mmap = generic_file_mmap,
|
||||
.write = do_sync_write,
|
||||
.aio_write = udf_file_aio_write,
|
||||
.release = udf_release_file,
|
||||
.fsync = udf_fsync_file,
|
||||
.sendfile = generic_file_sendfile,
|
||||
};
|
||||
|
||||
const struct inode_operations udf_file_inode_operations = {
|
||||
.truncate = udf_truncate,
|
||||
};
|
||||
51
fs/udf/fsync.c
Normal file
51
fs/udf/fsync.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* fsync.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Fsync handling routines for the OSTA-UDF(tm) filesystem.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*
|
||||
* (C) 1999-2001 Ben Fennema
|
||||
* (C) 1999-2000 Stelias Computing Inc
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
* 05/22/99 blf Created.
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/smp_lock.h>
|
||||
|
||||
static int udf_fsync_inode(struct inode *, int);
|
||||
|
||||
/*
|
||||
* File may be NULL when we are called. Perhaps we shouldn't
|
||||
* even pass file to fsync ?
|
||||
*/
|
||||
|
||||
int udf_fsync_file(struct file * file, struct dentry *dentry, int datasync)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
return udf_fsync_inode(inode, datasync);
|
||||
}
|
||||
|
||||
static int udf_fsync_inode(struct inode *inode, int datasync)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = sync_mapping_buffers(inode->i_mapping);
|
||||
if (!(inode->i_state & I_DIRTY))
|
||||
return err;
|
||||
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
|
||||
return err;
|
||||
|
||||
err |= udf_sync_inode (inode);
|
||||
return err ? -EIO : 0;
|
||||
}
|
||||
163
fs/udf/ialloc.c
Normal file
163
fs/udf/ialloc.c
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* ialloc.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Inode allocation handling routines for the OSTA-UDF(tm) filesystem.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*
|
||||
* (C) 1998-2001 Ben Fennema
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
* 02/24/99 blf Created.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
#include <linux/fs.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/udf_fs.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "udf_i.h"
|
||||
#include "udf_sb.h"
|
||||
|
||||
void udf_free_inode(struct inode * inode)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
|
||||
/*
|
||||
* Note: we must free any quota before locking the superblock,
|
||||
* as writing the quota to disk may need the lock as well.
|
||||
*/
|
||||
DQUOT_FREE_INODE(inode);
|
||||
DQUOT_DROP(inode);
|
||||
|
||||
clear_inode(inode);
|
||||
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
if (sbi->s_lvidbh) {
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
UDF_SB_LVIDIU(sb)->numDirs =
|
||||
cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) - 1);
|
||||
else
|
||||
UDF_SB_LVIDIU(sb)->numFiles =
|
||||
cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) - 1);
|
||||
|
||||
mark_buffer_dirty(sbi->s_lvidbh);
|
||||
}
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
|
||||
udf_free_blocks(sb, NULL, UDF_I_LOCATION(inode), 0, 1);
|
||||
}
|
||||
|
||||
struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
struct inode * inode;
|
||||
int block;
|
||||
uint32_t start = UDF_I_LOCATION(dir).logicalBlockNum;
|
||||
|
||||
inode = new_inode(sb);
|
||||
|
||||
if (!inode)
|
||||
{
|
||||
*err = -ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
*err = -ENOSPC;
|
||||
|
||||
UDF_I_UNIQUE(inode) = 0;
|
||||
UDF_I_LENEXTENTS(inode) = 0;
|
||||
UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
|
||||
UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
|
||||
UDF_I_STRAT4096(inode) = 0;
|
||||
|
||||
block = udf_new_block(dir->i_sb, NULL, UDF_I_LOCATION(dir).partitionReferenceNum,
|
||||
start, err);
|
||||
if (*err)
|
||||
{
|
||||
iput(inode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
if (UDF_SB_LVIDBH(sb))
|
||||
{
|
||||
struct logicalVolHeaderDesc *lvhd;
|
||||
uint64_t uniqueID;
|
||||
lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(sb)->logicalVolContentsUse);
|
||||
if (S_ISDIR(mode))
|
||||
UDF_SB_LVIDIU(sb)->numDirs =
|
||||
cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) + 1);
|
||||
else
|
||||
UDF_SB_LVIDIU(sb)->numFiles =
|
||||
cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) + 1);
|
||||
UDF_I_UNIQUE(inode) = uniqueID = le64_to_cpu(lvhd->uniqueID);
|
||||
if (!(++uniqueID & 0x00000000FFFFFFFFUL))
|
||||
uniqueID += 16;
|
||||
lvhd->uniqueID = cpu_to_le64(uniqueID);
|
||||
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
|
||||
}
|
||||
inode->i_mode = mode;
|
||||
inode->i_uid = current->fsuid;
|
||||
if (dir->i_mode & S_ISGID)
|
||||
{
|
||||
inode->i_gid = dir->i_gid;
|
||||
if (S_ISDIR(mode))
|
||||
mode |= S_ISGID;
|
||||
}
|
||||
else
|
||||
inode->i_gid = current->fsgid;
|
||||
|
||||
UDF_I_LOCATION(inode).logicalBlockNum = block;
|
||||
UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
|
||||
inode->i_ino = udf_get_lb_pblock(sb, UDF_I_LOCATION(inode), 0);
|
||||
inode->i_blocks = 0;
|
||||
UDF_I_LENEATTR(inode) = 0;
|
||||
UDF_I_LENALLOC(inode) = 0;
|
||||
UDF_I_USE(inode) = 0;
|
||||
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE))
|
||||
{
|
||||
UDF_I_EFE(inode) = 1;
|
||||
UDF_UPDATE_UDFREV(inode->i_sb, UDF_VERS_USE_EXTENDED_FE);
|
||||
UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
|
||||
}
|
||||
else
|
||||
{
|
||||
UDF_I_EFE(inode) = 0;
|
||||
UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
|
||||
}
|
||||
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB))
|
||||
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
|
||||
else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
|
||||
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT;
|
||||
else
|
||||
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG;
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime =
|
||||
UDF_I_CRTIME(inode) = current_fs_time(inode->i_sb);
|
||||
insert_inode_hash(inode);
|
||||
mark_inode_dirty(inode);
|
||||
mutex_unlock(&sbi->s_alloc_mutex);
|
||||
|
||||
if (DQUOT_ALLOC_INODE(inode))
|
||||
{
|
||||
DQUOT_DROP(inode);
|
||||
inode->i_flags |= S_NOQUOTA;
|
||||
inode->i_nlink = 0;
|
||||
iput(inode);
|
||||
*err = -EDQUOT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*err = 0;
|
||||
return inode;
|
||||
}
|
||||
2004
fs/udf/inode.c
Normal file
2004
fs/udf/inode.c
Normal file
File diff suppressed because it is too large
Load Diff
72
fs/udf/lowlevel.c
Normal file
72
fs/udf/lowlevel.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* lowlevel.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Low Level Device Routines for the UDF filesystem
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*
|
||||
* (C) 1999-2001 Ben Fennema
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
* 03/26/99 blf Created.
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/cdrom.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/udf_fs.h>
|
||||
#include "udf_sb.h"
|
||||
|
||||
unsigned int
|
||||
udf_get_last_session(struct super_block *sb)
|
||||
{
|
||||
struct cdrom_multisession ms_info;
|
||||
unsigned int vol_desc_start;
|
||||
struct block_device *bdev = sb->s_bdev;
|
||||
int i;
|
||||
|
||||
vol_desc_start=0;
|
||||
ms_info.addr_format=CDROM_LBA;
|
||||
i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
|
||||
|
||||
#define WE_OBEY_THE_WRITTEN_STANDARDS 1
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
udf_debug("XA disk: %s, vol_desc_start=%d\n",
|
||||
(ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
|
||||
#if WE_OBEY_THE_WRITTEN_STANDARDS
|
||||
if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
|
||||
#endif
|
||||
vol_desc_start = ms_info.addr.lba;
|
||||
}
|
||||
else
|
||||
{
|
||||
udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
|
||||
}
|
||||
return vol_desc_start;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
udf_get_last_block(struct super_block *sb)
|
||||
{
|
||||
struct block_device *bdev = sb->s_bdev;
|
||||
unsigned long lblock = 0;
|
||||
|
||||
if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock))
|
||||
lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits;
|
||||
|
||||
if (lblock)
|
||||
return lblock - 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
308
fs/udf/misc.c
Normal file
308
fs/udf/misc.c
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* misc.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Miscellaneous routines for the OSTA-UDF(tm) filesystem.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*
|
||||
* (C) 1998 Dave Boynton
|
||||
* (C) 1998-2004 Ben Fennema
|
||||
* (C) 1999-2000 Stelias Computing Inc
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
* 04/19/99 blf partial support for reading/writing specific EA's
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/udf_fs.h>
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
#include "udf_i.h"
|
||||
#include "udf_sb.h"
|
||||
|
||||
struct buffer_head *
|
||||
udf_tgetblk(struct super_block *sb, int block)
|
||||
{
|
||||
if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
|
||||
return sb_getblk(sb, udf_fixed_to_variable(block));
|
||||
else
|
||||
return sb_getblk(sb, block);
|
||||
}
|
||||
|
||||
struct buffer_head *
|
||||
udf_tread(struct super_block *sb, int block)
|
||||
{
|
||||
if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
|
||||
return sb_bread(sb, udf_fixed_to_variable(block));
|
||||
else
|
||||
return sb_bread(sb, block);
|
||||
}
|
||||
|
||||
struct genericFormat *
|
||||
udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
|
||||
uint8_t loc)
|
||||
{
|
||||
uint8_t *ea = NULL, *ad = NULL;
|
||||
int offset;
|
||||
uint16_t crclen;
|
||||
int i;
|
||||
|
||||
ea = UDF_I_DATA(inode);
|
||||
if (UDF_I_LENEATTR(inode))
|
||||
ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
|
||||
else
|
||||
{
|
||||
ad = ea;
|
||||
size += sizeof(struct extendedAttrHeaderDesc);
|
||||
}
|
||||
|
||||
offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) -
|
||||
UDF_I_LENALLOC(inode);
|
||||
|
||||
/* TODO - Check for FreeEASpace */
|
||||
|
||||
if (loc & 0x01 && offset >= size)
|
||||
{
|
||||
struct extendedAttrHeaderDesc *eahd;
|
||||
eahd = (struct extendedAttrHeaderDesc *)ea;
|
||||
|
||||
if (UDF_I_LENALLOC(inode))
|
||||
{
|
||||
memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
|
||||
}
|
||||
|
||||
if (UDF_I_LENEATTR(inode))
|
||||
{
|
||||
/* check checksum/crc */
|
||||
if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
|
||||
le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size -= sizeof(struct extendedAttrHeaderDesc);
|
||||
UDF_I_LENEATTR(inode) += sizeof(struct extendedAttrHeaderDesc);
|
||||
eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
|
||||
if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
|
||||
eahd->descTag.descVersion = cpu_to_le16(3);
|
||||
else
|
||||
eahd->descTag.descVersion = cpu_to_le16(2);
|
||||
eahd->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb));
|
||||
eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
|
||||
eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
|
||||
eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
offset = UDF_I_LENEATTR(inode);
|
||||
if (type < 2048)
|
||||
{
|
||||
if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
|
||||
{
|
||||
uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
|
||||
memmove(&ea[offset - aal + size],
|
||||
&ea[aal], offset - aal);
|
||||
offset -= aal;
|
||||
eahd->appAttrLocation = cpu_to_le32(aal + size);
|
||||
}
|
||||
if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
|
||||
{
|
||||
uint32_t ial = le32_to_cpu(eahd->impAttrLocation);
|
||||
memmove(&ea[offset - ial + size],
|
||||
&ea[ial], offset - ial);
|
||||
offset -= ial;
|
||||
eahd->impAttrLocation = cpu_to_le32(ial + size);
|
||||
}
|
||||
}
|
||||
else if (type < 65536)
|
||||
{
|
||||
if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
|
||||
{
|
||||
uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
|
||||
memmove(&ea[offset - aal + size],
|
||||
&ea[aal], offset - aal);
|
||||
offset -= aal;
|
||||
eahd->appAttrLocation = cpu_to_le32(aal + size);
|
||||
}
|
||||
}
|
||||
/* rewrite CRC + checksum of eahd */
|
||||
crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag);
|
||||
eahd->descTag.descCRCLength = cpu_to_le16(crclen);
|
||||
eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + sizeof(tag), crclen, 0));
|
||||
eahd->descTag.tagChecksum = 0;
|
||||
for (i=0; i<16; i++)
|
||||
if (i != 4)
|
||||
eahd->descTag.tagChecksum += ((uint8_t *)&(eahd->descTag))[i];
|
||||
UDF_I_LENEATTR(inode) += size;
|
||||
return (struct genericFormat *)&ea[offset];
|
||||
}
|
||||
if (loc & 0x02)
|
||||
{
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct genericFormat *
|
||||
udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
|
||||
{
|
||||
struct genericFormat *gaf;
|
||||
uint8_t *ea = NULL;
|
||||
uint32_t offset;
|
||||
|
||||
ea = UDF_I_DATA(inode);
|
||||
|
||||
if (UDF_I_LENEATTR(inode))
|
||||
{
|
||||
struct extendedAttrHeaderDesc *eahd;
|
||||
eahd = (struct extendedAttrHeaderDesc *)ea;
|
||||
|
||||
/* check checksum/crc */
|
||||
if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
|
||||
le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (type < 2048)
|
||||
offset = sizeof(struct extendedAttrHeaderDesc);
|
||||
else if (type < 65536)
|
||||
offset = le32_to_cpu(eahd->impAttrLocation);
|
||||
else
|
||||
offset = le32_to_cpu(eahd->appAttrLocation);
|
||||
|
||||
while (offset < UDF_I_LENEATTR(inode))
|
||||
{
|
||||
gaf = (struct genericFormat *)&ea[offset];
|
||||
if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
|
||||
return gaf;
|
||||
else
|
||||
offset += le32_to_cpu(gaf->attrLength);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* udf_read_tagged
|
||||
*
|
||||
* PURPOSE
|
||||
* Read the first block of a tagged descriptor.
|
||||
*
|
||||
* HISTORY
|
||||
* July 1, 1997 - Andrew E. Mileski
|
||||
* Written, tested, and released.
|
||||
*/
|
||||
struct buffer_head *
|
||||
udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint16_t *ident)
|
||||
{
|
||||
tag *tag_p;
|
||||
struct buffer_head *bh = NULL;
|
||||
register uint8_t checksum;
|
||||
register int i;
|
||||
|
||||
/* Read the block */
|
||||
if (block == 0xFFFFFFFF)
|
||||
return NULL;
|
||||
|
||||
bh = udf_tread(sb, block + UDF_SB_SESSION(sb));
|
||||
if (!bh)
|
||||
{
|
||||
udf_debug("block=%d, location=%d: read failed\n", block + UDF_SB_SESSION(sb), location);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tag_p = (tag *)(bh->b_data);
|
||||
|
||||
*ident = le16_to_cpu(tag_p->tagIdent);
|
||||
|
||||
if ( location != le32_to_cpu(tag_p->tagLocation) )
|
||||
{
|
||||
udf_debug("location mismatch block %u, tag %u != %u\n",
|
||||
block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
/* Verify the tag checksum */
|
||||
checksum = 0U;
|
||||
for (i = 0; i < 4; i++)
|
||||
checksum += (uint8_t)(bh->b_data[i]);
|
||||
for (i = 5; i < 16; i++)
|
||||
checksum += (uint8_t)(bh->b_data[i]);
|
||||
if (checksum != tag_p->tagChecksum) {
|
||||
printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
/* Verify the tag version */
|
||||
if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
|
||||
le16_to_cpu(tag_p->descVersion) != 0x0003U)
|
||||
{
|
||||
udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
|
||||
le16_to_cpu(tag_p->descVersion), block);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
/* Verify the descriptor CRC */
|
||||
if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
|
||||
le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
|
||||
le16_to_cpu(tag_p->descCRCLength), 0))
|
||||
{
|
||||
return bh;
|
||||
}
|
||||
udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
|
||||
block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
|
||||
|
||||
error_out:
|
||||
brelse(bh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct buffer_head *
|
||||
udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc, uint32_t offset, uint16_t *ident)
|
||||
{
|
||||
return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
|
||||
loc.logicalBlockNum + offset, ident);
|
||||
}
|
||||
|
||||
void udf_release_data(struct buffer_head *bh)
|
||||
{
|
||||
if (bh)
|
||||
brelse(bh);
|
||||
}
|
||||
|
||||
void udf_update_tag(char *data, int length)
|
||||
{
|
||||
tag *tptr = (tag *)data;
|
||||
int i;
|
||||
|
||||
length -= sizeof(tag);
|
||||
|
||||
tptr->tagChecksum = 0;
|
||||
tptr->descCRCLength = cpu_to_le16(length);
|
||||
tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0));
|
||||
|
||||
for (i=0; i<16; i++)
|
||||
if (i != 4)
|
||||
tptr->tagChecksum += (uint8_t)(data[i]);
|
||||
}
|
||||
|
||||
void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
|
||||
uint32_t loc, int length)
|
||||
{
|
||||
tag *tptr = (tag *)data;
|
||||
tptr->tagIdent = cpu_to_le16(ident);
|
||||
tptr->descVersion = cpu_to_le16(version);
|
||||
tptr->tagSerialNum = cpu_to_le16(snum);
|
||||
tptr->tagLocation = cpu_to_le32(loc);
|
||||
udf_update_tag(data, length);
|
||||
}
|
||||
1321
fs/udf/namei.c
Normal file
1321
fs/udf/namei.c
Normal file
File diff suppressed because it is too large
Load Diff
296
fs/udf/osta_udf.h
Normal file
296
fs/udf/osta_udf.h
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* osta_udf.h
|
||||
*
|
||||
* This file is based on OSTA UDF(tm) 2.50 (April 30, 2003)
|
||||
* http://www.osta.org
|
||||
*
|
||||
* Copyright (c) 2001-2004 Ben Fennema <bfennema@falcon.csc.calpoly.edu>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU Public License ("GPL").
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ecma_167.h"
|
||||
|
||||
#ifndef _OSTA_UDF_H
|
||||
#define _OSTA_UDF_H 1
|
||||
|
||||
/* OSTA CS0 Charspec (UDF 2.50 2.1.2) */
|
||||
#define UDF_CHAR_SET_TYPE 0
|
||||
#define UDF_CHAR_SET_INFO "OSTA Compressed Unicode"
|
||||
|
||||
/* Entity Identifier (UDF 2.50 2.1.5) */
|
||||
/* Identifiers (UDF 2.50 2.1.5.2) */
|
||||
#define UDF_ID_DEVELOPER "*Linux UDFFS"
|
||||
#define UDF_ID_COMPLIANT "*OSTA UDF Compliant"
|
||||
#define UDF_ID_LV_INFO "*UDF LV Info"
|
||||
#define UDF_ID_FREE_EA "*UDF FreeEASpace"
|
||||
#define UDF_ID_FREE_APP_EA "*UDF FreeAppEASpace"
|
||||
#define UDF_ID_DVD_CGMS "*UDF DVD CGMS Info"
|
||||
#define UDF_ID_OS2_EA "*UDF OS/2 EA"
|
||||
#define UDF_ID_OS2_EA_LENGTH "*UDF OS/2 EALength"
|
||||
#define UDF_ID_MAC_VOLUME "*UDF Mac VolumeInfo"
|
||||
#define UDF_ID_MAC_FINDER "*UDF Mac FinderInfo"
|
||||
#define UDF_ID_MAC_UNIQUE "*UDF Mac UniqueIDTable"
|
||||
#define UDF_ID_MAC_RESOURCE "*UDF Mac ResourceFork"
|
||||
#define UDF_ID_VIRTUAL "*UDF Virtual Partition"
|
||||
#define UDF_ID_SPARABLE "*UDF Sparable Partition"
|
||||
#define UDF_ID_ALLOC "*UDF Virtual Alloc Tbl"
|
||||
#define UDF_ID_SPARING "*UDF Sparing Table"
|
||||
#define UDF_ID_METADATA "*UDF Metadata Partition"
|
||||
|
||||
/* Identifier Suffix (UDF 2.50 2.1.5.3) */
|
||||
#define IS_DF_HARD_WRITE_PROTECT 0x01
|
||||
#define IS_DF_SOFT_WRITE_PROTECT 0x02
|
||||
|
||||
struct UDFIdentSuffix
|
||||
{
|
||||
__le16 UDFRevision;
|
||||
uint8_t OSClass;
|
||||
uint8_t OSIdentifier;
|
||||
uint8_t reserved[4];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct impIdentSuffix
|
||||
{
|
||||
uint8_t OSClass;
|
||||
uint8_t OSIdentifier;
|
||||
uint8_t reserved[6];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct appIdentSuffix
|
||||
{
|
||||
uint8_t impUse[8];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */
|
||||
/* Implementation Use (UDF 2.50 2.2.6.4) */
|
||||
struct logicalVolIntegrityDescImpUse
|
||||
{
|
||||
regid impIdent;
|
||||
__le32 numFiles;
|
||||
__le32 numDirs;
|
||||
__le16 minUDFReadRev;
|
||||
__le16 minUDFWriteRev;
|
||||
__le16 maxUDFWriteRev;
|
||||
uint8_t impUse[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */
|
||||
/* Implementation Use (UDF 2.50 2.2.7.2) */
|
||||
struct impUseVolDescImpUse
|
||||
{
|
||||
charspec LVICharset;
|
||||
dstring logicalVolIdent[128];
|
||||
dstring LVInfo1[36];
|
||||
dstring LVInfo2[36];
|
||||
dstring LVInfo3[36];
|
||||
regid impIdent;
|
||||
uint8_t impUse[128];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct udfPartitionMap2
|
||||
{
|
||||
uint8_t partitionMapType;
|
||||
uint8_t partitionMapLength;
|
||||
uint8_t reserved1[2];
|
||||
regid partIdent;
|
||||
__le16 volSeqNum;
|
||||
__le16 partitionNum;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Virtual Partition Map (UDF 2.50 2.2.8) */
|
||||
struct virtualPartitionMap
|
||||
{
|
||||
uint8_t partitionMapType;
|
||||
uint8_t partitionMapLength;
|
||||
uint8_t reserved1[2];
|
||||
regid partIdent;
|
||||
__le16 volSeqNum;
|
||||
__le16 partitionNum;
|
||||
uint8_t reserved2[24];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Sparable Partition Map (UDF 2.50 2.2.9) */
|
||||
struct sparablePartitionMap
|
||||
{
|
||||
uint8_t partitionMapType;
|
||||
uint8_t partitionMapLength;
|
||||
uint8_t reserved1[2];
|
||||
regid partIdent;
|
||||
__le16 volSeqNum;
|
||||
__le16 partitionNum;
|
||||
__le16 packetLength;
|
||||
uint8_t numSparingTables;
|
||||
uint8_t reserved2[1];
|
||||
__le32 sizeSparingTable;
|
||||
__le32 locSparingTable[4];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Metadata Partition Map (UDF 2.4.0 2.2.10) */
|
||||
struct metadataPartitionMap
|
||||
{
|
||||
uint8_t partitionMapType;
|
||||
uint8_t partitionMapLength;
|
||||
uint8_t reserved1[2];
|
||||
regid partIdent;
|
||||
__le16 volSeqNum;
|
||||
__le16 partitionNum;
|
||||
__le32 metadataFileLoc;
|
||||
__le32 metadataMirrorFileLoc;
|
||||
__le32 metadataBitmapFileLoc;
|
||||
__le32 allocUnitSize;
|
||||
__le16 alignUnitSize;
|
||||
uint8_t flags;
|
||||
uint8_t reserved2[5];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Virtual Allocation Table (UDF 1.5 2.2.10) */
|
||||
struct virtualAllocationTable15
|
||||
{
|
||||
__le32 VirtualSector[0];
|
||||
regid vatIdent;
|
||||
__le32 previousVATICBLoc;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define ICBTAG_FILE_TYPE_VAT15 0x00U
|
||||
|
||||
/* Virtual Allocation Table (UDF 2.50 2.2.11) */
|
||||
struct virtualAllocationTable20
|
||||
{
|
||||
__le16 lengthHeader;
|
||||
__le16 lengthImpUse;
|
||||
dstring logicalVolIdent[128];
|
||||
__le32 previousVATICBLoc;
|
||||
__le32 numFiles;
|
||||
__le32 numDirs;
|
||||
__le16 minReadRevision;
|
||||
__le16 minWriteRevision;
|
||||
__le16 maxWriteRevision;
|
||||
__le16 reserved;
|
||||
uint8_t impUse[0];
|
||||
__le32 vatEntry[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define ICBTAG_FILE_TYPE_VAT20 0xF8U
|
||||
|
||||
/* Sparing Table (UDF 2.50 2.2.12) */
|
||||
struct sparingEntry
|
||||
{
|
||||
__le32 origLocation;
|
||||
__le32 mappedLocation;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct sparingTable
|
||||
{
|
||||
tag descTag;
|
||||
regid sparingIdent;
|
||||
__le16 reallocationTableLen;
|
||||
__le16 reserved;
|
||||
__le32 sequenceNum;
|
||||
struct sparingEntry
|
||||
mapEntry[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Metadata File (and Metadata Mirror File) (UDF 2.50 2.2.13.1) */
|
||||
#define ICBTAG_FILE_TYPE_MAIN 0xFA
|
||||
#define ICBTAG_FILE_TYPE_MIRROR 0xFB
|
||||
#define ICBTAG_FILE_TYPE_BITMAP 0xFC
|
||||
|
||||
/* struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */
|
||||
struct allocDescImpUse
|
||||
{
|
||||
__le16 flags;
|
||||
uint8_t impUse[4];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#define AD_IU_EXT_ERASED 0x0001
|
||||
|
||||
/* Real-Time Files (UDF 2.50 6.11) */
|
||||
#define ICBTAG_FILE_TYPE_REALTIME 0xF9U
|
||||
|
||||
/* Implementation Use Extended Attribute (UDF 2.50 3.3.4.5) */
|
||||
/* FreeEASpace (UDF 2.50 3.3.4.5.1.1) */
|
||||
struct freeEaSpace
|
||||
{
|
||||
__le16 headerChecksum;
|
||||
uint8_t freeEASpace[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */
|
||||
struct DVDCopyrightImpUse
|
||||
{
|
||||
__le16 headerChecksum;
|
||||
uint8_t CGMSInfo;
|
||||
uint8_t dataType;
|
||||
uint8_t protectionSystemInfo[4];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */
|
||||
/* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */
|
||||
struct freeAppEASpace
|
||||
{
|
||||
__le16 headerChecksum;
|
||||
uint8_t freeEASpace[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* UDF Defined System Stream (UDF 2.50 3.3.7) */
|
||||
#define UDF_ID_UNIQUE_ID "*UDF Unique ID Mapping Data"
|
||||
#define UDF_ID_NON_ALLOC "*UDF Non-Allocatable Space"
|
||||
#define UDF_ID_POWER_CAL "*UDF Power Cal Table"
|
||||
#define UDF_ID_BACKUP "*UDF Backup"
|
||||
|
||||
/* Operating System Identifiers (UDF 2.50 6.3) */
|
||||
#define UDF_OS_CLASS_UNDEF 0x00U
|
||||
#define UDF_OS_CLASS_DOS 0x01U
|
||||
#define UDF_OS_CLASS_OS2 0x02U
|
||||
#define UDF_OS_CLASS_MAC 0x03U
|
||||
#define UDF_OS_CLASS_UNIX 0x04U
|
||||
#define UDF_OS_CLASS_WIN9X 0x05U
|
||||
#define UDF_OS_CLASS_WINNT 0x06U
|
||||
#define UDF_OS_CLASS_OS400 0x07U
|
||||
#define UDF_OS_CLASS_BEOS 0x08U
|
||||
#define UDF_OS_CLASS_WINCE 0x09U
|
||||
|
||||
#define UDF_OS_ID_UNDEF 0x00U
|
||||
#define UDF_OS_ID_DOS 0x00U
|
||||
#define UDF_OS_ID_OS2 0x00U
|
||||
#define UDF_OS_ID_MAC 0x00U
|
||||
#define UDF_OS_ID_MAX_OSX 0x01U
|
||||
#define UDF_OS_ID_UNIX 0x00U
|
||||
#define UDF_OS_ID_AIX 0x01U
|
||||
#define UDF_OS_ID_SOLARIS 0x02U
|
||||
#define UDF_OS_ID_HPUX 0x03U
|
||||
#define UDF_OS_ID_IRIX 0x04U
|
||||
#define UDF_OS_ID_LINUX 0x05U
|
||||
#define UDF_OS_ID_MKLINUX 0x06U
|
||||
#define UDF_OS_ID_FREEBSD 0x07U
|
||||
#define UDF_OS_ID_WIN9X 0x00U
|
||||
#define UDF_OS_ID_WINNT 0x00U
|
||||
#define UDF_OS_ID_OS400 0x00U
|
||||
#define UDF_OS_ID_BEOS 0x00U
|
||||
#define UDF_OS_ID_WINCE 0x00U
|
||||
|
||||
#endif /* _OSTA_UDF_H */
|
||||
221
fs/udf/partition.c
Normal file
221
fs/udf/partition.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* partition.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Partition handling routines for the OSTA-UDF(tm) filesystem.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*
|
||||
* (C) 1998-2001 Ben Fennema
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
* 12/06/98 blf Created file.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
#include "udf_sb.h"
|
||||
#include "udf_i.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/udf_fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
|
||||
{
|
||||
if (partition >= UDF_SB_NUMPARTS(sb))
|
||||
{
|
||||
udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
|
||||
block, partition, offset);
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
if (UDF_SB_PARTFUNC(sb, partition))
|
||||
return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
|
||||
else
|
||||
return UDF_SB_PARTROOT(sb, partition) + block + offset;
|
||||
}
|
||||
|
||||
uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
|
||||
{
|
||||
struct buffer_head *bh = NULL;
|
||||
uint32_t newblock;
|
||||
uint32_t index;
|
||||
uint32_t loc;
|
||||
|
||||
index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t);
|
||||
|
||||
if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
|
||||
{
|
||||
udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
|
||||
block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
if (block >= index)
|
||||
{
|
||||
block -= index;
|
||||
newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
|
||||
index = block % (sb->s_blocksize / sizeof(uint32_t));
|
||||
}
|
||||
else
|
||||
{
|
||||
newblock = 0;
|
||||
index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block;
|
||||
}
|
||||
|
||||
loc = udf_block_map(UDF_SB_VAT(sb), newblock);
|
||||
|
||||
if (!(bh = sb_bread(sb, loc)))
|
||||
{
|
||||
udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
|
||||
sb, block, partition, loc, index);
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
|
||||
|
||||
udf_release_data(bh);
|
||||
|
||||
if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
|
||||
{
|
||||
udf_debug("recursive call to udf_get_pblock!\n");
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
|
||||
}
|
||||
|
||||
inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
|
||||
{
|
||||
return udf_get_pblock_virt15(sb, block, partition, offset);
|
||||
}
|
||||
|
||||
uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
|
||||
{
|
||||
int i;
|
||||
struct sparingTable *st = NULL;
|
||||
uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
|
||||
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL)
|
||||
{
|
||||
st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (st)
|
||||
{
|
||||
for (i=0; i<le16_to_cpu(st->reallocationTableLen); i++)
|
||||
{
|
||||
if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0)
|
||||
break;
|
||||
else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet)
|
||||
{
|
||||
return le32_to_cpu(st->mapEntry[i].mappedLocation) +
|
||||
((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
|
||||
}
|
||||
else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return UDF_SB_PARTROOT(sb,partition) + block + offset;
|
||||
}
|
||||
|
||||
int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
|
||||
{
|
||||
struct udf_sparing_data *sdata;
|
||||
struct sparingTable *st = NULL;
|
||||
struct sparingEntry mapEntry;
|
||||
uint32_t packet;
|
||||
int i, j, k, l;
|
||||
|
||||
for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
|
||||
{
|
||||
if (old_block > UDF_SB_PARTROOT(sb,i) &&
|
||||
old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i))
|
||||
{
|
||||
sdata = &UDF_SB_TYPESPAR(sb,i);
|
||||
packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);
|
||||
|
||||
for (j=0; j<4; j++)
|
||||
{
|
||||
if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
|
||||
{
|
||||
st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!st)
|
||||
return 1;
|
||||
|
||||
for (k=0; k<le16_to_cpu(st->reallocationTableLen); k++)
|
||||
{
|
||||
if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF)
|
||||
{
|
||||
for (; j<4; j++)
|
||||
{
|
||||
if (sdata->s_spar_map[j])
|
||||
{
|
||||
st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
|
||||
st->mapEntry[k].origLocation = cpu_to_le32(packet);
|
||||
udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
|
||||
mark_buffer_dirty(sdata->s_spar_map[j]);
|
||||
}
|
||||
}
|
||||
*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
|
||||
((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
|
||||
return 0;
|
||||
}
|
||||
else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet)
|
||||
{
|
||||
*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
|
||||
((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
|
||||
return 0;
|
||||
}
|
||||
else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet)
|
||||
break;
|
||||
}
|
||||
for (l=k; l<le16_to_cpu(st->reallocationTableLen); l++)
|
||||
{
|
||||
if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF)
|
||||
{
|
||||
for (; j<4; j++)
|
||||
{
|
||||
if (sdata->s_spar_map[j])
|
||||
{
|
||||
st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
|
||||
mapEntry = st->mapEntry[l];
|
||||
mapEntry.origLocation = cpu_to_le32(packet);
|
||||
memmove(&st->mapEntry[k+1], &st->mapEntry[k], (l-k)*sizeof(struct sparingEntry));
|
||||
st->mapEntry[k] = mapEntry;
|
||||
udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
|
||||
mark_buffer_dirty(sdata->s_spar_map[j]);
|
||||
}
|
||||
}
|
||||
*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
|
||||
((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (i == UDF_SB_NUMPARTS(sb))
|
||||
{
|
||||
/* outside of partitions */
|
||||
/* for now, fail =) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1953
fs/udf/super.c
Normal file
1953
fs/udf/super.c
Normal file
File diff suppressed because it is too large
Load Diff
118
fs/udf/symlink.c
Normal file
118
fs/udf/symlink.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* symlink.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Symlink handling routines for the OSTA-UDF(tm) filesystem.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*
|
||||
* (C) 1998-2001 Ben Fennema
|
||||
* (C) 1999 Stelias Computing Inc
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
* 04/16/99 blf Created.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/udf_fs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include "udf_i.h"
|
||||
|
||||
static void udf_pc_to_char(struct super_block *sb, char *from, int fromlen, char *to)
|
||||
{
|
||||
struct pathComponent *pc;
|
||||
int elen = 0;
|
||||
char *p = to;
|
||||
|
||||
while (elen < fromlen)
|
||||
{
|
||||
pc = (struct pathComponent *)(from + elen);
|
||||
switch (pc->componentType)
|
||||
{
|
||||
case 1:
|
||||
if (pc->lengthComponentIdent == 0)
|
||||
{
|
||||
p = to;
|
||||
*p++ = '/';
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
memcpy(p, "../", 3);
|
||||
p += 3;
|
||||
break;
|
||||
case 4:
|
||||
memcpy(p, "./", 2);
|
||||
p += 2;
|
||||
/* that would be . - just ignore */
|
||||
break;
|
||||
case 5:
|
||||
p += udf_get_filename(sb, pc->componentIdent, p, pc->lengthComponentIdent);
|
||||
*p++ = '/';
|
||||
break;
|
||||
}
|
||||
elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
|
||||
}
|
||||
if (p > to+1)
|
||||
p[-1] = '\0';
|
||||
else
|
||||
p[0] = '\0';
|
||||
}
|
||||
|
||||
static int udf_symlink_filler(struct file *file, struct page *page)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct buffer_head *bh = NULL;
|
||||
char *symlink;
|
||||
int err = -EIO;
|
||||
char *p = kmap(page);
|
||||
|
||||
lock_kernel();
|
||||
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
|
||||
symlink = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
|
||||
else
|
||||
{
|
||||
bh = sb_bread(inode->i_sb, udf_block_map(inode, 0));
|
||||
|
||||
if (!bh)
|
||||
goto out;
|
||||
|
||||
symlink = bh->b_data;
|
||||
}
|
||||
|
||||
udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p);
|
||||
udf_release_data(bh);
|
||||
|
||||
unlock_kernel();
|
||||
SetPageUptodate(page);
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
out:
|
||||
unlock_kernel();
|
||||
SetPageError(page);
|
||||
kunmap(page);
|
||||
unlock_page(page);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* symlinks can't do much...
|
||||
*/
|
||||
const struct address_space_operations udf_symlink_aops = {
|
||||
.readpage = udf_symlink_filler,
|
||||
};
|
||||
293
fs/udf/truncate.c
Normal file
293
fs/udf/truncate.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* truncate.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Truncate handling routines for the OSTA-UDF(tm) filesystem.
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*
|
||||
* (C) 1999-2004 Ben Fennema
|
||||
* (C) 1999 Stelias Computing Inc
|
||||
*
|
||||
* HISTORY
|
||||
*
|
||||
* 02/24/99 blf Created.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/udf_fs.h>
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
#include "udf_i.h"
|
||||
#include "udf_sb.h"
|
||||
|
||||
static void extent_trunc(struct inode * inode, kernel_lb_addr bloc, int extoffset,
|
||||
kernel_lb_addr eloc, int8_t etype, uint32_t elen, struct buffer_head *bh, uint32_t nelen)
|
||||
{
|
||||
kernel_lb_addr neloc = { 0, 0 };
|
||||
int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
|
||||
int first_block = (nelen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
|
||||
|
||||
if (nelen)
|
||||
{
|
||||
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
|
||||
{
|
||||
udf_free_blocks(inode->i_sb, inode, eloc, 0, last_block);
|
||||
etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30);
|
||||
}
|
||||
else
|
||||
neloc = eloc;
|
||||
nelen = (etype << 30) | nelen;
|
||||
}
|
||||
|
||||
if (elen != nelen)
|
||||
{
|
||||
udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
|
||||
if (last_block - first_block > 0)
|
||||
{
|
||||
if (etype == (EXT_RECORDED_ALLOCATED >> 30))
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
|
||||
udf_free_blocks(inode->i_sb, inode, eloc, first_block, last_block - first_block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void udf_discard_prealloc(struct inode * inode)
|
||||
{
|
||||
kernel_lb_addr bloc, eloc;
|
||||
uint32_t extoffset = 0, elen, nelen;
|
||||
uint64_t lbcount = 0;
|
||||
int8_t etype = -1, netype;
|
||||
struct buffer_head *bh = NULL;
|
||||
int adsize;
|
||||
|
||||
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
|
||||
inode->i_size == UDF_I_LENEXTENTS(inode))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
|
||||
adsize = sizeof(short_ad);
|
||||
else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
|
||||
adsize = sizeof(long_ad);
|
||||
else
|
||||
adsize = 0;
|
||||
|
||||
bloc = UDF_I_LOCATION(inode);
|
||||
|
||||
while ((netype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
|
||||
{
|
||||
etype = netype;
|
||||
lbcount += elen;
|
||||
if (lbcount > inode->i_size && lbcount - inode->i_size < inode->i_sb->s_blocksize)
|
||||
{
|
||||
nelen = elen - (lbcount - inode->i_size);
|
||||
extent_trunc(inode, bloc, extoffset-adsize, eloc, etype, elen, bh, nelen);
|
||||
lbcount = inode->i_size;
|
||||
}
|
||||
}
|
||||
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
|
||||
{
|
||||
extoffset -= adsize;
|
||||
lbcount -= elen;
|
||||
extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
|
||||
if (!bh)
|
||||
{
|
||||
UDF_I_LENALLOC(inode) = extoffset - udf_file_entry_alloc_offset(inode);
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
|
||||
aed->lengthAllocDescs = cpu_to_le32(extoffset - sizeof(struct allocExtDesc));
|
||||
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
|
||||
udf_update_tag(bh->b_data, extoffset);
|
||||
else
|
||||
udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
|
||||
mark_buffer_dirty_inode(bh, inode);
|
||||
}
|
||||
}
|
||||
UDF_I_LENEXTENTS(inode) = lbcount;
|
||||
|
||||
udf_release_data(bh);
|
||||
}
|
||||
|
||||
void udf_truncate_extents(struct inode * inode)
|
||||
{
|
||||
kernel_lb_addr bloc, eloc, neloc = { 0, 0 };
|
||||
uint32_t extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
|
||||
int8_t etype;
|
||||
int first_block = inode->i_size >> inode->i_sb->s_blocksize_bits;
|
||||
struct buffer_head *bh = NULL;
|
||||
int adsize;
|
||||
|
||||
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
|
||||
adsize = sizeof(short_ad);
|
||||
else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
|
||||
adsize = sizeof(long_ad);
|
||||
else
|
||||
adsize = 0;
|
||||
|
||||
etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
|
||||
offset += (inode->i_size & (inode->i_sb->s_blocksize - 1));
|
||||
if (etype != -1)
|
||||
{
|
||||
extoffset -= adsize;
|
||||
extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, offset);
|
||||
extoffset += adsize;
|
||||
|
||||
if (offset)
|
||||
lenalloc = extoffset;
|
||||
else
|
||||
lenalloc = extoffset - adsize;
|
||||
|
||||
if (!bh)
|
||||
lenalloc -= udf_file_entry_alloc_offset(inode);
|
||||
else
|
||||
lenalloc -= sizeof(struct allocExtDesc);
|
||||
|
||||
while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1)
|
||||
{
|
||||
if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30))
|
||||
{
|
||||
udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
|
||||
extoffset = 0;
|
||||
if (lelen)
|
||||
{
|
||||
if (!bh)
|
||||
BUG();
|
||||
else
|
||||
memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
|
||||
udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!bh)
|
||||
{
|
||||
UDF_I_LENALLOC(inode) = lenalloc;
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
|
||||
aed->lengthAllocDescs = cpu_to_le32(lenalloc);
|
||||
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
|
||||
udf_update_tag(bh->b_data, lenalloc +
|
||||
sizeof(struct allocExtDesc));
|
||||
else
|
||||
udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
|
||||
mark_buffer_dirty_inode(bh, inode);
|
||||
}
|
||||
}
|
||||
|
||||
udf_release_data(bh);
|
||||
extoffset = sizeof(struct allocExtDesc);
|
||||
bloc = eloc;
|
||||
bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, bloc, 0));
|
||||
if (elen)
|
||||
lelen = (elen + inode->i_sb->s_blocksize - 1) >>
|
||||
inode->i_sb->s_blocksize_bits;
|
||||
else
|
||||
lelen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
|
||||
extoffset += adsize;
|
||||
}
|
||||
}
|
||||
|
||||
if (lelen)
|
||||
{
|
||||
if (!bh)
|
||||
BUG();
|
||||
else
|
||||
memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
|
||||
udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!bh)
|
||||
{
|
||||
UDF_I_LENALLOC(inode) = lenalloc;
|
||||
mark_inode_dirty(inode);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
|
||||
aed->lengthAllocDescs = cpu_to_le32(lenalloc);
|
||||
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
|
||||
udf_update_tag(bh->b_data, lenalloc +
|
||||
sizeof(struct allocExtDesc));
|
||||
else
|
||||
udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
|
||||
mark_buffer_dirty_inode(bh, inode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (inode->i_size)
|
||||
{
|
||||
if (offset)
|
||||
{
|
||||
/*
|
||||
* OK, there is not extent covering inode->i_size and
|
||||
* no extent above inode->i_size => truncate is
|
||||
* extending the file by 'offset'.
|
||||
*/
|
||||
if ((!bh && extoffset == udf_file_entry_alloc_offset(inode)) ||
|
||||
(bh && extoffset == sizeof(struct allocExtDesc))) {
|
||||
/* File has no extents at all! */
|
||||
memset(&eloc, 0x00, sizeof(kernel_lb_addr));
|
||||
elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
|
||||
udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
|
||||
}
|
||||
else {
|
||||
extoffset -= adsize;
|
||||
etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
|
||||
if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
|
||||
{
|
||||
extoffset -= adsize;
|
||||
elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + offset);
|
||||
udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0);
|
||||
}
|
||||
else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
|
||||
{
|
||||
kernel_lb_addr neloc = { 0, 0 };
|
||||
extoffset -= adsize;
|
||||
nelen = EXT_NOT_RECORDED_NOT_ALLOCATED |
|
||||
((elen + offset + inode->i_sb->s_blocksize - 1) &
|
||||
~(inode->i_sb->s_blocksize - 1));
|
||||
udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
|
||||
udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (elen & (inode->i_sb->s_blocksize - 1))
|
||||
{
|
||||
extoffset -= adsize;
|
||||
elen = EXT_RECORDED_ALLOCATED |
|
||||
((elen + inode->i_sb->s_blocksize - 1) &
|
||||
~(inode->i_sb->s_blocksize - 1));
|
||||
udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1);
|
||||
}
|
||||
memset(&eloc, 0x00, sizeof(kernel_lb_addr));
|
||||
elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
|
||||
udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
UDF_I_LENEXTENTS(inode) = inode->i_size;
|
||||
|
||||
udf_release_data(bh);
|
||||
}
|
||||
26
fs/udf/udf_i.h
Normal file
26
fs/udf/udf_i.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef __LINUX_UDF_I_H
|
||||
#define __LINUX_UDF_I_H
|
||||
|
||||
#include <linux/udf_fs_i.h>
|
||||
static inline struct udf_inode_info *UDF_I(struct inode *inode)
|
||||
{
|
||||
return list_entry(inode, struct udf_inode_info, vfs_inode);
|
||||
}
|
||||
|
||||
#define UDF_I_LOCATION(X) ( UDF_I(X)->i_location )
|
||||
#define UDF_I_LENEATTR(X) ( UDF_I(X)->i_lenEAttr )
|
||||
#define UDF_I_LENALLOC(X) ( UDF_I(X)->i_lenAlloc )
|
||||
#define UDF_I_LENEXTENTS(X) ( UDF_I(X)->i_lenExtents )
|
||||
#define UDF_I_UNIQUE(X) ( UDF_I(X)->i_unique )
|
||||
#define UDF_I_ALLOCTYPE(X) ( UDF_I(X)->i_alloc_type )
|
||||
#define UDF_I_EFE(X) ( UDF_I(X)->i_efe )
|
||||
#define UDF_I_USE(X) ( UDF_I(X)->i_use )
|
||||
#define UDF_I_STRAT4096(X) ( UDF_I(X)->i_strat4096 )
|
||||
#define UDF_I_NEXT_ALLOC_BLOCK(X) ( UDF_I(X)->i_next_alloc_block )
|
||||
#define UDF_I_NEXT_ALLOC_GOAL(X) ( UDF_I(X)->i_next_alloc_goal )
|
||||
#define UDF_I_CRTIME(X) ( UDF_I(X)->i_crtime )
|
||||
#define UDF_I_SAD(X) ( UDF_I(X)->i_ext.i_sad )
|
||||
#define UDF_I_LAD(X) ( UDF_I(X)->i_ext.i_lad )
|
||||
#define UDF_I_DATA(X) ( UDF_I(X)->i_ext.i_data )
|
||||
|
||||
#endif /* !defined(_LINUX_UDF_I_H) */
|
||||
142
fs/udf/udf_sb.h
Normal file
142
fs/udf/udf_sb.h
Normal file
@@ -0,0 +1,142 @@
|
||||
#ifndef __LINUX_UDF_SB_H
|
||||
#define __LINUX_UDF_SB_H
|
||||
|
||||
/* Since UDF 2.01 is ISO 13346 based... */
|
||||
#define UDF_SUPER_MAGIC 0x15013346
|
||||
|
||||
#define UDF_MAX_READ_VERSION 0x0201
|
||||
#define UDF_MAX_WRITE_VERSION 0x0201
|
||||
|
||||
#define UDF_FLAG_USE_EXTENDED_FE 0
|
||||
#define UDF_VERS_USE_EXTENDED_FE 0x0200
|
||||
#define UDF_FLAG_USE_STREAMS 1
|
||||
#define UDF_VERS_USE_STREAMS 0x0200
|
||||
#define UDF_FLAG_USE_SHORT_AD 2
|
||||
#define UDF_FLAG_USE_AD_IN_ICB 3
|
||||
#define UDF_FLAG_USE_FILE_CTIME_EA 4
|
||||
#define UDF_FLAG_STRICT 5
|
||||
#define UDF_FLAG_UNDELETE 6
|
||||
#define UDF_FLAG_UNHIDE 7
|
||||
#define UDF_FLAG_VARCONV 8
|
||||
#define UDF_FLAG_NLS_MAP 9
|
||||
#define UDF_FLAG_UTF8 10
|
||||
#define UDF_FLAG_UID_FORGET 11 /* save -1 for uid to disk */
|
||||
#define UDF_FLAG_UID_IGNORE 12 /* use sb uid instead of on disk uid */
|
||||
#define UDF_FLAG_GID_FORGET 13
|
||||
#define UDF_FLAG_GID_IGNORE 14
|
||||
|
||||
#define UDF_PART_FLAG_UNALLOC_BITMAP 0x0001
|
||||
#define UDF_PART_FLAG_UNALLOC_TABLE 0x0002
|
||||
#define UDF_PART_FLAG_FREED_BITMAP 0x0004
|
||||
#define UDF_PART_FLAG_FREED_TABLE 0x0008
|
||||
#define UDF_PART_FLAG_READ_ONLY 0x0010
|
||||
#define UDF_PART_FLAG_WRITE_ONCE 0x0020
|
||||
#define UDF_PART_FLAG_REWRITABLE 0x0040
|
||||
#define UDF_PART_FLAG_OVERWRITABLE 0x0080
|
||||
|
||||
static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
|
||||
{
|
||||
return sb->s_fs_info;
|
||||
}
|
||||
|
||||
#define UDF_SB_FREE(X)\
|
||||
{\
|
||||
if (UDF_SB(X))\
|
||||
{\
|
||||
kfree(UDF_SB_PARTMAPS(X));\
|
||||
UDF_SB_PARTMAPS(X) = NULL;\
|
||||
}\
|
||||
}
|
||||
|
||||
#define UDF_SB_ALLOC_PARTMAPS(X,Y)\
|
||||
{\
|
||||
UDF_SB_PARTMAPS(X) = kmalloc(sizeof(struct udf_part_map) * Y, GFP_KERNEL);\
|
||||
if (UDF_SB_PARTMAPS(X) != NULL)\
|
||||
{\
|
||||
UDF_SB_NUMPARTS(X) = Y;\
|
||||
memset(UDF_SB_PARTMAPS(X), 0x00, sizeof(struct udf_part_map) * Y);\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
UDF_SB_NUMPARTS(X) = 0;\
|
||||
udf_error(X, __FUNCTION__, "Unable to allocate space for %d partition maps", Y);\
|
||||
}\
|
||||
}
|
||||
|
||||
#define UDF_SB_ALLOC_BITMAP(X,Y,Z)\
|
||||
{\
|
||||
int nr_groups = ((UDF_SB_PARTLEN((X),(Y)) + (sizeof(struct spaceBitmapDesc) << 3) +\
|
||||
((X)->s_blocksize * 8) - 1) / ((X)->s_blocksize * 8));\
|
||||
int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\
|
||||
if (size <= PAGE_SIZE)\
|
||||
UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(size, GFP_KERNEL);\
|
||||
else\
|
||||
UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = vmalloc(size);\
|
||||
if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL)\
|
||||
{\
|
||||
memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00, size);\
|
||||
UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap =\
|
||||
(struct buffer_head **)(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap + 1);\
|
||||
UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups = nr_groups;\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
udf_error(X, __FUNCTION__, "Unable to allocate space for bitmap and %d buffer_head pointers", nr_groups);\
|
||||
}\
|
||||
}
|
||||
|
||||
#define UDF_SB_FREE_BITMAP(X,Y,Z)\
|
||||
{\
|
||||
int i;\
|
||||
int nr_groups = UDF_SB_BITMAP_NR_GROUPS(X,Y,Z);\
|
||||
int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\
|
||||
for (i=0; i<nr_groups; i++)\
|
||||
{\
|
||||
if (UDF_SB_BITMAP(X,Y,Z,i))\
|
||||
udf_release_data(UDF_SB_BITMAP(X,Y,Z,i));\
|
||||
}\
|
||||
if (size <= PAGE_SIZE)\
|
||||
kfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\
|
||||
else\
|
||||
vfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\
|
||||
}
|
||||
|
||||
#define UDF_QUERY_FLAG(X,Y) ( UDF_SB(X)->s_flags & ( 1 << (Y) ) )
|
||||
#define UDF_SET_FLAG(X,Y) ( UDF_SB(X)->s_flags |= ( 1 << (Y) ) )
|
||||
#define UDF_CLEAR_FLAG(X,Y) ( UDF_SB(X)->s_flags &= ~( 1 << (Y) ) )
|
||||
|
||||
#define UDF_UPDATE_UDFREV(X,Y) ( ((Y) > UDF_SB_UDFREV(X)) ? UDF_SB_UDFREV(X) = (Y) : UDF_SB_UDFREV(X) )
|
||||
|
||||
#define UDF_SB_PARTMAPS(X) ( UDF_SB(X)->s_partmaps )
|
||||
#define UDF_SB_PARTTYPE(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_type )
|
||||
#define UDF_SB_PARTROOT(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_root )
|
||||
#define UDF_SB_PARTLEN(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_len )
|
||||
#define UDF_SB_PARTVSN(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_volumeseqnum )
|
||||
#define UDF_SB_PARTNUM(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_num )
|
||||
#define UDF_SB_TYPESPAR(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_type_specific.s_sparing )
|
||||
#define UDF_SB_TYPEVIRT(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_type_specific.s_virtual )
|
||||
#define UDF_SB_PARTFUNC(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_func )
|
||||
#define UDF_SB_PARTFLAGS(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_flags )
|
||||
#define UDF_SB_BITMAP(X,Y,Z,I) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap[I] )
|
||||
#define UDF_SB_BITMAP_NR_GROUPS(X,Y,Z) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups )
|
||||
|
||||
#define UDF_SB_VOLIDENT(X) ( UDF_SB(X)->s_volident )
|
||||
#define UDF_SB_NUMPARTS(X) ( UDF_SB(X)->s_partitions )
|
||||
#define UDF_SB_PARTITION(X) ( UDF_SB(X)->s_partition )
|
||||
#define UDF_SB_SESSION(X) ( UDF_SB(X)->s_session )
|
||||
#define UDF_SB_ANCHOR(X) ( UDF_SB(X)->s_anchor )
|
||||
#define UDF_SB_LASTBLOCK(X) ( UDF_SB(X)->s_lastblock )
|
||||
#define UDF_SB_LVIDBH(X) ( UDF_SB(X)->s_lvidbh )
|
||||
#define UDF_SB_LVID(X) ( (struct logicalVolIntegrityDesc *)UDF_SB_LVIDBH(X)->b_data )
|
||||
#define UDF_SB_LVIDIU(X) ( (struct logicalVolIntegrityDescImpUse *)&(UDF_SB_LVID(X)->impUse[le32_to_cpu(UDF_SB_LVID(X)->numOfPartitions) * 2 * sizeof(uint32_t)/sizeof(uint8_t)]) )
|
||||
|
||||
#define UDF_SB_UMASK(X) ( UDF_SB(X)->s_umask )
|
||||
#define UDF_SB_GID(X) ( UDF_SB(X)->s_gid )
|
||||
#define UDF_SB_UID(X) ( UDF_SB(X)->s_uid )
|
||||
#define UDF_SB_RECORDTIME(X) ( UDF_SB(X)->s_recordtime )
|
||||
#define UDF_SB_SERIALNUM(X) ( UDF_SB(X)->s_serialnum )
|
||||
#define UDF_SB_UDFREV(X) ( UDF_SB(X)->s_udfrev )
|
||||
#define UDF_SB_FLAGS(X) ( UDF_SB(X)->s_flags )
|
||||
#define UDF_SB_VAT(X) ( UDF_SB(X)->s_vat )
|
||||
|
||||
#endif /* __LINUX_UDF_SB_H */
|
||||
166
fs/udf/udfdecl.h
Normal file
166
fs/udf/udfdecl.h
Normal file
@@ -0,0 +1,166 @@
|
||||
#ifndef __UDF_DECL_H
|
||||
#define __UDF_DECL_H
|
||||
|
||||
#include <linux/udf_fs.h>
|
||||
#include "ecma_167.h"
|
||||
#include "osta_udf.h"
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/udf_fs_i.h>
|
||||
#include <linux/udf_fs_sb.h>
|
||||
#include <linux/buffer_head.h>
|
||||
|
||||
#include "udfend.h"
|
||||
|
||||
#define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) )
|
||||
#define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) )
|
||||
|
||||
#define UDF_EXTENT_LENGTH_MASK 0x3FFFFFFF
|
||||
#define UDF_EXTENT_FLAG_MASK 0xC0000000
|
||||
|
||||
#define UDF_NAME_PAD 4
|
||||
#define UDF_NAME_LEN 256
|
||||
#define UDF_PATH_LEN 1023
|
||||
|
||||
#define udf_file_entry_alloc_offset(inode)\
|
||||
(UDF_I_USE(inode) ?\
|
||||
sizeof(struct unallocSpaceEntry) :\
|
||||
((UDF_I_EFE(inode) ?\
|
||||
sizeof(struct extendedFileEntry) :\
|
||||
sizeof(struct fileEntry)) + UDF_I_LENEATTR(inode)))
|
||||
|
||||
#define udf_ext0_offset(inode)\
|
||||
(UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ?\
|
||||
udf_file_entry_alloc_offset(inode) : 0)
|
||||
|
||||
#define udf_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset))
|
||||
|
||||
struct dentry;
|
||||
struct inode;
|
||||
struct task_struct;
|
||||
struct buffer_head;
|
||||
struct super_block;
|
||||
|
||||
extern const struct inode_operations udf_dir_inode_operations;
|
||||
extern const struct file_operations udf_dir_operations;
|
||||
extern const struct inode_operations udf_file_inode_operations;
|
||||
extern const struct file_operations udf_file_operations;
|
||||
extern const struct address_space_operations udf_aops;
|
||||
extern const struct address_space_operations udf_adinicb_aops;
|
||||
extern const struct address_space_operations udf_symlink_aops;
|
||||
|
||||
struct udf_fileident_bh
|
||||
{
|
||||
struct buffer_head *sbh;
|
||||
struct buffer_head *ebh;
|
||||
int soffset;
|
||||
int eoffset;
|
||||
};
|
||||
|
||||
struct udf_vds_record
|
||||
{
|
||||
uint32_t block;
|
||||
uint32_t volDescSeqNum;
|
||||
};
|
||||
|
||||
struct generic_desc
|
||||
{
|
||||
tag descTag;
|
||||
__le32 volDescSeqNum;
|
||||
};
|
||||
|
||||
struct ustr
|
||||
{
|
||||
uint8_t u_cmpID;
|
||||
uint8_t u_name[UDF_NAME_LEN-2];
|
||||
uint8_t u_len;
|
||||
};
|
||||
|
||||
/* super.c */
|
||||
extern void udf_error(struct super_block *, const char *, const char *, ...);
|
||||
extern void udf_warning(struct super_block *, const char *, const char *, ...);
|
||||
|
||||
/* namei.c */
|
||||
extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, struct fileIdentDesc *, struct udf_fileident_bh *, uint8_t *, uint8_t *);
|
||||
|
||||
/* file.c */
|
||||
extern int udf_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
|
||||
|
||||
/* inode.c */
|
||||
extern struct inode *udf_iget(struct super_block *, kernel_lb_addr);
|
||||
extern int udf_sync_inode(struct inode *);
|
||||
extern void udf_expand_file_adinicb(struct inode *, int, int *);
|
||||
extern struct buffer_head * udf_expand_dir_adinicb(struct inode *, int *, int *);
|
||||
extern struct buffer_head * udf_bread(struct inode *, int, int, int *);
|
||||
extern void udf_truncate(struct inode *);
|
||||
extern void udf_read_inode(struct inode *);
|
||||
extern void udf_delete_inode(struct inode *);
|
||||
extern void udf_clear_inode(struct inode *);
|
||||
extern int udf_write_inode(struct inode *, int);
|
||||
extern long udf_block_map(struct inode *, long);
|
||||
extern int8_t inode_bmap(struct inode *, int, kernel_lb_addr *, uint32_t *, kernel_lb_addr *, uint32_t *, uint32_t *, struct buffer_head **);
|
||||
extern int8_t udf_add_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr, uint32_t, struct buffer_head **, int);
|
||||
extern int8_t udf_write_aext(struct inode *, kernel_lb_addr, int *, kernel_lb_addr, uint32_t, struct buffer_head *, int);
|
||||
extern int8_t udf_delete_aext(struct inode *, kernel_lb_addr, int, kernel_lb_addr, uint32_t, struct buffer_head *);
|
||||
extern int8_t udf_next_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr *, uint32_t *, struct buffer_head **, int);
|
||||
extern int8_t udf_current_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr *, uint32_t *, struct buffer_head **, int);
|
||||
|
||||
/* misc.c */
|
||||
extern struct buffer_head *udf_tgetblk(struct super_block *, int);
|
||||
extern struct buffer_head *udf_tread(struct super_block *, int);
|
||||
extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint32_t, uint8_t);
|
||||
extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t);
|
||||
extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t, uint32_t, uint16_t *);
|
||||
extern struct buffer_head *udf_read_ptagged(struct super_block *, kernel_lb_addr, uint32_t, uint16_t *);
|
||||
extern void udf_release_data(struct buffer_head *);
|
||||
extern void udf_update_tag(char *, int);
|
||||
extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int);
|
||||
|
||||
/* lowlevel.c */
|
||||
extern unsigned int udf_get_last_session(struct super_block *);
|
||||
extern unsigned long udf_get_last_block(struct super_block *);
|
||||
|
||||
/* partition.c */
|
||||
extern uint32_t udf_get_pblock(struct super_block *, uint32_t, uint16_t, uint32_t);
|
||||
extern uint32_t udf_get_pblock_virt15(struct super_block *, uint32_t, uint16_t, uint32_t);
|
||||
extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t, uint32_t);
|
||||
extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t, uint32_t);
|
||||
extern int udf_relocate_blocks(struct super_block *, long, long *);
|
||||
|
||||
/* unicode.c */
|
||||
extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int);
|
||||
extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, int);
|
||||
extern int udf_build_ustr(struct ustr *, dstring *, int);
|
||||
extern int udf_CS0toUTF8(struct ustr *, struct ustr *);
|
||||
|
||||
/* ialloc.c */
|
||||
extern void udf_free_inode(struct inode *);
|
||||
extern struct inode * udf_new_inode (struct inode *, int, int *);
|
||||
|
||||
/* truncate.c */
|
||||
extern void udf_discard_prealloc(struct inode *);
|
||||
extern void udf_truncate_extents(struct inode *);
|
||||
|
||||
/* balloc.c */
|
||||
extern void udf_free_blocks(struct super_block *, struct inode *, kernel_lb_addr, uint32_t, uint32_t);
|
||||
extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t, uint32_t, uint32_t);
|
||||
extern int udf_new_block(struct super_block *, struct inode *, uint16_t, uint32_t, int *);
|
||||
|
||||
/* fsync.c */
|
||||
extern int udf_fsync_file(struct file *, struct dentry *, int);
|
||||
|
||||
/* directory.c */
|
||||
extern struct fileIdentDesc * udf_fileident_read(struct inode *, loff_t *, struct udf_fileident_bh *, struct fileIdentDesc *, kernel_lb_addr *, uint32_t *, kernel_lb_addr *, uint32_t *, uint32_t *, struct buffer_head **);
|
||||
extern struct fileIdentDesc * udf_get_fileident(void * buffer, int bufsize, int * offset);
|
||||
extern long_ad * udf_get_filelongad(uint8_t *, int, int *, int);
|
||||
extern short_ad * udf_get_fileshortad(uint8_t *, int, int *, int);
|
||||
|
||||
/* crc.c */
|
||||
extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t);
|
||||
|
||||
/* udftime.c */
|
||||
extern time_t *udf_stamp_to_time(time_t *, long *, kernel_timestamp);
|
||||
extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *, struct timespec);
|
||||
|
||||
#endif /* __UDF_DECL_H */
|
||||
81
fs/udf/udfend.h
Normal file
81
fs/udf/udfend.h
Normal file
@@ -0,0 +1,81 @@
|
||||
#ifndef __UDF_ENDIAN_H
|
||||
#define __UDF_ENDIAN_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
static inline kernel_lb_addr lelb_to_cpu(lb_addr in)
|
||||
{
|
||||
kernel_lb_addr out;
|
||||
out.logicalBlockNum = le32_to_cpu(in.logicalBlockNum);
|
||||
out.partitionReferenceNum = le16_to_cpu(in.partitionReferenceNum);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline lb_addr cpu_to_lelb(kernel_lb_addr in)
|
||||
{
|
||||
lb_addr out;
|
||||
out.logicalBlockNum = cpu_to_le32(in.logicalBlockNum);
|
||||
out.partitionReferenceNum = cpu_to_le16(in.partitionReferenceNum);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline kernel_timestamp lets_to_cpu(timestamp in)
|
||||
{
|
||||
kernel_timestamp out;
|
||||
memcpy(&out, &in, sizeof(timestamp));
|
||||
out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone);
|
||||
out.year = le16_to_cpu(in.year);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline short_ad lesa_to_cpu(short_ad in)
|
||||
{
|
||||
short_ad out;
|
||||
out.extLength = le32_to_cpu(in.extLength);
|
||||
out.extPosition = le32_to_cpu(in.extPosition);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline short_ad cpu_to_lesa(short_ad in)
|
||||
{
|
||||
short_ad out;
|
||||
out.extLength = cpu_to_le32(in.extLength);
|
||||
out.extPosition = cpu_to_le32(in.extPosition);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline kernel_long_ad lela_to_cpu(long_ad in)
|
||||
{
|
||||
kernel_long_ad out;
|
||||
out.extLength = le32_to_cpu(in.extLength);
|
||||
out.extLocation = lelb_to_cpu(in.extLocation);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline long_ad cpu_to_lela(kernel_long_ad in)
|
||||
{
|
||||
long_ad out;
|
||||
out.extLength = cpu_to_le32(in.extLength);
|
||||
out.extLocation = cpu_to_lelb(in.extLocation);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline kernel_extent_ad leea_to_cpu(extent_ad in)
|
||||
{
|
||||
kernel_extent_ad out;
|
||||
out.extLength = le32_to_cpu(in.extLength);
|
||||
out.extLocation = le32_to_cpu(in.extLocation);
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline timestamp cpu_to_lets(kernel_timestamp in)
|
||||
{
|
||||
timestamp out;
|
||||
memcpy(&out, &in, sizeof(timestamp));
|
||||
out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone);
|
||||
out.year = cpu_to_le16(in.year);
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif /* __UDF_ENDIAN_H */
|
||||
174
fs/udf/udftime.c
Normal file
174
fs/udf/udftime.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Paul Eggert (eggert@twinsun.com).
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/*
|
||||
* dgb 10/02/98: ripped this from glibc source to help convert timestamps to unix time
|
||||
* 10/04/98: added new table-based lookup after seeing how ugly the gnu code is
|
||||
* blf 09/27/99: ripped out all the old code and inserted new table from
|
||||
* John Brockmeyer (without leap second corrections)
|
||||
* rewrote udf_stamp_to_time and fixed timezone accounting in
|
||||
udf_time_to_stamp.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We don't take into account leap seconds. This may be correct or incorrect.
|
||||
* For more NIST information (especially dealing with leap seconds), see:
|
||||
* http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "udfdecl.h"
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
|
||||
#ifndef __isleap
|
||||
/* Nonzero if YEAR is a leap year (every 4 years,
|
||||
except every 100th isn't, and every 400th is). */
|
||||
#define __isleap(year) \
|
||||
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
|
||||
#endif
|
||||
|
||||
/* How many days come before each month (0-12). */
|
||||
static const unsigned short int __mon_yday[2][13] =
|
||||
{
|
||||
/* Normal years. */
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||
/* Leap years. */
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
|
||||
#define MAX_YEAR_SECONDS 69
|
||||
#define SPD 0x15180 /*3600*24*/
|
||||
#define SPY(y,l,s) (SPD * (365*y+l)+s)
|
||||
|
||||
static time_t year_seconds[MAX_YEAR_SECONDS]= {
|
||||
/*1970*/ SPY( 0, 0,0), SPY( 1, 0,0), SPY( 2, 0,0), SPY( 3, 1,0),
|
||||
/*1974*/ SPY( 4, 1,0), SPY( 5, 1,0), SPY( 6, 1,0), SPY( 7, 2,0),
|
||||
/*1978*/ SPY( 8, 2,0), SPY( 9, 2,0), SPY(10, 2,0), SPY(11, 3,0),
|
||||
/*1982*/ SPY(12, 3,0), SPY(13, 3,0), SPY(14, 3,0), SPY(15, 4,0),
|
||||
/*1986*/ SPY(16, 4,0), SPY(17, 4,0), SPY(18, 4,0), SPY(19, 5,0),
|
||||
/*1990*/ SPY(20, 5,0), SPY(21, 5,0), SPY(22, 5,0), SPY(23, 6,0),
|
||||
/*1994*/ SPY(24, 6,0), SPY(25, 6,0), SPY(26, 6,0), SPY(27, 7,0),
|
||||
/*1998*/ SPY(28, 7,0), SPY(29, 7,0), SPY(30, 7,0), SPY(31, 8,0),
|
||||
/*2002*/ SPY(32, 8,0), SPY(33, 8,0), SPY(34, 8,0), SPY(35, 9,0),
|
||||
/*2006*/ SPY(36, 9,0), SPY(37, 9,0), SPY(38, 9,0), SPY(39,10,0),
|
||||
/*2010*/ SPY(40,10,0), SPY(41,10,0), SPY(42,10,0), SPY(43,11,0),
|
||||
/*2014*/ SPY(44,11,0), SPY(45,11,0), SPY(46,11,0), SPY(47,12,0),
|
||||
/*2018*/ SPY(48,12,0), SPY(49,12,0), SPY(50,12,0), SPY(51,13,0),
|
||||
/*2022*/ SPY(52,13,0), SPY(53,13,0), SPY(54,13,0), SPY(55,14,0),
|
||||
/*2026*/ SPY(56,14,0), SPY(57,14,0), SPY(58,14,0), SPY(59,15,0),
|
||||
/*2030*/ SPY(60,15,0), SPY(61,15,0), SPY(62,15,0), SPY(63,16,0),
|
||||
/*2034*/ SPY(64,16,0), SPY(65,16,0), SPY(66,16,0), SPY(67,17,0),
|
||||
/*2038*/ SPY(68,17,0)
|
||||
};
|
||||
|
||||
extern struct timezone sys_tz;
|
||||
|
||||
#define SECS_PER_HOUR (60 * 60)
|
||||
#define SECS_PER_DAY (SECS_PER_HOUR * 24)
|
||||
|
||||
time_t *
|
||||
udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src)
|
||||
{
|
||||
int yday;
|
||||
uint8_t type = src.typeAndTimezone >> 12;
|
||||
int16_t offset;
|
||||
|
||||
if (type == 1)
|
||||
{
|
||||
offset = src.typeAndTimezone << 4;
|
||||
/* sign extent offset */
|
||||
offset = (offset >> 4);
|
||||
if (offset == -2047) /* unspecified offset */
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
offset = 0;
|
||||
|
||||
if ((src.year < EPOCH_YEAR) ||
|
||||
(src.year >= EPOCH_YEAR+MAX_YEAR_SECONDS))
|
||||
{
|
||||
*dest = -1;
|
||||
*dest_usec = -1;
|
||||
return NULL;
|
||||
}
|
||||
*dest = year_seconds[src.year - EPOCH_YEAR];
|
||||
*dest -= offset * 60;
|
||||
|
||||
yday = ((__mon_yday[__isleap (src.year)]
|
||||
[src.month-1]) + (src.day-1));
|
||||
*dest += ( ( (yday* 24) + src.hour ) * 60 + src.minute ) * 60 + src.second;
|
||||
*dest_usec = src.centiseconds * 10000 + src.hundredsOfMicroseconds * 100 + src.microseconds;
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
kernel_timestamp *
|
||||
udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
|
||||
{
|
||||
long int days, rem, y;
|
||||
const unsigned short int *ip;
|
||||
int16_t offset;
|
||||
|
||||
offset = -sys_tz.tz_minuteswest;
|
||||
|
||||
if (!dest)
|
||||
return NULL;
|
||||
|
||||
dest->typeAndTimezone = 0x1000 | (offset & 0x0FFF);
|
||||
|
||||
ts.tv_sec += offset * 60;
|
||||
days = ts.tv_sec / SECS_PER_DAY;
|
||||
rem = ts.tv_sec % SECS_PER_DAY;
|
||||
dest->hour = rem / SECS_PER_HOUR;
|
||||
rem %= SECS_PER_HOUR;
|
||||
dest->minute = rem / 60;
|
||||
dest->second = rem % 60;
|
||||
y = 1970;
|
||||
|
||||
#define DIV(a,b) ((a) / (b) - ((a) % (b) < 0))
|
||||
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
|
||||
|
||||
while (days < 0 || days >= (__isleap(y) ? 366 : 365))
|
||||
{
|
||||
long int yg = y + days / 365 - (days % 365 < 0);
|
||||
|
||||
/* Adjust DAYS and Y to match the guessed year. */
|
||||
days -= ((yg - y) * 365
|
||||
+ LEAPS_THRU_END_OF (yg - 1)
|
||||
- LEAPS_THRU_END_OF (y - 1));
|
||||
y = yg;
|
||||
}
|
||||
dest->year = y;
|
||||
ip = __mon_yday[__isleap(y)];
|
||||
for (y = 11; days < (long int) ip[y]; --y)
|
||||
continue;
|
||||
days -= ip[y];
|
||||
dest->month = y + 1;
|
||||
dest->day = days + 1;
|
||||
|
||||
dest->centiseconds = ts.tv_nsec / 10000000;
|
||||
dest->hundredsOfMicroseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000) / 100;
|
||||
dest->microseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000 -
|
||||
dest->hundredsOfMicroseconds * 100);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
511
fs/udf/unicode.c
Normal file
511
fs/udf/unicode.c
Normal file
@@ -0,0 +1,511 @@
|
||||
/*
|
||||
* unicode.c
|
||||
*
|
||||
* PURPOSE
|
||||
* Routines for converting between UTF-8 and OSTA Compressed Unicode.
|
||||
* Also handles filename mangling
|
||||
*
|
||||
* DESCRIPTION
|
||||
* OSTA Compressed Unicode is explained in the OSTA UDF specification.
|
||||
* http://www.osta.org/
|
||||
* UTF-8 is explained in the IETF RFC XXXX.
|
||||
* ftp://ftp.internic.net/rfc/rfcxxxx.txt
|
||||
*
|
||||
* COPYRIGHT
|
||||
* This file is distributed under the terms of the GNU General Public
|
||||
* License (GPL). Copies of the GPL can be obtained from:
|
||||
* ftp://prep.ai.mit.edu/pub/gnu/GPL
|
||||
* Each contributing author retains all rights to their own work.
|
||||
*/
|
||||
|
||||
#include "udfdecl.h"
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h> /* for memset */
|
||||
#include <linux/nls.h>
|
||||
#include <linux/udf_fs.h>
|
||||
|
||||
#include "udf_sb.h"
|
||||
|
||||
static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int);
|
||||
|
||||
static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
|
||||
{
|
||||
if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN-2) )
|
||||
return 0;
|
||||
memset(dest, 0, sizeof(struct ustr));
|
||||
memcpy(dest->u_name, src, strlen);
|
||||
dest->u_cmpID = 0x08;
|
||||
dest->u_len = strlen;
|
||||
return strlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* udf_build_ustr
|
||||
*/
|
||||
int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
|
||||
{
|
||||
int usesize;
|
||||
|
||||
if ( (!dest) || (!ptr) || (!size) )
|
||||
return -1;
|
||||
|
||||
memset(dest, 0, sizeof(struct ustr));
|
||||
usesize= (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size;
|
||||
dest->u_cmpID=ptr[0];
|
||||
dest->u_len=ptr[size-1];
|
||||
memcpy(dest->u_name, ptr+1, usesize-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* udf_build_ustr_exact
|
||||
*/
|
||||
static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
|
||||
{
|
||||
if ( (!dest) || (!ptr) || (!exactsize) )
|
||||
return -1;
|
||||
|
||||
memset(dest, 0, sizeof(struct ustr));
|
||||
dest->u_cmpID=ptr[0];
|
||||
dest->u_len=exactsize-1;
|
||||
memcpy(dest->u_name, ptr+1, exactsize-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* udf_ocu_to_utf8
|
||||
*
|
||||
* PURPOSE
|
||||
* Convert OSTA Compressed Unicode to the UTF-8 equivalent.
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine is only called by udf_filldir().
|
||||
*
|
||||
* PRE-CONDITIONS
|
||||
* utf Pointer to UTF-8 output buffer.
|
||||
* ocu Pointer to OSTA Compressed Unicode input buffer
|
||||
* of size UDF_NAME_LEN bytes.
|
||||
* both of type "struct ustr *"
|
||||
*
|
||||
* POST-CONDITIONS
|
||||
* <return> Zero on success.
|
||||
*
|
||||
* HISTORY
|
||||
* November 12, 1997 - Andrew E. Mileski
|
||||
* Written, tested, and released.
|
||||
*/
|
||||
int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
|
||||
{
|
||||
uint8_t *ocu;
|
||||
uint32_t c;
|
||||
uint8_t cmp_id, ocu_len;
|
||||
int i;
|
||||
|
||||
ocu = ocu_i->u_name;
|
||||
|
||||
ocu_len = ocu_i->u_len;
|
||||
cmp_id = ocu_i->u_cmpID;
|
||||
utf_o->u_len = 0;
|
||||
|
||||
if (ocu_len == 0)
|
||||
{
|
||||
memset(utf_o, 0, sizeof(struct ustr));
|
||||
utf_o->u_cmpID = 0;
|
||||
utf_o->u_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((cmp_id != 8) && (cmp_id != 16))
|
||||
{
|
||||
printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
|
||||
{
|
||||
|
||||
/* Expand OSTA compressed Unicode to Unicode */
|
||||
c = ocu[i++];
|
||||
if (cmp_id == 16)
|
||||
c = (c << 8) | ocu[i++];
|
||||
|
||||
/* Compress Unicode to UTF-8 */
|
||||
if (c < 0x80U)
|
||||
utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
|
||||
else if (c < 0x800U)
|
||||
{
|
||||
utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xc0 | (c >> 6));
|
||||
utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
|
||||
}
|
||||
else
|
||||
{
|
||||
utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xe0 | (c >> 12));
|
||||
utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | ((c >> 6) & 0x3f));
|
||||
utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
|
||||
}
|
||||
}
|
||||
utf_o->u_cmpID=8;
|
||||
|
||||
return utf_o->u_len;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* udf_utf8_to_ocu
|
||||
*
|
||||
* PURPOSE
|
||||
* Convert UTF-8 to the OSTA Compressed Unicode equivalent.
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This routine is only called by udf_lookup().
|
||||
*
|
||||
* PRE-CONDITIONS
|
||||
* ocu Pointer to OSTA Compressed Unicode output
|
||||
* buffer of size UDF_NAME_LEN bytes.
|
||||
* utf Pointer to UTF-8 input buffer.
|
||||
* utf_len Length of UTF-8 input buffer in bytes.
|
||||
*
|
||||
* POST-CONDITIONS
|
||||
* <return> Zero on success.
|
||||
*
|
||||
* HISTORY
|
||||
* November 12, 1997 - Andrew E. Mileski
|
||||
* Written, tested, and released.
|
||||
*/
|
||||
static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
|
||||
{
|
||||
unsigned c, i, max_val, utf_char;
|
||||
int utf_cnt, u_len;
|
||||
|
||||
memset(ocu, 0, sizeof(dstring) * length);
|
||||
ocu[0] = 8;
|
||||
max_val = 0xffU;
|
||||
|
||||
try_again:
|
||||
u_len = 0U;
|
||||
utf_char = 0U;
|
||||
utf_cnt = 0U;
|
||||
for (i = 0U; i < utf->u_len; i++)
|
||||
{
|
||||
c = (uint8_t)utf->u_name[i];
|
||||
|
||||
/* Complete a multi-byte UTF-8 character */
|
||||
if (utf_cnt)
|
||||
{
|
||||
utf_char = (utf_char << 6) | (c & 0x3fU);
|
||||
if (--utf_cnt)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check for a multi-byte UTF-8 character */
|
||||
if (c & 0x80U)
|
||||
{
|
||||
/* Start a multi-byte UTF-8 character */
|
||||
if ((c & 0xe0U) == 0xc0U)
|
||||
{
|
||||
utf_char = c & 0x1fU;
|
||||
utf_cnt = 1;
|
||||
}
|
||||
else if ((c & 0xf0U) == 0xe0U)
|
||||
{
|
||||
utf_char = c & 0x0fU;
|
||||
utf_cnt = 2;
|
||||
}
|
||||
else if ((c & 0xf8U) == 0xf0U)
|
||||
{
|
||||
utf_char = c & 0x07U;
|
||||
utf_cnt = 3;
|
||||
}
|
||||
else if ((c & 0xfcU) == 0xf8U)
|
||||
{
|
||||
utf_char = c & 0x03U;
|
||||
utf_cnt = 4;
|
||||
}
|
||||
else if ((c & 0xfeU) == 0xfcU)
|
||||
{
|
||||
utf_char = c & 0x01U;
|
||||
utf_cnt = 5;
|
||||
}
|
||||
else
|
||||
goto error_out;
|
||||
continue;
|
||||
} else
|
||||
/* Single byte UTF-8 character (most common) */
|
||||
utf_char = c;
|
||||
}
|
||||
|
||||
/* Choose no compression if necessary */
|
||||
if (utf_char > max_val)
|
||||
{
|
||||
if ( 0xffU == max_val )
|
||||
{
|
||||
max_val = 0xffffU;
|
||||
ocu[0] = (uint8_t)0x10U;
|
||||
goto try_again;
|
||||
}
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (max_val == 0xffffU)
|
||||
{
|
||||
ocu[++u_len] = (uint8_t)(utf_char >> 8);
|
||||
}
|
||||
ocu[++u_len] = (uint8_t)(utf_char & 0xffU);
|
||||
}
|
||||
|
||||
|
||||
if (utf_cnt)
|
||||
{
|
||||
error_out:
|
||||
ocu[++u_len] = '?';
|
||||
printk(KERN_DEBUG "udf: bad UTF-8 character\n");
|
||||
}
|
||||
|
||||
ocu[length - 1] = (uint8_t)u_len + 1;
|
||||
return u_len + 1;
|
||||
}
|
||||
|
||||
static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *ocu_i)
|
||||
{
|
||||
uint8_t *ocu;
|
||||
uint32_t c;
|
||||
uint8_t cmp_id, ocu_len;
|
||||
int i;
|
||||
|
||||
ocu = ocu_i->u_name;
|
||||
|
||||
ocu_len = ocu_i->u_len;
|
||||
cmp_id = ocu_i->u_cmpID;
|
||||
utf_o->u_len = 0;
|
||||
|
||||
if (ocu_len == 0)
|
||||
{
|
||||
memset(utf_o, 0, sizeof(struct ustr));
|
||||
utf_o->u_cmpID = 0;
|
||||
utf_o->u_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((cmp_id != 8) && (cmp_id != 16))
|
||||
{
|
||||
printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
|
||||
{
|
||||
/* Expand OSTA compressed Unicode to Unicode */
|
||||
c = ocu[i++];
|
||||
if (cmp_id == 16)
|
||||
c = (c << 8) | ocu[i++];
|
||||
|
||||
utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
|
||||
UDF_NAME_LEN - utf_o->u_len);
|
||||
}
|
||||
utf_o->u_cmpID=8;
|
||||
|
||||
return utf_o->u_len;
|
||||
}
|
||||
|
||||
static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int length)
|
||||
{
|
||||
unsigned len, i, max_val;
|
||||
uint16_t uni_char;
|
||||
int u_len;
|
||||
|
||||
memset(ocu, 0, sizeof(dstring) * length);
|
||||
ocu[0] = 8;
|
||||
max_val = 0xffU;
|
||||
|
||||
try_again:
|
||||
u_len = 0U;
|
||||
for (i = 0U; i < uni->u_len; i++)
|
||||
{
|
||||
len = nls->char2uni(&uni->u_name[i], uni->u_len-i, &uni_char);
|
||||
if (len <= 0)
|
||||
continue;
|
||||
|
||||
if (uni_char > max_val)
|
||||
{
|
||||
max_val = 0xffffU;
|
||||
ocu[0] = (uint8_t)0x10U;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
if (max_val == 0xffffU)
|
||||
ocu[++u_len] = (uint8_t)(uni_char >> 8);
|
||||
ocu[++u_len] = (uint8_t)(uni_char & 0xffU);
|
||||
i += len - 1;
|
||||
}
|
||||
|
||||
ocu[length - 1] = (uint8_t)u_len + 1;
|
||||
return u_len + 1;
|
||||
}
|
||||
|
||||
int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname, int flen)
|
||||
{
|
||||
struct ustr filename, unifilename;
|
||||
int len;
|
||||
|
||||
if (udf_build_ustr_exact(&unifilename, sname, flen))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
|
||||
{
|
||||
if (!udf_CS0toUTF8(&filename, &unifilename) )
|
||||
{
|
||||
udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
|
||||
{
|
||||
if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename, &unifilename) )
|
||||
{
|
||||
udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
if ((len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
|
||||
unifilename.u_name, unifilename.u_len)))
|
||||
{
|
||||
return len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udf_put_filename(struct super_block *sb, const uint8_t *sname, uint8_t *dname, int flen)
|
||||
{
|
||||
struct ustr unifilename;
|
||||
int namelen;
|
||||
|
||||
if ( !(udf_char_to_ustr(&unifilename, sname, flen)) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
|
||||
{
|
||||
if ( !(namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN)) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
|
||||
{
|
||||
if ( !(namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, &unifilename, UDF_NAME_LEN)) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
return namelen;
|
||||
}
|
||||
|
||||
#define ILLEGAL_CHAR_MARK '_'
|
||||
#define EXT_MARK '.'
|
||||
#define CRC_MARK '#'
|
||||
#define EXT_SIZE 5
|
||||
|
||||
static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen, uint8_t *fidName, int fidNameLen)
|
||||
{
|
||||
int index, newIndex = 0, needsCRC = 0;
|
||||
int extIndex = 0, newExtIndex = 0, hasExt = 0;
|
||||
unsigned short valueCRC;
|
||||
uint8_t curr;
|
||||
const uint8_t hexChar[] = "0123456789ABCDEF";
|
||||
|
||||
if (udfName[0] == '.' && (udfLen == 1 ||
|
||||
(udfLen == 2 && udfName[1] == '.')))
|
||||
{
|
||||
needsCRC = 1;
|
||||
newIndex = udfLen;
|
||||
memcpy(newName, udfName, udfLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (index = 0; index < udfLen; index++)
|
||||
{
|
||||
curr = udfName[index];
|
||||
if (curr == '/' || curr == 0)
|
||||
{
|
||||
needsCRC = 1;
|
||||
curr = ILLEGAL_CHAR_MARK;
|
||||
while (index+1 < udfLen && (udfName[index+1] == '/' ||
|
||||
udfName[index+1] == 0))
|
||||
index++;
|
||||
}
|
||||
if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE)
|
||||
{
|
||||
if (udfLen == index + 1)
|
||||
hasExt = 0;
|
||||
else
|
||||
{
|
||||
hasExt = 1;
|
||||
extIndex = index;
|
||||
newExtIndex = newIndex;
|
||||
}
|
||||
}
|
||||
if (newIndex < 256)
|
||||
newName[newIndex++] = curr;
|
||||
else
|
||||
needsCRC = 1;
|
||||
}
|
||||
}
|
||||
if (needsCRC)
|
||||
{
|
||||
uint8_t ext[EXT_SIZE];
|
||||
int localExtIndex = 0;
|
||||
|
||||
if (hasExt)
|
||||
{
|
||||
int maxFilenameLen;
|
||||
for(index = 0; index<EXT_SIZE && extIndex + index +1 < udfLen;
|
||||
index++ )
|
||||
{
|
||||
curr = udfName[extIndex + index + 1];
|
||||
|
||||
if (curr == '/' || curr == 0)
|
||||
{
|
||||
needsCRC = 1;
|
||||
curr = ILLEGAL_CHAR_MARK;
|
||||
while(extIndex + index + 2 < udfLen && (index + 1 < EXT_SIZE
|
||||
&& (udfName[extIndex + index + 2] == '/' ||
|
||||
udfName[extIndex + index + 2] == 0)))
|
||||
index++;
|
||||
}
|
||||
ext[localExtIndex++] = curr;
|
||||
}
|
||||
maxFilenameLen = 250 - localExtIndex;
|
||||
if (newIndex > maxFilenameLen)
|
||||
newIndex = maxFilenameLen;
|
||||
else
|
||||
newIndex = newExtIndex;
|
||||
}
|
||||
else if (newIndex > 250)
|
||||
newIndex = 250;
|
||||
newName[newIndex++] = CRC_MARK;
|
||||
valueCRC = udf_crc(fidName, fidNameLen, 0);
|
||||
newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
|
||||
newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8];
|
||||
newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
|
||||
newName[newIndex++] = hexChar[(valueCRC & 0x000f)];
|
||||
|
||||
if (hasExt)
|
||||
{
|
||||
newName[newIndex++] = EXT_MARK;
|
||||
for (index = 0;index < localExtIndex ;index++ )
|
||||
newName[newIndex++] = ext[index];
|
||||
}
|
||||
}
|
||||
return newIndex;
|
||||
}
|
||||
Reference in New Issue
Block a user