add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

18
kernel/fs/udf/Kconfig Normal file
View File

@@ -0,0 +1,18 @@
config UDF_FS
tristate "UDF file system support"
select CRC_ITU_T
help
This is the new file system used on some CD-ROMs and DVDs. Say Y if
you intend to mount DVD discs or CDRW's written in packet mode, or
if written to by other UDF utilities, such as DirectCD.
Please read <file:Documentation/filesystems/udf.txt>.
To compile this file system support as a module, choose M here: the
module will be called udf.
If unsure, say N.
config UDF_NLS
bool
default y
depends on (UDF_FS=m && NLS) || (UDF_FS=y && NLS=y)

9
kernel/fs/udf/Makefile Normal file
View 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 \
directory.o misc.o udftime.o unicode.o

900
kernel/fs/udf/balloc.c Normal file
View File

@@ -0,0 +1,900 @@
/*
* 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)) {
tmp = leBPL_to_cpup(p++);
if (tmp)
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;
struct kernel_lb_addr loc;
loc.logicalBlockNum = bitmap->s_extPosition;
loc.partitionReferenceNum = UDF_SB(sb)->s_partition;
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_add_free_space(struct super_block *sb, u16 partition, u32 cnt)
{
struct udf_sb_info *sbi = UDF_SB(sb);
struct logicalVolIntegrityDesc *lvid;
if (!sbi->s_lvid_bh)
return;
lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data;
le32_add_cpu(&lvid->freeSpaceTable[partition], cnt);
udf_updated_lvid(sb);
}
static void udf_bitmap_free_blocks(struct super_block *sb,
struct inode *inode,
struct udf_bitmap *bitmap,
struct kernel_lb_addr *bloc,
uint32_t offset,
uint32_t count)
{
struct udf_sb_info *sbi = UDF_SB(sb);
struct buffer_head *bh = NULL;
struct udf_part_map *partmap;
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);
partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
if (bloc->logicalBlockNum < 0 ||
(bloc->logicalBlockNum + count) >
partmap->s_partition_len) {
udf_debug("%d < %d || %d + %d > %d\n",
bloc->logicalBlockNum, 0, bloc->logicalBlockNum,
count, partmap->s_partition_len);
goto error_return;
}
block = bloc->logicalBlockNum + offset +
(sizeof(struct spaceBitmapDesc) << 3);
do {
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)
vfs_dq_free_block(inode, 1);
udf_add_free_space(sb, sbi->s_partition, 1);
}
}
mark_buffer_dirty(bh);
if (overflow) {
block += count;
count = overflow;
}
} while (overflow);
error_return:
mutex_unlock(&sbi->s_alloc_mutex);
}
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;
__u32 part_len;
mutex_lock(&sbi->s_alloc_mutex);
part_len = sbi->s_partmaps[partition].s_partition_len;
if (first_block >= part_len)
goto out;
if (first_block + block_count > part_len)
block_count = part_len - first_block;
do {
nr_groups = udf_compute_nr_groups(sb, partition);
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 (vfs_dq_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);
vfs_dq_free_block(inode, 1);
goto out;
}
block_count--;
alloc_count++;
bit++;
block++;
}
mark_buffer_dirty(bh);
} while (block_count > 0);
out:
udf_add_free_space(sb, partition, -alloc_count);
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 >= sbi->s_partmaps[partition].s_partition_len)
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:
i = 0;
while (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 && vfs_dq_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);
udf_add_free_space(sb, partition, -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,
struct kernel_lb_addr *bloc,
uint32_t offset,
uint32_t count)
{
struct udf_sb_info *sbi = UDF_SB(sb);
struct udf_part_map *partmap;
uint32_t start, end;
uint32_t elen;
struct kernel_lb_addr eloc;
struct extent_position oepos, epos;
int8_t etype;
int i;
struct udf_inode_info *iinfo;
mutex_lock(&sbi->s_alloc_mutex);
partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
if (bloc->logicalBlockNum < 0 ||
(bloc->logicalBlockNum + count) >
partmap->s_partition_len) {
udf_debug("%d < %d || %d + %d > %d\n",
bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
partmap->s_partition_len);
goto error_return;
}
iinfo = UDF_I(table);
/* We do this up front - There are some error conditions that
could occure, but.. oh well */
if (inode)
vfs_dq_free_block(inode, count);
udf_add_free_space(sb, sbi->s_partition, count);
start = bloc->logicalBlockNum + offset;
end = bloc->logicalBlockNum + offset + count - 1;
epos.offset = oepos.offset = sizeof(struct unallocSpaceEntry);
elen = 0;
epos.block = oepos.block = iinfo->i_location;
epos.bh = oepos.bh = NULL;
while (count &&
(etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
if (((eloc.logicalBlockNum +
(elen >> sb->s_blocksize_bits)) == start)) {
if ((0x3FFFFFFF - elen) <
(count << sb->s_blocksize_bits)) {
uint32_t tmp = ((0x3FFFFFFF - elen) >>
sb->s_blocksize_bits);
count -= tmp;
start += tmp;
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, &oepos, &eloc, elen, 1);
} else if (eloc.logicalBlockNum == (end + 1)) {
if ((0x3FFFFFFF - elen) <
(count << sb->s_blocksize_bits)) {
uint32_t tmp = ((0x3FFFFFFF - elen) >>
sb->s_blocksize_bits);
count -= tmp;
end -= tmp;
eloc.logicalBlockNum -= tmp;
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, &oepos, &eloc, elen, 1);
}
if (epos.bh != oepos.bh) {
i = -1;
oepos.block = epos.block;
brelse(oepos.bh);
get_bh(epos.bh);
oepos.bh = epos.bh;
oepos.offset = 0;
} else {
oepos.offset = epos.offset;
}
}
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;
struct short_ad *sad = NULL;
struct long_ad *lad = NULL;
struct allocExtDesc *aed;
eloc.logicalBlockNum = start;
elen = EXT_RECORDED_ALLOCATED |
(count << sb->s_blocksize_bits);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(struct long_ad);
else {
brelse(oepos.bh);
brelse(epos.bh);
goto error_return;
}
if (epos.offset + (2 * adsize) > sb->s_blocksize) {
char *sptr, *dptr;
int loffset;
brelse(oepos.bh);
oepos = epos;
/* Steal a block from the extent being free'd */
epos.block.logicalBlockNum = eloc.logicalBlockNum;
eloc.logicalBlockNum++;
elen -= sb->s_blocksize;
epos.bh = udf_tread(sb,
udf_get_lb_pblock(sb, &epos.block, 0));
if (!epos.bh) {
brelse(oepos.bh);
goto error_return;
}
aed = (struct allocExtDesc *)(epos.bh->b_data);
aed->previousAllocExtLocation =
cpu_to_le32(oepos.block.logicalBlockNum);
if (epos.offset + adsize > sb->s_blocksize) {
loffset = epos.offset;
aed->lengthAllocDescs = cpu_to_le32(adsize);
sptr = iinfo->i_ext.i_data + epos.offset
- adsize;
dptr = epos.bh->b_data +
sizeof(struct allocExtDesc);
memcpy(dptr, sptr, adsize);
epos.offset = sizeof(struct allocExtDesc) +
adsize;
} else {
loffset = epos.offset + adsize;
aed->lengthAllocDescs = cpu_to_le32(0);
if (oepos.bh) {
sptr = oepos.bh->b_data + epos.offset;
aed = (struct allocExtDesc *)
oepos.bh->b_data;
le32_add_cpu(&aed->lengthAllocDescs,
adsize);
} else {
sptr = iinfo->i_ext.i_data +
epos.offset;
iinfo->i_lenAlloc += adsize;
mark_inode_dirty(table);
}
epos.offset = sizeof(struct allocExtDesc);
}
if (sbi->s_udfrev >= 0x0200)
udf_new_tag(epos.bh->b_data, TAG_IDENT_AED,
3, 1, epos.block.logicalBlockNum,
sizeof(struct tag));
else
udf_new_tag(epos.bh->b_data, TAG_IDENT_AED,
2, 1, epos.block.logicalBlockNum,
sizeof(struct tag));
switch (iinfo->i_alloc_type) {
case ICBTAG_FLAG_AD_SHORT:
sad = (struct short_ad *)sptr;
sad->extLength = cpu_to_le32(
EXT_NEXT_EXTENT_ALLOCDECS |
sb->s_blocksize);
sad->extPosition =
cpu_to_le32(epos.block.logicalBlockNum);
break;
case ICBTAG_FLAG_AD_LONG:
lad = (struct long_ad *)sptr;
lad->extLength = cpu_to_le32(
EXT_NEXT_EXTENT_ALLOCDECS |
sb->s_blocksize);
lad->extLocation =
cpu_to_lelb(epos.block);
break;
}
if (oepos.bh) {
udf_update_tag(oepos.bh->b_data, loffset);
mark_buffer_dirty(oepos.bh);
} else {
mark_inode_dirty(table);
}
}
/* It's possible that stealing the block emptied the extent */
if (elen) {
udf_write_aext(table, &epos, &eloc, elen, 1);
if (!epos.bh) {
iinfo->i_lenAlloc += adsize;
mark_inode_dirty(table);
} else {
aed = (struct allocExtDesc *)epos.bh->b_data;
le32_add_cpu(&aed->lengthAllocDescs, adsize);
udf_update_tag(epos.bh->b_data, epos.offset);
mark_buffer_dirty(epos.bh);
}
}
}
brelse(epos.bh);
brelse(oepos.bh);
error_return:
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 elen, adsize;
struct kernel_lb_addr eloc;
struct extent_position epos;
int8_t etype = -1;
struct udf_inode_info *iinfo;
if (first_block >= sbi->s_partmaps[partition].s_partition_len)
return 0;
iinfo = UDF_I(table);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(struct long_ad);
else
return 0;
mutex_lock(&sbi->s_alloc_mutex);
epos.offset = sizeof(struct unallocSpaceEntry);
epos.block = iinfo->i_location;
epos.bh = NULL;
eloc.logicalBlockNum = 0xFFFFFFFF;
while (first_block != eloc.logicalBlockNum &&
(etype = udf_next_aext(table, &epos, &eloc, &elen, 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) {
epos.offset -= adsize;
alloc_count = (elen >> sb->s_blocksize_bits);
if (inode && vfs_dq_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, &epos, &eloc,
(etype << 30) | elen, 1);
} else
udf_delete_aext(table, epos, eloc,
(etype << 30) | elen);
} else {
alloc_count = 0;
}
brelse(epos.bh);
if (alloc_count)
udf_add_free_space(sb, partition, -alloc_count);
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 elen, goal_elen = 0;
struct kernel_lb_addr eloc, uninitialized_var(goal_eloc);
struct extent_position epos, goal_epos;
int8_t etype;
struct udf_inode_info *iinfo = UDF_I(table);
*err = -ENOSPC;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(struct long_ad);
else
return newblock;
mutex_lock(&sbi->s_alloc_mutex);
if (goal >= sbi->s_partmaps[partition].s_partition_len)
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.
*/
epos.offset = sizeof(struct unallocSpaceEntry);
epos.block = iinfo->i_location;
epos.bh = goal_epos.bh = NULL;
while (spread &&
(etype = udf_next_aext(table, &epos, &eloc, &elen, 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_epos.bh != epos.bh) {
brelse(goal_epos.bh);
goal_epos.bh = epos.bh;
get_bh(goal_epos.bh);
}
goal_epos.block = epos.block;
goal_epos.offset = epos.offset - adsize;
goal_eloc = eloc;
goal_elen = (etype << 30) | elen;
}
}
brelse(epos.bh);
if (spread == 0xFFFFFFFF) {
brelse(goal_epos.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 && vfs_dq_alloc_block(inode, 1)) {
brelse(goal_epos.bh);
mutex_unlock(&sbi->s_alloc_mutex);
*err = -EDQUOT;
return 0;
}
if (goal_elen)
udf_write_aext(table, &goal_epos, &goal_eloc, goal_elen, 1);
else
udf_delete_aext(table, goal_epos, goal_eloc, goal_elen);
brelse(goal_epos.bh);
udf_add_free_space(sb, partition, -1);
mutex_unlock(&sbi->s_alloc_mutex);
*err = 0;
return newblock;
}
void udf_free_blocks(struct super_block *sb, struct inode *inode,
struct kernel_lb_addr *bloc, uint32_t offset,
uint32_t count)
{
uint16_t partition = bloc->partitionReferenceNum;
struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) {
udf_bitmap_free_blocks(sb, inode, map->s_uspace.s_bitmap,
bloc, offset, count);
} else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) {
udf_table_free_blocks(sb, inode, map->s_uspace.s_table,
bloc, offset, count);
} else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) {
udf_bitmap_free_blocks(sb, inode, map->s_fspace.s_bitmap,
bloc, offset, count);
} else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) {
udf_table_free_blocks(sb, inode, map->s_fspace.s_table,
bloc, offset, count);
}
}
inline int udf_prealloc_blocks(struct super_block *sb,
struct inode *inode,
uint16_t partition, uint32_t first_block,
uint32_t block_count)
{
struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
return udf_bitmap_prealloc_blocks(sb, inode,
map->s_uspace.s_bitmap,
partition, first_block,
block_count);
else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
return udf_table_prealloc_blocks(sb, inode,
map->s_uspace.s_table,
partition, first_block,
block_count);
else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
return udf_bitmap_prealloc_blocks(sb, inode,
map->s_fspace.s_bitmap,
partition, first_block,
block_count);
else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
return udf_table_prealloc_blocks(sb, inode,
map->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)
{
struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
return udf_bitmap_new_block(sb, inode,
map->s_uspace.s_bitmap,
partition, goal, err);
else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
return udf_table_new_block(sb, inode,
map->s_uspace.s_table,
partition, goal, err);
else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
return udf_bitmap_new_block(sb, inode,
map->s_fspace.s_bitmap,
partition, goal, err);
else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
return udf_table_new_block(sb, inode,
map->s_fspace.s_table,
partition, goal, err);
else {
*err = -EIO;
return 0;
}
}

214
kernel/fs/udf/dir.c Normal file
View File

@@ -0,0 +1,214 @@
/*
* 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"
static int do_udf_readdir(struct inode *dir, struct file *filp,
filldir_t filldir, void *dirent)
{
struct udf_fileident_bh fibh = { .sbh = NULL, .ebh = NULL};
struct fileIdentDesc *fi = NULL;
struct fileIdentDesc cfi;
int block, iblock;
loff_t nf_pos = (filp->f_pos - 1) << 2;
int flen;
char *fname = NULL;
char *nameptr;
uint16_t liu;
uint8_t lfi;
loff_t size = udf_ext0_offset(dir) + dir->i_size;
struct buffer_head *tmp, *bha[16];
struct kernel_lb_addr eloc;
uint32_t elen;
sector_t offset;
int i, num, ret = 0;
unsigned int dt_type;
struct extent_position epos = { NULL, 0, {0, 0} };
struct udf_inode_info *iinfo;
if (nf_pos >= size)
goto out;
fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
if (!fname) {
ret = -ENOMEM;
goto out;
}
if (nf_pos == 0)
nf_pos = udf_ext0_offset(dir);
fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1);
iinfo = UDF_I(dir);
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits,
&epos, &eloc, &elen, &offset)
!= (EXT_RECORDED_ALLOCATED >> 30)) {
ret = -ENOENT;
goto out;
}
block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
epos.offset -= sizeof(struct short_ad);
else if (iinfo->i_alloc_type ==
ICBTAG_FLAG_AD_LONG)
epos.offset -= sizeof(struct long_ad);
} else {
offset = 0;
}
if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
ret = -EIO;
goto out;
}
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]);
}
}
}
while (nf_pos < size) {
filp->f_pos = (nf_pos >> 2) + 1;
fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
&elen, &offset);
if (!fi)
goto out;
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 {
struct 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 && filldir(dirent, fname, flen, filp->f_pos,
iblock, dt_type) < 0)
goto out;
} /* end while */
filp->f_pos = (nf_pos >> 2) + 1;
out:
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
brelse(fibh.sbh);
brelse(epos.bh);
kfree(fname);
return ret;
}
static 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;
}
/* readdir and lookup functions */
const struct file_operations udf_dir_operations = {
.read = generic_read_dir,
.readdir = udf_readdir,
.ioctl = udf_ioctl,
.fsync = simple_fsync,
};

