diff --git a/[refs] b/[refs] index 6a34bbf31159..5d9a8281c2dc 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 62429f434091586d54b37b8dd46076e7c08b27b9 +refs/heads/master: cf2a299e48cbeb6c942e1f765b92ca6058355f68 diff --git a/trunk/drivers/block/brd.c b/trunk/drivers/block/brd.c index 7bd76639544c..85364804364f 100644 --- a/trunk/drivers/block/brd.c +++ b/trunk/drivers/block/brd.c @@ -108,7 +108,7 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector) #ifndef CONFIG_BLK_DEV_XIP gfp_flags |= __GFP_HIGHMEM; #endif - page = alloc_page(gfp_flags); + page = alloc_page(GFP_NOIO | __GFP_HIGHMEM | __GFP_ZERO); if (!page) return NULL; diff --git a/trunk/drivers/hid/usbhid/hiddev.c b/trunk/drivers/hid/usbhid/hiddev.c index 5fc4019956ba..95cc192bc7af 100644 --- a/trunk/drivers/hid/usbhid/hiddev.c +++ b/trunk/drivers/hid/usbhid/hiddev.c @@ -393,6 +393,153 @@ static unsigned int hiddev_poll(struct file *file, poll_table *wait) /* * "ioctl" file op */ +static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg) +{ + struct hid_device *hid = hiddev->hid; + struct hiddev_report_info rinfo; + struct hiddev_usage_ref_multi *uref_multi = NULL; + struct hiddev_usage_ref *uref; + struct hid_report *report; + struct hid_field *field; + int i; + + uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); + if (!uref_multi) + return -ENOMEM; + uref = &uref_multi->uref; + if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { + if (copy_from_user(uref_multi, user_arg, + sizeof(*uref_multi))) + goto fault; + } else { + if (copy_from_user(uref, user_arg, sizeof(*uref))) + goto fault; + } + + switch (cmd) { + case HIDIOCGUCODE: + rinfo.report_type = uref->report_type; + rinfo.report_id = uref->report_id; + if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) + goto inval; + + if (uref->field_index >= report->maxfield) + goto inval; + + field = report->field[uref->field_index]; + if (uref->usage_index >= field->maxusage) + goto inval; + + uref->usage_code = field->usage[uref->usage_index].hid; + + if (copy_to_user(user_arg, uref, sizeof(*uref))) + goto fault; + + kfree(uref_multi); + return 0; + + default: + if (cmd != HIDIOCGUSAGE && + cmd != HIDIOCGUSAGES && + uref->report_type == HID_REPORT_TYPE_INPUT) + goto inval; + + if (uref->report_id == HID_REPORT_ID_UNKNOWN) { + field = hiddev_lookup_usage(hid, uref); + if (field == NULL) + goto inval; + } else { + rinfo.report_type = uref->report_type; + rinfo.report_id = uref->report_id; + if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) + goto inval; + + if (uref->field_index >= report->maxfield) + goto inval; + + field = report->field[uref->field_index]; + + if (cmd == HIDIOCGCOLLECTIONINDEX) { + if (uref->usage_index >= field->maxusage) + goto inval; + } else if (uref->usage_index >= field->report_count) + goto inval; + + else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && + (uref_multi->num_values > HID_MAX_MULTI_USAGES || + uref->usage_index + uref_multi->num_values > field->report_count)) + goto inval; + } + + switch (cmd) { + case HIDIOCGUSAGE: + uref->value = field->value[uref->usage_index]; + if (copy_to_user(user_arg, uref, sizeof(*uref))) + goto fault; + goto goodreturn; + + case HIDIOCSUSAGE: + field->value[uref->usage_index] = uref->value; + goto goodreturn; + + case HIDIOCGCOLLECTIONINDEX: + kfree(uref_multi); + return field->usage[uref->usage_index].collection_index; + case HIDIOCGUSAGES: + for (i = 0; i < uref_multi->num_values; i++) + uref_multi->values[i] = + field->value[uref->usage_index + i]; + if (copy_to_user(user_arg, uref_multi, + sizeof(*uref_multi))) + goto fault; + goto goodreturn; + case HIDIOCSUSAGES: + for (i = 0; i < uref_multi->num_values; i++) + field->value[uref->usage_index + i] = + uref_multi->values[i]; + goto goodreturn; + } + +goodreturn: + kfree(uref_multi); + return 0; +fault: + kfree(uref_multi); + return -EFAULT; +inval: + kfree(uref_multi); + return -EINVAL; + } +} + +static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg) +{ + struct hid_device *hid = hiddev->hid; + struct usb_device *dev = hid_to_usb_dev(hid); + int idx, len; + char *buf; + + if (get_user(idx, (int __user *)user_arg)) + return -EFAULT; + + if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL) + return -ENOMEM; + + if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) { + kfree(buf); + return -EINVAL; + } + + if (copy_to_user(user_arg+sizeof(int), buf, len+1)) { + kfree(buf); + return -EFAULT; + } + + kfree(buf); + + return len; +} + static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct hiddev_list *list = file->private_data; @@ -402,8 +549,6 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; - struct hiddev_usage_ref_multi *uref_multi = NULL; - struct hiddev_usage_ref *uref; struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; @@ -470,30 +615,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd } case HIDIOCGSTRING: - { - int idx, len; - char *buf; - - if (get_user(idx, (int __user *)arg)) - return -EFAULT; - - if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL) - return -ENOMEM; - - if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) { - kfree(buf); - return -EINVAL; - } - - if (copy_to_user(user_arg+sizeof(int), buf, len+1)) { - kfree(buf); - return -EFAULT; - } - - kfree(buf); - - return len; - } + return hiddev_ioctl_string(hiddev, cmd, user_arg); case HIDIOCINITREPORT: usbhid_init_reports(hid); @@ -578,121 +700,13 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd return 0; case HIDIOCGUCODE: - uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); - if (!uref_multi) - return -ENOMEM; - uref = &uref_multi->uref; - if (copy_from_user(uref, user_arg, sizeof(*uref))) - goto fault; - - rinfo.report_type = uref->report_type; - rinfo.report_id = uref->report_id; - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - goto inval; - - if (uref->field_index >= report->maxfield) - goto inval; - - field = report->field[uref->field_index]; - if (uref->usage_index >= field->maxusage) - goto inval; - - uref->usage_code = field->usage[uref->usage_index].hid; - - if (copy_to_user(user_arg, uref, sizeof(*uref))) - goto fault; - - kfree(uref_multi); - return 0; - + /* fall through */ case HIDIOCGUSAGE: case HIDIOCSUSAGE: case HIDIOCGUSAGES: case HIDIOCSUSAGES: case HIDIOCGCOLLECTIONINDEX: - uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL); - if (!uref_multi) - return -ENOMEM; - uref = &uref_multi->uref; - if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (copy_from_user(uref_multi, user_arg, - sizeof(*uref_multi))) - goto fault; - } else { - if (copy_from_user(uref, user_arg, sizeof(*uref))) - goto fault; - } - - if (cmd != HIDIOCGUSAGE && - cmd != HIDIOCGUSAGES && - uref->report_type == HID_REPORT_TYPE_INPUT) - goto inval; - - if (uref->report_id == HID_REPORT_ID_UNKNOWN) { - field = hiddev_lookup_usage(hid, uref); - if (field == NULL) - goto inval; - } else { - rinfo.report_type = uref->report_type; - rinfo.report_id = uref->report_id; - if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) - goto inval; - - if (uref->field_index >= report->maxfield) - goto inval; - - field = report->field[uref->field_index]; - - if (cmd == HIDIOCGCOLLECTIONINDEX) { - if (uref->usage_index >= field->maxusage) - goto inval; - } else if (uref->usage_index >= field->report_count) - goto inval; - - else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && - (uref_multi->num_values > HID_MAX_MULTI_USAGES || - uref->usage_index + uref_multi->num_values > field->report_count)) - goto inval; - } - - switch (cmd) { - case HIDIOCGUSAGE: - uref->value = field->value[uref->usage_index]; - if (copy_to_user(user_arg, uref, sizeof(*uref))) - goto fault; - goto goodreturn; - - case HIDIOCSUSAGE: - field->value[uref->usage_index] = uref->value; - goto goodreturn; - - case HIDIOCGCOLLECTIONINDEX: - kfree(uref_multi); - return field->usage[uref->usage_index].collection_index; - case HIDIOCGUSAGES: - for (i = 0; i < uref_multi->num_values; i++) - uref_multi->values[i] = - field->value[uref->usage_index + i]; - if (copy_to_user(user_arg, uref_multi, - sizeof(*uref_multi))) - goto fault; - goto goodreturn; - case HIDIOCSUSAGES: - for (i = 0; i < uref_multi->num_values; i++) - field->value[uref->usage_index + i] = - uref_multi->values[i]; - goto goodreturn; - } - -goodreturn: - kfree(uref_multi); - return 0; -fault: - kfree(uref_multi); - return -EFAULT; -inval: - kfree(uref_multi); - return -EINVAL; + return hiddev_ioctl_usage(hiddev, cmd, user_arg); case HIDIOCGCOLLECTIONINFO: if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) diff --git a/trunk/fs/Kconfig b/trunk/fs/Kconfig index 8b18a8758677..028ae38ecc52 100644 --- a/trunk/fs/Kconfig +++ b/trunk/fs/Kconfig @@ -689,7 +689,6 @@ config ZISOFS 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 diff --git a/trunk/fs/udf/Makefile b/trunk/fs/udf/Makefile index 0d4503f7446d..be845e7540ef 100644 --- a/trunk/fs/udf/Makefile +++ b/trunk/fs/udf/Makefile @@ -6,4 +6,4 @@ obj-$(CONFIG_UDF_FS) += udf.o udf-objs := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \ partition.o super.o truncate.o symlink.o fsync.o \ - directory.o misc.o udftime.o unicode.o + crc.o directory.o misc.o udftime.o unicode.o diff --git a/trunk/fs/udf/balloc.c b/trunk/fs/udf/balloc.c index 1b809bd494bd..f855dcbbdfb8 100644 --- a/trunk/fs/udf/balloc.c +++ b/trunk/fs/udf/balloc.c @@ -149,7 +149,8 @@ static bool udf_add_free_space(struct udf_sb_info *sbi, return false; lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data; - le32_add_cpu(&lvid->freeSpaceTable[partition], cnt); + lvid->freeSpaceTable[partition] = cpu_to_le32(le32_to_cpu( + lvid->freeSpaceTable[partition]) + cnt); return true; } @@ -588,8 +589,10 @@ static void udf_table_free_blocks(struct super_block *sb, sptr = oepos.bh->b_data + epos.offset; aed = (struct allocExtDesc *) oepos.bh->b_data; - le32_add_cpu(&aed->lengthAllocDescs, - adsize); + aed->lengthAllocDescs = + cpu_to_le32(le32_to_cpu( + aed->lengthAllocDescs) + + adsize); } else { sptr = iinfo->i_ext.i_data + epos.offset; @@ -642,7 +645,9 @@ static void udf_table_free_blocks(struct super_block *sb, mark_inode_dirty(table); } else { aed = (struct allocExtDesc *)epos.bh->b_data; - le32_add_cpu(&aed->lengthAllocDescs, adsize); + aed->lengthAllocDescs = + cpu_to_le32(le32_to_cpu( + aed->lengthAllocDescs) + adsize); udf_update_tag(epos.bh->b_data, epos.offset); mark_buffer_dirty(epos.bh); } diff --git a/trunk/fs/udf/crc.c b/trunk/fs/udf/crc.c new file mode 100644 index 000000000000..b1661296e786 --- /dev/null +++ b/trunk/fs/udf/crc.c @@ -0,0 +1,172 @@ +/* + * crc.c + * + * PURPOSE + * Routines to generate, calculate, and test a 16-bit CRC. + * + * DESCRIPTION + * The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories + * and Ned W. Rhodes of Software Systems Group. It has been published in + * "Design and Validation of Computer Protocols", Prentice Hall, + * Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4. + * + * Copyright is held by AT&T. + * + * AT&T gives permission for the free use of the CRC source code. + * + * COPYRIGHT + * This file is distributed under the terms of the GNU General Public + * License (GPL). Copies of the GPL can be obtained from: + * ftp://prep.ai.mit.edu/pub/gnu/GPL + * Each contributing author retains all rights to their own work. + */ + +#include "udfdecl.h" + +static uint16_t crc_table[256] = { + 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U, + 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU, + 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U, + 0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU, + 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U, + 0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU, + 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U, + 0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU, + 0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, + 0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU, + 0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U, + 0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU, + 0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U, + 0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U, + 0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U, + 0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U, + 0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU, + 0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, + 0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU, + 0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, + 0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU, + 0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, + 0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU, + 0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, + 0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU, + 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U, + 0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU, + 0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U, + 0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U, + 0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U, + 0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U, + 0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U +}; + +/* + * udf_crc + * + * PURPOSE + * Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial. + * + * DESCRIPTION + * The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory. + * The polynomial used is: x^16 + x^12 + x^15 + 1 + * + * PRE-CONDITIONS + * data Pointer to the data block. + * size Size of the data block. + * + * POST-CONDITIONS + * CRC of the data block. + * + * HISTORY + * July 21, 1997 - Andrew E. Mileski + * Adapted from OSTA-UDF(tm) 1.50 standard. + */ +uint16_t udf_crc(uint8_t *data, uint32_t size, uint16_t crc) +{ + while (size--) + crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8); + + return crc; +} + +/****************************************************************************/ +#if defined(TEST) + +/* + * PURPOSE + * Test udf_crc() + * + * HISTORY + * July 21, 1997 - Andrew E. Mileski + * Adapted from OSTA-UDF(tm) 1.50 standard. + */ + +unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U }; + +int main(void) +{ + unsigned short x; + + x = udf_crc(bytes, sizeof bytes); + printf("udf_crc: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U); + + return 0; +} + +#endif /* defined(TEST) */ + +/****************************************************************************/ +#if defined(GENERATE) + +/* + * PURPOSE + * Generate a table for fast 16-bit CRC calculations (any polynomial). + * + * DESCRIPTION + * The ITU-T V.41 polynomial is 010041. + * + * HISTORY + * July 21, 1997 - Andrew E. Mileski + * Adapted from OSTA-UDF(tm) 1.50 standard. + */ + +#include + +int main(int argc, char **argv) +{ + unsigned long crc, poly; + int n, i; + + /* Get the polynomial */ + sscanf(argv[1], "%lo", &poly); + if (poly & 0xffff0000U) { + fprintf(stderr, "polynomial is too large\en"); + exit(1); + } + + printf("/* CRC 0%o */\n", poly); + + /* Create a table */ + printf("static unsigned short crc_table[256] = {\n"); + for (n = 0; n < 256; n++) { + if (n % 8 == 0) + printf("\t"); + crc = n << 8; + for (i = 0; i < 8; i++) { + if (crc & 0x8000U) + crc = (crc << 1) ^ poly; + else + crc <<= 1; + crc &= 0xFFFFU; + } + if (n == 255) + printf("0x%04xU ", crc); + else + printf("0x%04xU, ", crc); + if (n % 8 == 7) + printf("\n"); + } + printf("};\n"); + + return 0; +} + +#endif /* defined(GENERATE) */ diff --git a/trunk/fs/udf/dir.c b/trunk/fs/udf/dir.c index 62dc270c69d1..8d8643ada199 100644 --- a/trunk/fs/udf/dir.c +++ b/trunk/fs/udf/dir.c @@ -39,13 +39,13 @@ 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 udf_fileident_bh fibh; 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 fname[UDF_NAME_LEN]; char *nameptr; uint16_t liu; uint8_t lfi; @@ -54,32 +54,23 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, kernel_lb_addr eloc; uint32_t elen; sector_t offset; - int i, num, ret = 0; + int i, num; 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; - } + return 0; 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; - } + if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { + fibh.sbh = fibh.ebh = NULL; + } else if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits, + &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) { 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) @@ -92,8 +83,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, } if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) { - ret = -EIO; - goto out; + brelse(epos.bh); + return -EIO; } if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) { @@ -114,6 +105,9 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, brelse(bha[i]); } } + } else { + brelse(epos.bh); + return -ENOENT; } while (nf_pos < size) { @@ -121,8 +115,13 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset); - if (!fi) - goto out; + if (!fi) { + if (fibh.sbh != fibh.ebh) + brelse(fibh.ebh); + brelse(fibh.sbh); + brelse(epos.bh); + return 0; + } liu = le16_to_cpu(cfi.lengthOfImpUse); lfi = cfi.lengthFileIdent; @@ -168,23 +167,53 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, dt_type = DT_UNKNOWN; } - if (flen && filldir(dirent, fname, flen, filp->f_pos, - iblock, dt_type) < 0) - goto out; + if (flen) { + if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) { + if (fibh.sbh != fibh.ebh) + brelse(fibh.ebh); + brelse(fibh.sbh); + brelse(epos.bh); + return 0; + } + } } /* 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; + return 0; } +/* + * udf_readdir + * + * PURPOSE + * Read a directory entry. + * + * DESCRIPTION + * Optional - sys_getdents() will return -ENOTDIR if this routine is not + * available. + * + * Refer to sys_getdents() in fs/readdir.c + * sys_getdents() -> . + * + * PRE-CONDITIONS + * filp Pointer to directory file. + * buf Pointer to directory entry buffer. + * filldir Pointer to filldir function. + * + * POST-CONDITIONS + * >=0 on success. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ + static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct inode *dir = filp->f_path.dentry->d_inode; diff --git a/trunk/fs/udf/ecma_167.h b/trunk/fs/udf/ecma_167.h index a0974df82b31..56387711589b 100644 --- a/trunk/fs/udf/ecma_167.h +++ b/trunk/fs/udf/ecma_167.h @@ -70,6 +70,19 @@ typedef struct { uint8_t microseconds; } __attribute__ ((packed)) timestamp; +typedef struct { + uint16_t typeAndTimezone; + int16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t centiseconds; + uint8_t hundredsOfMicroseconds; + uint8_t microseconds; +} __attribute__ ((packed)) kernel_timestamp; + /* Type and Time Zone (ECMA 167r3 1/7.3.1) */ #define TIMESTAMP_TYPE_MASK 0xF000 #define TIMESTAMP_TYPE_CUT 0x0000 diff --git a/trunk/fs/udf/file.c b/trunk/fs/udf/file.c index 0ed6e146a0d9..97c71ae7c689 100644 --- a/trunk/fs/udf/file.c +++ b/trunk/fs/udf/file.c @@ -27,6 +27,7 @@ #include "udfdecl.h" #include +#include #include #include #include /* memset */ @@ -143,6 +144,40 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, return retval; } +/* + * udf_ioctl + * + * PURPOSE + * Issue an ioctl. + * + * DESCRIPTION + * Optional - sys_ioctl() will return -ENOTTY if this routine is not + * available, and the ioctl cannot be handled without filesystem help. + * + * sys_ioctl() handles these ioctls that apply only to regular files: + * FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD + * These ioctls are also handled by sys_ioctl(): + * FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC + * All other ioctls are passed to the filesystem. + * + * Refer to sys_ioctl() in fs/ioctl.c + * sys_ioctl() -> . + * + * PRE-CONDITIONS + * inode Pointer to inode that ioctl was issued on. + * filp Pointer to file that ioctl was issued on. + * cmd The ioctl command. + * arg The ioctl argument [can be interpreted as a + * user-space pointer if desired]. + * + * POST-CONDITIONS + * Success (>=0) or an error code (<=0) that + * sys_ioctl() will return. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -190,6 +225,18 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return result; } +/* + * udf_release_file + * + * PURPOSE + * Called when all references to the file are closed + * + * DESCRIPTION + * Discard prealloced blocks + * + * HISTORY + * + */ static int udf_release_file(struct inode *inode, struct file *filp) { if (filp->f_mode & FMODE_WRITE) { diff --git a/trunk/fs/udf/ialloc.c b/trunk/fs/udf/ialloc.c index eb9cfa23dc3d..84360315aca2 100644 --- a/trunk/fs/udf/ialloc.c +++ b/trunk/fs/udf/ialloc.c @@ -21,6 +21,7 @@ #include "udfdecl.h" #include #include +#include #include #include @@ -46,9 +47,11 @@ void udf_free_inode(struct inode *inode) struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sbi); if (S_ISDIR(inode->i_mode)) - le32_add_cpu(&lvidiu->numDirs, -1); + lvidiu->numDirs = + cpu_to_le32(le32_to_cpu(lvidiu->numDirs) - 1); else - le32_add_cpu(&lvidiu->numFiles, -1); + lvidiu->numFiles = + cpu_to_le32(le32_to_cpu(lvidiu->numFiles) - 1); mark_buffer_dirty(sbi->s_lvid_bh); } @@ -102,9 +105,11 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) lvhd = (struct logicalVolHeaderDesc *) (lvid->logicalVolContentsUse); if (S_ISDIR(mode)) - le32_add_cpu(&lvidiu->numDirs, 1); + lvidiu->numDirs = + cpu_to_le32(le32_to_cpu(lvidiu->numDirs) + 1); else - le32_add_cpu(&lvidiu->numFiles, 1); + lvidiu->numFiles = + cpu_to_le32(le32_to_cpu(lvidiu->numFiles) + 1); iinfo->i_unique = uniqueID = le64_to_cpu(lvhd->uniqueID); if (!(++uniqueID & 0x00000000FFFFFFFFUL)) uniqueID += 16; diff --git a/trunk/fs/udf/inode.c b/trunk/fs/udf/inode.c index 6e74b117aaf0..24cfa55d0fdc 100644 --- a/trunk/fs/udf/inode.c +++ b/trunk/fs/udf/inode.c @@ -37,7 +37,6 @@ #include #include #include -#include #include "udf_i.h" #include "udf_sb.h" @@ -67,7 +66,22 @@ static void udf_update_extents(struct inode *, struct extent_position *); static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); - +/* + * udf_delete_inode + * + * PURPOSE + * Clean-up before the specified inode is destroyed. + * + * DESCRIPTION + * This routine is called when the kernel destroys an inode structure + * ie. when iput() finds i_count == 0. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + * + * Called at the last iput() if i_nlink is zero. + */ void udf_delete_inode(struct inode *inode) { truncate_inode_pages(&inode->i_data, 0); @@ -309,6 +323,9 @@ static int udf_get_block(struct inode *inode, sector_t block, lock_kernel(); + if (block < 0) + goto abort_negative; + iinfo = UDF_I(inode); if (block == iinfo->i_next_alloc_block + 1) { iinfo->i_next_alloc_block++; @@ -330,6 +347,10 @@ static int udf_get_block(struct inode *inode, sector_t block, abort: unlock_kernel(); return err; + +abort_negative: + udf_warning(inode->i_sb, "udf_get_block", "block < 0"); + goto abort; } static struct buffer_head *udf_getblk(struct inode *inode, long block, @@ -1095,36 +1116,42 @@ static void __udf_read_inode(struct inode *inode) fe = (struct fileEntry *)bh->b_data; if (fe->icbTag.strategyType == cpu_to_le16(4096)) { - struct buffer_head *ibh; + struct buffer_head *ibh = NULL, *nbh = NULL; + struct indirectEntry *ie; ibh = udf_read_ptagged(inode->i_sb, iinfo->i_location, 1, &ident); - if (ident == TAG_IDENT_IE && ibh) { - struct buffer_head *nbh = NULL; - kernel_lb_addr loc; - struct indirectEntry *ie; - - ie = (struct indirectEntry *)ibh->b_data; - loc = lelb_to_cpu(ie->indirectICB.extLocation); - - if (ie->indirectICB.extLength && - (nbh = udf_read_ptagged(inode->i_sb, loc, 0, - &ident))) { - if (ident == TAG_IDENT_FE || - ident == TAG_IDENT_EFE) { - memcpy(&iinfo->i_location, - &loc, - sizeof(kernel_lb_addr)); - brelse(bh); + if (ident == TAG_IDENT_IE) { + if (ibh) { + kernel_lb_addr loc; + ie = (struct indirectEntry *)ibh->b_data; + + loc = lelb_to_cpu(ie->indirectICB.extLocation); + + if (ie->indirectICB.extLength && + (nbh = udf_read_ptagged(inode->i_sb, loc, 0, + &ident))) { + if (ident == TAG_IDENT_FE || + ident == TAG_IDENT_EFE) { + memcpy(&iinfo->i_location, + &loc, + sizeof(kernel_lb_addr)); + brelse(bh); + brelse(ibh); + brelse(nbh); + __udf_read_inode(inode); + return; + } else { + brelse(nbh); + brelse(ibh); + } + } else { brelse(ibh); - brelse(nbh); - __udf_read_inode(inode); - return; } - brelse(nbh); } + } else { + brelse(ibh); } - brelse(ibh); } else if (fe->icbTag.strategyType != cpu_to_le16(4)) { printk(KERN_ERR "udf: unsupported strategy type: %d\n", le16_to_cpu(fe->icbTag.strategyType)); @@ -1141,6 +1168,8 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) { struct fileEntry *fe; struct extendedFileEntry *efe; + time_t convtime; + long convtime_usec; int offset; struct udf_sb_info *sbi = UDF_SB(inode->i_sb); struct udf_inode_info *iinfo = UDF_I(inode); @@ -1228,15 +1257,29 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << (inode->i_sb->s_blocksize_bits - 9); - if (!udf_disk_stamp_to_time(&inode->i_atime, fe->accessTime)) + if (udf_stamp_to_time(&convtime, &convtime_usec, + lets_to_cpu(fe->accessTime))) { + inode->i_atime.tv_sec = convtime; + inode->i_atime.tv_nsec = convtime_usec * 1000; + } else { inode->i_atime = sbi->s_record_time; + } - if (!udf_disk_stamp_to_time(&inode->i_mtime, - fe->modificationTime)) + if (udf_stamp_to_time(&convtime, &convtime_usec, + lets_to_cpu(fe->modificationTime))) { + inode->i_mtime.tv_sec = convtime; + inode->i_mtime.tv_nsec = convtime_usec * 1000; + } else { inode->i_mtime = sbi->s_record_time; + } - if (!udf_disk_stamp_to_time(&inode->i_ctime, fe->attrTime)) + if (udf_stamp_to_time(&convtime, &convtime_usec, + lets_to_cpu(fe->attrTime))) { + inode->i_ctime.tv_sec = convtime; + inode->i_ctime.tv_nsec = convtime_usec * 1000; + } else { inode->i_ctime = sbi->s_record_time; + } iinfo->i_unique = le64_to_cpu(fe->uniqueID); iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr); @@ -1246,18 +1289,37 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << (inode->i_sb->s_blocksize_bits - 9); - if (!udf_disk_stamp_to_time(&inode->i_atime, efe->accessTime)) + if (udf_stamp_to_time(&convtime, &convtime_usec, + lets_to_cpu(efe->accessTime))) { + inode->i_atime.tv_sec = convtime; + inode->i_atime.tv_nsec = convtime_usec * 1000; + } else { inode->i_atime = sbi->s_record_time; + } - if (!udf_disk_stamp_to_time(&inode->i_mtime, - efe->modificationTime)) + if (udf_stamp_to_time(&convtime, &convtime_usec, + lets_to_cpu(efe->modificationTime))) { + inode->i_mtime.tv_sec = convtime; + inode->i_mtime.tv_nsec = convtime_usec * 1000; + } else { inode->i_mtime = sbi->s_record_time; + } - if (!udf_disk_stamp_to_time(&iinfo->i_crtime, efe->createTime)) + if (udf_stamp_to_time(&convtime, &convtime_usec, + lets_to_cpu(efe->createTime))) { + iinfo->i_crtime.tv_sec = convtime; + iinfo->i_crtime.tv_nsec = convtime_usec * 1000; + } else { iinfo->i_crtime = sbi->s_record_time; + } - if (!udf_disk_stamp_to_time(&inode->i_ctime, efe->attrTime)) + if (udf_stamp_to_time(&convtime, &convtime_usec, + lets_to_cpu(efe->attrTime))) { + inode->i_ctime.tv_sec = convtime; + inode->i_ctime.tv_nsec = convtime_usec * 1000; + } else { inode->i_ctime = sbi->s_record_time; + } iinfo->i_unique = le64_to_cpu(efe->uniqueID); iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr); @@ -1276,7 +1338,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) case ICBTAG_FILE_TYPE_REALTIME: case ICBTAG_FILE_TYPE_REGULAR: case ICBTAG_FILE_TYPE_UNDEF: - case ICBTAG_FILE_TYPE_VAT20: if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) inode->i_data.a_ops = &udf_adinicb_aops; else @@ -1302,15 +1363,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) inode->i_op = &page_symlink_inode_operations; inode->i_mode = S_IFLNK | S_IRWXUGO; break; - case ICBTAG_FILE_TYPE_MAIN: - udf_debug("METADATA FILE-----\n"); - break; - case ICBTAG_FILE_TYPE_MIRROR: - udf_debug("METADATA MIRROR FILE-----\n"); - break; - case ICBTAG_FILE_TYPE_BITMAP: - udf_debug("METADATA BITMAP FILE-----\n"); - break; default: printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown " "file type=%d\n", inode->i_ino, @@ -1364,6 +1416,21 @@ static mode_t udf_convert_permissions(struct fileEntry *fe) return mode; } +/* + * udf_write_inode + * + * PURPOSE + * Write out the specified inode. + * + * DESCRIPTION + * This routine is called whenever an inode is synced. + * Currently this routine is just a placeholder. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ + int udf_write_inode(struct inode *inode, int sync) { int ret; @@ -1388,6 +1455,7 @@ static int udf_update_inode(struct inode *inode, int do_sync) uint32_t udfperms; uint16_t icbflags; uint16_t crclen; + kernel_timestamp cpu_time; int err = 0; struct udf_sb_info *sbi = UDF_SB(inode->i_sb); unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; @@ -1420,9 +1488,9 @@ static int udf_update_inode(struct inode *inode, int do_sync) iinfo->i_location. logicalBlockNum); use->descTag.descCRCLength = cpu_to_le16(crclen); - use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use + - sizeof(tag), - crclen)); + use->descTag.descCRC = cpu_to_le16(udf_crc((char *)use + + sizeof(tag), crclen, + 0)); use->descTag.tagChecksum = udf_tag_checksum(&use->descTag); mark_buffer_dirty(bh); @@ -1490,9 +1558,12 @@ static int udf_update_inode(struct inode *inode, int do_sync) (inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >> (blocksize_bits - 9)); - udf_time_to_disk_stamp(&fe->accessTime, inode->i_atime); - udf_time_to_disk_stamp(&fe->modificationTime, inode->i_mtime); - udf_time_to_disk_stamp(&fe->attrTime, inode->i_ctime); + if (udf_time_to_stamp(&cpu_time, inode->i_atime)) + fe->accessTime = cpu_to_lets(cpu_time); + if (udf_time_to_stamp(&cpu_time, inode->i_mtime)) + fe->modificationTime = cpu_to_lets(cpu_time); + if (udf_time_to_stamp(&cpu_time, inode->i_ctime)) + fe->attrTime = cpu_to_lets(cpu_time); memset(&(fe->impIdent), 0, sizeof(regid)); strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER); fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; @@ -1527,10 +1598,14 @@ static int udf_update_inode(struct inode *inode, int do_sync) iinfo->i_crtime.tv_nsec > inode->i_ctime.tv_nsec)) iinfo->i_crtime = inode->i_ctime; - udf_time_to_disk_stamp(&efe->accessTime, inode->i_atime); - udf_time_to_disk_stamp(&efe->modificationTime, inode->i_mtime); - udf_time_to_disk_stamp(&efe->createTime, iinfo->i_crtime); - udf_time_to_disk_stamp(&efe->attrTime, inode->i_ctime); + if (udf_time_to_stamp(&cpu_time, inode->i_atime)) + efe->accessTime = cpu_to_lets(cpu_time); + if (udf_time_to_stamp(&cpu_time, inode->i_mtime)) + efe->modificationTime = cpu_to_lets(cpu_time); + if (udf_time_to_stamp(&cpu_time, iinfo->i_crtime)) + efe->createTime = cpu_to_lets(cpu_time); + if (udf_time_to_stamp(&cpu_time, inode->i_ctime)) + efe->attrTime = cpu_to_lets(cpu_time); memset(&(efe->impIdent), 0, sizeof(regid)); strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER); @@ -1585,8 +1660,8 @@ static int udf_update_inode(struct inode *inode, int do_sync) crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc - sizeof(tag); fe->descTag.descCRCLength = cpu_to_le16(crclen); - fe->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)fe + sizeof(tag), - crclen)); + fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), + crclen, 0)); fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag); /* write the data blocks */ @@ -1703,7 +1778,9 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, if (epos->bh) { aed = (struct allocExtDesc *)epos->bh->b_data; - le32_add_cpu(&aed->lengthAllocDescs, adsize); + aed->lengthAllocDescs = + cpu_to_le32(le32_to_cpu( + aed->lengthAllocDescs) + adsize); } else { iinfo->i_lenAlloc += adsize; mark_inode_dirty(inode); @@ -1753,7 +1830,9 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, mark_inode_dirty(inode); } else { aed = (struct allocExtDesc *)epos->bh->b_data; - le32_add_cpu(&aed->lengthAllocDescs, adsize); + aed->lengthAllocDescs = + cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + + adsize); 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, @@ -1967,7 +2046,9 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, mark_inode_dirty(inode); } else { aed = (struct allocExtDesc *)oepos.bh->b_data; - le32_add_cpu(&aed->lengthAllocDescs, -(2 * adsize)); + aed->lengthAllocDescs = + cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - + (2 * adsize)); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) udf_update_tag(oepos.bh->b_data, @@ -1984,7 +2065,9 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, mark_inode_dirty(inode); } else { aed = (struct allocExtDesc *)oepos.bh->b_data; - le32_add_cpu(&aed->lengthAllocDescs, -adsize); + aed->lengthAllocDescs = + cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - + adsize); if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) udf_update_tag(oepos.bh->b_data, @@ -2012,6 +2095,11 @@ int8_t inode_bmap(struct inode *inode, sector_t block, int8_t etype; struct udf_inode_info *iinfo; + if (block < 0) { + printk(KERN_ERR "udf: inode_bmap: block < 0\n"); + return -1; + } + iinfo = UDF_I(inode); pos->offset = 0; pos->block = iinfo->i_location; diff --git a/trunk/fs/udf/lowlevel.c b/trunk/fs/udf/lowlevel.c index 703843f30ffd..579bae71e67e 100644 --- a/trunk/fs/udf/lowlevel.c +++ b/trunk/fs/udf/lowlevel.c @@ -23,6 +23,7 @@ #include #include +#include #include "udf_sb.h" unsigned int udf_get_last_session(struct super_block *sb) diff --git a/trunk/fs/udf/misc.c b/trunk/fs/udf/misc.c index 84bf0fd4a4f1..a1d6da0caf71 100644 --- a/trunk/fs/udf/misc.c +++ b/trunk/fs/udf/misc.c @@ -23,8 +23,8 @@ #include #include +#include #include -#include #include "udf_i.h" #include "udf_sb.h" @@ -136,8 +136,8 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size, /* rewrite CRC + checksum of eahd */ crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag); eahd->descTag.descCRCLength = cpu_to_le16(crclen); - eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd + - sizeof(tag), crclen)); + eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + + sizeof(tag), crclen, 0)); eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag); iinfo->i_lenEAttr += size; return (struct genericFormat *)&ea[offset]; @@ -204,15 +204,16 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, { tag *tag_p; struct buffer_head *bh = NULL; + struct udf_sb_info *sbi = UDF_SB(sb); /* Read the block */ if (block == 0xFFFFFFFF) return NULL; - bh = udf_tread(sb, block); + bh = udf_tread(sb, block + sbi->s_session); if (!bh) { udf_debug("block=%d, location=%d: read failed\n", - block, location); + block + sbi->s_session, location); return NULL; } @@ -222,7 +223,8 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, 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); + block + sbi->s_session, + le32_to_cpu(tag_p->tagLocation), location); goto error_out; } @@ -242,13 +244,13 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, /* Verify the descriptor CRC */ if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize || - le16_to_cpu(tag_p->descCRC) == crc_itu_t(0, - bh->b_data + sizeof(tag), - le16_to_cpu(tag_p->descCRCLength))) + le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag), + le16_to_cpu(tag_p->descCRCLength), 0)) return bh; - udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", block, - le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength)); + udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", + block + sbi->s_session, le16_to_cpu(tag_p->descCRC), + le16_to_cpu(tag_p->descCRCLength)); error_out: brelse(bh); @@ -268,7 +270,7 @@ void udf_update_tag(char *data, int length) length -= sizeof(tag); tptr->descCRCLength = cpu_to_le16(length); - tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(tag), length)); + tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0)); tptr->tagChecksum = udf_tag_checksum(tptr); } diff --git a/trunk/fs/udf/namei.c b/trunk/fs/udf/namei.c index ba5537d4bc15..112a5fb0b27b 100644 --- a/trunk/fs/udf/namei.c +++ b/trunk/fs/udf/namei.c @@ -31,7 +31,6 @@ #include #include #include -#include static inline int udf_match(int len1, const char *name1, int len2, const char *name2) @@ -98,23 +97,25 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi, memset(fibh->ebh->b_data, 0x00, padlen + offset); } - crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(tag), - sizeof(struct fileIdentDesc) - sizeof(tag)); + crc = udf_crc((uint8_t *)cfi + sizeof(tag), + sizeof(struct fileIdentDesc) - sizeof(tag), 0); if (fibh->sbh == fibh->ebh) { - crc = crc_itu_t(crc, (uint8_t *)sfi->impUse, + crc = udf_crc((uint8_t *)sfi->impUse, crclen + sizeof(tag) - - sizeof(struct fileIdentDesc)); + sizeof(struct fileIdentDesc), crc); } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) { - crc = crc_itu_t(crc, fibh->ebh->b_data + + crc = udf_crc(fibh->ebh->b_data + sizeof(struct fileIdentDesc) + fibh->soffset, crclen + sizeof(tag) - - sizeof(struct fileIdentDesc)); + sizeof(struct fileIdentDesc), + crc); } else { - crc = crc_itu_t(crc, (uint8_t *)sfi->impUse, - -fibh->soffset - sizeof(struct fileIdentDesc)); - crc = crc_itu_t(crc, fibh->ebh->b_data, fibh->eoffset); + crc = udf_crc((uint8_t *)sfi->impUse, + -fibh->soffset - sizeof(struct fileIdentDesc), + crc); + crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc); } cfi->descTag.descCRC = cpu_to_le16(crc); @@ -148,7 +149,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, struct fileIdentDesc *fi = NULL; loff_t f_pos; int block, flen; - char *fname = NULL; + char fname[UDF_NAME_LEN]; char *nameptr; uint8_t lfi; uint16_t liu; @@ -162,12 +163,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, size = udf_ext0_offset(dir) + dir->i_size; f_pos = udf_ext0_offset(dir); - fibh->sbh = fibh->ebh = NULL; fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); - if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { - if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, - &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) - goto out_err; + if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) + fibh->sbh = fibh->ebh = NULL; + else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, + &epos, &eloc, &elen, &offset) == + (EXT_RECORDED_ALLOCATED >> 30)) { block = udf_get_lb_pblock(dir->i_sb, eloc, offset); if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) @@ -178,19 +179,25 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, offset = 0; fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); - if (!fibh->sbh) - goto out_err; + if (!fibh->sbh) { + brelse(epos.bh); + return NULL; + } + } else { + brelse(epos.bh); + return NULL; } - fname = kmalloc(UDF_NAME_LEN, GFP_NOFS); - if (!fname) - goto out_err; - while (f_pos < size) { fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset); - if (!fi) - goto out_err; + if (!fi) { + if (fibh->sbh != fibh->ebh) + brelse(fibh->ebh); + brelse(fibh->sbh); + brelse(epos.bh); + return NULL; + } liu = le16_to_cpu(cfi->lengthOfImpUse); lfi = cfi->lengthFileIdent; @@ -230,22 +237,53 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); if (flen && udf_match(flen, fname, dentry->d_name.len, - dentry->d_name.name)) - goto out_ok; + dentry->d_name.name)) { + brelse(epos.bh); + return fi; + } } -out_err: - fi = NULL; if (fibh->sbh != fibh->ebh) brelse(fibh->ebh); brelse(fibh->sbh); -out_ok: brelse(epos.bh); - kfree(fname); - return fi; + return NULL; } +/* + * udf_lookup + * + * PURPOSE + * Look-up the inode for a given name. + * + * DESCRIPTION + * Required - lookup_dentry() will return -ENOTDIR if this routine is not + * available for a directory. The filesystem is useless if this routine is + * not available for at least the filesystem's root directory. + * + * This routine is passed an incomplete dentry - it must be completed by + * calling d_add(dentry, inode). If the name does not exist, then the + * specified inode must be set to null. An error should only be returned + * when the lookup fails for a reason other than the name not existing. + * Note that the directory inode semaphore is held during the call. + * + * Refer to lookup_dentry() in fs/namei.c + * lookup_dentry() -> lookup() -> real_lookup() -> . + * + * PRE-CONDITIONS + * dir Pointer to inode of parent directory. + * dentry Pointer to dentry to complete. + * nd Pointer to lookup nameidata + * + * POST-CONDITIONS + * Zero on success. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ + static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { @@ -298,9 +336,11 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, { struct super_block *sb = dir->i_sb; struct fileIdentDesc *fi = NULL; - char *name = NULL; + char name[UDF_NAME_LEN], fname[UDF_NAME_LEN]; int namelen; loff_t f_pos; + int flen; + char *nameptr; loff_t size = udf_ext0_offset(dir) + dir->i_size; int nfidlen; uint8_t lfi; @@ -312,23 +352,16 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, struct extent_position epos = {}; struct udf_inode_info *dinfo; - fibh->sbh = fibh->ebh = NULL; - name = kmalloc(UDF_NAME_LEN, GFP_NOFS); - if (!name) { - *err = -ENOMEM; - goto out_err; - } - if (dentry) { if (!dentry->d_name.len) { *err = -EINVAL; - goto out_err; + return NULL; } namelen = udf_put_filename(sb, dentry->d_name.name, name, dentry->d_name.len); if (!namelen) { *err = -ENAMETOOLONG; - goto out_err; + return NULL; } } else { namelen = 0; @@ -340,14 +373,11 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); dinfo = UDF_I(dir); - if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { - if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, - &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) { - block = udf_get_lb_pblock(dir->i_sb, - dinfo->i_location, 0); - fibh->soffset = fibh->eoffset = sb->s_blocksize; - goto add; - } + if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) + fibh->sbh = fibh->ebh = NULL; + else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, + &epos, &eloc, &elen, &offset) == + (EXT_RECORDED_ALLOCATED >> 30)) { block = udf_get_lb_pblock(dir->i_sb, eloc, offset); if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) @@ -359,11 +389,17 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); if (!fibh->sbh) { + brelse(epos.bh); *err = -EIO; - goto out_err; + return NULL; } block = dinfo->i_location.logicalBlockNum; + } else { + block = udf_get_lb_pblock(dir->i_sb, dinfo->i_location, 0); + fibh->sbh = fibh->ebh = NULL; + fibh->soffset = fibh->eoffset = sb->s_blocksize; + goto add; } while (f_pos < size) { @@ -371,16 +407,41 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, &elen, &offset); if (!fi) { + if (fibh->sbh != fibh->ebh) + brelse(fibh->ebh); + brelse(fibh->sbh); + brelse(epos.bh); *err = -EIO; - goto out_err; + return NULL; } 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 (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen) { + brelse(epos.bh); cfi->descTag.tagSerialNum = cpu_to_le16(1); cfi->fileVersionNum = cpu_to_le16(1); cfi->fileCharacteristics = 0; @@ -388,13 +449,27 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, cfi->lengthOfImpUse = cpu_to_le16(0); if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) - goto out_ok; + return fi; else { *err = -EIO; - goto out_err; + return NULL; } } } + + if (!lfi || !dentry) + continue; + + flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); + if (flen && udf_match(flen, fname, dentry->d_name.len, + dentry->d_name.name)) { + if (fibh->sbh != fibh->ebh) + brelse(fibh->ebh); + brelse(fibh->sbh); + brelse(epos.bh); + *err = -EEXIST; + return NULL; + } } add: @@ -421,7 +496,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, fibh->sbh = fibh->ebh = udf_expand_dir_adinicb(dir, &block, err); if (!fibh->sbh) - goto out_err; + return NULL; epos.block = dinfo->i_location; epos.offset = udf_file_entry_alloc_offset(dir); /* Load extent udf_expand_dir_adinicb() has created */ @@ -462,8 +537,11 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, dir->i_sb->s_blocksize_bits); fibh->ebh = udf_bread(dir, f_pos >> dir->i_sb->s_blocksize_bits, 1, err); - if (!fibh->ebh) - goto out_err; + if (!fibh->ebh) { + brelse(epos.bh); + brelse(fibh->sbh); + return NULL; + } if (!fibh->soffset) { if (udf_next_aext(dir, &epos, &eloc, &elen, 1) == @@ -494,25 +572,20 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, cfi->lengthFileIdent = namelen; cfi->lengthOfImpUse = cpu_to_le16(0); if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) { + brelse(epos.bh); dir->i_size += nfidlen; if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) dinfo->i_lenAlloc += nfidlen; mark_inode_dirty(dir); - goto out_ok; + return fi; } else { + brelse(epos.bh); + if (fibh->sbh != fibh->ebh) + brelse(fibh->ebh); + brelse(fibh->sbh); *err = -EIO; - goto out_err; + return NULL; } - -out_err: - fi = NULL; - if (fibh->sbh != fibh->ebh) - brelse(fibh->ebh); - brelse(fibh->sbh); -out_ok: - brelse(epos.bh); - kfree(name); - return fi; } static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, @@ -867,7 +940,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, char *ea; int err; int block; - char *name = NULL; + char name[UDF_NAME_LEN]; int namelen; struct buffer_head *bh; struct udf_inode_info *iinfo; @@ -877,12 +950,6 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, if (!inode) goto out; - name = kmalloc(UDF_NAME_LEN, GFP_NOFS); - if (!name) { - err = -ENOMEM; - goto out_no_entry; - } - iinfo = UDF_I(inode); inode->i_mode = S_IFLNK | S_IRWXUGO; inode->i_data.a_ops = &udf_symlink_aops; @@ -1022,7 +1089,6 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, err = 0; out: - kfree(name); unlock_kernel(); return err; diff --git a/trunk/fs/udf/partition.c b/trunk/fs/udf/partition.c index 63610f026ae1..fc533345ab89 100644 --- a/trunk/fs/udf/partition.c +++ b/trunk/fs/udf/partition.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -54,10 +55,11 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, 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); + struct udf_inode_info *iinfo; map = &sbi->s_partmaps[partition]; vdata = &map->s_type_specific.s_virtual; + index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t); if (block > vdata->s_num_entries) { udf_debug("Trying to access block beyond end of VAT " @@ -65,12 +67,6 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, 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))); @@ -93,7 +89,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, brelse(bh); -translate: + iinfo = UDF_I(sbi->s_vat_inode); if (iinfo->i_location.partitionReferenceNum == partition) { udf_debug("recursive call to udf_get_pblock!\n"); return 0xFFFFFFFF; @@ -267,58 +263,3 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) 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; - 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; -} diff --git a/trunk/fs/udf/super.c b/trunk/fs/udf/super.c index b564fc140fe4..f3ac4abfc946 100644 --- a/trunk/fs/udf/super.c +++ b/trunk/fs/udf/super.c @@ -55,10 +55,9 @@ #include #include #include -#include -#include #include +#include #include "udf_sb.h" #include "udf_i.h" @@ -85,19 +84,22 @@ static void udf_write_super(struct super_block *); static int udf_remount_fs(struct super_block *, int *, char *); static int udf_check_valid(struct super_block *, int, int); static int udf_vrs(struct super_block *sb, int silent); +static int udf_load_partition(struct super_block *, kernel_lb_addr *); +static int udf_load_logicalvol(struct super_block *, struct buffer_head *, + kernel_lb_addr *); static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad); static void udf_find_anchor(struct super_block *); static int udf_find_fileset(struct super_block *, kernel_lb_addr *, kernel_lb_addr *); +static void udf_load_pvoldesc(struct super_block *, struct buffer_head *); static void udf_load_fileset(struct super_block *, struct buffer_head *, kernel_lb_addr *); +static int udf_load_partdesc(struct super_block *, struct buffer_head *); static void udf_open_lvid(struct super_block *); static void udf_close_lvid(struct super_block *); static unsigned int udf_count_free(struct super_block *); static int udf_statfs(struct dentry *, struct kstatfs *); static int udf_show_options(struct seq_file *, struct vfsmount *); -static void udf_error(struct super_block *sb, const char *function, - const char *fmt, ...); struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi) { @@ -585,10 +587,48 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) return 0; } +/* + * udf_set_blocksize + * + * PURPOSE + * Set the block size to be used in all transfers. + * + * DESCRIPTION + * To allow room for a DMA transfer, it is best to guess big when unsure. + * This routine picks 2048 bytes as the blocksize when guessing. This + * should be adequate until devices with larger block sizes become common. + * + * Note that the Linux kernel can currently only deal with blocksizes of + * 512, 1024, 2048, 4096, and 8192 bytes. + * + * PRE-CONDITIONS + * sb Pointer to _locked_ superblock. + * + * POST-CONDITIONS + * sb->s_blocksize Blocksize. + * sb->s_blocksize_bits log2 of blocksize. + * 0 Blocksize is valid. + * 1 Blocksize is invalid. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ +static int udf_set_blocksize(struct super_block *sb, int bsize) +{ + if (!sb_min_blocksize(sb, bsize)) { + udf_debug("Bad block size (%d)\n", bsize); + printk(KERN_ERR "udf: bad block size (%d)\n", bsize); + return 0; + } + + return sb->s_blocksize; +} + static int udf_vrs(struct super_block *sb, int silent) { struct volStructDesc *vsd = NULL; - loff_t sector = 32768; + int sector = 32768; int sectorsize; struct buffer_head *bh = NULL; int iso9660 = 0; @@ -609,8 +649,7 @@ static int udf_vrs(struct super_block *sb, int silent) sector += (sbi->s_session << sb->s_blocksize_bits); udf_debug("Starting at sector %u (%ld byte sectors)\n", - (unsigned int)(sector >> sb->s_blocksize_bits), - sb->s_blocksize); + (sector >> sb->s_blocksize_bits), sb->s_blocksize); /* Process the sequence (if applicable) */ for (; !nsr02 && !nsr03; sector += sectorsize) { /* Read a block */ @@ -680,140 +719,162 @@ static int udf_vrs(struct super_block *sb, int silent) } /* - * Check whether there is an anchor block in the given block + * udf_find_anchor + * + * PURPOSE + * Find an anchor volume descriptor. + * + * PRE-CONDITIONS + * sb Pointer to _locked_ superblock. + * lastblock Last block on media. + * + * POST-CONDITIONS + * 1 if not found, 0 if ok + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. */ -static int udf_check_anchor_block(struct super_block *sb, sector_t block, - bool varconv) +static void udf_find_anchor(struct super_block *sb) { + int lastblock; struct buffer_head *bh = NULL; - tag *t; uint16_t ident; uint32_t location; - - if (varconv) { - if (udf_fixed_to_variable(block) >= - sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) - return 0; - bh = sb_bread(sb, udf_fixed_to_variable(block)); - } - else - bh = sb_bread(sb, block); - - if (!bh) - return 0; - - t = (tag *)bh->b_data; - ident = le16_to_cpu(t->tagIdent); - location = le32_to_cpu(t->tagLocation); - brelse(bh); - if (ident != TAG_IDENT_AVDP) - return 0; - return location == block; -} - -/* Search for an anchor volume descriptor pointer */ -static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, - sector_t lastblock) -{ - sector_t last[6]; int i; - struct udf_sb_info *sbi = UDF_SB(sb); + struct udf_sb_info *sbi; - last[0] = lastblock; - last[1] = last[0] - 1; - last[2] = last[0] + 1; - last[3] = last[0] - 2; - last[4] = last[0] - 150; - last[5] = last[0] - 152; - - /* according to spec, anchor is in either: - * block 256 - * lastblock-256 - * lastblock - * however, if the disc isn't closed, it could be 512 */ - - for (i = 0; i < ARRAY_SIZE(last); i++) { - if (last[i] < 0) - continue; - if (last[i] >= sb->s_bdev->bd_inode->i_size >> - sb->s_blocksize_bits) - continue; + sbi = UDF_SB(sb); + lastblock = sbi->s_last_block; - if (udf_check_anchor_block(sb, last[i], varconv)) { - sbi->s_anchor[0] = last[i]; - sbi->s_anchor[1] = last[i] - 256; - return last[i]; - } + if (lastblock) { + int varlastblock = udf_variable_to_fixed(lastblock); + int last[] = { lastblock, lastblock - 2, + lastblock - 150, lastblock - 152, + varlastblock, varlastblock - 2, + varlastblock - 150, varlastblock - 152 }; + + lastblock = 0; + + /* Search for an anchor volume descriptor pointer */ + + /* according to spec, anchor is in either: + * block 256 + * lastblock-256 + * lastblock + * however, if the disc isn't closed, it could be 512 */ + + for (i = 0; !lastblock && i < ARRAY_SIZE(last); i++) { + ident = location = 0; + if (last[i] >= 0) { + bh = sb_bread(sb, last[i]); + if (bh) { + tag *t = (tag *)bh->b_data; + ident = le16_to_cpu(t->tagIdent); + location = le32_to_cpu(t->tagLocation); + brelse(bh); + } + } - if (last[i] < 256) - continue; + if (ident == TAG_IDENT_AVDP) { + if (location == last[i] - sbi->s_session) { + lastblock = last[i] - sbi->s_session; + sbi->s_anchor[0] = lastblock; + sbi->s_anchor[1] = lastblock - 256; + } else if (location == + udf_variable_to_fixed(last[i]) - + sbi->s_session) { + UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); + lastblock = + udf_variable_to_fixed(last[i]) - + sbi->s_session; + sbi->s_anchor[0] = lastblock; + sbi->s_anchor[1] = lastblock - 256 - + sbi->s_session; + } else { + udf_debug("Anchor found at block %d, " + "location mismatch %d.\n", + last[i], location); + } + } else if (ident == TAG_IDENT_FE || + ident == TAG_IDENT_EFE) { + lastblock = last[i]; + sbi->s_anchor[3] = 512; + } else { + ident = location = 0; + if (last[i] >= 256) { + bh = sb_bread(sb, last[i] - 256); + if (bh) { + tag *t = (tag *)bh->b_data; + ident = le16_to_cpu( + t->tagIdent); + location = le32_to_cpu( + t->tagLocation); + brelse(bh); + } + } - if (udf_check_anchor_block(sb, last[i] - 256, varconv)) { - sbi->s_anchor[1] = last[i] - 256; - return last[i]; - } - } + if (ident == TAG_IDENT_AVDP && + location == last[i] - 256 - + sbi->s_session) { + lastblock = last[i]; + sbi->s_anchor[1] = last[i] - 256; + } else { + ident = location = 0; + if (last[i] >= 312 + sbi->s_session) { + bh = sb_bread(sb, + last[i] - 312 - + sbi->s_session); + if (bh) { + tag *t = (tag *) + bh->b_data; + ident = le16_to_cpu( + t->tagIdent); + location = le32_to_cpu( + t->tagLocation); + brelse(bh); + } + } - if (udf_check_anchor_block(sb, sbi->s_session + 256, varconv)) { - sbi->s_anchor[0] = sbi->s_session + 256; - return last[0]; - } - if (udf_check_anchor_block(sb, sbi->s_session + 512, varconv)) { - sbi->s_anchor[0] = sbi->s_session + 512; - return last[0]; + if (ident == TAG_IDENT_AVDP && + location == udf_variable_to_fixed(last[i]) - 256) { + UDF_SET_FLAG(sb, + UDF_FLAG_VARCONV); + lastblock = udf_variable_to_fixed(last[i]); + sbi->s_anchor[1] = lastblock - 256; + } + } + } + } } - return 0; -} -/* - * Find an anchor volume descriptor. The function expects sbi->s_lastblock to - * be the last block on the media. - * - * Return 1 if not found, 0 if ok - * - */ -static void udf_find_anchor(struct super_block *sb) -{ - sector_t lastblock; - struct buffer_head *bh = NULL; - uint16_t ident; - int i; - struct udf_sb_info *sbi = UDF_SB(sb); - - lastblock = udf_scan_anchors(sb, 0, sbi->s_last_block); - if (lastblock) - goto check_anchor; + if (!lastblock) { + /* We haven't found the lastblock. check 312 */ + bh = sb_bread(sb, 312 + sbi->s_session); + if (bh) { + tag *t = (tag *)bh->b_data; + ident = le16_to_cpu(t->tagIdent); + location = le32_to_cpu(t->tagLocation); + brelse(bh); - /* No anchor found? Try VARCONV conversion of block numbers */ - /* Firstly, we try to not convert number of the last block */ - lastblock = udf_scan_anchors(sb, 1, - udf_variable_to_fixed(sbi->s_last_block)); - if (lastblock) { - UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); - goto check_anchor; + if (ident == TAG_IDENT_AVDP && location == 256) + UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); + } } - /* Secondly, we try with converted number of the last block */ - lastblock = udf_scan_anchors(sb, 1, sbi->s_last_block); - if (lastblock) - UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); - -check_anchor: - /* - * Check located anchors and the anchor block supplied via - * mount options - */ for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { - if (!sbi->s_anchor[i]) - continue; - bh = udf_read_tagged(sb, sbi->s_anchor[i], - sbi->s_anchor[i], &ident); - if (!bh) - sbi->s_anchor[i] = 0; - else { - brelse(bh); - if (ident != TAG_IDENT_AVDP) + if (sbi->s_anchor[i]) { + bh = udf_read_tagged(sb, sbi->s_anchor[i], + sbi->s_anchor[i], &ident); + if (!bh) sbi->s_anchor[i] = 0; + else { + brelse(bh); + if ((ident != TAG_IDENT_AVDP) && + (i || (ident != TAG_IDENT_FE && + ident != TAG_IDENT_EFE))) + sbi->s_anchor[i] = 0; + } } } @@ -910,30 +971,27 @@ static int udf_find_fileset(struct super_block *sb, return 1; } -static int udf_load_pvoldesc(struct super_block *sb, sector_t block) +static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) { struct primaryVolDesc *pvoldesc; + time_t recording; + long recording_usec; struct ustr instr; struct ustr outstr; - struct buffer_head *bh; - uint16_t ident; - - bh = udf_read_tagged(sb, block, block, &ident); - if (!bh) - return 1; - BUG_ON(ident != TAG_IDENT_PVD); pvoldesc = (struct primaryVolDesc *)bh->b_data; - if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time, - pvoldesc->recordingDateAndTime)) { -#ifdef UDFFS_DEBUG - timestamp *ts = &pvoldesc->recordingDateAndTime; - udf_debug("recording time %04u/%02u/%02u" + if (udf_stamp_to_time(&recording, &recording_usec, + lets_to_cpu(pvoldesc->recordingDateAndTime))) { + kernel_timestamp ts; + ts = lets_to_cpu(pvoldesc->recordingDateAndTime); + udf_debug("recording time %ld/%ld, %04u/%02u/%02u" " %02u:%02u (%x)\n", - le16_to_cpu(ts->year), ts->month, ts->day, ts->hour, - ts->minute, le16_to_cpu(ts->typeAndTimezone)); -#endif + recording, recording_usec, + ts.year, ts.month, ts.day, ts.hour, + ts.minute, ts.typeAndTimezone); + UDF_SB(sb)->s_record_time.tv_sec = recording; + UDF_SB(sb)->s_record_time.tv_nsec = recording_usec * 1000; } if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32)) @@ -947,104 +1005,6 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block) if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128)) if (udf_CS0toUTF8(&outstr, &instr)) udf_debug("volSetIdent[] = '%s'\n", outstr.u_name); - - brelse(bh); - return 0; -} - -static int udf_load_metadata_files(struct super_block *sb, int partition) -{ - struct udf_sb_info *sbi = UDF_SB(sb); - struct udf_part_map *map; - struct udf_meta_data *mdata; - kernel_lb_addr addr; - int fe_error = 0; - - map = &sbi->s_partmaps[partition]; - mdata = &map->s_type_specific.s_metadata; - - /* metadata address */ - addr.logicalBlockNum = mdata->s_meta_file_loc; - addr.partitionReferenceNum = map->s_partition_num; - - udf_debug("Metadata file location: block = %d part = %d\n", - addr.logicalBlockNum, addr.partitionReferenceNum); - - mdata->s_metadata_fe = udf_iget(sb, addr); - - if (mdata->s_metadata_fe == NULL) { - udf_warning(sb, __func__, "metadata inode efe not found, " - "will try mirror inode."); - fe_error = 1; - } else if (UDF_I(mdata->s_metadata_fe)->i_alloc_type != - ICBTAG_FLAG_AD_SHORT) { - udf_warning(sb, __func__, "metadata inode efe does not have " - "short allocation descriptors!"); - fe_error = 1; - iput(mdata->s_metadata_fe); - mdata->s_metadata_fe = NULL; - } - - /* mirror file entry */ - addr.logicalBlockNum = mdata->s_mirror_file_loc; - addr.partitionReferenceNum = map->s_partition_num; - - udf_debug("Mirror metadata file location: block = %d part = %d\n", - addr.logicalBlockNum, addr.partitionReferenceNum); - - mdata->s_mirror_fe = udf_iget(sb, addr); - - if (mdata->s_mirror_fe == NULL) { - if (fe_error) { - udf_error(sb, __func__, "mirror inode efe not found " - "and metadata inode is missing too, exiting..."); - goto error_exit; - } else - udf_warning(sb, __func__, "mirror inode efe not found," - " but metadata inode is OK"); - } else if (UDF_I(mdata->s_mirror_fe)->i_alloc_type != - ICBTAG_FLAG_AD_SHORT) { - udf_warning(sb, __func__, "mirror inode efe does not have " - "short allocation descriptors!"); - iput(mdata->s_mirror_fe); - mdata->s_mirror_fe = NULL; - if (fe_error) - goto error_exit; - } - - /* - * bitmap file entry - * Note: - * Load only if bitmap file location differs from 0xFFFFFFFF (DCN-5102) - */ - if (mdata->s_bitmap_file_loc != 0xFFFFFFFF) { - addr.logicalBlockNum = mdata->s_bitmap_file_loc; - addr.partitionReferenceNum = map->s_partition_num; - - udf_debug("Bitmap file location: block = %d part = %d\n", - addr.logicalBlockNum, addr.partitionReferenceNum); - - mdata->s_bitmap_fe = udf_iget(sb, addr); - - if (mdata->s_bitmap_fe == NULL) { - if (sb->s_flags & MS_RDONLY) - udf_warning(sb, __func__, "bitmap inode efe " - "not found but it's ok since the disc" - " is mounted read-only"); - else { - udf_error(sb, __func__, "bitmap inode efe not " - "found and attempted read-write mount"); - goto error_exit; - } - } - } - - udf_debug("udf_load_metadata_files Ok\n"); - - return 0; - -error_exit: - return 1; } static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, @@ -1065,9 +1025,10 @@ static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, int udf_compute_nr_groups(struct super_block *sb, u32 partition) { struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; - return DIV_ROUND_UP(map->s_partition_len + - (sizeof(struct spaceBitmapDesc) << 3), - sb->s_blocksize * 8); + return (map->s_partition_len + + (sizeof(struct spaceBitmapDesc) << 3) + + (sb->s_blocksize * 8) - 1) / + (sb->s_blocksize * 8); } static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) @@ -1098,241 +1059,134 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) return bitmap; } -static int udf_fill_partdesc_info(struct super_block *sb, - struct partitionDesc *p, int p_index) -{ - struct udf_part_map *map; - struct udf_sb_info *sbi = UDF_SB(sb); - struct partitionHeaderDesc *phd; - - map = &sbi->s_partmaps[p_index]; - - map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */ - map->s_partition_root = le32_to_cpu(p->partitionStartingLocation); - - if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) - map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY; - if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) - map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE; - if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) - map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE; - if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) - map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE; - - udf_debug("Partition (%d type %x) starts at physical %d, " - "block length %d\n", p_index, - map->s_partition_type, map->s_partition_root, - map->s_partition_len); - - if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) && - strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) - return 0; - - phd = (struct partitionHeaderDesc *)p->partitionContentsUse; - if (phd->unallocSpaceTable.extLength) { - kernel_lb_addr loc = { - .logicalBlockNum = le32_to_cpu( - phd->unallocSpaceTable.extPosition), - .partitionReferenceNum = p_index, - }; - - map->s_uspace.s_table = udf_iget(sb, loc); - if (!map->s_uspace.s_table) { - udf_debug("cannot load unallocSpaceTable (part %d)\n", - p_index); - return 1; - } - map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE; - udf_debug("unallocSpaceTable (part %d) @ %ld\n", - p_index, map->s_uspace.s_table->i_ino); - } - - if (phd->unallocSpaceBitmap.extLength) { - struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); - if (!bitmap) - return 1; - map->s_uspace.s_bitmap = bitmap; - bitmap->s_extLength = le32_to_cpu( - phd->unallocSpaceBitmap.extLength); - bitmap->s_extPosition = le32_to_cpu( - phd->unallocSpaceBitmap.extPosition); - map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; - udf_debug("unallocSpaceBitmap (part %d) @ %d\n", p_index, - bitmap->s_extPosition); - } - - if (phd->partitionIntegrityTable.extLength) - udf_debug("partitionIntegrityTable (part %d)\n", p_index); - - if (phd->freedSpaceTable.extLength) { - kernel_lb_addr loc = { - .logicalBlockNum = le32_to_cpu( - phd->freedSpaceTable.extPosition), - .partitionReferenceNum = p_index, - }; - - map->s_fspace.s_table = udf_iget(sb, loc); - if (!map->s_fspace.s_table) { - udf_debug("cannot load freedSpaceTable (part %d)\n", - p_index); - return 1; - } - - map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE; - udf_debug("freedSpaceTable (part %d) @ %ld\n", - p_index, map->s_fspace.s_table->i_ino); - } - - if (phd->freedSpaceBitmap.extLength) { - struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); - if (!bitmap) - return 1; - map->s_fspace.s_bitmap = bitmap; - bitmap->s_extLength = le32_to_cpu( - phd->freedSpaceBitmap.extLength); - bitmap->s_extPosition = le32_to_cpu( - phd->freedSpaceBitmap.extPosition); - map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; - udf_debug("freedSpaceBitmap (part %d) @ %d\n", p_index, - bitmap->s_extPosition); - } - return 0; -} - -static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) -{ - struct udf_sb_info *sbi = UDF_SB(sb); - struct udf_part_map *map = &sbi->s_partmaps[p_index]; - kernel_lb_addr ino; - struct buffer_head *bh = NULL; - struct udf_inode_info *vati; - uint32_t pos; - struct virtualAllocationTable20 *vat20; - - /* VAT file entry is in the last recorded block */ - ino.partitionReferenceNum = type1_index; - ino.logicalBlockNum = sbi->s_last_block - map->s_partition_root; - sbi->s_vat_inode = udf_iget(sb, ino); - if (!sbi->s_vat_inode) - return 1; - - if (map->s_partition_type == UDF_VIRTUAL_MAP15) { - map->s_type_specific.s_virtual.s_start_offset = 0; - map->s_type_specific.s_virtual.s_num_entries = - (sbi->s_vat_inode->i_size - 36) >> 2; - } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { - vati = UDF_I(sbi->s_vat_inode); - if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { - pos = udf_block_map(sbi->s_vat_inode, 0); - bh = sb_bread(sb, pos); - if (!bh) - return 1; - vat20 = (struct virtualAllocationTable20 *)bh->b_data; - } else { - vat20 = (struct virtualAllocationTable20 *) - vati->i_ext.i_data; - } - - map->s_type_specific.s_virtual.s_start_offset = - le16_to_cpu(vat20->lengthHeader); - map->s_type_specific.s_virtual.s_num_entries = - (sbi->s_vat_inode->i_size - - map->s_type_specific.s_virtual. - s_start_offset) >> 2; - brelse(bh); - } - return 0; -} - -static int udf_load_partdesc(struct super_block *sb, sector_t block) +static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) { - struct buffer_head *bh; struct partitionDesc *p; + int i; struct udf_part_map *map; - struct udf_sb_info *sbi = UDF_SB(sb); - int i, type1_idx; - uint16_t partitionNumber; - uint16_t ident; - int ret = 0; - - bh = udf_read_tagged(sb, block, block, &ident); - if (!bh) - return 1; - if (ident != TAG_IDENT_PD) - goto out_bh; + struct udf_sb_info *sbi; p = (struct partitionDesc *)bh->b_data; - partitionNumber = le16_to_cpu(p->partitionNumber); + sbi = UDF_SB(sb); - /* First scan for TYPE1, SPARABLE and METADATA partitions */ for (i = 0; i < sbi->s_partitions; i++) { map = &sbi->s_partmaps[i]; udf_debug("Searching map: (%d == %d)\n", - map->s_partition_num, partitionNumber); - if (map->s_partition_num == partitionNumber && - (map->s_partition_type == UDF_TYPE1_MAP15 || - map->s_partition_type == UDF_SPARABLE_MAP15)) - break; - } - - if (i >= sbi->s_partitions) { - udf_debug("Partition (%d) not found in partition map\n", - partitionNumber); - goto out_bh; - } - - ret = udf_fill_partdesc_info(sb, p, i); - - /* - * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and - * PHYSICAL partitions are already set up - */ - type1_idx = i; - for (i = 0; i < sbi->s_partitions; i++) { - map = &sbi->s_partmaps[i]; - - if (map->s_partition_num == partitionNumber && - (map->s_partition_type == UDF_VIRTUAL_MAP15 || - map->s_partition_type == UDF_VIRTUAL_MAP20 || - map->s_partition_type == UDF_METADATA_MAP25)) + map->s_partition_num, + le16_to_cpu(p->partitionNumber)); + if (map->s_partition_num == + le16_to_cpu(p->partitionNumber)) { + map->s_partition_len = + le32_to_cpu(p->partitionLength); /* blocks */ + map->s_partition_root = + le32_to_cpu(p->partitionStartingLocation); + if (p->accessType == + cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) + map->s_partition_flags |= + UDF_PART_FLAG_READ_ONLY; + if (p->accessType == + cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) + map->s_partition_flags |= + UDF_PART_FLAG_WRITE_ONCE; + if (p->accessType == + cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) + map->s_partition_flags |= + UDF_PART_FLAG_REWRITABLE; + if (p->accessType == + cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) + map->s_partition_flags |= + UDF_PART_FLAG_OVERWRITABLE; + + if (!strcmp(p->partitionContents.ident, + PD_PARTITION_CONTENTS_NSR02) || + !strcmp(p->partitionContents.ident, + PD_PARTITION_CONTENTS_NSR03)) { + struct partitionHeaderDesc *phd; + + phd = (struct partitionHeaderDesc *) + (p->partitionContentsUse); + if (phd->unallocSpaceTable.extLength) { + kernel_lb_addr loc = { + .logicalBlockNum = le32_to_cpu(phd->unallocSpaceTable.extPosition), + .partitionReferenceNum = i, + }; + + map->s_uspace.s_table = + udf_iget(sb, loc); + if (!map->s_uspace.s_table) { + udf_debug("cannot load unallocSpaceTable (part %d)\n", i); + return 1; + } + map->s_partition_flags |= + UDF_PART_FLAG_UNALLOC_TABLE; + udf_debug("unallocSpaceTable (part %d) @ %ld\n", + i, map->s_uspace.s_table->i_ino); + } + if (phd->unallocSpaceBitmap.extLength) { + struct udf_bitmap *bitmap = + udf_sb_alloc_bitmap(sb, i); + map->s_uspace.s_bitmap = bitmap; + if (bitmap != NULL) { + bitmap->s_extLength = + le32_to_cpu(phd->unallocSpaceBitmap.extLength); + bitmap->s_extPosition = + le32_to_cpu(phd->unallocSpaceBitmap.extPosition); + map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; + udf_debug("unallocSpaceBitmap (part %d) @ %d\n", + i, bitmap->s_extPosition); + } + } + if (phd->partitionIntegrityTable.extLength) + udf_debug("partitionIntegrityTable (part %d)\n", i); + if (phd->freedSpaceTable.extLength) { + kernel_lb_addr loc = { + .logicalBlockNum = le32_to_cpu(phd->freedSpaceTable.extPosition), + .partitionReferenceNum = i, + }; + + map->s_fspace.s_table = + udf_iget(sb, loc); + if (!map->s_fspace.s_table) { + udf_debug("cannot load freedSpaceTable (part %d)\n", i); + return 1; + } + map->s_partition_flags |= + UDF_PART_FLAG_FREED_TABLE; + udf_debug("freedSpaceTable (part %d) @ %ld\n", + i, map->s_fspace.s_table->i_ino); + } + if (phd->freedSpaceBitmap.extLength) { + struct udf_bitmap *bitmap = + udf_sb_alloc_bitmap(sb, i); + map->s_fspace.s_bitmap = bitmap; + if (bitmap != NULL) { + bitmap->s_extLength = + le32_to_cpu(phd->freedSpaceBitmap.extLength); + bitmap->s_extPosition = + le32_to_cpu(phd->freedSpaceBitmap.extPosition); + map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; + udf_debug("freedSpaceBitmap (part %d) @ %d\n", + i, bitmap->s_extPosition); + } + } + } break; - } - - if (i >= sbi->s_partitions) - goto out_bh; - - ret = udf_fill_partdesc_info(sb, p, i); - if (ret) - goto out_bh; - - if (map->s_partition_type == UDF_METADATA_MAP25) { - ret = udf_load_metadata_files(sb, i); - if (ret) { - printk(KERN_ERR "UDF-fs: error loading MetaData " - "partition map %d\n", i); - goto out_bh; } - } else { - ret = udf_load_vat(sb, i, type1_idx); - if (ret) - goto out_bh; - /* - * Mark filesystem read-only if we have a partition with - * virtual map since we don't handle writing to it (we - * overwrite blocks instead of relocating them). - */ - sb->s_flags |= MS_RDONLY; - printk(KERN_NOTICE "UDF-fs: Filesystem marked read-only " - "because writing to pseudooverwrite partition is " - "not implemented.\n"); } -out_bh: - /* In case loading failed, we handle cleanup in udf_fill_super */ - brelse(bh); - return ret; + if (i == sbi->s_partitions) + udf_debug("Partition (%d) not found in partition map\n", + le16_to_cpu(p->partitionNumber)); + else + udf_debug("Partition (%d:%d type %x) starts at physical %d, " + "block length %d\n", + le16_to_cpu(p->partitionNumber), i, + map->s_partition_type, + map->s_partition_root, + map->s_partition_len); + return 0; } -static int udf_load_logicalvol(struct super_block *sb, sector_t block, +static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, kernel_lb_addr *fileset) { struct logicalVolDesc *lvd; @@ -1340,21 +1194,12 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, uint8_t type; struct udf_sb_info *sbi = UDF_SB(sb); struct genericPartitionMap *gpm; - uint16_t ident; - struct buffer_head *bh; - int ret = 0; - bh = udf_read_tagged(sb, block, block, &ident); - if (!bh) - return 1; - BUG_ON(ident != TAG_IDENT_LVD); lvd = (struct logicalVolDesc *)bh->b_data; i = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); - if (i != 0) { - ret = i; - goto out_bh; - } + if (i != 0) + return i; for (i = 0, offset = 0; i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength); @@ -1378,12 +1223,12 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, u16 suf = le16_to_cpu(((__le16 *)upm2->partIdent. identSuffix)[0]); - if (suf < 0x0200) { + if (suf == 0x0150) { map->s_partition_type = UDF_VIRTUAL_MAP15; map->s_partition_func = udf_get_pblock_virt15; - } else { + } else if (suf == 0x0200) { map->s_partition_type = UDF_VIRTUAL_MAP20; map->s_partition_func = @@ -1393,6 +1238,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) { uint32_t loc; + uint16_t ident; struct sparingTable *st; struct sparablePartitionMap *spm = (struct sparablePartitionMap *)gpm; @@ -1410,64 +1256,22 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, map->s_type_specific.s_sparing. s_spar_map[j] = bh2; - if (bh2 == NULL) - continue; - - st = (struct sparingTable *)bh2->b_data; - if (ident != 0 || strncmp( - st->sparingIdent.ident, - UDF_ID_SPARING, - strlen(UDF_ID_SPARING))) { - brelse(bh2); - map->s_type_specific.s_sparing. - s_spar_map[j] = NULL; + if (bh2 != NULL) { + st = (struct sparingTable *) + bh2->b_data; + if (ident != 0 || strncmp( + st->sparingIdent.ident, + UDF_ID_SPARING, + strlen(UDF_ID_SPARING))) { + brelse(bh2); + map->s_type_specific. + s_sparing. + s_spar_map[j] = + NULL; + } } } map->s_partition_func = udf_get_pblock_spar15; - } else if (!strncmp(upm2->partIdent.ident, - UDF_ID_METADATA, - strlen(UDF_ID_METADATA))) { - struct udf_meta_data *mdata = - &map->s_type_specific.s_metadata; - struct metadataPartitionMap *mdm = - (struct metadataPartitionMap *) - &(lvd->partitionMaps[offset]); - udf_debug("Parsing Logical vol part %d " - "type %d id=%s\n", i, type, - UDF_ID_METADATA); - - map->s_partition_type = UDF_METADATA_MAP25; - map->s_partition_func = udf_get_pblock_meta25; - - mdata->s_meta_file_loc = - le32_to_cpu(mdm->metadataFileLoc); - mdata->s_mirror_file_loc = - le32_to_cpu(mdm->metadataMirrorFileLoc); - mdata->s_bitmap_file_loc = - le32_to_cpu(mdm->metadataBitmapFileLoc); - mdata->s_alloc_unit_size = - le32_to_cpu(mdm->allocUnitSize); - mdata->s_align_unit_size = - le16_to_cpu(mdm->alignUnitSize); - mdata->s_dup_md_flag = - mdm->flags & 0x01; - - udf_debug("Metadata Ident suffix=0x%x\n", - (le16_to_cpu( - ((__le16 *) - mdm->partIdent.identSuffix)[0]))); - udf_debug("Metadata part num=%d\n", - le16_to_cpu(mdm->partitionNum)); - udf_debug("Metadata part alloc unit size=%d\n", - le32_to_cpu(mdm->allocUnitSize)); - udf_debug("Metadata file loc=%d\n", - le32_to_cpu(mdm->metadataFileLoc)); - udf_debug("Mirror file loc=%d\n", - le32_to_cpu(mdm->metadataMirrorFileLoc)); - udf_debug("Bitmap file loc=%d\n", - le32_to_cpu(mdm->metadataBitmapFileLoc)); - udf_debug("Duplicate Flag: %d %d\n", - mdata->s_dup_md_flag, mdm->flags); } else { udf_debug("Unknown ident: %s\n", upm2->partIdent.ident); @@ -1492,9 +1296,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, if (lvd->integritySeqExt.extLength) udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); -out_bh: - brelse(bh); - return ret; + return 0; } /* @@ -1543,7 +1345,7 @@ static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc) * July 1, 1997 - Andrew E. Mileski * Written, tested, and released. */ -static noinline int udf_process_sequence(struct super_block *sb, long block, +static int udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_lb_addr *fileset) { struct buffer_head *bh = NULL; @@ -1552,25 +1354,19 @@ static noinline int udf_process_sequence(struct super_block *sb, long block, struct generic_desc *gd; struct volDescPtr *vdp; int done = 0; + int i, j; uint32_t vdsn; uint16_t ident; long next_s = 0, next_e = 0; memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); - /* - * Read the main descriptor sequence and find which descriptors - * are in it. - */ + /* Read the main descriptor sequence */ for (; (!done && block <= lastblock); block++) { bh = udf_read_tagged(sb, block, block, &ident); - if (!bh) { - printk(KERN_ERR "udf: Block %Lu of volume descriptor " - "sequence is corrupted or we could not read " - "it.\n", (unsigned long long)block); - return 1; - } + if (!bh) + break; /* Process each descriptor (ISO 13346 3/8.3-8.4) */ gd = (struct generic_desc *)bh->b_data; @@ -1636,31 +1432,41 @@ static noinline int udf_process_sequence(struct super_block *sb, long block, } brelse(bh); } - /* - * Now read interesting descriptors again and process them - * in a suitable order - */ - if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) { - printk(KERN_ERR "udf: Primary Volume Descriptor not found!\n"); - return 1; - } - if (udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block)) - return 1; - - if (vds[VDS_POS_LOGICAL_VOL_DESC].block && udf_load_logicalvol(sb, - vds[VDS_POS_LOGICAL_VOL_DESC].block, fileset)) - return 1; - - if (vds[VDS_POS_PARTITION_DESC].block) { - /* - * We rescan the whole descriptor sequence to find - * partition descriptor blocks and process them. - */ - for (block = vds[VDS_POS_PARTITION_DESC].block; - block < vds[VDS_POS_TERMINATING_DESC].block; - block++) - if (udf_load_partdesc(sb, block)) - return 1; + for (i = 0; i < VDS_POS_LENGTH; i++) { + if (vds[i].block) { + bh = udf_read_tagged(sb, vds[i].block, vds[i].block, + &ident); + + if (i == VDS_POS_PRIMARY_VOL_DESC) { + udf_load_pvoldesc(sb, bh); + } else if (i == VDS_POS_LOGICAL_VOL_DESC) { + if (udf_load_logicalvol(sb, bh, fileset)) { + brelse(bh); + return 1; + } + } else if (i == VDS_POS_PARTITION_DESC) { + struct buffer_head *bh2 = NULL; + if (udf_load_partdesc(sb, bh)) { + brelse(bh); + return 1; + } + for (j = vds[i].block + 1; + j < vds[VDS_POS_TERMINATING_DESC].block; + j++) { + bh2 = udf_read_tagged(sb, j, j, &ident); + gd = (struct generic_desc *)bh2->b_data; + if (ident == TAG_IDENT_PD) + if (udf_load_partdesc(sb, + bh2)) { + brelse(bh); + brelse(bh2); + return 1; + } + brelse(bh2); + } + } + brelse(bh); + } } return 0; @@ -1672,7 +1478,6 @@ static noinline int udf_process_sequence(struct super_block *sb, long block, static int udf_check_valid(struct super_block *sb, int novrs, int silent) { long block; - struct udf_sb_info *sbi = UDF_SB(sb); if (novrs) { udf_debug("Validity check skipped because of novrs option\n"); @@ -1680,22 +1485,27 @@ static int udf_check_valid(struct super_block *sb, int novrs, int silent) } /* Check that it is NSR02 compliant */ /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ - block = udf_vrs(sb, silent); - if (block == -1) - udf_debug("Failed to read byte 32768. Assuming open " - "disc. Skipping validity check\n"); - if (block && !sbi->s_last_block) - sbi->s_last_block = udf_get_last_block(sb); - return !block; + else { + block = udf_vrs(sb, silent); + if (block == -1) { + struct udf_sb_info *sbi = UDF_SB(sb); + udf_debug("Failed to read byte 32768. Assuming open " + "disc. Skipping validity check\n"); + if (!sbi->s_last_block) + sbi->s_last_block = udf_get_last_block(sb); + return 0; + } else + return !block; + } } -static int udf_load_sequence(struct super_block *sb, kernel_lb_addr *fileset) +static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) { struct anchorVolDescPtr *anchor; uint16_t ident; struct buffer_head *bh; long main_s, main_e, reserve_s, reserve_e; - int i; + int i, j; struct udf_sb_info *sbi; if (!sb) @@ -1705,7 +1515,6 @@ static int udf_load_sequence(struct super_block *sb, kernel_lb_addr *fileset) for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { if (!sbi->s_anchor[i]) continue; - bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i], &ident); if (!bh) @@ -1744,6 +1553,76 @@ static int udf_load_sequence(struct super_block *sb, kernel_lb_addr *fileset) } udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]); + for (i = 0; i < sbi->s_partitions; i++) { + kernel_lb_addr uninitialized_var(ino); + struct udf_part_map *map = &sbi->s_partmaps[i]; + switch (map->s_partition_type) { + case UDF_VIRTUAL_MAP15: + case UDF_VIRTUAL_MAP20: + if (!sbi->s_last_block) { + sbi->s_last_block = udf_get_last_block(sb); + udf_find_anchor(sb); + } + + if (!sbi->s_last_block) { + udf_debug("Unable to determine Lastblock (For " + "Virtual Partition)\n"); + return 1; + } + + for (j = 0; j < sbi->s_partitions; j++) { + struct udf_part_map *map2 = &sbi->s_partmaps[j]; + if (j != i && + map->s_volumeseqnum == + map2->s_volumeseqnum && + map->s_partition_num == + map2->s_partition_num) { + ino.partitionReferenceNum = j; + ino.logicalBlockNum = + sbi->s_last_block - + map2->s_partition_root; + break; + } + } + + if (j == sbi->s_partitions) + return 1; + + sbi->s_vat_inode = udf_iget(sb, ino); + if (!sbi->s_vat_inode) + return 1; + + if (map->s_partition_type == UDF_VIRTUAL_MAP15) { + map->s_type_specific.s_virtual.s_start_offset = + udf_ext0_offset(sbi->s_vat_inode); + map->s_type_specific.s_virtual.s_num_entries = + (sbi->s_vat_inode->i_size - 36) >> 2; + } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { + uint32_t pos; + struct virtualAllocationTable20 *vat20; + + pos = udf_block_map(sbi->s_vat_inode, 0); + bh = sb_bread(sb, pos); + if (!bh) + return 1; + vat20 = (struct virtualAllocationTable20 *) + bh->b_data + + udf_ext0_offset(sbi->s_vat_inode); + map->s_type_specific.s_virtual.s_start_offset = + le16_to_cpu(vat20->lengthHeader) + + udf_ext0_offset(sbi->s_vat_inode); + map->s_type_specific.s_virtual.s_num_entries = + (sbi->s_vat_inode->i_size - + map->s_type_specific.s_virtual. + s_start_offset) >> 2; + brelse(bh); + } + map->s_partition_root = udf_get_pblock(sb, 0, i, 0); + map->s_partition_len = + sbi->s_partmaps[ino.partitionReferenceNum]. + s_partition_len; + } + } return 0; } @@ -1751,61 +1630,65 @@ static void udf_open_lvid(struct super_block *sb) { struct udf_sb_info *sbi = UDF_SB(sb); struct buffer_head *bh = sbi->s_lvid_bh; - struct logicalVolIntegrityDesc *lvid; - struct logicalVolIntegrityDescImpUse *lvidiu; - if (!bh) - return; - - lvid = (struct logicalVolIntegrityDesc *)bh->b_data; - lvidiu = udf_sb_lvidiu(sbi); + if (bh) { + kernel_timestamp cpu_time; + struct logicalVolIntegrityDesc *lvid = + (struct logicalVolIntegrityDesc *)bh->b_data; + struct logicalVolIntegrityDescImpUse *lvidiu = + udf_sb_lvidiu(sbi); - lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; - lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - udf_time_to_disk_stamp(&lvid->recordingDateAndTime, - CURRENT_TIME); - lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; + lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; + lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; + if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) + lvid->recordingDateAndTime = cpu_to_lets(cpu_time); + lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; - lvid->descTag.descCRC = cpu_to_le16( - crc_itu_t(0, (char *)lvid + sizeof(tag), - le16_to_cpu(lvid->descTag.descCRCLength))); + lvid->descTag.descCRC = cpu_to_le16( + udf_crc((char *)lvid + sizeof(tag), + le16_to_cpu(lvid->descTag.descCRCLength), + 0)); - lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); - mark_buffer_dirty(bh); + lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); + mark_buffer_dirty(bh); + } } static void udf_close_lvid(struct super_block *sb) { + kernel_timestamp cpu_time; struct udf_sb_info *sbi = UDF_SB(sb); struct buffer_head *bh = sbi->s_lvid_bh; struct logicalVolIntegrityDesc *lvid; - struct logicalVolIntegrityDescImpUse *lvidiu; if (!bh) return; lvid = (struct logicalVolIntegrityDesc *)bh->b_data; - if (lvid->integrityType != LVID_INTEGRITY_TYPE_OPEN) - return; - - lvidiu = udf_sb_lvidiu(sbi); - lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; - lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME); - if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) - lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION); - if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) - lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); - if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) - lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev); - lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); - - lvid->descTag.descCRC = cpu_to_le16( - crc_itu_t(0, (char *)lvid + sizeof(tag), - le16_to_cpu(lvid->descTag.descCRCLength))); - - lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); - mark_buffer_dirty(bh); + if (lvid->integrityType == LVID_INTEGRITY_TYPE_OPEN) { + struct logicalVolIntegrityDescImpUse *lvidiu = + udf_sb_lvidiu(sbi); + lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; + lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; + if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) + lvid->recordingDateAndTime = cpu_to_lets(cpu_time); + if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) + lvidiu->maxUDFWriteRev = + cpu_to_le16(UDF_MAX_WRITE_VERSION); + if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) + lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); + if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) + lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev); + lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); + + lvid->descTag.descCRC = cpu_to_le16( + udf_crc((char *)lvid + sizeof(tag), + le16_to_cpu(lvid->descTag.descCRCLength), + 0)); + + lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); + mark_buffer_dirty(bh); + } } static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) @@ -1825,35 +1708,22 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) vfree(bitmap); } -static void udf_free_partition(struct udf_part_map *map) -{ - int i; - struct udf_meta_data *mdata; - - if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) - iput(map->s_uspace.s_table); - if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) - iput(map->s_fspace.s_table); - if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) - udf_sb_free_bitmap(map->s_uspace.s_bitmap); - if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) - udf_sb_free_bitmap(map->s_fspace.s_bitmap); - if (map->s_partition_type == UDF_SPARABLE_MAP15) - for (i = 0; i < 4; i++) - brelse(map->s_type_specific.s_sparing.s_spar_map[i]); - else if (map->s_partition_type == UDF_METADATA_MAP25) { - mdata = &map->s_type_specific.s_metadata; - iput(mdata->s_metadata_fe); - mdata->s_metadata_fe = NULL; - - iput(mdata->s_mirror_fe); - mdata->s_mirror_fe = NULL; - - iput(mdata->s_bitmap_fe); - mdata->s_bitmap_fe = NULL; - } -} - +/* + * udf_read_super + * + * PURPOSE + * Complete the specified super block. + * + * PRE-CONDITIONS + * sb Pointer to superblock to complete - never NULL. + * sb->s_dev Device to read suberblock from. + * options Pointer to mount options. + * silent Silent flag. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ static int udf_fill_super(struct super_block *sb, void *options, int silent) { int i; @@ -1906,11 +1776,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) sbi->s_nls_map = uopt.nls_map; /* Set the block size for all transfers */ - if (!sb_min_blocksize(sb, uopt.blocksize)) { - udf_debug("Bad block size (%d)\n", uopt.blocksize); - printk(KERN_ERR "udf: bad block size (%d)\n", uopt.blocksize); + if (!udf_set_blocksize(sb, uopt.blocksize)) goto error_out; - } if (uopt.session == 0xFFFFFFFF) sbi->s_session = udf_get_last_session(sb); @@ -1922,6 +1789,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) sbi->s_last_block = uopt.lastblock; sbi->s_anchor[0] = sbi->s_anchor[1] = 0; sbi->s_anchor[2] = uopt.anchor; + sbi->s_anchor[3] = 256; if (udf_check_valid(sb, uopt.novrs, silent)) { /* read volume recognition sequences */ @@ -1938,7 +1806,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) sb->s_magic = UDF_SUPER_MAGIC; sb->s_time_gran = 1000; - if (udf_load_sequence(sb, &fileset)) { + if (udf_load_partition(sb, &fileset)) { printk(KERN_WARNING "UDF-fs: No partition found (1)\n"); goto error_out; } @@ -1988,12 +1856,12 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) } if (!silent) { - timestamp ts; - udf_time_to_disk_stamp(&ts, sbi->s_record_time); + kernel_timestamp ts; + udf_time_to_stamp(&ts, sbi->s_record_time); udf_info("UDF: Mounting volume '%s', " "timestamp %04u/%02u/%02u %02u:%02u (%x)\n", - sbi->s_volume_ident, le16_to_cpu(ts.year), ts.month, ts.day, - ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone)); + sbi->s_volume_ident, ts.year, ts.month, ts.day, + ts.hour, ts.minute, ts.typeAndTimezone); } if (!(sb->s_flags & MS_RDONLY)) udf_open_lvid(sb); @@ -2022,9 +1890,21 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) error_out: if (sbi->s_vat_inode) iput(sbi->s_vat_inode); - if (sbi->s_partitions) - for (i = 0; i < sbi->s_partitions; i++) - udf_free_partition(&sbi->s_partmaps[i]); + if (sbi->s_partitions) { + struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition]; + if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) + iput(map->s_uspace.s_table); + if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) + iput(map->s_fspace.s_table); + if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) + udf_sb_free_bitmap(map->s_uspace.s_bitmap); + if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) + udf_sb_free_bitmap(map->s_fspace.s_bitmap); + if (map->s_partition_type == UDF_SPARABLE_MAP15) + for (i = 0; i < 4; i++) + brelse(map->s_type_specific.s_sparing. + s_spar_map[i]); + } #ifdef CONFIG_UDF_NLS if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) unload_nls(sbi->s_nls_map); @@ -2040,8 +1920,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) return -EINVAL; } -static void udf_error(struct super_block *sb, const char *function, - const char *fmt, ...) +void udf_error(struct super_block *sb, const char *function, + const char *fmt, ...) { va_list args; @@ -2068,6 +1948,19 @@ void udf_warning(struct super_block *sb, const char *function, sb->s_id, function, error_buf); } +/* + * udf_put_super + * + * PURPOSE + * Prepare for destruction of the superblock. + * + * DESCRIPTION + * Called before the filesystem is unmounted. + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ static void udf_put_super(struct super_block *sb) { int i; @@ -2076,9 +1969,21 @@ static void udf_put_super(struct super_block *sb) sbi = UDF_SB(sb); if (sbi->s_vat_inode) iput(sbi->s_vat_inode); - if (sbi->s_partitions) - for (i = 0; i < sbi->s_partitions; i++) - udf_free_partition(&sbi->s_partmaps[i]); + if (sbi->s_partitions) { + struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition]; + if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) + iput(map->s_uspace.s_table); + if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) + iput(map->s_fspace.s_table); + if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) + udf_sb_free_bitmap(map->s_uspace.s_bitmap); + if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) + udf_sb_free_bitmap(map->s_fspace.s_bitmap); + if (map->s_partition_type == UDF_SPARABLE_MAP15) + for (i = 0; i < 4; i++) + brelse(map->s_type_specific.s_sparing. + s_spar_map[i]); + } #ifdef CONFIG_UDF_NLS if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) unload_nls(sbi->s_nls_map); @@ -2091,6 +1996,19 @@ static void udf_put_super(struct super_block *sb) sb->s_fs_info = NULL; } +/* + * udf_stat_fs + * + * PURPOSE + * Return info about the filesystem. + * + * DESCRIPTION + * Called by sys_statfs() + * + * HISTORY + * July 1, 1997 - Andrew E. Mileski + * Written, tested, and released. + */ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; @@ -2117,6 +2035,10 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } +static unsigned char udf_bitmap_lookup[16] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 +}; + static unsigned int udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap) { @@ -2126,6 +2048,7 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, int block = 0, newblock; kernel_lb_addr loc; uint32_t bytes; + uint8_t value; uint8_t *ptr; uint16_t ident; struct spaceBitmapDesc *bm; @@ -2151,10 +2074,13 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, ptr = (uint8_t *)bh->b_data; while (bytes > 0) { - u32 cur_bytes = min_t(u32, bytes, sb->s_blocksize - index); - accum += bitmap_weight((const unsigned long *)(ptr + index), - cur_bytes * 8); - bytes -= cur_bytes; + while ((bytes > 0) && (index < sb->s_blocksize)) { + value = ptr[index]; + accum += udf_bitmap_lookup[value & 0x0f]; + accum += udf_bitmap_lookup[value >> 4]; + index++; + bytes--; + } if (bytes) { brelse(bh); newblock = udf_get_lb_pblock(sb, loc, ++block); diff --git a/trunk/fs/udf/symlink.c b/trunk/fs/udf/symlink.c index c3265e1385d4..6ec99221e50c 100644 --- a/trunk/fs/udf/symlink.c +++ b/trunk/fs/udf/symlink.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/fs/udf/truncate.c b/trunk/fs/udf/truncate.c index 65e19b4f9424..fe61be17cdab 100644 --- a/trunk/fs/udf/truncate.c +++ b/trunk/fs/udf/truncate.c @@ -22,6 +22,7 @@ #include "udfdecl.h" #include #include +#include #include #include "udf_i.h" @@ -179,24 +180,6 @@ void udf_discard_prealloc(struct inode *inode) 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; @@ -204,6 +187,7 @@ void udf_truncate_extents(struct inode *inode) uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc; int8_t etype; struct super_block *sb = inode->i_sb; + struct udf_sb_info *sbi = UDF_SB(sb); sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset; loff_t byte_offset; int adsize; @@ -240,15 +224,35 @@ void udf_truncate_extents(struct inode *inode) if (indirect_ext_len) { /* We managed to free all extents in the * indirect extent - free it too */ - BUG_ON(!epos.bh); + if (!epos.bh) + BUG(); 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 (!epos.bh) { + iinfo->i_lenAlloc = + lenalloc; + mark_inode_dirty(inode); + } else { + 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); + } + } brelse(epos.bh); epos.offset = sizeof(struct allocExtDesc); epos.block = eloc; @@ -268,14 +272,29 @@ void udf_truncate_extents(struct inode *inode) } if (indirect_ext_len) { - BUG_ON(!epos.bh); + if (!epos.bh) + BUG(); 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 (!epos.bh) { + iinfo->i_lenAlloc = lenalloc; + mark_inode_dirty(inode); + } else { + struct allocExtDesc *aed = + (struct allocExtDesc *)(epos.bh->b_data); + aed->lengthAllocDescs = cpu_to_le32(lenalloc); + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || + sbi->s_udfrev >= 0x0201) + udf_update_tag(epos.bh->b_data, + lenalloc + + sizeof(struct allocExtDesc)); + else + udf_update_tag(epos.bh->b_data, + sizeof(struct allocExtDesc)); + mark_buffer_dirty_inode(epos.bh, inode); + } + } } else if (inode->i_size) { if (byte_offset) { kernel_long_ad extent; diff --git a/trunk/fs/udf/udf_i.h b/trunk/fs/udf/udf_i.h index 4f86b1d98a5d..ccc52f16bf7d 100644 --- a/trunk/fs/udf/udf_i.h +++ b/trunk/fs/udf/udf_i.h @@ -1,32 +1,10 @@ -#ifndef _UDF_I_H -#define _UDF_I_H - -struct udf_inode_info { - struct timespec i_crtime; - /* Physical address of inode */ - 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 { - short_ad *i_sad; - long_ad *i_lad; - __u8 *i_data; - } i_ext; - struct inode vfs_inode; -}; +#ifndef __LINUX_UDF_I_H +#define __LINUX_UDF_I_H +#include 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) */ +#endif /* !defined(_LINUX_UDF_I_H) */ diff --git a/trunk/fs/udf/udf_sb.h b/trunk/fs/udf/udf_sb.h index 1c1c514a9725..737d1c604eea 100644 --- a/trunk/fs/udf/udf_sb.h +++ b/trunk/fs/udf/udf_sb.h @@ -1,12 +1,10 @@ #ifndef __LINUX_UDF_SB_H #define __LINUX_UDF_SB_H -#include - /* Since UDF 2.01 is ISO 13346 based... */ #define UDF_SUPER_MAGIC 0x15013346 -#define UDF_MAX_READ_VERSION 0x0250 +#define UDF_MAX_READ_VERSION 0x0201 #define UDF_MAX_WRITE_VERSION 0x0201 #define UDF_FLAG_USE_EXTENDED_FE 0 @@ -40,111 +38,6 @@ #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 - -#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[3]; - __u32 s_last_block; - - struct buffer_head *s_lvid_bh; - - /* Default permissions */ - mode_t s_umask; - gid_t s_gid; - uid_t s_uid; - - /* 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; -}; - static inline struct udf_sb_info *UDF_SB(struct super_block *sb) { return sb->s_fs_info; diff --git a/trunk/fs/udf/udfdecl.h b/trunk/fs/udf/udfdecl.h index f3f45d029277..681dc2b66cdb 100644 --- a/trunk/fs/udf/udfdecl.h +++ b/trunk/fs/udf/udfdecl.h @@ -1,37 +1,17 @@ #ifndef __UDF_DECL_H #define __UDF_DECL_H +#include #include "ecma_167.h" #include "osta_udf.h" #include #include -#include #include +#include +#include -#include "udf_sb.h" #include "udfend.h" -#include "udf_i.h" - -#define UDF_PREALLOCATE -#define UDF_DEFAULT_PREALLOC_BLOCKS 8 - -#define 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 ) ) @@ -43,24 +23,16 @@ do { \ #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; -} +#define udf_file_entry_alloc_offset(inode)\ + (UDF_I(inode)->i_use ?\ + sizeof(struct unallocSpaceEntry) :\ + ((UDF_I(inode)->i_efe ?\ + sizeof(struct extendedFileEntry) :\ + sizeof(struct fileEntry)) + UDF_I(inode)->i_lenEAttr)) + +#define udf_ext0_offset(inode)\ + (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ?\ + udf_file_entry_alloc_offset(inode) : 0) #define udf_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset)) @@ -111,6 +83,7 @@ struct extent_position { }; /* super.c */ +extern void udf_error(struct super_block *, const char *, const char *, ...); extern void udf_warning(struct super_block *, const char *, const char *, ...); /* namei.c */ @@ -177,8 +150,6 @@ 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 *); /* unicode.c */ @@ -186,7 +157,7 @@ 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 *); +extern int udf_CS0toUTF8(struct ustr *, struct ustr *); /* ialloc.c */ extern void udf_free_inode(struct inode *); @@ -220,9 +191,11 @@ extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, extern long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int); extern short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int); +/* crc.c */ +extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t); + /* udftime.c */ -extern struct timespec *udf_disk_stamp_to_time(struct timespec *dest, - timestamp src); -extern timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec src); +extern time_t *udf_stamp_to_time(time_t *, long *, kernel_timestamp); +extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *, struct timespec); #endif /* __UDF_DECL_H */ diff --git a/trunk/fs/udf/udfend.h b/trunk/fs/udf/udfend.h index 489f52fb428c..c4bd1203f857 100644 --- a/trunk/fs/udf/udfend.h +++ b/trunk/fs/udf/udfend.h @@ -24,6 +24,17 @@ static inline lb_addr cpu_to_lelb(kernel_lb_addr in) return out; } +static inline kernel_timestamp lets_to_cpu(timestamp in) +{ + kernel_timestamp out; + + memcpy(&out, &in, sizeof(timestamp)); + out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone); + out.year = le16_to_cpu(in.year); + + return out; +} + static inline short_ad lesa_to_cpu(short_ad in) { short_ad out; @@ -74,4 +85,15 @@ static inline kernel_extent_ad leea_to_cpu(extent_ad in) return out; } +static inline timestamp cpu_to_lets(kernel_timestamp in) +{ + timestamp out; + + memcpy(&out, &in, sizeof(timestamp)); + out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone); + out.year = cpu_to_le16(in.year); + + return out; +} + #endif /* __UDF_ENDIAN_H */ diff --git a/trunk/fs/udf/udftime.c b/trunk/fs/udf/udftime.c index 5f811655c9b5..ce595732ba6f 100644 --- a/trunk/fs/udf/udftime.c +++ b/trunk/fs/udf/udftime.c @@ -85,38 +85,39 @@ 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, timestamp src) +time_t *udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src) { int yday; - u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone); - u16 year = le16_to_cpu(src.year); - uint8_t type = typeAndTimezone >> 12; + uint8_t type = src.typeAndTimezone >> 12; int16_t offset; if (type == 1) { - offset = typeAndTimezone << 4; + offset = src.typeAndTimezone << 4; /* sign extent offset */ offset = (offset >> 4); if (offset == -2047) /* unspecified offset */ offset = 0; - } else + } else { offset = 0; + } - if ((year < EPOCH_YEAR) || - (year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) { + if ((src.year < EPOCH_YEAR) || + (src.year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) { + *dest = -1; + *dest_usec = -1; return NULL; } - dest->tv_sec = year_seconds[year - EPOCH_YEAR]; - dest->tv_sec -= offset * 60; + *dest = year_seconds[src.year - EPOCH_YEAR]; + *dest -= 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); + yday = ((__mon_yday[__isleap(src.year)][src.month - 1]) + src.day - 1); + *dest += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second; + *dest_usec = src.centiseconds * 10000 + + src.hundredsOfMicroseconds * 100 + src.microseconds; return dest; } -timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec ts) +kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts) { long int days, rem, y; const unsigned short int *ip; @@ -127,7 +128,7 @@ timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec ts) if (!dest) return NULL; - dest->typeAndTimezone = cpu_to_le16(0x1000 | (offset & 0x0FFF)); + dest->typeAndTimezone = 0x1000 | (offset & 0x0FFF); ts.tv_sec += offset * 60; days = ts.tv_sec / SECS_PER_DAY; @@ -150,7 +151,7 @@ timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec ts) - LEAPS_THRU_END_OF(y - 1)); y = yg; } - dest->year = cpu_to_le16(y); + dest->year = y; ip = __mon_yday[__isleap(y)]; for (y = 11; days < (long int)ip[y]; --y) continue; diff --git a/trunk/fs/udf/unicode.c b/trunk/fs/udf/unicode.c index 9fdf8c93c58e..e533b11703bf 100644 --- a/trunk/fs/udf/unicode.c +++ b/trunk/fs/udf/unicode.c @@ -23,7 +23,7 @@ #include #include /* for memset */ #include -#include +#include #include "udf_sb.h" @@ -49,16 +49,14 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size) { int usesize; - if (!dest || !ptr || !size) + 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); + memset(dest, 0, sizeof(struct ustr)); + usesize = (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size; 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); + dest->u_len = ptr[size - 1]; + memcpy(dest->u_name, ptr + 1, usesize - 1); return 0; } @@ -85,6 +83,9 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) * PURPOSE * Convert OSTA Compressed Unicode to the UTF-8 equivalent. * + * DESCRIPTION + * This routine is only called by udf_filldir(). + * * PRE-CONDITIONS * utf Pointer to UTF-8 output buffer. * ocu Pointer to OSTA Compressed Unicode input buffer @@ -98,39 +99,43 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) * November 12, 1997 - Andrew E. Mileski * Written, tested, and released. */ -int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i) +int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i) { - const uint8_t *ocu; + uint8_t *ocu; + uint32_t c; uint8_t cmp_id, ocu_len; int i; + ocu = ocu_i->u_name; + ocu_len = ocu_i->u_len; + cmp_id = ocu_i->u_cmpID; + utf_o->u_len = 0; + if (ocu_len == 0) { memset(utf_o, 0, sizeof(struct ustr)); + utf_o->u_cmpID = 0; + utf_o->u_len = 0; return 0; } - cmp_id = ocu_i->u_cmpID; - if (cmp_id != 8 && cmp_id != 16) { - memset(utf_o, 0, sizeof(struct ustr)); + if ((cmp_id != 8) && (cmp_id != 16)) { printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name); return 0; } - 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++]; + c = ocu[i++]; if (cmp_id == 16) c = (c << 8) | ocu[i++]; /* Compress Unicode to UTF-8 */ - if (c < 0x80U) + if (c < 0x80U) { utf_o->u_name[utf_o->u_len++] = (uint8_t)c; - else if (c < 0x800U) { + } 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++] = @@ -250,32 +255,35 @@ static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) } static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, - const struct ustr *ocu_i) + struct ustr *ocu_i) { - const uint8_t *ocu; + uint8_t *ocu; + uint32_t c; uint8_t cmp_id, ocu_len; int i; + ocu = ocu_i->u_name; ocu_len = ocu_i->u_len; + cmp_id = ocu_i->u_cmpID; + utf_o->u_len = 0; + if (ocu_len == 0) { memset(utf_o, 0, sizeof(struct ustr)); + utf_o->u_cmpID = 0; + utf_o->u_len = 0; return 0; } - cmp_id = ocu_i->u_cmpID; - if (cmp_id != 8 && cmp_id != 16) { - memset(utf_o, 0, sizeof(struct ustr)); + if ((cmp_id != 8) && (cmp_id != 16)) { printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name); return 0; } - 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++]; + c = ocu[i++]; if (cmp_id == 16) c = (c << 8) | ocu[i++]; @@ -455,7 +463,7 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, } else if (newIndex > 250) newIndex = 250; newName[newIndex++] = CRC_MARK; - valueCRC = crc_itu_t(0, fidName, fidNameLen); + valueCRC = udf_crc(fidName, fidNameLen, 0); newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; diff --git a/trunk/include/linux/Kbuild b/trunk/include/linux/Kbuild index 34624835d90f..b3d9ccde0c27 100644 --- a/trunk/include/linux/Kbuild +++ b/trunk/include/linux/Kbuild @@ -150,7 +150,6 @@ header-y += tiocl.h header-y += tipc.h header-y += tipc_config.h header-y += toshiba.h -header-y += udf_fs_i.h header-y += ultrasound.h header-y += un.h header-y += utime.h @@ -335,6 +334,7 @@ unifdef-y += time.h unifdef-y += timex.h unifdef-y += tty.h unifdef-y += types.h +unifdef-y += udf_fs_i.h unifdef-y += udp.h unifdef-y += uinput.h unifdef-y += uio.h diff --git a/trunk/include/linux/udf_fs.h b/trunk/include/linux/udf_fs.h new file mode 100644 index 000000000000..aa88654eb76b --- /dev/null +++ b/trunk/include/linux/udf_fs.h @@ -0,0 +1,51 @@ +/* + * udf_fs.h + * + * PURPOSE + * Included by fs/filesystems.c + * + * DESCRIPTION + * OSTA-UDF(tm) = Optical Storage Technology Association + * Universal Disk Format. + * + * This code is based on version 2.50 of the UDF specification, + * and revision 3 of the ECMA 167 standard [equivalent to ISO 13346]. + * http://www.osta.org/ * http://www.ecma.ch/ + * http://www.iso.org/ + * + * 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-2000 Stelias Computing Inc + * + * HISTORY + * + */ + +#ifndef _UDF_FS_H +#define _UDF_FS_H 1 + +#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__, __FUNCTION__); \ + 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); + +#endif /* _UDF_FS_H */ diff --git a/trunk/include/linux/udf_fs_i.h b/trunk/include/linux/udf_fs_i.h index 3536965913b0..ffaf05679ffb 100644 --- a/trunk/include/linux/udf_fs_i.h +++ b/trunk/include/linux/udf_fs_i.h @@ -9,10 +9,41 @@ * ftp://prep.ai.mit.edu/pub/gnu/GPL * Each contributing author retains all rights to their own work. */ + #ifndef _UDF_FS_I_H #define _UDF_FS_I_H 1 +#ifdef __KERNEL__ + +struct udf_inode_info +{ + struct timespec i_crtime; + /* Physical address of inode */ + 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; + unsigned i_use : 1; + unsigned i_strat4096 : 1; + unsigned reserved : 26; + union + { + short_ad *i_sad; + long_ad *i_lad; + __u8 *i_data; + } i_ext; + struct inode vfs_inode; +}; + +#endif + /* exported IOCTLs, we have 'l', 0x40-0x7f */ + #define UDF_GETEASIZE _IOR('l', 0x40, int) #define UDF_GETEABLOCK _IOR('l', 0x41, void *) #define UDF_GETVOLIDENT _IOR('l', 0x42, void *) diff --git a/trunk/include/linux/udf_fs_sb.h b/trunk/include/linux/udf_fs_sb.h new file mode 100644 index 000000000000..9bc47352b6b4 --- /dev/null +++ b/trunk/include/linux/udf_fs_sb.h @@ -0,0 +1,117 @@ +/* + * udf_fs_sb.h + * + * This include file is for the Linux kernel/module. + * + * 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. + */ + +#ifndef _UDF_FS_SB_H +#define _UDF_FS_SB_H 1 + +#include + +#pragma pack(1) + +#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 + +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; + } 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[4]; + __u32 s_last_block; + + struct buffer_head *s_lvid_bh; + + /* Default permissions */ + mode_t s_umask; + gid_t s_gid; + uid_t s_uid; + + /* 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; +}; + +#endif /* _UDF_FS_SB_H */