241
kernel/fs/udf/directory.c Normal file
View File

@@ -0,0 +1,241 @@
/*
* 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>
struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
struct udf_fileident_bh *fibh,
struct fileIdentDesc *cfi,
struct extent_position *epos,
struct kernel_lb_addr *eloc, uint32_t *elen,
sector_t *offset)
{
struct fileIdentDesc *fi;
int i, num, block;
struct buffer_head *tmp, *bha[16];
struct udf_inode_info *iinfo = UDF_I(dir);
fibh->soffset = fibh->eoffset;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
fi = udf_get_fileident(iinfo->i_ext.i_data -
(iinfo->i_efe ?
sizeof(struct extendedFileEntry) :
sizeof(struct fileEntry)),
dir->i_sb->s_blocksize,
&(fibh->eoffset));
if (!fi)
return NULL;
*nf_pos += fibh->eoffset - fibh->soffset;
memcpy((uint8_t *)cfi, (uint8_t *)fi,
sizeof(struct fileIdentDesc));
return fi;
}
if (fibh->eoffset == dir->i_sb->s_blocksize) {
int lextoffset = epos->offset;
unsigned char blocksize_bits = dir->i_sb->s_blocksize_bits;
if (udf_next_aext(dir, epos, eloc, elen, 1) !=
(EXT_RECORDED_ALLOCATED >> 30))
return NULL;
block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
(*offset)++;
if ((*offset << blocksize_bits) >= *elen)
*offset = 0;
else
epos->offset = lextoffset;
brelse(fibh->sbh);
fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
if (!fibh->sbh)
return NULL;
fibh->soffset = fibh->eoffset = 0;
if (!(*offset & ((16 >> (blocksize_bits - 9)) - 1))) {
i = 16 >> (blocksize_bits - 9);
if (i + *offset > (*elen >> blocksize_bits))
i = (*elen >> 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) {
brelse(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;
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 = epos->offset;
if (udf_next_aext(dir, epos, eloc, elen, 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
epos->offset = lextoffset;
fibh->soffset -= dir->i_sb->s_blocksize;
fibh->eoffset -= dir->i_sb->s_blocksize;
fibh->ebh = udf_tread(dir->i_sb, block);
if (!fibh->ebh)
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);
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 (fi->descTag.tagIdent != cpu_to_le16(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;
}
struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset,
int inc)
{
struct short_ad *sa;
if ((!ptr) || (!offset)) {
printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n");
return NULL;
}
if ((*offset + sizeof(struct short_ad)) > maxoffset)
return NULL;
else {
sa = (struct short_ad *)ptr;
if (sa->extLength == 0)
return NULL;
}
if (inc)
*offset += sizeof(struct short_ad);
return sa;
}
struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc)
{
struct long_ad *la;
if ((!ptr) || (!offset)) {
printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n");
return NULL;
}
if ((*offset + sizeof(struct long_ad)) > maxoffset)
return NULL;
else {
la = (struct long_ad *)ptr;
if (la->extLength == 0)
return NULL;
}
if (inc)
*offset += sizeof(struct long_ad);
return la;
}

796
kernel/fs/udf/ecma_167.h Normal file
View File

@@ -0,0 +1,796 @@
/*
* 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) */
struct charspec {
uint8_t charSetType;
uint8_t charSetInfo[63];
} __attribute__ ((packed));
/* 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) */
struct timestamp {
__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));
/* 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) */
struct regid {
uint8_t flags;
uint8_t ident[23];
uint8_t identSuffix[8];
} __attribute__ ((packed));
/* 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;
struct regid archType;
struct regid bootIdent;
__le32 bootExtLocation;
__le32 bootExtLength;
__le64 loadAddress;
__le64 startAddress;
struct 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) */
struct extent_ad {
__le32 extLength;
__le32 extLocation;
} __attribute__ ((packed));
struct kernel_extent_ad {
uint32_t extLength;
uint32_t extLocation;
};
/* Descriptor Tag (ECMA 167r3 3/7.2) */
struct tag {
__le16 tagIdent;
__le16 descVersion;
uint8_t tagChecksum;
uint8_t reserved;
__le16 tagSerialNum;
__le16 descCRC;
__le16 descCRCLength;
__le32 tagLocation;
} __attribute__ ((packed));
/* 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 {
struct tag descTag;
__le32 volDescSeqNum;
__le32 primaryVolDescNum;
dstring volIdent[32];
__le16 volSeqNum;
__le16 maxVolSeqNum;
__le16 interchangeLvl;
__le16 maxInterchangeLvl;
__le32 charSetList;
__le32 maxCharSetList;
dstring volSetIdent[128];
struct charspec descCharSet;
struct charspec explanatoryCharSet;
struct extent_ad volAbstract;
struct extent_ad volCopyright;
struct regid appIdent;
struct timestamp recordingDateAndTime;
struct 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 {
struct tag descTag;
struct extent_ad mainVolDescSeqExt;
struct extent_ad reserveVolDescSeqExt;
uint8_t reserved[480];
} __attribute__ ((packed));
/* Volume Descriptor Pointer (ECMA 167r3 3/10.3) */
struct volDescPtr {
struct tag descTag;
__le32 volDescSeqNum;
struct extent_ad nextVolDescSeqExt;
uint8_t reserved[484];
} __attribute__ ((packed));
/* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) */
struct impUseVolDesc {
struct tag descTag;
__le32 volDescSeqNum;
struct regid impIdent;
uint8_t impUse[460];
} __attribute__ ((packed));
/* Partition Descriptor (ECMA 167r3 3/10.5) */
struct partitionDesc {
struct tag descTag;
__le32 volDescSeqNum;
__le16 partitionFlags;
__le16 partitionNumber;
struct regid partitionContents;
uint8_t partitionContentsUse[128];
__le32 accessType;
__le32 partitionStartingLocation;
__le32 partitionLength;
struct 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 {
struct tag descTag;
__le32 volDescSeqNum;
struct charspec descCharSet;
dstring logicalVolIdent[128];
__le32 logicalBlockSize;
struct regid domainIdent;
uint8_t logicalVolContentsUse[16];
__le32 mapTableLength;
__le32 numPartitionMaps;
struct regid impIdent;
uint8_t impUse[128];
struct 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 {
struct tag descTag;
__le32 volDescSeqNum;
__le32 numAllocDescs;
struct extent_ad allocDescs[0];
} __attribute__ ((packed));
/* Terminating Descriptor (ECMA 167r3 3/10.9) */
struct terminatingDesc {
struct tag descTag;
uint8_t reserved[496];
} __attribute__ ((packed));
/* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) */
struct logicalVolIntegrityDesc {
struct tag descTag;
struct timestamp recordingDateAndTime;
__le32 integrityType;
struct 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) */
struct lb_addr {
__le32 logicalBlockNum;
__le16 partitionReferenceNum;
} __attribute__ ((packed));
/* ... and its in-core analog */
struct kernel_lb_addr {
uint32_t logicalBlockNum;
uint16_t partitionReferenceNum;
};
/* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
struct short_ad {
__le32 extLength;
__le32 extPosition;
} __attribute__ ((packed));
/* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */
struct long_ad {
__le32 extLength;
struct lb_addr extLocation;
uint8_t impUse[6];
} __attribute__ ((packed));
struct kernel_long_ad {
uint32_t extLength;
struct kernel_lb_addr extLocation;
uint8_t impUse[6];
};
/* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */
struct ext_ad {
__le32 extLength;
__le32 recordedLength;
__le32 informationLength;
struct lb_addr extLocation;
} __attribute__ ((packed));
struct kernel_ext_ad {
uint32_t extLength;
uint32_t recordedLength;
uint32_t informationLength;
struct kernel_lb_addr extLocation;
};
/* 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 {
struct tag descTag;
struct timestamp recordingDateAndTime;
__le16 interchangeLvl;
__le16 maxInterchangeLvl;
__le32 charSetList;
__le32 maxCharSetList;
__le32 fileSetNum;
__le32 fileSetDescNum;
struct charspec logicalVolIdentCharSet;
dstring logicalVolIdent[128];
struct charspec fileSetCharSet;
dstring fileSetIdent[32];
dstring copyrightFileIdent[32];
dstring abstractFileIdent[32];
struct long_ad rootDirectoryICB;
struct regid domainIdent;
struct long_ad nextExt;
struct long_ad streamDirectoryICB;
uint8_t reserved[32];
} __attribute__ ((packed));
/* Partition Header Descriptor (ECMA 167r3 4/14.3) */
struct partitionHeaderDesc {
struct short_ad unallocSpaceTable;
struct short_ad unallocSpaceBitmap;
struct short_ad partitionIntegrityTable;
struct short_ad freedSpaceTable;
struct short_ad freedSpaceBitmap;
uint8_t reserved[88];
} __attribute__ ((packed));
/* File Identifier Descriptor (ECMA 167r3 4/14.4) */
struct fileIdentDesc {
struct tag descTag;
__le16 fileVersionNum;
uint8_t fileCharacteristics;
uint8_t lengthFileIdent;
struct 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 {
struct tag descTag;
__le32 previousAllocExtLocation;
__le32 lengthAllocDescs;
} __attribute__ ((packed));
/* ICB Tag (ECMA 167r3 4/14.6) */
struct icbtag {
__le32 priorRecordedNumDirectEntries;
__le16 strategyType;
__le16 strategyParameter;
__le16 numEntries;
uint8_t reserved;
uint8_t fileType;
struct lb_addr parentICBLocation;
__le16 flags;
} __attribute__ ((packed));
/* 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 {
struct tag descTag;
struct icbtag icbTag;
struct long_ad indirectICB;
} __attribute__ ((packed));
/* Terminal Entry (ECMA 167r3 4/14.8) */
struct terminalEntry {
struct tag descTag;
struct icbtag icbTag;
} __attribute__ ((packed));
/* File Entry (ECMA 167r3 4/14.9) */
struct fileEntry {
struct tag descTag;
struct icbtag icbTag;
__le32 uid;
__le32 gid;
__le32 permissions;
__le16 fileLinkCount;
uint8_t recordFormat;
uint8_t recordDisplayAttr;
__le32 recordLength;
__le64 informationLength;
__le64 logicalBlocksRecorded;
struct timestamp accessTime;
struct timestamp modificationTime;
struct timestamp attrTime;
__le32 checkpoint;
struct long_ad extendedAttrICB;
struct 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 {
struct 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;
struct 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;
struct 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 {
struct tag descTag;
struct icbtag icbTag;
__le32 lengthAllocDescs;
uint8_t allocDescs[0];
} __attribute__ ((packed));
/* Space Bitmap Descriptor (ECMA 167r3 4/14.12) */
struct spaceBitmapDesc {
struct tag descTag;
__le32 numOfBits;
__le32 numOfBytes;
uint8_t bitmap[0];
} __attribute__ ((packed));
/* Partition Integrity Entry (ECMA 167r3 4/14.13) */
struct partitionIntegrityEntry {
struct tag descTag;
struct icbtag icbTag;
struct timestamp recordingDateAndTime;
uint8_t integrityType;
uint8_t reserved[175];
struct 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 {
struct tag descTag;
struct icbtag icbTag;
__le32 uid;
__le32 gid;
__le32 permissions;
__le16 fileLinkCount;
uint8_t recordFormat;
uint8_t recordDisplayAttr;
__le32 recordLength;
__le64 informationLength;
__le64 objectSize;
__le64 logicalBlocksRecorded;
struct timestamp accessTime;
struct timestamp modificationTime;
struct timestamp createTime;
struct timestamp attrTime;
__le32 checkpoint;
__le32 reserved;
struct long_ad extendedAttrICB;
struct long_ad streamDirectoryICB;
struct regid impIdent;
__le64 uniqueID;
__le32 lengthExtendedAttr;
__le32 lengthAllocDescs;
uint8_t extendedAttr[0];
uint8_t allocDescs[0];
} __attribute__ ((packed));
#endif /* _ECMA_167_H */

221
kernel/fs/udf/file.c Normal file
View File

@@ -0,0 +1,221 @@
/*
* 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 <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 <linux/aio.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;
struct udf_inode_info *iinfo = UDF_I(inode);
BUG_ON(!PageLocked(page));
kaddr = kmap(page);
memset(kaddr, 0, PAGE_CACHE_SIZE);
memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, 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;
struct udf_inode_info *iinfo = UDF_I(inode);
BUG_ON(!PageLocked(page));
kaddr = kmap(page);
memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr, inode->i_size);
mark_inode_dirty(inode);
SetPageUptodate(page);
kunmap(page);
unlock_page(page);
return 0;
}
static int udf_adinicb_write_end(struct file *file,
struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied,
struct page *page, void *fsdata)
{
struct inode *inode = mapping->host;
unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
char *kaddr;
struct udf_inode_info *iinfo = UDF_I(inode);
kaddr = kmap_atomic(page, KM_USER0);
memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr + offset,
kaddr + offset, copied);
kunmap_atomic(kaddr, KM_USER0);
return simple_write_end(file, mapping, pos, len, copied, page, fsdata);
}
const struct address_space_operations udf_adinicb_aops = {
.readpage = udf_adinicb_readpage,
.writepage = udf_adinicb_writepage,
.sync_page = block_sync_page,
.write_begin = simple_write_begin,
.write_end = udf_adinicb_write_end,
};
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;
struct udf_inode_info *iinfo = UDF_I(inode);
if (iinfo->i_alloc_type == 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 (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
udf_debug("udf_expand_adinicb: err=%d\n", err);
return err;
}
} else {
if (pos + count > inode->i_size)
iinfo->i_lenAlloc = pos + count;
else
iinfo->i_lenAlloc = inode->i_size;
}
}
retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
if (retval > 0)
mark_inode_dirty(inode);
return retval;
}
int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
long old_block, new_block;
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:
if (copy_to_user((char __user *)arg,
UDF_SB(inode->i_sb)->s_volume_ident, 32))
return -EFAULT;
else
return 0;
case UDF_RELOCATE_BLOCKS:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (get_user(old_block, (long __user *)arg))
return -EFAULT;
result = udf_relocate_blocks(inode->i_sb,
old_block, &new_block);
if (result == 0)
result = put_user(new_block, (long __user *)arg);
return result;
case UDF_GETEASIZE:
result = put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg);
break;
case UDF_GETEABLOCK:
result = copy_to_user((char __user *)arg,
UDF_I(inode)->i_ext.i_data,
UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0;
break;
}
return result;
}
static int udf_release_file(struct inode *inode, struct file *filp)
{
if (filp->f_mode & FMODE_WRITE) {
mutex_lock(&inode->i_mutex);
lock_kernel();
udf_discard_prealloc(inode);
unlock_kernel();
mutex_unlock(&inode->i_mutex);
}
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 = simple_fsync,
.splice_read = generic_file_splice_read,
.llseek = generic_file_llseek,
};
const struct inode_operations udf_file_inode_operations = {
.truncate = udf_truncate,
};

167
kernel/fs/udf/ialloc.c Normal file
View File

@@ -0,0 +1,167 @@
/*
* 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/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.
*/
vfs_dq_free_inode(inode);
vfs_dq_drop(inode);
clear_inode(inode);
mutex_lock(&sbi->s_alloc_mutex);
if (sbi->s_lvid_bh) {
struct logicalVolIntegrityDescImpUse *lvidiu =
udf_sb_lvidiu(sbi);
if (S_ISDIR(inode->i_mode))
le32_add_cpu(&lvidiu->numDirs, -1);
else
le32_add_cpu(&lvidiu->numFiles, -1);
udf_updated_lvid(sb);
}
mutex_unlock(&sbi->s_alloc_mutex);
udf_free_blocks(sb, NULL, &UDF_I(inode)->i_location, 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(dir)->i_location.logicalBlockNum;
struct udf_inode_info *iinfo;
struct udf_inode_info *dinfo = UDF_I(dir);
inode = new_inode(sb);
if (!inode) {
*err = -ENOMEM;
return NULL;
}
*err = -ENOSPC;
iinfo = UDF_I(inode);
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE)) {
iinfo->i_efe = 1;
if (UDF_VERS_USE_EXTENDED_FE > sbi->s_udfrev)
sbi->s_udfrev = UDF_VERS_USE_EXTENDED_FE;
iinfo->i_ext.i_data = kzalloc(inode->i_sb->s_blocksize -
sizeof(struct extendedFileEntry),
GFP_KERNEL);
} else {
iinfo->i_efe = 0;
iinfo->i_ext.i_data = kzalloc(inode->i_sb->s_blocksize -
sizeof(struct fileEntry),
GFP_KERNEL);
}
if (!iinfo->i_ext.i_data) {
iput(inode);
*err = -ENOMEM;
return NULL;
}
block = udf_new_block(dir->i_sb, NULL,
dinfo->i_location.partitionReferenceNum,
start, err);
if (*err) {
iput(inode);
return NULL;
}
mutex_lock(&sbi->s_alloc_mutex);
if (sbi->s_lvid_bh) {
struct logicalVolIntegrityDesc *lvid =
(struct logicalVolIntegrityDesc *)
sbi->s_lvid_bh->b_data;
struct logicalVolIntegrityDescImpUse *lvidiu =
udf_sb_lvidiu(sbi);
struct logicalVolHeaderDesc *lvhd;
uint64_t uniqueID;
lvhd = (struct logicalVolHeaderDesc *)
(lvid->logicalVolContentsUse);
if (S_ISDIR(mode))
le32_add_cpu(&lvidiu->numDirs, 1);
else
le32_add_cpu(&lvidiu->numFiles, 1);
iinfo->i_unique = uniqueID = le64_to_cpu(lvhd->uniqueID);
if (!(++uniqueID & 0x00000000FFFFFFFFUL))
uniqueID += 16;
lvhd->uniqueID = cpu_to_le64(uniqueID);
udf_updated_lvid(sb);
}
mutex_unlock(&sbi->s_alloc_mutex);
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();
}
iinfo->i_location.logicalBlockNum = block;
iinfo->i_location.partitionReferenceNum =
dinfo->i_location.partitionReferenceNum;
inode->i_ino = udf_get_lb_pblock(sb, &iinfo->i_location, 0);
inode->i_blocks = 0;
iinfo->i_lenEAttr = 0;
iinfo->i_lenAlloc = 0;
iinfo->i_use = 0;
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB))
iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
else
iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
inode->i_mtime = inode->i_atime = inode->i_ctime =
iinfo->i_crtime = current_fs_time(inode->i_sb);
insert_inode_hash(inode);
mark_inode_dirty(inode);
if (vfs_dq_alloc_inode(inode)) {
vfs_dq_drop(inode);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
*err = -EDQUOT;
return NULL;
}
*err = 0;
return inode;
}

2068
kernel/fs/udf/inode.c Normal file

File diff suppressed because it is too large Load Diff

67
kernel/fs/udf/lowlevel.c Normal file
View File

@@ -0,0 +1,67 @@
/*
* 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 "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);
if (i == 0) {
udf_debug("XA disk: %s, vol_desc_start=%d\n",
(ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
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;
/*
* ioctl failed or returned obviously bogus value?
* Try using the device size...
*/
if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock) ||
lblock == 0)
lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits;
if (lblock)
return lblock - 1;
else
return 0;
}

296
kernel/fs/udf/misc.c Normal file
View File

@@ -0,0 +1,296 @@
/*
* 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/buffer_head.h>
#include <linux/crc-itu-t.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;
struct udf_inode_info *iinfo = UDF_I(inode);
ea = iinfo->i_ext.i_data;
if (iinfo->i_lenEAttr) {
ad = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
} else {
ad = ea;
size += sizeof(struct extendedAttrHeaderDesc);
}
offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) -
iinfo->i_lenAlloc;
/* TODO - Check for FreeEASpace */
if (loc & 0x01 && offset >= size) {
struct extendedAttrHeaderDesc *eahd;
eahd = (struct extendedAttrHeaderDesc *)ea;
if (iinfo->i_lenAlloc)
memmove(&ad[size], ad, iinfo->i_lenAlloc);
if (iinfo->i_lenEAttr) {
/* check checksum/crc */
if (eahd->descTag.tagIdent !=
cpu_to_le16(TAG_IDENT_EAHD) ||
le32_to_cpu(eahd->descTag.tagLocation) !=
iinfo->i_location.logicalBlockNum)
return NULL;
} else {
struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
size -= sizeof(struct extendedAttrHeaderDesc);
iinfo->i_lenEAttr +=
sizeof(struct extendedAttrHeaderDesc);
eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
if (sbi->s_udfrev >= 0x0200)
eahd->descTag.descVersion = cpu_to_le16(3);
else
eahd->descTag.descVersion = cpu_to_le16(2);
eahd->descTag.tagSerialNum =
cpu_to_le16(sbi->s_serial_number);
eahd->descTag.tagLocation = cpu_to_le32(
iinfo->i_location.logicalBlockNum);
eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
}
offset = iinfo->i_lenEAttr;
if (type < 2048) {
if (le32_to_cpu(eahd->appAttrLocation) <
iinfo->i_lenEAttr) {
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) <
iinfo->i_lenEAttr) {
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) <
iinfo->i_lenEAttr) {
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(struct tag);
eahd->descTag.descCRCLength = cpu_to_le16(crclen);
eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd +
sizeof(struct tag), crclen));
eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag);
iinfo->i_lenEAttr += 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;
struct udf_inode_info *iinfo = UDF_I(inode);
ea = iinfo->i_ext.i_data;
if (iinfo->i_lenEAttr) {
struct extendedAttrHeaderDesc *eahd;
eahd = (struct extendedAttrHeaderDesc *)ea;
/* check checksum/crc */
if (eahd->descTag.tagIdent !=
cpu_to_le16(TAG_IDENT_EAHD) ||
le32_to_cpu(eahd->descTag.tagLocation) !=
iinfo->i_location.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 < iinfo->i_lenEAttr) {
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)
{
struct tag *tag_p;
struct buffer_head *bh = NULL;
/* Read the block */
if (block == 0xFFFFFFFF)
return NULL;
bh = udf_tread(sb, block);
if (!bh) {
udf_debug("block=%d, location=%d: read failed\n",
block, location);
return NULL;
}
tag_p = (struct 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, le32_to_cpu(tag_p->tagLocation), location);
goto error_out;
}
/* Verify the tag checksum */
if (udf_tag_checksum(tag_p) != tag_p->tagChecksum) {
printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
goto error_out;
}
/* Verify the tag version */
if (tag_p->descVersion != cpu_to_le16(0x0002U) &&
tag_p->descVersion != cpu_to_le16(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(struct tag) > sb->s_blocksize ||
le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
bh->b_data + sizeof(struct tag),
le16_to_cpu(tag_p->descCRCLength)))
return bh;
udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", block,
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,
struct 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_update_tag(char *data, int length)
{
struct tag *tptr = (struct tag *)data;
length -= sizeof(struct tag);
tptr->descCRCLength = cpu_to_le16(length);
tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(struct tag), length));
tptr->tagChecksum = udf_tag_checksum(tptr);
}
void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
uint32_t loc, int length)
{
struct tag *tptr = (struct 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);
}
u8 udf_tag_checksum(const struct tag *t)
{
u8 *data = (u8 *)t;
u8 checksum = 0;
int i;
for (i = 0; i < sizeof(struct tag); ++i)
if (i != 4) /* position of checksum */
checksum += data[i];
return checksum;
}

1368
kernel/fs/udf/namei.c Normal file

File diff suppressed because it is too large Load Diff

279
kernel/fs/udf/osta_udf.h Normal file
View File

@@ -0,0 +1,279 @@
/*
* 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 {
struct 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 {
struct charspec LVICharset;
dstring logicalVolIdent[128];
dstring LVInfo1[36];
dstring LVInfo2[36];
dstring LVInfo3[36];
struct regid impIdent;
uint8_t impUse[128];
} __attribute__ ((packed));
struct udfPartitionMap2 {
uint8_t partitionMapType;
uint8_t partitionMapLength;
uint8_t reserved1[2];
struct 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];
struct 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];
struct 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];
struct 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];
struct 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 {
struct tag descTag;
struct 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 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 */

324
kernel/fs/udf/partition.c Normal file
View File

@@ -0,0 +1,324 @@
/*
* 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/slab.h>
#include <linux/buffer_head.h>
uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
uint16_t partition, uint32_t offset)
{
struct udf_sb_info *sbi = UDF_SB(sb);
struct udf_part_map *map;
if (partition >= sbi->s_partitions) {
udf_debug("block=%d, partition=%d, offset=%d: "
"invalid partition\n", block, partition, offset);
return 0xFFFFFFFF;
}
map = &sbi->s_partmaps[partition];
if (map->s_partition_func)
return map->s_partition_func(sb, block, partition, offset);
else
return map->s_partition_root + 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;
struct udf_sb_info *sbi = UDF_SB(sb);
struct udf_part_map *map;
struct udf_virtual_data *vdata;
struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
map = &sbi->s_partmaps[partition];
vdata = &map->s_type_specific.s_virtual;
if (block > vdata->s_num_entries) {
udf_debug("Trying to access block beyond end of VAT "
"(%d max %d)\n", block, vdata->s_num_entries);
return 0xFFFFFFFF;
}
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
loc = le32_to_cpu(((__le32 *)(iinfo->i_ext.i_data +
vdata->s_start_offset))[block]);
goto translate;
}
index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
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 = vdata->s_start_offset / sizeof(uint32_t) + block;
}
loc = udf_block_map(sbi->s_vat_inode, newblock);
bh = sb_bread(sb, loc);
if (!bh) {
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]);
brelse(bh);
translate:
if (iinfo->i_location.partitionReferenceNum == partition) {
udf_debug("recursive call to udf_get_pblock!\n");
return 0xFFFFFFFF;
}
return udf_get_pblock(sb, loc,
iinfo->i_location.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;
struct udf_sb_info *sbi = UDF_SB(sb);
struct udf_part_map *map;
uint32_t packet;
struct udf_sparing_data *sdata;
map = &sbi->s_partmaps[partition];
sdata = &map->s_type_specific.s_sparing;
packet = (block + offset) & ~(sdata->s_packet_len - 1);
for (i = 0; i < 4; i++) {
if (sdata->s_spar_map[i] != NULL) {
st = (struct sparingTable *)
sdata->s_spar_map[i]->b_data;
break;
}
}
if (st) {
for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
struct sparingEntry *entry = &st->mapEntry[i];
u32 origLoc = le32_to_cpu(entry->origLocation);
if (origLoc >= 0xFFFFFFF0)
break;
else if (origLoc == packet)
return le32_to_cpu(entry->mappedLocation) +
((block + offset) &
(sdata->s_packet_len - 1));
else if (origLoc > packet)
break;
}
}
return map->s_partition_root + 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;
struct udf_sb_info *sbi = UDF_SB(sb);
u16 reallocationTableLen;
struct buffer_head *bh;
for (i = 0; i < sbi->s_partitions; i++) {
struct udf_part_map *map = &sbi->s_partmaps[i];
if (old_block > map->s_partition_root &&
old_block < map->s_partition_root + map->s_partition_len) {
sdata = &map->s_type_specific.s_sparing;
packet = (old_block - map->s_partition_root) &
~(sdata->s_packet_len - 1);
for (j = 0; j < 4; j++)
if (sdata->s_spar_map[j] != NULL) {
st = (struct sparingTable *)
sdata->s_spar_map[j]->b_data;
break;
}
if (!st)
return 1;
reallocationTableLen =
le16_to_cpu(st->reallocationTableLen);
for (k = 0; k < reallocationTableLen; k++) {
struct sparingEntry *entry = &st->mapEntry[k];
u32 origLoc = le32_to_cpu(entry->origLocation);
if (origLoc == 0xFFFFFFFF) {
for (; j < 4; j++) {
int len;
bh = sdata->s_spar_map[j];
if (!bh)
continue;
st = (struct sparingTable *)
bh->b_data;
entry->origLocation =
cpu_to_le32(packet);
len =
sizeof(struct sparingTable) +
reallocationTableLen *
sizeof(struct sparingEntry);
udf_update_tag((char *)st, len);
mark_buffer_dirty(bh);
}
*new_block = le32_to_cpu(
entry->mappedLocation) +
((old_block -
map->s_partition_root) &
(sdata->s_packet_len - 1));
return 0;
} else if (origLoc == packet) {
*new_block = le32_to_cpu(
entry->mappedLocation) +
((old_block -
map->s_partition_root) &
(sdata->s_packet_len - 1));
return 0;
} else if (origLoc > packet)
break;
}
for (l = k; l < reallocationTableLen; l++) {
struct sparingEntry *entry = &st->mapEntry[l];
u32 origLoc = le32_to_cpu(entry->origLocation);
if (origLoc != 0xFFFFFFFF)
continue;
for (; j < 4; j++) {
bh = sdata->s_spar_map[j];
if (!bh)
continue;
st = (struct sparingTable *)bh->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) +
reallocationTableLen *
sizeof(struct sparingEntry));
mark_buffer_dirty(bh);
}
*new_block =
le32_to_cpu(
st->mapEntry[k].mappedLocation) +
((old_block - map->s_partition_root) &
(sdata->s_packet_len - 1));
return 0;
}
return 1;
} /* if old_block */
}
if (i == sbi->s_partitions) {
/* outside of partitions */
/* for now, fail =) */
return 1;
}
return 0;
}
static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
uint16_t partition, uint32_t offset)
{
struct super_block *sb = inode->i_sb;
struct udf_part_map *map;
struct kernel_lb_addr eloc;
uint32_t elen;
sector_t ext_offset;
struct extent_position epos = {};
uint32_t phyblock;
if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) !=
(EXT_RECORDED_ALLOCATED >> 30))
phyblock = 0xFFFFFFFF;
else {
map = &UDF_SB(sb)->s_partmaps[partition];
/* map to sparable/physical partition desc */
phyblock = udf_get_pblock(sb, eloc.logicalBlockNum,
map->s_partition_num, ext_offset + offset);
}
brelse(epos.bh);
return phyblock;
}
uint32_t udf_get_pblock_meta25(struct super_block *sb, uint32_t block,
uint16_t partition, uint32_t offset)
{
struct udf_sb_info *sbi = UDF_SB(sb);
struct udf_part_map *map;
struct udf_meta_data *mdata;
uint32_t retblk;
struct inode *inode;
udf_debug("READING from METADATA\n");
map = &sbi->s_partmaps[partition];
mdata = &map->s_type_specific.s_metadata;
inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe;
/* We shouldn't mount such media... */
BUG_ON(!inode);
retblk = udf_try_read_meta(inode, block, partition, offset);
if (retblk == 0xFFFFFFFF) {
udf_warning(sb, __func__, "error reading from METADATA, "
"trying to read from MIRROR");
inode = mdata->s_mirror_fe;
if (!inode)
return 0xFFFFFFFF;
retblk = udf_try_read_meta(inode, block, partition, offset);
}
return retblk;
}

2293
kernel/fs/udf/super.c Normal file

File diff suppressed because it is too large Load Diff

118
kernel/fs/udf/symlink.c Normal file
View 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/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);
struct udf_inode_info *iinfo;
lock_kernel();
iinfo = UDF_I(inode);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
} 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);
brelse(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,
};

315
kernel/fs/udf/truncate.c Normal file
View File

@@ -0,0 +1,315 @@
/*
* 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/buffer_head.h>
#include "udf_i.h"
#include "udf_sb.h"
static void extent_trunc(struct inode *inode, struct extent_position *epos,
struct kernel_lb_addr *eloc, int8_t etype, uint32_t elen,
uint32_t nelen)
{
struct kernel_lb_addr neloc = {};
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, epos, &neloc, nelen, 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);
}
}
}
/*
* Truncate the last extent to match i_size. This function assumes
* that preallocation extent is already truncated.
*/
void udf_truncate_tail_extent(struct inode *inode)
{
struct extent_position epos = {};
struct kernel_lb_addr eloc;
uint32_t elen, nelen;
uint64_t lbcount = 0;
int8_t etype = -1, netype;
int adsize;
struct udf_inode_info *iinfo = UDF_I(inode);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
inode->i_size == iinfo->i_lenExtents)
return;
/* Are we going to delete the file anyway? */
if (inode->i_nlink == 0)
return;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(struct long_ad);
else
BUG();
/* Find the last extent in the file */
while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
etype = netype;
lbcount += elen;
if (lbcount > inode->i_size) {
if (lbcount - inode->i_size >= inode->i_sb->s_blocksize)
printk(KERN_WARNING
"udf_truncate_tail_extent(): Too long "
"extent after EOF in inode %u: i_size: "
"%Ld lbcount: %Ld extent %u+%u\n",
(unsigned)inode->i_ino,
(long long)inode->i_size,
(long long)lbcount,
(unsigned)eloc.logicalBlockNum,
(unsigned)elen);
nelen = elen - (lbcount - inode->i_size);
epos.offset -= adsize;
extent_trunc(inode, &epos, &eloc, etype, elen, nelen);
epos.offset += adsize;
if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1)
printk(KERN_ERR "udf_truncate_tail_extent(): "
"Extent after EOF in inode %u.\n",
(unsigned)inode->i_ino);
break;
}
}
/* This inode entry is in-memory only and thus we don't have to mark
* the inode dirty */
iinfo->i_lenExtents = inode->i_size;
brelse(epos.bh);
}
void udf_discard_prealloc(struct inode *inode)
{
struct extent_position epos = { NULL, 0, {0, 0} };
struct kernel_lb_addr eloc;
uint32_t elen;
uint64_t lbcount = 0;
int8_t etype = -1, netype;
int adsize;
struct udf_inode_info *iinfo = UDF_I(inode);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
inode->i_size == iinfo->i_lenExtents)
return;
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(struct long_ad);
else
adsize = 0;
epos.block = iinfo->i_location;
/* Find the last extent in the file */
while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
etype = netype;
lbcount += elen;
}
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
epos.offset -= adsize;
lbcount -= elen;
extent_trunc(inode, &epos, &eloc, etype, elen, 0);
if (!epos.bh) {
iinfo->i_lenAlloc =
epos.offset -
udf_file_entry_alloc_offset(inode);
mark_inode_dirty(inode);
} else {
struct allocExtDesc *aed =
(struct allocExtDesc *)(epos.bh->b_data);
aed->lengthAllocDescs =
cpu_to_le32(epos.offset -
sizeof(struct allocExtDesc));
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
udf_update_tag(epos.bh->b_data, epos.offset);
else
udf_update_tag(epos.bh->b_data,
sizeof(struct allocExtDesc));
mark_buffer_dirty_inode(epos.bh, inode);
}
}
/* This inode entry is in-memory only and thus we don't have to mark
* the inode dirty */
iinfo->i_lenExtents = lbcount;
brelse(epos.bh);
}
static void udf_update_alloc_ext_desc(struct inode *inode,
struct extent_position *epos,
u32 lenalloc)
{
struct super_block *sb = inode->i_sb;
struct udf_sb_info *sbi = UDF_SB(sb);
struct allocExtDesc *aed = (struct allocExtDesc *) (epos->bh->b_data);
int len = sizeof(struct allocExtDesc);
aed->lengthAllocDescs = cpu_to_le32(lenalloc);
if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || sbi->s_udfrev >= 0x0201)
len += lenalloc;
udf_update_tag(epos->bh->b_data, len);
mark_buffer_dirty_inode(epos->bh, inode);
}
void udf_truncate_extents(struct inode *inode)
{
struct extent_position epos;
struct kernel_lb_addr eloc, neloc = {};
uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
int8_t etype;
struct super_block *sb = inode->i_sb;
sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset;
loff_t byte_offset;
int adsize;
struct udf_inode_info *iinfo = UDF_I(inode);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(struct short_ad);
else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(struct long_ad);
else
BUG();
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
byte_offset = (offset << sb->s_blocksize_bits) +
(inode->i_size & (sb->s_blocksize - 1));
if (etype != -1) {
epos.offset -= adsize;
extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset);
epos.offset += adsize;
if (byte_offset)
lenalloc = epos.offset;
else
lenalloc = epos.offset - adsize;
if (!epos.bh)
lenalloc -= udf_file_entry_alloc_offset(inode);
else
lenalloc -= sizeof(struct allocExtDesc);
while ((etype = udf_current_aext(inode, &epos, &eloc,
&elen, 0)) != -1) {
if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
udf_write_aext(inode, &epos, &neloc, nelen, 0);
if (indirect_ext_len) {
/* We managed to free all extents in the
* indirect extent - free it too */
BUG_ON(!epos.bh);
udf_free_blocks(sb, inode, &epos.block,
0, indirect_ext_len);
} else if (!epos.bh) {
iinfo->i_lenAlloc = lenalloc;
mark_inode_dirty(inode);
} else
udf_update_alloc_ext_desc(inode,
&epos, lenalloc);
brelse(epos.bh);
epos.offset = sizeof(struct allocExtDesc);
epos.block = eloc;
epos.bh = udf_tread(sb,
udf_get_lb_pblock(sb, &eloc, 0));
if (elen)
indirect_ext_len =
(elen + sb->s_blocksize - 1) >>
sb->s_blocksize_bits;
else
indirect_ext_len = 1;
} else {
extent_trunc(inode, &epos, &eloc, etype,
elen, 0);
epos.offset += adsize;
}
}
if (indirect_ext_len) {
BUG_ON(!epos.bh);
udf_free_blocks(sb, inode, &epos.block, 0,
indirect_ext_len);
} else if (!epos.bh) {
iinfo->i_lenAlloc = lenalloc;
mark_inode_dirty(inode);
} else
udf_update_alloc_ext_desc(inode, &epos, lenalloc);
} else if (inode->i_size) {
if (byte_offset) {
struct kernel_long_ad extent;
/*
* OK, there is not extent covering inode->i_size and
* no extent above inode->i_size => truncate is
* extending the file by 'offset' blocks.
*/
if ((!epos.bh &&
epos.offset ==
udf_file_entry_alloc_offset(inode)) ||
(epos.bh && epos.offset ==
sizeof(struct allocExtDesc))) {
/* File has no extents at all or has empty last
* indirect extent! Create a fake extent... */
extent.extLocation.logicalBlockNum = 0;
extent.extLocation.partitionReferenceNum = 0;
extent.extLength =
EXT_NOT_RECORDED_NOT_ALLOCATED;
} else {
epos.offset -= adsize;
etype = udf_next_aext(inode, &epos,
&extent.extLocation,
&extent.extLength, 0);
extent.extLength |= etype << 30;
}
udf_extend_file(inode, &epos, &extent,
offset +
((inode->i_size &
(sb->s_blocksize - 1)) != 0));
}
}
iinfo->i_lenExtents = inode->i_size;
brelse(epos.bh);
}

32
kernel/fs/udf/udf_i.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef _UDF_I_H
#define _UDF_I_H
struct udf_inode_info {
struct timespec i_crtime;
/* Physical address of inode */
struct kernel_lb_addr i_location;
__u64 i_unique;
__u32 i_lenEAttr;
__u32 i_lenAlloc;
__u64 i_lenExtents;
__u32 i_next_alloc_block;
__u32 i_next_alloc_goal;
unsigned i_alloc_type : 3;
unsigned i_efe : 1; /* extendedFileEntry */
unsigned i_use : 1; /* unallocSpaceEntry */
unsigned i_strat4096 : 1;
unsigned reserved : 26;
union {
struct short_ad *i_sad;
struct long_ad *i_lad;
__u8 *i_data;
} i_ext;
struct inode vfs_inode;
};
static inline struct udf_inode_info *UDF_I(struct inode *inode)
{
return list_entry(inode, struct udf_inode_info, vfs_inode);
}
#endif /* _UDF_I_H) */

168
kernel/fs/udf/udf_sb.h Normal file
View File

@@ -0,0 +1,168 @@
#ifndef __LINUX_UDF_SB_H
#define __LINUX_UDF_SB_H
#include <linux/mutex.h>
/* Since UDF 2.01 is ISO 13346 based... */
#define UDF_SUPER_MAGIC 0x15013346
#define UDF_MAX_READ_VERSION 0x0250
#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_FLAG_UID_SET 15
#define UDF_FLAG_GID_SET 16
#define UDF_FLAG_SESSION_SET 17
#define UDF_FLAG_LASTBLOCK_SET 18
#define UDF_FLAG_BLOCKSIZE_SET 19
#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
#define UDF_MAX_BLOCK_LOADED 8
#define UDF_TYPE1_MAP15 0x1511U
#define UDF_VIRTUAL_MAP15 0x1512U
#define UDF_VIRTUAL_MAP20 0x2012U
#define UDF_SPARABLE_MAP15 0x1522U
#define UDF_METADATA_MAP25 0x2511U
#define UDF_INVALID_MODE ((mode_t)-1)
#pragma pack(1) /* XXX(hch): Why? This file just defines in-core structures */
struct udf_meta_data {
__u32 s_meta_file_loc;
__u32 s_mirror_file_loc;
__u32 s_bitmap_file_loc;
__u32 s_alloc_unit_size;
__u16 s_align_unit_size;
__u8 s_dup_md_flag;
struct inode *s_metadata_fe;
struct inode *s_mirror_fe;
struct inode *s_bitmap_fe;
};
struct udf_sparing_data {
__u16 s_packet_len;
struct buffer_head *s_spar_map[4];
};
struct udf_virtual_data {
__u32 s_num_entries;
__u16 s_start_offset;
};
struct udf_bitmap {
__u32 s_extLength;
__u32 s_extPosition;
__u16 s_nr_groups;
struct buffer_head **s_block_bitmap;
};
struct udf_part_map {
union {
struct udf_bitmap *s_bitmap;
struct inode *s_table;
} s_uspace;
union {
struct udf_bitmap *s_bitmap;
struct inode *s_table;
} s_fspace;
__u32 s_partition_root;
__u32 s_partition_len;
__u16 s_partition_type;
__u16 s_partition_num;
union {
struct udf_sparing_data s_sparing;
struct udf_virtual_data s_virtual;
struct udf_meta_data s_metadata;
} s_type_specific;
__u32 (*s_partition_func)(struct super_block *, __u32, __u16, __u32);
__u16 s_volumeseqnum;
__u16 s_partition_flags;
};
#pragma pack()
struct udf_sb_info {
struct udf_part_map *s_partmaps;
__u8 s_volume_ident[32];
/* Overall info */
__u16 s_partitions;
__u16 s_partition;
/* Sector headers */
__s32 s_session;
__u32 s_anchor;
__u32 s_last_block;
struct buffer_head *s_lvid_bh;
/* Default permissions */
mode_t s_umask;
gid_t s_gid;
uid_t s_uid;
mode_t s_fmode;
mode_t s_dmode;
/* Root Info */
struct timespec s_record_time;
/* Fileset Info */
__u16 s_serial_number;
/* highest UDF revision we have recorded to this media */
__u16 s_udfrev;
/* Miscellaneous flags */
__u32 s_flags;
/* Encoding info */
struct nls_table *s_nls_map;
/* VAT inode */
struct inode *s_vat_inode;
struct mutex s_alloc_mutex;
/* Protected by s_alloc_mutex */
unsigned int s_lvid_dirty;
};
static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
{
return sb->s_fs_info;
}
struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi);
int udf_compute_nr_groups(struct super_block *sb, u32 partition);
#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) ) )
#endif /* __LINUX_UDF_SB_H */

243
kernel/fs/udf/udfdecl.h Normal file
View File

@@ -0,0 +1,243 @@
#ifndef __UDF_DECL_H
#define __UDF_DECL_H
#include "ecma_167.h"
#include "osta_udf.h"
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/buffer_head.h>
#include <linux/udf_fs_i.h>
#include "udf_sb.h"
#include "udfend.h"
#include "udf_i.h"
#define UDF_PREALLOCATE
#define UDF_DEFAULT_PREALLOC_BLOCKS 8
#undef UDFFS_DEBUG
#ifdef UDFFS_DEBUG
#define udf_debug(f, a...) \
do { \
printk(KERN_DEBUG "UDF-fs DEBUG %s:%d:%s: ", \
__FILE__, __LINE__, __func__); \
printk(f, ##a); \
} while (0)
#else
#define udf_debug(f, a...) /**/
#endif
#define udf_info(f, a...) \
printk(KERN_INFO "UDF-fs INFO " f, ##a);
#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
static inline size_t udf_file_entry_alloc_offset(struct inode *inode)
{
struct udf_inode_info *iinfo = UDF_I(inode);
if (iinfo->i_use)
return sizeof(struct unallocSpaceEntry);
else if (iinfo->i_efe)
return sizeof(struct extendedFileEntry) + iinfo->i_lenEAttr;
else
return sizeof(struct fileEntry) + iinfo->i_lenEAttr;
}
static inline size_t udf_ext0_offset(struct inode *inode)
{
if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
return udf_file_entry_alloc_offset(inode);
else
return 0;
}
/* computes tag checksum */
u8 udf_tag_checksum(const struct tag *t);
struct dentry;
struct inode;
struct task_struct;
struct buffer_head;
struct super_block;
extern const struct export_operations udf_export_ops;
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 {
struct tag descTag;
__le32 volDescSeqNum;
};
struct ustr {
uint8_t u_cmpID;
uint8_t u_name[UDF_NAME_LEN - 2];
uint8_t u_len;
};
struct extent_position {
struct buffer_head *bh;
uint32_t offset;
struct kernel_lb_addr block;
};
/* super.c */
extern void udf_warning(struct super_block *, const char *, const char *, ...);
static inline void udf_updated_lvid(struct super_block *sb)
{
struct buffer_head *bh = UDF_SB(sb)->s_lvid_bh;
BUG_ON(!bh);
WARN_ON_ONCE(((struct logicalVolIntegrityDesc *)
bh->b_data)->integrityType !=
cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN));
sb->s_dirt = 1;
UDF_SB(sb)->s_lvid_dirty = 1;
}
/* 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 *, struct 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 *, sector_t);
extern int udf_extend_file(struct inode *, struct extent_position *,
struct kernel_long_ad *, sector_t);
extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
struct kernel_lb_addr *, uint32_t *, sector_t *);
extern int8_t udf_add_aext(struct inode *, struct extent_position *,
struct kernel_lb_addr *, uint32_t, int);
extern int8_t udf_write_aext(struct inode *, struct extent_position *,
struct kernel_lb_addr *, uint32_t, int);
extern int8_t udf_delete_aext(struct inode *, struct extent_position,
struct kernel_lb_addr, uint32_t);
extern int8_t udf_next_aext(struct inode *, struct extent_position *,
struct kernel_lb_addr *, uint32_t *, int);
extern int8_t udf_current_aext(struct inode *, struct extent_position *,
struct kernel_lb_addr *, uint32_t *, 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 *,
struct kernel_lb_addr *, uint32_t,
uint16_t *);
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 uint32_t udf_get_pblock_meta25(struct super_block *, uint32_t, uint16_t,
uint32_t);
extern int udf_relocate_blocks(struct super_block *, long, long *);
static inline uint32_t
udf_get_lb_pblock(struct super_block *sb, struct kernel_lb_addr *loc,
uint32_t offset)
{
return udf_get_pblock(sb, loc->logicalBlockNum,
loc->partitionReferenceNum, offset);
}
/* 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 *, const 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_truncate_tail_extent(struct inode *);
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 *,
struct 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 *);
/* directory.c */
extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *,
struct udf_fileident_bh *,
struct fileIdentDesc *,
struct extent_position *,
struct kernel_lb_addr *, uint32_t *,
sector_t *);
extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize,
int *offset);
extern struct long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int);
extern struct short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int);
/* udftime.c */
extern struct timespec *udf_disk_stamp_to_time(struct timespec *dest,
struct timestamp src);
extern struct timestamp *udf_time_to_disk_stamp(struct timestamp *dest, struct timespec src);
#endif /* __UDF_DECL_H */

77
kernel/fs/udf/udfend.h Normal file
View File

@@ -0,0 +1,77 @@
#ifndef __UDF_ENDIAN_H
#define __UDF_ENDIAN_H
#include <asm/byteorder.h>
#include <linux/string.h>
static inline struct kernel_lb_addr lelb_to_cpu(struct lb_addr in)
{
struct kernel_lb_addr out;
out.logicalBlockNum = le32_to_cpu(in.logicalBlockNum);
out.partitionReferenceNum = le16_to_cpu(in.partitionReferenceNum);
return out;
}
static inline struct lb_addr cpu_to_lelb(struct kernel_lb_addr in)
{
struct lb_addr out;
out.logicalBlockNum = cpu_to_le32(in.logicalBlockNum);
out.partitionReferenceNum = cpu_to_le16(in.partitionReferenceNum);
return out;
}
static inline struct short_ad lesa_to_cpu(struct short_ad in)
{
struct short_ad out;
out.extLength = le32_to_cpu(in.extLength);
out.extPosition = le32_to_cpu(in.extPosition);
return out;
}
static inline struct short_ad cpu_to_lesa(struct short_ad in)
{
struct short_ad out;
out.extLength = cpu_to_le32(in.extLength);
out.extPosition = cpu_to_le32(in.extPosition);
return out;
}
static inline struct kernel_long_ad lela_to_cpu(struct long_ad in)
{
struct kernel_long_ad out;
out.extLength = le32_to_cpu(in.extLength);
out.extLocation = lelb_to_cpu(in.extLocation);
return out;
}
static inline struct long_ad cpu_to_lela(struct kernel_long_ad in)
{
struct long_ad out;
out.extLength = cpu_to_le32(in.extLength);
out.extLocation = cpu_to_lelb(in.extLocation);
return out;
}
static inline struct kernel_extent_ad leea_to_cpu(struct extent_ad in)
{
struct kernel_extent_ad out;
out.extLength = le32_to_cpu(in.extLength);
out.extLocation = le32_to_cpu(in.extLocation);
return out;
}
#endif /* __UDF_ENDIAN_H */

171
kernel/fs/udf/udftime.c Normal file
View File

@@ -0,0 +1,171 @@
/* 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)
struct timespec *
udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
{
int yday;
u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone);
u16 year = le16_to_cpu(src.year);
uint8_t type = typeAndTimezone >> 12;
int16_t offset;
if (type == 1) {
offset = typeAndTimezone << 4;
/* sign extent offset */
offset = (offset >> 4);
if (offset == -2047) /* unspecified offset */
offset = 0;
} else
offset = 0;
if ((year < EPOCH_YEAR) ||
(year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) {
return NULL;
}
dest->tv_sec = year_seconds[year - EPOCH_YEAR];
dest->tv_sec -= offset * 60;
yday = ((__mon_yday[__isleap(year)][src.month - 1]) + src.day - 1);
dest->tv_sec += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second;
dest->tv_nsec = 1000 * (src.centiseconds * 10000 +
src.hundredsOfMicroseconds * 100 + src.microseconds);
return dest;
}
struct timestamp *
udf_time_to_disk_stamp(struct 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 = cpu_to_le16(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 = cpu_to_le16(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 */

492
kernel/fs/udf/unicode.c Normal file
View File

@@ -0,0 +1,492 @@
/*
* 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/crc-itu-t.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;
BUG_ON(size < 2);
usesize = min_t(size_t, ptr[size - 1], sizeof(dest->u_name));
usesize = min(usesize, size - 2);
dest->u_cmpID = ptr[0];
dest->u_len = usesize;
memcpy(dest->u_name, ptr + 1, usesize);
memset(dest->u_name + usesize, 0, sizeof(dest->u_name) - usesize);
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.
*
* 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, const struct ustr *ocu_i)
{
const uint8_t *ocu;
uint8_t cmp_id, ocu_len;
int i;
ocu_len = ocu_i->u_len;
if (ocu_len == 0) {
memset(utf_o, 0, sizeof(struct ustr));
return 0;
}
cmp_id = ocu_i->u_cmpID;
if (cmp_id != 8 && cmp_id != 16) {
memset(utf_o, 0, sizeof(struct ustr));
printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n",
cmp_id, ocu_i->u_name);
return 0;
}
ocu = ocu_i->u_name;
utf_o->u_len = 0;
for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
/* Expand OSTA compressed Unicode to Unicode */
uint32_t 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 (max_val == 0xffU) {
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,
const struct ustr *ocu_i)
{
const uint8_t *ocu;
uint8_t cmp_id, ocu_len;
int i, len;
ocu_len = ocu_i->u_len;
if (ocu_len == 0) {
memset(utf_o, 0, sizeof(struct ustr));
return 0;
}
cmp_id = ocu_i->u_cmpID;
if (cmp_id != 8 && cmp_id != 16) {
memset(utf_o, 0, sizeof(struct ustr));
printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n",
cmp_id, ocu_i->u_name);
return 0;
}
ocu = ocu_i->u_name;
utf_o->u_len = 0;
for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
/* Expand OSTA compressed Unicode to Unicode */
uint32_t c = ocu[i++];
if (cmp_id == 16)
c = (c << 8) | ocu[i++];
len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
UDF_NAME_LEN - utf_o->u_len);
/* Valid character? */
if (len >= 0)
utf_o->u_len += len;
else
utf_o->u_name[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)
{
int len;
unsigned 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)
continue;
/* Invalid character, deal with it */
if (len < 0) {
len = 1;
uni_char = '?';
}
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 = 0;
filename = kmalloc(sizeof(struct ustr), GFP_NOFS);
if (!filename)
return 0;
unifilename = kmalloc(sizeof(struct ustr), GFP_NOFS);
if (!unifilename)
goto out1;
if (udf_build_ustr_exact(unifilename, sname, flen))
goto out2;
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
if (!udf_CS0toUTF8(filename, unifilename)) {
udf_debug("Failed in udf_get_filename: sname = %s\n",
sname);
goto out2;
}
} 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);
goto out2;
}
} else
goto out2;
len = udf_translate_to_linux(dname, filename->u_name, filename->u_len,
unifilename->u_name, unifilename->u_len);
out2:
kfree(unifilename);
out1:
kfree(filename);
return len;
}
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)) {
namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN);
if (!namelen)
return 0;
} else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname,
&unifilename, UDF_NAME_LEN);
if (!namelen)
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 = crc_itu_t(0, fidName, fidNameLen);
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;
}