Commit 62429f43 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-udf-2.6

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-udf-2.6: (41 commits)
  udf: use crc_itu_t from lib instead of udf_crc
  udf: Fix compilation warnings when UDF debug is on
  udf: Fix bug in VAT mapping code
  udf: Add read-only support for 2.50 UDF media
  udf: Fix handling of multisession media
  udf: Mount filesystem read-only if it has pseudooverwrite partition
  udf: Handle VAT packed inside inode properly
  udf: Allow loading of VAT inode
  udf: Fix detection of VAT version
  udf: Silence warning about accesses beyond end of device
  udf: Improve anchor block detection
  udf: Cleanup anchor block detection.
  udf: Move processing of virtual partitions
  udf: Move filling of partition descriptor info into a separate function
  udf: Improve error recovery on mount
  udf: Cleanup volume descriptor sequence processing
  udf: fix anchor point detection
  udf: Remove declarations of arrays of size UDF_NAME_LEN (256 bytes)
  udf: Remove checking of existence of filename in udf_add_entry()
  udf: Mark udf_process_sequence() as noinline
  ...
parents 26defe34 f845fced
...@@ -689,6 +689,7 @@ config ZISOFS ...@@ -689,6 +689,7 @@ config ZISOFS
config UDF_FS config UDF_FS
tristate "UDF file system support" tristate "UDF file system support"
select CRC_ITU_T
help help
This is the new file system used on some CD-ROMs and DVDs. Say Y if 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 you intend to mount DVD discs or CDRW's written in packet mode, or
......
...@@ -6,4 +6,4 @@ obj-$(CONFIG_UDF_FS) += udf.o ...@@ -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 \ 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 \ partition.o super.o truncate.o symlink.o fsync.o \
crc.o directory.o misc.o udftime.o unicode.o directory.o misc.o udftime.o unicode.o
...@@ -149,8 +149,7 @@ static bool udf_add_free_space(struct udf_sb_info *sbi, ...@@ -149,8 +149,7 @@ static bool udf_add_free_space(struct udf_sb_info *sbi,
return false; return false;
lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data; lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data;
lvid->freeSpaceTable[partition] = cpu_to_le32(le32_to_cpu( le32_add_cpu(&lvid->freeSpaceTable[partition], cnt);
lvid->freeSpaceTable[partition]) + cnt);
return true; return true;
} }
...@@ -589,9 +588,7 @@ static void udf_table_free_blocks(struct super_block *sb, ...@@ -589,9 +588,7 @@ static void udf_table_free_blocks(struct super_block *sb,
sptr = oepos.bh->b_data + epos.offset; sptr = oepos.bh->b_data + epos.offset;
aed = (struct allocExtDesc *) aed = (struct allocExtDesc *)
oepos.bh->b_data; oepos.bh->b_data;
aed->lengthAllocDescs = le32_add_cpu(&aed->lengthAllocDescs,
cpu_to_le32(le32_to_cpu(
aed->lengthAllocDescs) +
adsize); adsize);
} else { } else {
sptr = iinfo->i_ext.i_data + sptr = iinfo->i_ext.i_data +
...@@ -645,9 +642,7 @@ static void udf_table_free_blocks(struct super_block *sb, ...@@ -645,9 +642,7 @@ static void udf_table_free_blocks(struct super_block *sb,
mark_inode_dirty(table); mark_inode_dirty(table);
} else { } else {
aed = (struct allocExtDesc *)epos.bh->b_data; aed = (struct allocExtDesc *)epos.bh->b_data;
aed->lengthAllocDescs = le32_add_cpu(&aed->lengthAllocDescs, adsize);
cpu_to_le32(le32_to_cpu(
aed->lengthAllocDescs) + adsize);
udf_update_tag(epos.bh->b_data, epos.offset); udf_update_tag(epos.bh->b_data, epos.offset);
mark_buffer_dirty(epos.bh); mark_buffer_dirty(epos.bh);
} }
......
/*
* crc.c
*
* PURPOSE
* Routines to generate, calculate, and test a 16-bit CRC.
*
* DESCRIPTION
* The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories
* and Ned W. Rhodes of Software Systems Group. It has been published in
* "Design and Validation of Computer Protocols", Prentice Hall,
* Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4.
*
* Copyright is held by AT&T.
*
* AT&T gives permission for the free use of the CRC source code.
*
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
* ftp://prep.ai.mit.edu/pub/gnu/GPL
* Each contributing author retains all rights to their own work.
*/
#include "udfdecl.h"
static uint16_t crc_table[256] = {
0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U,
0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU,
0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U,
0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU,
0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U,
0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU,
0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U,
0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU,
0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U,
0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU,
0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U,
0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU,
0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U,
0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U,
0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U,
0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U,
0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU,
0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U,
0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU,
0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U,
0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU,
0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U,
0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU,
0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U,
0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU,
0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U,
0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU,
0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U,
0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U,
0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U,
0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U,
0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U
};
/*
* udf_crc
*
* PURPOSE
* Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial.
*
* DESCRIPTION
* The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
* The polynomial used is: x^16 + x^12 + x^15 + 1
*
* PRE-CONDITIONS
* data Pointer to the data block.
* size Size of the data block.
*
* POST-CONDITIONS
* <return> CRC of the data block.
*
* HISTORY
* July 21, 1997 - Andrew E. Mileski
* Adapted from OSTA-UDF(tm) 1.50 standard.
*/
uint16_t udf_crc(uint8_t *data, uint32_t size, uint16_t crc)
{
while (size--)
crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8);
return crc;
}
/****************************************************************************/
#if defined(TEST)
/*
* PURPOSE
* Test udf_crc()
*
* HISTORY
* July 21, 1997 - Andrew E. Mileski
* Adapted from OSTA-UDF(tm) 1.50 standard.
*/
unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U };
int main(void)
{
unsigned short x;
x = udf_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 <stdio.h>
int main(int argc, char **argv)
{
unsigned long crc, poly;
int n, i;
/* Get the polynomial */
sscanf(argv[1], "%lo", &poly);
if (poly & 0xffff0000U) {
fprintf(stderr, "polynomial is too large\en");
exit(1);
}
printf("/* CRC 0%o */\n", poly);
/* Create a table */
printf("static unsigned short crc_table[256] = {\n");
for (n = 0; n < 256; n++) {
if (n % 8 == 0)
printf("\t");
crc = n << 8;
for (i = 0; i < 8; i++) {
if (crc & 0x8000U)
crc = (crc << 1) ^ poly;
else
crc <<= 1;
crc &= 0xFFFFU;
}
if (n == 255)
printf("0x%04xU ", crc);
else
printf("0x%04xU, ", crc);
if (n % 8 == 7)
printf("\n");
}
printf("};\n");
return 0;
}
#endif /* defined(GENERATE) */
...@@ -39,13 +39,13 @@ ...@@ -39,13 +39,13 @@
static int do_udf_readdir(struct inode *dir, struct file *filp, static int do_udf_readdir(struct inode *dir, struct file *filp,
filldir_t filldir, void *dirent) filldir_t filldir, void *dirent)
{ {
struct udf_fileident_bh fibh; struct udf_fileident_bh fibh = { .sbh = NULL, .ebh = NULL};
struct fileIdentDesc *fi = NULL; struct fileIdentDesc *fi = NULL;
struct fileIdentDesc cfi; struct fileIdentDesc cfi;
int block, iblock; int block, iblock;
loff_t nf_pos = (filp->f_pos - 1) << 2; loff_t nf_pos = (filp->f_pos - 1) << 2;
int flen; int flen;
char fname[UDF_NAME_LEN]; char *fname = NULL;
char *nameptr; char *nameptr;
uint16_t liu; uint16_t liu;
uint8_t lfi; uint8_t lfi;
...@@ -54,23 +54,32 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, ...@@ -54,23 +54,32 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
kernel_lb_addr eloc; kernel_lb_addr eloc;
uint32_t elen; uint32_t elen;
sector_t offset; sector_t offset;
int i, num; int i, num, ret = 0;
unsigned int dt_type; unsigned int dt_type;
struct extent_position epos = { NULL, 0, {0, 0} }; struct extent_position epos = { NULL, 0, {0, 0} };
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
if (nf_pos >= size) if (nf_pos >= size)
return 0; goto out;
fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
if (!fname) {
ret = -ENOMEM;
goto out;
}
if (nf_pos == 0) if (nf_pos == 0)
nf_pos = udf_ext0_offset(dir); nf_pos = udf_ext0_offset(dir);
fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1); fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1);
iinfo = UDF_I(dir); iinfo = UDF_I(dir);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
fibh.sbh = fibh.ebh = NULL; if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits,
} else if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits, &epos, &eloc, &elen, &offset)
&epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) { != (EXT_RECORDED_ALLOCATED >> 30)) {
ret = -ENOENT;
goto out;
}
block = udf_get_lb_pblock(dir->i_sb, eloc, offset); block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
...@@ -83,8 +92,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, ...@@ -83,8 +92,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
} }
if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) { if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
brelse(epos.bh); ret = -EIO;
return -EIO; goto out;
} }
if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) { if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
...@@ -105,9 +114,6 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, ...@@ -105,9 +114,6 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
brelse(bha[i]); brelse(bha[i]);
} }
} }
} else {
brelse(epos.bh);
return -ENOENT;
} }
while (nf_pos < size) { while (nf_pos < size) {
...@@ -115,13 +121,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, ...@@ -115,13 +121,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc, fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
&elen, &offset); &elen, &offset);
if (!fi) { if (!fi)
if (fibh.sbh != fibh.ebh) goto out;
brelse(fibh.ebh);
brelse(fibh.sbh);
brelse(epos.bh);
return 0;
}
liu = le16_to_cpu(cfi.lengthOfImpUse); liu = le16_to_cpu(cfi.lengthOfImpUse);
lfi = cfi.lengthFileIdent; lfi = cfi.lengthFileIdent;
...@@ -167,53 +168,23 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, ...@@ -167,53 +168,23 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
dt_type = DT_UNKNOWN; dt_type = DT_UNKNOWN;
} }
if (flen) { if (flen && filldir(dirent, fname, flen, filp->f_pos,
if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) { iblock, dt_type) < 0)
if (fibh.sbh != fibh.ebh) goto out;
brelse(fibh.ebh);
brelse(fibh.sbh);
brelse(epos.bh);
return 0;
}
}
} /* end while */ } /* end while */
filp->f_pos = (nf_pos >> 2) + 1; filp->f_pos = (nf_pos >> 2) + 1;
out:
if (fibh.sbh != fibh.ebh) if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh); brelse(fibh.ebh);
brelse(fibh.sbh); brelse(fibh.sbh);
brelse(epos.bh); brelse(epos.bh);
kfree(fname);
return 0; return ret;
} }
/*
* udf_readdir
*
* PURPOSE
* Read a directory entry.
*
* DESCRIPTION
* Optional - sys_getdents() will return -ENOTDIR if this routine is not
* available.
*
* Refer to sys_getdents() in fs/readdir.c
* sys_getdents() -> .
*
* PRE-CONDITIONS
* filp Pointer to directory file.
* buf Pointer to directory entry buffer.
* filldir Pointer to filldir function.
*
* POST-CONDITIONS
* <return> >=0 on success.
*
* HISTORY
* July 1, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/
static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
{ {
struct inode *dir = filp->f_path.dentry->d_inode; struct inode *dir = filp->f_path.dentry->d_inode;
......
...@@ -70,19 +70,6 @@ typedef struct { ...@@ -70,19 +70,6 @@ typedef struct {
uint8_t microseconds; uint8_t microseconds;
} __attribute__ ((packed)) timestamp; } __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) */ /* Type and Time Zone (ECMA 167r3 1/7.3.1) */
#define TIMESTAMP_TYPE_MASK 0xF000 #define TIMESTAMP_TYPE_MASK 0xF000
#define TIMESTAMP_TYPE_CUT 0x0000 #define TIMESTAMP_TYPE_CUT 0x0000
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include "udfdecl.h" #include "udfdecl.h"
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/udf_fs.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/string.h> /* memset */ #include <linux/string.h> /* memset */
...@@ -144,40 +143,6 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -144,40 +143,6 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
return retval; return retval;
} }
/*
* udf_ioctl
*
* PURPOSE
* Issue an ioctl.
*
* DESCRIPTION
* Optional - sys_ioctl() will return -ENOTTY if this routine is not
* available, and the ioctl cannot be handled without filesystem help.
*
* sys_ioctl() handles these ioctls that apply only to regular files:
* FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD
* These ioctls are also handled by sys_ioctl():
* FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC
* All other ioctls are passed to the filesystem.
*
* Refer to sys_ioctl() in fs/ioctl.c
* sys_ioctl() -> .
*
* PRE-CONDITIONS
* inode Pointer to inode that ioctl was issued on.
* filp Pointer to file that ioctl was issued on.
* cmd The ioctl command.
* arg The ioctl argument [can be interpreted as a
* user-space pointer if desired].
*
* POST-CONDITIONS
* <return> Success (>=0) or an error code (<=0) that
* sys_ioctl() will return.
*
* HISTORY
* July 1, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/
int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
...@@ -225,18 +190,6 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, ...@@ -225,18 +190,6 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
return result; 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) static int udf_release_file(struct inode *inode, struct file *filp)
{ {
if (filp->f_mode & FMODE_WRITE) { if (filp->f_mode & FMODE_WRITE) {
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include "udfdecl.h" #include "udfdecl.h"
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/quotaops.h> #include <linux/quotaops.h>
#include <linux/udf_fs.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -47,11 +46,9 @@ void udf_free_inode(struct inode *inode) ...@@ -47,11 +46,9 @@ void udf_free_inode(struct inode *inode)
struct logicalVolIntegrityDescImpUse *lvidiu = struct logicalVolIntegrityDescImpUse *lvidiu =
udf_sb_lvidiu(sbi); udf_sb_lvidiu(sbi);
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
lvidiu->numDirs = le32_add_cpu(&lvidiu->numDirs, -1);
cpu_to_le32(le32_to_cpu(lvidiu->numDirs) - 1);
else else
lvidiu->numFiles = le32_add_cpu(&lvidiu->numFiles, -1);
cpu_to_le32(le32_to_cpu(lvidiu->numFiles) - 1);
mark_buffer_dirty(sbi->s_lvid_bh); mark_buffer_dirty(sbi->s_lvid_bh);
} }
...@@ -105,11 +102,9 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) ...@@ -105,11 +102,9 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
lvhd = (struct logicalVolHeaderDesc *) lvhd = (struct logicalVolHeaderDesc *)
(lvid->logicalVolContentsUse); (lvid->logicalVolContentsUse);
if (S_ISDIR(mode)) if (S_ISDIR(mode))
lvidiu->numDirs = le32_add_cpu(&lvidiu->numDirs, 1);
cpu_to_le32(le32_to_cpu(lvidiu->numDirs) + 1);
else else
lvidiu->numFiles = le32_add_cpu(&lvidiu->numFiles, 1);
cpu_to_le32(le32_to_cpu(lvidiu->numFiles) + 1);
iinfo->i_unique = uniqueID = le64_to_cpu(lvhd->uniqueID); iinfo->i_unique = uniqueID = le64_to_cpu(lvhd->uniqueID);
if (!(++uniqueID & 0x00000000FFFFFFFFUL)) if (!(++uniqueID & 0x00000000FFFFFFFFUL))
uniqueID += 16; uniqueID += 16;
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/crc-itu-t.h>
#include "udf_i.h" #include "udf_i.h"
#include "udf_sb.h" #include "udf_sb.h"
...@@ -66,22 +67,7 @@ static void udf_update_extents(struct inode *, ...@@ -66,22 +67,7 @@ static void udf_update_extents(struct inode *,
struct extent_position *); struct extent_position *);
static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); 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) void udf_delete_inode(struct inode *inode)
{ {
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
...@@ -323,9 +309,6 @@ static int udf_get_block(struct inode *inode, sector_t block, ...@@ -323,9 +309,6 @@ static int udf_get_block(struct inode *inode, sector_t block,
lock_kernel(); lock_kernel();
if (block < 0)
goto abort_negative;
iinfo = UDF_I(inode); iinfo = UDF_I(inode);
if (block == iinfo->i_next_alloc_block + 1) { if (block == iinfo->i_next_alloc_block + 1) {
iinfo->i_next_alloc_block++; iinfo->i_next_alloc_block++;
...@@ -347,10 +330,6 @@ static int udf_get_block(struct inode *inode, sector_t block, ...@@ -347,10 +330,6 @@ static int udf_get_block(struct inode *inode, sector_t block,
abort: abort:
unlock_kernel(); unlock_kernel();
return err; 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, static struct buffer_head *udf_getblk(struct inode *inode, long block,
...@@ -1116,16 +1095,16 @@ static void __udf_read_inode(struct inode *inode) ...@@ -1116,16 +1095,16 @@ static void __udf_read_inode(struct inode *inode)
fe = (struct fileEntry *)bh->b_data; fe = (struct fileEntry *)bh->b_data;
if (fe->icbTag.strategyType == cpu_to_le16(4096)) { if (fe->icbTag.strategyType == cpu_to_le16(4096)) {
struct buffer_head *ibh = NULL, *nbh = NULL; struct buffer_head *ibh;
struct indirectEntry *ie;
ibh = udf_read_ptagged(inode->i_sb, iinfo->i_location, 1, ibh = udf_read_ptagged(inode->i_sb, iinfo->i_location, 1,
&ident); &ident);
if (ident == TAG_IDENT_IE) { if (ident == TAG_IDENT_IE && ibh) {
if (ibh) { struct buffer_head *nbh = NULL;
kernel_lb_addr loc; kernel_lb_addr loc;
ie = (struct indirectEntry *)ibh->b_data; struct indirectEntry *ie;
ie = (struct indirectEntry *)ibh->b_data;
loc = lelb_to_cpu(ie->indirectICB.extLocation); loc = lelb_to_cpu(ie->indirectICB.extLocation);
if (ie->indirectICB.extLength && if (ie->indirectICB.extLength &&
...@@ -1141,17 +1120,11 @@ static void __udf_read_inode(struct inode *inode) ...@@ -1141,17 +1120,11 @@ static void __udf_read_inode(struct inode *inode)
brelse(nbh); brelse(nbh);
__udf_read_inode(inode); __udf_read_inode(inode);
return; return;
} else {
brelse(nbh);
brelse(ibh);
} }
} else { brelse(nbh);
brelse(ibh);
} }
} }
} else {
brelse(ibh); brelse(ibh);
}
} else if (fe->icbTag.strategyType != cpu_to_le16(4)) { } else if (fe->icbTag.strategyType != cpu_to_le16(4)) {
printk(KERN_ERR "udf: unsupported strategy type: %d\n", printk(KERN_ERR "udf: unsupported strategy type: %d\n",
le16_to_cpu(fe->icbTag.strategyType)); le16_to_cpu(fe->icbTag.strategyType));
...@@ -1168,8 +1141,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) ...@@ -1168,8 +1141,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
{ {
struct fileEntry *fe; struct fileEntry *fe;
struct extendedFileEntry *efe; struct extendedFileEntry *efe;
time_t convtime;
long convtime_usec;
int offset; int offset;
struct udf_sb_info *sbi = UDF_SB(inode->i_sb); struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
...@@ -1257,29 +1228,15 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) ...@@ -1257,29 +1228,15 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
(inode->i_sb->s_blocksize_bits - 9); (inode->i_sb->s_blocksize_bits - 9);
if (udf_stamp_to_time(&convtime, &convtime_usec, if (!udf_disk_stamp_to_time(&inode->i_atime, fe->accessTime))
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; inode->i_atime = sbi->s_record_time;
}
if (udf_stamp_to_time(&convtime, &convtime_usec, if (!udf_disk_stamp_to_time(&inode->i_mtime,
lets_to_cpu(fe->modificationTime))) { fe->modificationTime))
inode->i_mtime.tv_sec = convtime;
inode->i_mtime.tv_nsec = convtime_usec * 1000;
} else {
inode->i_mtime = sbi->s_record_time; inode->i_mtime = sbi->s_record_time;
}
if (udf_stamp_to_time(&convtime, &convtime_usec, if (!udf_disk_stamp_to_time(&inode->i_ctime, fe->attrTime))
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; inode->i_ctime = sbi->s_record_time;
}
iinfo->i_unique = le64_to_cpu(fe->uniqueID); iinfo->i_unique = le64_to_cpu(fe->uniqueID);
iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr); iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr);
...@@ -1289,37 +1246,18 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) ...@@ -1289,37 +1246,18 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
(inode->i_sb->s_blocksize_bits - 9); (inode->i_sb->s_blocksize_bits - 9);
if (udf_stamp_to_time(&convtime, &convtime_usec, if (!udf_disk_stamp_to_time(&inode->i_atime, efe->accessTime))
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; inode->i_atime = sbi->s_record_time;
}
if (udf_stamp_to_time(&convtime, &convtime_usec, if (!udf_disk_stamp_to_time(&inode->i_mtime,
lets_to_cpu(efe->modificationTime))) { efe->modificationTime))
inode->i_mtime.tv_sec = convtime;
inode->i_mtime.tv_nsec = convtime_usec * 1000;
} else {
inode->i_mtime = sbi->s_record_time; inode->i_mtime = sbi->s_record_time;
}
if (udf_stamp_to_time(&convtime, &convtime_usec, if (!udf_disk_stamp_to_time(&iinfo->i_crtime, efe->createTime))
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; iinfo->i_crtime = sbi->s_record_time;
}
if (udf_stamp_to_time(&convtime, &convtime_usec, if (!udf_disk_stamp_to_time(&inode->i_ctime, efe->attrTime))
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; inode->i_ctime = sbi->s_record_time;
}
iinfo->i_unique = le64_to_cpu(efe->uniqueID); iinfo->i_unique = le64_to_cpu(efe->uniqueID);
iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr); iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr);
...@@ -1338,6 +1276,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) ...@@ -1338,6 +1276,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
case ICBTAG_FILE_TYPE_REALTIME: case ICBTAG_FILE_TYPE_REALTIME:
case ICBTAG_FILE_TYPE_REGULAR: case ICBTAG_FILE_TYPE_REGULAR:
case ICBTAG_FILE_TYPE_UNDEF: case ICBTAG_FILE_TYPE_UNDEF:
case ICBTAG_FILE_TYPE_VAT20:
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
inode->i_data.a_ops = &udf_adinicb_aops; inode->i_data.a_ops = &udf_adinicb_aops;
else else
...@@ -1363,6 +1302,15 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) ...@@ -1363,6 +1302,15 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
inode->i_op = &page_symlink_inode_operations; inode->i_op = &page_symlink_inode_operations;
inode->i_mode = S_IFLNK | S_IRWXUGO; inode->i_mode = S_IFLNK | S_IRWXUGO;
break; 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: default:
printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown " printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown "
"file type=%d\n", inode->i_ino, "file type=%d\n", inode->i_ino,
...@@ -1416,21 +1364,6 @@ static mode_t udf_convert_permissions(struct fileEntry *fe) ...@@ -1416,21 +1364,6 @@ static mode_t udf_convert_permissions(struct fileEntry *fe)
return mode; 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 udf_write_inode(struct inode *inode, int sync)
{ {
int ret; int ret;
...@@ -1455,7 +1388,6 @@ static int udf_update_inode(struct inode *inode, int do_sync) ...@@ -1455,7 +1388,6 @@ static int udf_update_inode(struct inode *inode, int do_sync)
uint32_t udfperms; uint32_t udfperms;
uint16_t icbflags; uint16_t icbflags;
uint16_t crclen; uint16_t crclen;
kernel_timestamp cpu_time;
int err = 0; int err = 0;
struct udf_sb_info *sbi = UDF_SB(inode->i_sb); struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
...@@ -1488,9 +1420,9 @@ static int udf_update_inode(struct inode *inode, int do_sync) ...@@ -1488,9 +1420,9 @@ static int udf_update_inode(struct inode *inode, int do_sync)
iinfo->i_location. iinfo->i_location.
logicalBlockNum); logicalBlockNum);
use->descTag.descCRCLength = cpu_to_le16(crclen); use->descTag.descCRCLength = cpu_to_le16(crclen);
use->descTag.descCRC = cpu_to_le16(udf_crc((char *)use + use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use +
sizeof(tag), crclen, sizeof(tag),
0)); crclen));
use->descTag.tagChecksum = udf_tag_checksum(&use->descTag); use->descTag.tagChecksum = udf_tag_checksum(&use->descTag);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
...@@ -1558,12 +1490,9 @@ static int udf_update_inode(struct inode *inode, int do_sync) ...@@ -1558,12 +1490,9 @@ static int udf_update_inode(struct inode *inode, int do_sync)
(inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >> (inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >>
(blocksize_bits - 9)); (blocksize_bits - 9));
if (udf_time_to_stamp(&cpu_time, inode->i_atime)) udf_time_to_disk_stamp(&fe->accessTime, inode->i_atime);
fe->accessTime = cpu_to_lets(cpu_time); udf_time_to_disk_stamp(&fe->modificationTime, inode->i_mtime);
if (udf_time_to_stamp(&cpu_time, inode->i_mtime)) udf_time_to_disk_stamp(&fe->attrTime, inode->i_ctime);
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)); memset(&(fe->impIdent), 0, sizeof(regid));
strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER); strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER);
fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
...@@ -1598,14 +1527,10 @@ static int udf_update_inode(struct inode *inode, int do_sync) ...@@ -1598,14 +1527,10 @@ static int udf_update_inode(struct inode *inode, int do_sync)
iinfo->i_crtime.tv_nsec > inode->i_ctime.tv_nsec)) iinfo->i_crtime.tv_nsec > inode->i_ctime.tv_nsec))
iinfo->i_crtime = inode->i_ctime; iinfo->i_crtime = inode->i_ctime;
if (udf_time_to_stamp(&cpu_time, inode->i_atime)) udf_time_to_disk_stamp(&efe->accessTime, inode->i_atime);
efe->accessTime = cpu_to_lets(cpu_time); udf_time_to_disk_stamp(&efe->modificationTime, inode->i_mtime);
if (udf_time_to_stamp(&cpu_time, inode->i_mtime)) udf_time_to_disk_stamp(&efe->createTime, iinfo->i_crtime);
efe->modificationTime = cpu_to_lets(cpu_time); udf_time_to_disk_stamp(&efe->attrTime, inode->i_ctime);
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)); memset(&(efe->impIdent), 0, sizeof(regid));
strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER); strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER);
...@@ -1660,8 +1585,8 @@ static int udf_update_inode(struct inode *inode, int do_sync) ...@@ -1660,8 +1585,8 @@ static int udf_update_inode(struct inode *inode, int do_sync)
crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc - crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc -
sizeof(tag); sizeof(tag);
fe->descTag.descCRCLength = cpu_to_le16(crclen); fe->descTag.descCRCLength = cpu_to_le16(crclen);
fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), fe->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)fe + sizeof(tag),
crclen, 0)); crclen));
fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag); fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag);
/* write the data blocks */ /* write the data blocks */
...@@ -1778,9 +1703,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, ...@@ -1778,9 +1703,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
if (epos->bh) { if (epos->bh) {
aed = (struct allocExtDesc *)epos->bh->b_data; aed = (struct allocExtDesc *)epos->bh->b_data;
aed->lengthAllocDescs = le32_add_cpu(&aed->lengthAllocDescs, adsize);
cpu_to_le32(le32_to_cpu(
aed->lengthAllocDescs) + adsize);
} else { } else {
iinfo->i_lenAlloc += adsize; iinfo->i_lenAlloc += adsize;
mark_inode_dirty(inode); mark_inode_dirty(inode);
...@@ -1830,9 +1753,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos, ...@@ -1830,9 +1753,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
mark_inode_dirty(inode); mark_inode_dirty(inode);
} else { } else {
aed = (struct allocExtDesc *)epos->bh->b_data; aed = (struct allocExtDesc *)epos->bh->b_data;
aed->lengthAllocDescs = le32_add_cpu(&aed->lengthAllocDescs, adsize);
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) +
adsize);
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
udf_update_tag(epos->bh->b_data, udf_update_tag(epos->bh->b_data,
...@@ -2046,9 +1967,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, ...@@ -2046,9 +1967,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
mark_inode_dirty(inode); mark_inode_dirty(inode);
} else { } else {
aed = (struct allocExtDesc *)oepos.bh->b_data; aed = (struct allocExtDesc *)oepos.bh->b_data;
aed->lengthAllocDescs = le32_add_cpu(&aed->lengthAllocDescs, -(2 * adsize));
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) -
(2 * adsize));
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
udf_update_tag(oepos.bh->b_data, udf_update_tag(oepos.bh->b_data,
...@@ -2065,9 +1984,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos, ...@@ -2065,9 +1984,7 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
mark_inode_dirty(inode); mark_inode_dirty(inode);
} else { } else {
aed = (struct allocExtDesc *)oepos.bh->b_data; aed = (struct allocExtDesc *)oepos.bh->b_data;
aed->lengthAllocDescs = le32_add_cpu(&aed->lengthAllocDescs, -adsize);
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) -
adsize);
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
udf_update_tag(oepos.bh->b_data, udf_update_tag(oepos.bh->b_data,
...@@ -2095,11 +2012,6 @@ int8_t inode_bmap(struct inode *inode, sector_t block, ...@@ -2095,11 +2012,6 @@ int8_t inode_bmap(struct inode *inode, sector_t block,
int8_t etype; int8_t etype;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
if (block < 0) {
printk(KERN_ERR "udf: inode_bmap: block < 0\n");
return -1;
}
iinfo = UDF_I(inode); iinfo = UDF_I(inode);
pos->offset = 0; pos->offset = 0;
pos->block = iinfo->i_location; pos->block = iinfo->i_location;
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/udf_fs.h>
#include "udf_sb.h" #include "udf_sb.h"
unsigned int udf_get_last_session(struct super_block *sb) unsigned int udf_get_last_session(struct super_block *sb)
......
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/udf_fs.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/crc-itu-t.h>
#include "udf_i.h" #include "udf_i.h"
#include "udf_sb.h" #include "udf_sb.h"
...@@ -136,8 +136,8 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size, ...@@ -136,8 +136,8 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
/* rewrite CRC + checksum of eahd */ /* rewrite CRC + checksum of eahd */
crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag); crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag);
eahd->descTag.descCRCLength = cpu_to_le16(crclen); eahd->descTag.descCRCLength = cpu_to_le16(crclen);
eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd +
sizeof(tag), crclen, 0)); sizeof(tag), crclen));
eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag); eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag);
iinfo->i_lenEAttr += size; iinfo->i_lenEAttr += size;
return (struct genericFormat *)&ea[offset]; return (struct genericFormat *)&ea[offset];
...@@ -204,16 +204,15 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, ...@@ -204,16 +204,15 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
{ {
tag *tag_p; tag *tag_p;
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct udf_sb_info *sbi = UDF_SB(sb);
/* Read the block */ /* Read the block */
if (block == 0xFFFFFFFF) if (block == 0xFFFFFFFF)
return NULL; return NULL;
bh = udf_tread(sb, block + sbi->s_session); bh = udf_tread(sb, block);
if (!bh) { if (!bh) {
udf_debug("block=%d, location=%d: read failed\n", udf_debug("block=%d, location=%d: read failed\n",
block + sbi->s_session, location); block, location);
return NULL; return NULL;
} }
...@@ -223,8 +222,7 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, ...@@ -223,8 +222,7 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
if (location != le32_to_cpu(tag_p->tagLocation)) { if (location != le32_to_cpu(tag_p->tagLocation)) {
udf_debug("location mismatch block %u, tag %u != %u\n", udf_debug("location mismatch block %u, tag %u != %u\n",
block + sbi->s_session, block, le32_to_cpu(tag_p->tagLocation), location);
le32_to_cpu(tag_p->tagLocation), location);
goto error_out; goto error_out;
} }
...@@ -244,13 +242,13 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block, ...@@ -244,13 +242,13 @@ struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
/* Verify the descriptor CRC */ /* Verify the descriptor CRC */
if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize || if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag), le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
le16_to_cpu(tag_p->descCRCLength), 0)) bh->b_data + sizeof(tag),
le16_to_cpu(tag_p->descCRCLength)))
return bh; return bh;
udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", block,
block + sbi->s_session, le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
le16_to_cpu(tag_p->descCRCLength));
error_out: error_out:
brelse(bh); brelse(bh);
...@@ -270,7 +268,7 @@ void udf_update_tag(char *data, int length) ...@@ -270,7 +268,7 @@ void udf_update_tag(char *data, int length)
length -= sizeof(tag); length -= sizeof(tag);
tptr->descCRCLength = cpu_to_le16(length); tptr->descCRCLength = cpu_to_le16(length);
tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0)); tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(tag), length));
tptr->tagChecksum = udf_tag_checksum(tptr); tptr->tagChecksum = udf_tag_checksum(tptr);
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/crc-itu-t.h>
static inline int udf_match(int len1, const char *name1, int len2, static inline int udf_match(int len1, const char *name1, int len2,
const char *name2) const char *name2)
...@@ -97,25 +98,23 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi, ...@@ -97,25 +98,23 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
memset(fibh->ebh->b_data, 0x00, padlen + offset); memset(fibh->ebh->b_data, 0x00, padlen + offset);
} }
crc = udf_crc((uint8_t *)cfi + sizeof(tag), crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(tag),
sizeof(struct fileIdentDesc) - sizeof(tag), 0); sizeof(struct fileIdentDesc) - sizeof(tag));
if (fibh->sbh == fibh->ebh) { if (fibh->sbh == fibh->ebh) {
crc = udf_crc((uint8_t *)sfi->impUse, crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
crclen + sizeof(tag) - crclen + sizeof(tag) -
sizeof(struct fileIdentDesc), crc); sizeof(struct fileIdentDesc));
} else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) { } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) {
crc = udf_crc(fibh->ebh->b_data + crc = crc_itu_t(crc, fibh->ebh->b_data +
sizeof(struct fileIdentDesc) + sizeof(struct fileIdentDesc) +
fibh->soffset, fibh->soffset,
crclen + sizeof(tag) - crclen + sizeof(tag) -
sizeof(struct fileIdentDesc), sizeof(struct fileIdentDesc));
crc);
} else { } else {
crc = udf_crc((uint8_t *)sfi->impUse, crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
-fibh->soffset - sizeof(struct fileIdentDesc), -fibh->soffset - sizeof(struct fileIdentDesc));
crc); crc = crc_itu_t(crc, fibh->ebh->b_data, fibh->eoffset);
crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
} }
cfi->descTag.descCRC = cpu_to_le16(crc); cfi->descTag.descCRC = cpu_to_le16(crc);
...@@ -149,7 +148,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, ...@@ -149,7 +148,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
struct fileIdentDesc *fi = NULL; struct fileIdentDesc *fi = NULL;
loff_t f_pos; loff_t f_pos;
int block, flen; int block, flen;
char fname[UDF_NAME_LEN]; char *fname = NULL;
char *nameptr; char *nameptr;
uint8_t lfi; uint8_t lfi;
uint16_t liu; uint16_t liu;
...@@ -163,12 +162,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, ...@@ -163,12 +162,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
size = udf_ext0_offset(dir) + dir->i_size; size = udf_ext0_offset(dir) + dir->i_size;
f_pos = udf_ext0_offset(dir); f_pos = udf_ext0_offset(dir);
fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
fibh->sbh = fibh->ebh = NULL; fibh->sbh = fibh->ebh = NULL;
else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
&epos, &eloc, &elen, &offset) == if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
(EXT_RECORDED_ALLOCATED >> 30)) { if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
&eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30))
goto out_err;
block = udf_get_lb_pblock(dir->i_sb, eloc, offset); block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
...@@ -179,25 +178,19 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, ...@@ -179,25 +178,19 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
offset = 0; offset = 0;
fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
if (!fibh->sbh) { if (!fibh->sbh)
brelse(epos.bh); goto out_err;
return NULL;
}
} else {
brelse(epos.bh);
return NULL;
} }
fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
if (!fname)
goto out_err;
while (f_pos < size) { while (f_pos < size) {
fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
&elen, &offset); &elen, &offset);
if (!fi) { if (!fi)
if (fibh->sbh != fibh->ebh) goto out_err;
brelse(fibh->ebh);
brelse(fibh->sbh);
brelse(epos.bh);
return NULL;
}
liu = le16_to_cpu(cfi->lengthOfImpUse); liu = le16_to_cpu(cfi->lengthOfImpUse);
lfi = cfi->lengthFileIdent; lfi = cfi->lengthFileIdent;
...@@ -237,53 +230,22 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, ...@@ -237,53 +230,22 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
if (flen && udf_match(flen, fname, dentry->d_name.len, if (flen && udf_match(flen, fname, dentry->d_name.len,
dentry->d_name.name)) { dentry->d_name.name))
brelse(epos.bh); goto out_ok;
return fi;
}
} }
out_err:
fi = NULL;
if (fibh->sbh != fibh->ebh) if (fibh->sbh != fibh->ebh)
brelse(fibh->ebh); brelse(fibh->ebh);
brelse(fibh->sbh); brelse(fibh->sbh);
out_ok:
brelse(epos.bh); brelse(epos.bh);
kfree(fname);
return NULL; return fi;
} }
/*
* 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
* <return> 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, static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd) struct nameidata *nd)
{ {
...@@ -336,11 +298,9 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, ...@@ -336,11 +298,9 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
{ {
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
struct fileIdentDesc *fi = NULL; struct fileIdentDesc *fi = NULL;
char name[UDF_NAME_LEN], fname[UDF_NAME_LEN]; char *name = NULL;
int namelen; int namelen;
loff_t f_pos; loff_t f_pos;
int flen;
char *nameptr;
loff_t size = udf_ext0_offset(dir) + dir->i_size; loff_t size = udf_ext0_offset(dir) + dir->i_size;
int nfidlen; int nfidlen;
uint8_t lfi; uint8_t lfi;
...@@ -352,16 +312,23 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, ...@@ -352,16 +312,23 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
struct extent_position epos = {}; struct extent_position epos = {};
struct udf_inode_info *dinfo; 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) {
if (!dentry->d_name.len) { if (!dentry->d_name.len) {
*err = -EINVAL; *err = -EINVAL;
return NULL; goto out_err;
} }
namelen = udf_put_filename(sb, dentry->d_name.name, name, namelen = udf_put_filename(sb, dentry->d_name.name, name,
dentry->d_name.len); dentry->d_name.len);
if (!namelen) { if (!namelen) {
*err = -ENAMETOOLONG; *err = -ENAMETOOLONG;
return NULL; goto out_err;
} }
} else { } else {
namelen = 0; namelen = 0;
...@@ -373,11 +340,14 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, ...@@ -373,11 +340,14 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
dinfo = UDF_I(dir); dinfo = UDF_I(dir);
if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
fibh->sbh = fibh->ebh = NULL; if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) {
&epos, &eloc, &elen, &offset) == block = udf_get_lb_pblock(dir->i_sb,
(EXT_RECORDED_ALLOCATED >> 30)) { dinfo->i_location, 0);
fibh->soffset = fibh->eoffset = sb->s_blocksize;
goto add;
}
block = udf_get_lb_pblock(dir->i_sb, eloc, offset); block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
...@@ -389,17 +359,11 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, ...@@ -389,17 +359,11 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
if (!fibh->sbh) { if (!fibh->sbh) {
brelse(epos.bh);
*err = -EIO; *err = -EIO;
return NULL; goto out_err;
} }
block = dinfo->i_location.logicalBlockNum; 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) { while (f_pos < size) {
...@@ -407,41 +371,16 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, ...@@ -407,41 +371,16 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
&elen, &offset); &elen, &offset);
if (!fi) { if (!fi) {
if (fibh->sbh != fibh->ebh)
brelse(fibh->ebh);
brelse(fibh->sbh);
brelse(epos.bh);
*err = -EIO; *err = -EIO;
return NULL; goto out_err;
} }
liu = le16_to_cpu(cfi->lengthOfImpUse); liu = le16_to_cpu(cfi->lengthOfImpUse);
lfi = cfi->lengthFileIdent; 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 ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
if (((sizeof(struct fileIdentDesc) + if (((sizeof(struct fileIdentDesc) +
liu + lfi + 3) & ~3) == nfidlen) { liu + lfi + 3) & ~3) == nfidlen) {
brelse(epos.bh);
cfi->descTag.tagSerialNum = cpu_to_le16(1); cfi->descTag.tagSerialNum = cpu_to_le16(1);
cfi->fileVersionNum = cpu_to_le16(1); cfi->fileVersionNum = cpu_to_le16(1);
cfi->fileCharacteristics = 0; cfi->fileCharacteristics = 0;
...@@ -449,27 +388,13 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, ...@@ -449,27 +388,13 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
cfi->lengthOfImpUse = cpu_to_le16(0); cfi->lengthOfImpUse = cpu_to_le16(0);
if (!udf_write_fi(dir, cfi, fi, fibh, NULL, if (!udf_write_fi(dir, cfi, fi, fibh, NULL,
name)) name))
return fi; goto out_ok;
else { else {
*err = -EIO; *err = -EIO;
return NULL; goto out_err;
} }
} }
} }
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: add:
...@@ -496,7 +421,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, ...@@ -496,7 +421,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
fibh->sbh = fibh->ebh = fibh->sbh = fibh->ebh =
udf_expand_dir_adinicb(dir, &block, err); udf_expand_dir_adinicb(dir, &block, err);
if (!fibh->sbh) if (!fibh->sbh)
return NULL; goto out_err;
epos.block = dinfo->i_location; epos.block = dinfo->i_location;
epos.offset = udf_file_entry_alloc_offset(dir); epos.offset = udf_file_entry_alloc_offset(dir);
/* Load extent udf_expand_dir_adinicb() has created */ /* Load extent udf_expand_dir_adinicb() has created */
...@@ -537,11 +462,8 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, ...@@ -537,11 +462,8 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
dir->i_sb->s_blocksize_bits); dir->i_sb->s_blocksize_bits);
fibh->ebh = udf_bread(dir, fibh->ebh = udf_bread(dir,
f_pos >> dir->i_sb->s_blocksize_bits, 1, err); f_pos >> dir->i_sb->s_blocksize_bits, 1, err);
if (!fibh->ebh) { if (!fibh->ebh)
brelse(epos.bh); goto out_err;
brelse(fibh->sbh);
return NULL;
}
if (!fibh->soffset) { if (!fibh->soffset) {
if (udf_next_aext(dir, &epos, &eloc, &elen, 1) == if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
...@@ -572,20 +494,25 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, ...@@ -572,20 +494,25 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
cfi->lengthFileIdent = namelen; cfi->lengthFileIdent = namelen;
cfi->lengthOfImpUse = cpu_to_le16(0); cfi->lengthOfImpUse = cpu_to_le16(0);
if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) { if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
brelse(epos.bh);
dir->i_size += nfidlen; dir->i_size += nfidlen;
if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
dinfo->i_lenAlloc += nfidlen; dinfo->i_lenAlloc += nfidlen;
mark_inode_dirty(dir); mark_inode_dirty(dir);
return fi; goto out_ok;
} else { } else {
brelse(epos.bh); *err = -EIO;
goto out_err;
}
out_err:
fi = NULL;
if (fibh->sbh != fibh->ebh) if (fibh->sbh != fibh->ebh)
brelse(fibh->ebh); brelse(fibh->ebh);
brelse(fibh->sbh); brelse(fibh->sbh);
*err = -EIO; out_ok:
return NULL; brelse(epos.bh);
} kfree(name);
return fi;
} }
static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
...@@ -940,7 +867,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, ...@@ -940,7 +867,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
char *ea; char *ea;
int err; int err;
int block; int block;
char name[UDF_NAME_LEN]; char *name = NULL;
int namelen; int namelen;
struct buffer_head *bh; struct buffer_head *bh;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
...@@ -950,6 +877,12 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, ...@@ -950,6 +877,12 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
if (!inode) if (!inode)
goto out; goto out;
name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
if (!name) {
err = -ENOMEM;
goto out_no_entry;
}
iinfo = UDF_I(inode); iinfo = UDF_I(inode);
inode->i_mode = S_IFLNK | S_IRWXUGO; inode->i_mode = S_IFLNK | S_IRWXUGO;
inode->i_data.a_ops = &udf_symlink_aops; inode->i_data.a_ops = &udf_symlink_aops;
...@@ -1089,6 +1022,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, ...@@ -1089,6 +1022,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
err = 0; err = 0;
out: out:
kfree(name);
unlock_kernel(); unlock_kernel();
return err; return err;
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/udf_fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
...@@ -55,11 +54,10 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, ...@@ -55,11 +54,10 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
struct udf_part_map *map; struct udf_part_map *map;
struct udf_virtual_data *vdata; struct udf_virtual_data *vdata;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
map = &sbi->s_partmaps[partition]; map = &sbi->s_partmaps[partition];
vdata = &map->s_type_specific.s_virtual; vdata = &map->s_type_specific.s_virtual;
index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
if (block > vdata->s_num_entries) { if (block > vdata->s_num_entries) {
udf_debug("Trying to access block beyond end of VAT " udf_debug("Trying to access block beyond end of VAT "
...@@ -67,6 +65,12 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, ...@@ -67,6 +65,12 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
return 0xFFFFFFFF; 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) { if (block >= index) {
block -= index; block -= index;
newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t))); newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
...@@ -89,7 +93,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, ...@@ -89,7 +93,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
brelse(bh); brelse(bh);
iinfo = UDF_I(sbi->s_vat_inode); translate:
if (iinfo->i_location.partitionReferenceNum == partition) { if (iinfo->i_location.partitionReferenceNum == partition) {
udf_debug("recursive call to udf_get_pblock!\n"); udf_debug("recursive call to udf_get_pblock!\n");
return 0xFFFFFFFF; return 0xFFFFFFFF;
...@@ -263,3 +267,58 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) ...@@ -263,3 +267,58 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
return 0; 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;
}
...@@ -55,9 +55,10 @@ ...@@ -55,9 +55,10 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/bitmap.h>
#include <linux/crc-itu-t.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <linux/udf_fs.h>
#include "udf_sb.h" #include "udf_sb.h"
#include "udf_i.h" #include "udf_i.h"
...@@ -84,22 +85,19 @@ static void udf_write_super(struct super_block *); ...@@ -84,22 +85,19 @@ static void udf_write_super(struct super_block *);
static int udf_remount_fs(struct super_block *, int *, char *); static int udf_remount_fs(struct super_block *, int *, char *);
static int udf_check_valid(struct super_block *, int, int); static int udf_check_valid(struct super_block *, int, int);
static int udf_vrs(struct super_block *sb, int silent); 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_load_logicalvolint(struct super_block *, kernel_extent_ad);
static void udf_find_anchor(struct super_block *); static void udf_find_anchor(struct super_block *);
static int udf_find_fileset(struct super_block *, kernel_lb_addr *, static int udf_find_fileset(struct super_block *, kernel_lb_addr *,
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 *, static void udf_load_fileset(struct super_block *, struct buffer_head *,
kernel_lb_addr *); 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_open_lvid(struct super_block *);
static void udf_close_lvid(struct super_block *); static void udf_close_lvid(struct super_block *);
static unsigned int udf_count_free(struct super_block *); static unsigned int udf_count_free(struct super_block *);
static int udf_statfs(struct dentry *, struct kstatfs *); static int udf_statfs(struct dentry *, struct kstatfs *);
static int udf_show_options(struct seq_file *, struct vfsmount *); 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) struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi)
{ {
...@@ -587,48 +585,10 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) ...@@ -587,48 +585,10 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
return 0; 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.
* <return> 0 Blocksize is valid.
* <return> 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) static int udf_vrs(struct super_block *sb, int silent)
{ {
struct volStructDesc *vsd = NULL; struct volStructDesc *vsd = NULL;
int sector = 32768; loff_t sector = 32768;
int sectorsize; int sectorsize;
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
int iso9660 = 0; int iso9660 = 0;
...@@ -649,7 +609,8 @@ static int udf_vrs(struct super_block *sb, int silent) ...@@ -649,7 +609,8 @@ static int udf_vrs(struct super_block *sb, int silent)
sector += (sbi->s_session << sb->s_blocksize_bits); sector += (sbi->s_session << sb->s_blocksize_bits);
udf_debug("Starting at sector %u (%ld byte sectors)\n", udf_debug("Starting at sector %u (%ld byte sectors)\n",
(sector >> sb->s_blocksize_bits), sb->s_blocksize); (unsigned int)(sector >> sb->s_blocksize_bits),
sb->s_blocksize);
/* Process the sequence (if applicable) */ /* Process the sequence (if applicable) */
for (; !nsr02 && !nsr03; sector += sectorsize) { for (; !nsr02 && !nsr03; sector += sectorsize) {
/* Read a block */ /* Read a block */
...@@ -719,44 +680,51 @@ static int udf_vrs(struct super_block *sb, int silent) ...@@ -719,44 +680,51 @@ static int udf_vrs(struct super_block *sb, int silent)
} }
/* /*
* udf_find_anchor * Check whether there is an anchor block in the given block
*
* PURPOSE
* Find an anchor volume descriptor.
*
* PRE-CONDITIONS
* sb Pointer to _locked_ superblock.
* lastblock Last block on media.
*
* POST-CONDITIONS
* <return> 1 if not found, 0 if ok
*
* HISTORY
* July 1, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/ */
static void udf_find_anchor(struct super_block *sb) static int udf_check_anchor_block(struct super_block *sb, sector_t block,
bool varconv)
{ {
int lastblock;
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
tag *t;
uint16_t ident; uint16_t ident;
uint32_t location; uint32_t location;
int i;
struct udf_sb_info *sbi;
sbi = UDF_SB(sb); if (varconv) {
lastblock = sbi->s_last_block; 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 (lastblock) { if (!bh)
int varlastblock = udf_variable_to_fixed(lastblock); return 0;
int last[] = { lastblock, lastblock - 2,
lastblock - 150, lastblock - 152,
varlastblock, varlastblock - 2,
varlastblock - 150, varlastblock - 152 };
lastblock = 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);
/* Search for an anchor volume descriptor pointer */ 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: /* according to spec, anchor is in either:
* block 256 * block 256
...@@ -764,119 +732,90 @@ static void udf_find_anchor(struct super_block *sb) ...@@ -764,119 +732,90 @@ static void udf_find_anchor(struct super_block *sb)
* lastblock * lastblock
* however, if the disc isn't closed, it could be 512 */ * however, if the disc isn't closed, it could be 512 */
for (i = 0; !lastblock && i < ARRAY_SIZE(last); i++) { for (i = 0; i < ARRAY_SIZE(last); i++) {
ident = location = 0; if (last[i] < 0)
if (last[i] >= 0) { continue;
bh = sb_bread(sb, last[i]); if (last[i] >= sb->s_bdev->bd_inode->i_size >>
if (bh) { sb->s_blocksize_bits)
tag *t = (tag *)bh->b_data; continue;
ident = le16_to_cpu(t->tagIdent);
location = le32_to_cpu(t->tagLocation);
brelse(bh);
}
}
if (ident == TAG_IDENT_AVDP) { if (udf_check_anchor_block(sb, last[i], varconv)) {
if (location == last[i] - sbi->s_session) { sbi->s_anchor[0] = last[i];
lastblock = last[i] - sbi->s_session; sbi->s_anchor[1] = last[i] - 256;
sbi->s_anchor[0] = lastblock; return last[i];
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 (ident == TAG_IDENT_AVDP && if (last[i] < 256)
location == last[i] - 256 - continue;
sbi->s_session) {
lastblock = last[i]; if (udf_check_anchor_block(sb, last[i] - 256, varconv)) {
sbi->s_anchor[1] = last[i] - 256; sbi->s_anchor[1] = last[i] - 256;
} else { return last[i];
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 (ident == TAG_IDENT_AVDP && if (udf_check_anchor_block(sb, sbi->s_session + 256, varconv)) {
location == udf_variable_to_fixed(last[i]) - 256) { sbi->s_anchor[0] = sbi->s_session + 256;
UDF_SET_FLAG(sb, return last[0];
UDF_FLAG_VARCONV);
lastblock = udf_variable_to_fixed(last[i]);
sbi->s_anchor[1] = lastblock - 256;
}
}
}
} }
if (udf_check_anchor_block(sb, sbi->s_session + 512, varconv)) {
sbi->s_anchor[0] = sbi->s_session + 512;
return last[0];
} }
return 0;
}
if (!lastblock) { /*
/* We haven't found the lastblock. check 312 */ * Find an anchor volume descriptor. The function expects sbi->s_lastblock to
bh = sb_bread(sb, 312 + sbi->s_session); * be the last block on the media.
if (bh) { *
tag *t = (tag *)bh->b_data; * Return 1 if not found, 0 if ok
ident = le16_to_cpu(t->tagIdent); *
location = le32_to_cpu(t->tagLocation); */
brelse(bh); 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 (ident == TAG_IDENT_AVDP && location == 256) /* 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); UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
goto check_anchor;
} }
}
/* 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++) { for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) {
if (sbi->s_anchor[i]) { if (!sbi->s_anchor[i])
continue;
bh = udf_read_tagged(sb, sbi->s_anchor[i], bh = udf_read_tagged(sb, sbi->s_anchor[i],
sbi->s_anchor[i], &ident); sbi->s_anchor[i], &ident);
if (!bh) if (!bh)
sbi->s_anchor[i] = 0; sbi->s_anchor[i] = 0;
else { else {
brelse(bh); brelse(bh);
if ((ident != TAG_IDENT_AVDP) && if (ident != TAG_IDENT_AVDP)
(i || (ident != TAG_IDENT_FE &&
ident != TAG_IDENT_EFE)))
sbi->s_anchor[i] = 0; sbi->s_anchor[i] = 0;
} }
} }
}
sbi->s_last_block = lastblock; sbi->s_last_block = lastblock;
} }
...@@ -971,27 +910,30 @@ static int udf_find_fileset(struct super_block *sb, ...@@ -971,27 +910,30 @@ static int udf_find_fileset(struct super_block *sb,
return 1; return 1;
} }
static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
{ {
struct primaryVolDesc *pvoldesc; struct primaryVolDesc *pvoldesc;
time_t recording;
long recording_usec;
struct ustr instr; struct ustr instr;
struct ustr outstr; 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; pvoldesc = (struct primaryVolDesc *)bh->b_data;
if (udf_stamp_to_time(&recording, &recording_usec, if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time,
lets_to_cpu(pvoldesc->recordingDateAndTime))) { pvoldesc->recordingDateAndTime)) {
kernel_timestamp ts; #ifdef UDFFS_DEBUG
ts = lets_to_cpu(pvoldesc->recordingDateAndTime); timestamp *ts = &pvoldesc->recordingDateAndTime;
udf_debug("recording time %ld/%ld, %04u/%02u/%02u" udf_debug("recording time %04u/%02u/%02u"
" %02u:%02u (%x)\n", " %02u:%02u (%x)\n",
recording, recording_usec, le16_to_cpu(ts->year), ts->month, ts->day, ts->hour,
ts.year, ts.month, ts.day, ts.hour, ts->minute, le16_to_cpu(ts->typeAndTimezone));
ts.minute, ts.typeAndTimezone); #endif
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)) if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32))
...@@ -1005,6 +947,104 @@ static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) ...@@ -1005,6 +947,104 @@ static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128)) if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128))
if (udf_CS0toUTF8(&outstr, &instr)) if (udf_CS0toUTF8(&outstr, &instr))
udf_debug("volSetIdent[] = '%s'\n", outstr.u_name); 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, static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
...@@ -1025,10 +1065,9 @@ static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, ...@@ -1025,10 +1065,9 @@ static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
int udf_compute_nr_groups(struct super_block *sb, u32 partition) int udf_compute_nr_groups(struct super_block *sb, u32 partition)
{ {
struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
return (map->s_partition_len + return DIV_ROUND_UP(map->s_partition_len +
(sizeof(struct spaceBitmapDesc) << 3) + (sizeof(struct spaceBitmapDesc) << 3),
(sb->s_blocksize * 8) - 1) / sb->s_blocksize * 8);
(sb->s_blocksize * 8);
} }
static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index)
...@@ -1059,134 +1098,241 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) ...@@ -1059,134 +1098,241 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index)
return bitmap; return bitmap;
} }
static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) static int udf_fill_partdesc_info(struct super_block *sb,
struct partitionDesc *p, int p_index)
{ {
struct partitionDesc *p;
int i;
struct udf_part_map *map; struct udf_part_map *map;
struct udf_sb_info *sbi; struct udf_sb_info *sbi = UDF_SB(sb);
struct partitionHeaderDesc *phd;
p = (struct partitionDesc *)bh->b_data; map = &sbi->s_partmaps[p_index];
sbi = UDF_SB(sb);
for (i = 0; i < sbi->s_partitions; i++) { map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */
map = &sbi->s_partmaps[i]; map->s_partition_root = le32_to_cpu(p->partitionStartingLocation);
udf_debug("Searching map: (%d == %d)\n",
map->s_partition_num, if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY))
le16_to_cpu(p->partitionNumber)); map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY;
if (map->s_partition_num == if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE))
le16_to_cpu(p->partitionNumber)) { map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE;
map->s_partition_len = if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE))
le32_to_cpu(p->partitionLength); /* blocks */ map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE;
map->s_partition_root = if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE))
le32_to_cpu(p->partitionStartingLocation); map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE;
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 *) udf_debug("Partition (%d type %x) starts at physical %d, "
(p->partitionContentsUse); "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) { if (phd->unallocSpaceTable.extLength) {
kernel_lb_addr loc = { kernel_lb_addr loc = {
.logicalBlockNum = le32_to_cpu(phd->unallocSpaceTable.extPosition), .logicalBlockNum = le32_to_cpu(
.partitionReferenceNum = i, phd->unallocSpaceTable.extPosition),
.partitionReferenceNum = p_index,
}; };
map->s_uspace.s_table = map->s_uspace.s_table = udf_iget(sb, loc);
udf_iget(sb, loc);
if (!map->s_uspace.s_table) { if (!map->s_uspace.s_table) {
udf_debug("cannot load unallocSpaceTable (part %d)\n", i); udf_debug("cannot load unallocSpaceTable (part %d)\n",
p_index);
return 1; return 1;
} }
map->s_partition_flags |= map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE;
UDF_PART_FLAG_UNALLOC_TABLE;
udf_debug("unallocSpaceTable (part %d) @ %ld\n", udf_debug("unallocSpaceTable (part %d) @ %ld\n",
i, map->s_uspace.s_table->i_ino); p_index, map->s_uspace.s_table->i_ino);
} }
if (phd->unallocSpaceBitmap.extLength) { if (phd->unallocSpaceBitmap.extLength) {
struct udf_bitmap *bitmap = struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index);
udf_sb_alloc_bitmap(sb, i); if (!bitmap)
return 1;
map->s_uspace.s_bitmap = bitmap; map->s_uspace.s_bitmap = bitmap;
if (bitmap != NULL) { bitmap->s_extLength = le32_to_cpu(
bitmap->s_extLength = phd->unallocSpaceBitmap.extLength);
le32_to_cpu(phd->unallocSpaceBitmap.extLength); bitmap->s_extPosition = le32_to_cpu(
bitmap->s_extPosition = phd->unallocSpaceBitmap.extPosition);
le32_to_cpu(phd->unallocSpaceBitmap.extPosition);
map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP;
udf_debug("unallocSpaceBitmap (part %d) @ %d\n", udf_debug("unallocSpaceBitmap (part %d) @ %d\n", p_index,
i, bitmap->s_extPosition); bitmap->s_extPosition);
}
} }
if (phd->partitionIntegrityTable.extLength) if (phd->partitionIntegrityTable.extLength)
udf_debug("partitionIntegrityTable (part %d)\n", i); udf_debug("partitionIntegrityTable (part %d)\n", p_index);
if (phd->freedSpaceTable.extLength) { if (phd->freedSpaceTable.extLength) {
kernel_lb_addr loc = { kernel_lb_addr loc = {
.logicalBlockNum = le32_to_cpu(phd->freedSpaceTable.extPosition), .logicalBlockNum = le32_to_cpu(
.partitionReferenceNum = i, phd->freedSpaceTable.extPosition),
.partitionReferenceNum = p_index,
}; };
map->s_fspace.s_table = map->s_fspace.s_table = udf_iget(sb, loc);
udf_iget(sb, loc);
if (!map->s_fspace.s_table) { if (!map->s_fspace.s_table) {
udf_debug("cannot load freedSpaceTable (part %d)\n", i); udf_debug("cannot load freedSpaceTable (part %d)\n",
p_index);
return 1; return 1;
} }
map->s_partition_flags |=
UDF_PART_FLAG_FREED_TABLE; map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE;
udf_debug("freedSpaceTable (part %d) @ %ld\n", udf_debug("freedSpaceTable (part %d) @ %ld\n",
i, map->s_fspace.s_table->i_ino); p_index, map->s_fspace.s_table->i_ino);
} }
if (phd->freedSpaceBitmap.extLength) { if (phd->freedSpaceBitmap.extLength) {
struct udf_bitmap *bitmap = struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index);
udf_sb_alloc_bitmap(sb, i); if (!bitmap)
return 1;
map->s_fspace.s_bitmap = bitmap; map->s_fspace.s_bitmap = bitmap;
if (bitmap != NULL) { bitmap->s_extLength = le32_to_cpu(
bitmap->s_extLength = phd->freedSpaceBitmap.extLength);
le32_to_cpu(phd->freedSpaceBitmap.extLength); bitmap->s_extPosition = le32_to_cpu(
bitmap->s_extPosition = phd->freedSpaceBitmap.extPosition);
le32_to_cpu(phd->freedSpaceBitmap.extPosition);
map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP;
udf_debug("freedSpaceBitmap (part %d) @ %d\n", udf_debug("freedSpaceBitmap (part %d) @ %d\n", p_index,
i, bitmap->s_extPosition); 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)
{
struct buffer_head *bh;
struct partitionDesc *p;
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;
p = (struct partitionDesc *)bh->b_data;
partitionNumber = le16_to_cpu(p->partitionNumber);
/* 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; break;
} }
}
if (i == sbi->s_partitions) if (i >= sbi->s_partitions) {
udf_debug("Partition (%d) not found in partition map\n", udf_debug("Partition (%d) not found in partition map\n",
le16_to_cpu(p->partitionNumber)); partitionNumber);
else goto out_bh;
udf_debug("Partition (%d:%d type %x) starts at physical %d, " }
"block length %d\n",
le16_to_cpu(p->partitionNumber), i, ret = udf_fill_partdesc_info(sb, p, i);
map->s_partition_type,
map->s_partition_root, /*
map->s_partition_len); * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and
return 0; * 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))
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;
} }
static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, static int udf_load_logicalvol(struct super_block *sb, sector_t block,
kernel_lb_addr *fileset) kernel_lb_addr *fileset)
{ {
struct logicalVolDesc *lvd; struct logicalVolDesc *lvd;
...@@ -1194,12 +1340,21 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, ...@@ -1194,12 +1340,21 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
uint8_t type; uint8_t type;
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
struct genericPartitionMap *gpm; 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; lvd = (struct logicalVolDesc *)bh->b_data;
i = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); i = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps));
if (i != 0) if (i != 0) {
return i; ret = i;
goto out_bh;
}
for (i = 0, offset = 0; for (i = 0, offset = 0;
i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength); i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength);
...@@ -1223,12 +1378,12 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, ...@@ -1223,12 +1378,12 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
u16 suf = u16 suf =
le16_to_cpu(((__le16 *)upm2->partIdent. le16_to_cpu(((__le16 *)upm2->partIdent.
identSuffix)[0]); identSuffix)[0]);
if (suf == 0x0150) { if (suf < 0x0200) {
map->s_partition_type = map->s_partition_type =
UDF_VIRTUAL_MAP15; UDF_VIRTUAL_MAP15;
map->s_partition_func = map->s_partition_func =
udf_get_pblock_virt15; udf_get_pblock_virt15;
} else if (suf == 0x0200) { } else {
map->s_partition_type = map->s_partition_type =
UDF_VIRTUAL_MAP20; UDF_VIRTUAL_MAP20;
map->s_partition_func = map->s_partition_func =
...@@ -1238,7 +1393,6 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, ...@@ -1238,7 +1393,6 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
UDF_ID_SPARABLE, UDF_ID_SPARABLE,
strlen(UDF_ID_SPARABLE))) { strlen(UDF_ID_SPARABLE))) {
uint32_t loc; uint32_t loc;
uint16_t ident;
struct sparingTable *st; struct sparingTable *st;
struct sparablePartitionMap *spm = struct sparablePartitionMap *spm =
(struct sparablePartitionMap *)gpm; (struct sparablePartitionMap *)gpm;
...@@ -1256,22 +1410,64 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, ...@@ -1256,22 +1410,64 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
map->s_type_specific.s_sparing. map->s_type_specific.s_sparing.
s_spar_map[j] = bh2; s_spar_map[j] = bh2;
if (bh2 != NULL) { if (bh2 == NULL)
st = (struct sparingTable *) continue;
bh2->b_data;
st = (struct sparingTable *)bh2->b_data;
if (ident != 0 || strncmp( if (ident != 0 || strncmp(
st->sparingIdent.ident, st->sparingIdent.ident,
UDF_ID_SPARING, UDF_ID_SPARING,
strlen(UDF_ID_SPARING))) { strlen(UDF_ID_SPARING))) {
brelse(bh2); brelse(bh2);
map->s_type_specific. map->s_type_specific.s_sparing.
s_sparing. s_spar_map[j] = NULL;
s_spar_map[j] =
NULL;
}
} }
} }
map->s_partition_func = udf_get_pblock_spar15; 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 { } else {
udf_debug("Unknown ident: %s\n", udf_debug("Unknown ident: %s\n",
upm2->partIdent.ident); upm2->partIdent.ident);
...@@ -1296,7 +1492,9 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, ...@@ -1296,7 +1492,9 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
if (lvd->integritySeqExt.extLength) if (lvd->integritySeqExt.extLength)
udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt));
return 0; out_bh:
brelse(bh);
return ret;
} }
/* /*
...@@ -1345,7 +1543,7 @@ static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc) ...@@ -1345,7 +1543,7 @@ static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
* July 1, 1997 - Andrew E. Mileski * July 1, 1997 - Andrew E. Mileski
* Written, tested, and released. * Written, tested, and released.
*/ */
static int udf_process_sequence(struct super_block *sb, long block, static noinline int udf_process_sequence(struct super_block *sb, long block,
long lastblock, kernel_lb_addr *fileset) long lastblock, kernel_lb_addr *fileset)
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
...@@ -1354,19 +1552,25 @@ static int udf_process_sequence(struct super_block *sb, long block, ...@@ -1354,19 +1552,25 @@ static int udf_process_sequence(struct super_block *sb, long block,
struct generic_desc *gd; struct generic_desc *gd;
struct volDescPtr *vdp; struct volDescPtr *vdp;
int done = 0; int done = 0;
int i, j;
uint32_t vdsn; uint32_t vdsn;
uint16_t ident; uint16_t ident;
long next_s = 0, next_e = 0; long next_s = 0, next_e = 0;
memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
/* Read the main descriptor sequence */ /*
* Read the main descriptor sequence and find which descriptors
* are in it.
*/
for (; (!done && block <= lastblock); block++) { for (; (!done && block <= lastblock); block++) {
bh = udf_read_tagged(sb, block, block, &ident); bh = udf_read_tagged(sb, block, block, &ident);
if (!bh) if (!bh) {
break; 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;
}
/* Process each descriptor (ISO 13346 3/8.3-8.4) */ /* Process each descriptor (ISO 13346 3/8.3-8.4) */
gd = (struct generic_desc *)bh->b_data; gd = (struct generic_desc *)bh->b_data;
...@@ -1432,41 +1636,31 @@ static int udf_process_sequence(struct super_block *sb, long block, ...@@ -1432,41 +1636,31 @@ static int udf_process_sequence(struct super_block *sb, long block,
} }
brelse(bh); brelse(bh);
} }
for (i = 0; i < VDS_POS_LENGTH; i++) { /*
if (vds[i].block) { * Now read interesting descriptors again and process them
bh = udf_read_tagged(sb, vds[i].block, vds[i].block, * in a suitable order
&ident); */
if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) {
if (i == VDS_POS_PRIMARY_VOL_DESC) { printk(KERN_ERR "udf: Primary Volume Descriptor not found!\n");
udf_load_pvoldesc(sb, bh);
} else if (i == VDS_POS_LOGICAL_VOL_DESC) {
if (udf_load_logicalvol(sb, bh, fileset)) {
brelse(bh);
return 1; return 1;
} }
} else if (i == VDS_POS_PARTITION_DESC) { if (udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block))
struct buffer_head *bh2 = NULL;
if (udf_load_partdesc(sb, bh)) {
brelse(bh);
return 1; return 1;
}
for (j = vds[i].block + 1; if (vds[VDS_POS_LOGICAL_VOL_DESC].block && udf_load_logicalvol(sb,
j < vds[VDS_POS_TERMINATING_DESC].block; vds[VDS_POS_LOGICAL_VOL_DESC].block, fileset))
j++) { return 1;
bh2 = udf_read_tagged(sb, j, j, &ident);
gd = (struct generic_desc *)bh2->b_data; if (vds[VDS_POS_PARTITION_DESC].block) {
if (ident == TAG_IDENT_PD) /*
if (udf_load_partdesc(sb, * We rescan the whole descriptor sequence to find
bh2)) { * partition descriptor blocks and process them.
brelse(bh); */
brelse(bh2); for (block = vds[VDS_POS_PARTITION_DESC].block;
block < vds[VDS_POS_TERMINATING_DESC].block;
block++)
if (udf_load_partdesc(sb, block))
return 1; return 1;
}
brelse(bh2);
}
}
brelse(bh);
}
} }
return 0; return 0;
...@@ -1478,6 +1672,7 @@ static int udf_process_sequence(struct super_block *sb, long block, ...@@ -1478,6 +1672,7 @@ static int udf_process_sequence(struct super_block *sb, long block,
static int udf_check_valid(struct super_block *sb, int novrs, int silent) static int udf_check_valid(struct super_block *sb, int novrs, int silent)
{ {
long block; long block;
struct udf_sb_info *sbi = UDF_SB(sb);
if (novrs) { if (novrs) {
udf_debug("Validity check skipped because of novrs option\n"); udf_debug("Validity check skipped because of novrs option\n");
...@@ -1485,27 +1680,22 @@ static int udf_check_valid(struct super_block *sb, int novrs, int silent) ...@@ -1485,27 +1680,22 @@ static int udf_check_valid(struct super_block *sb, int novrs, int silent)
} }
/* Check that it is NSR02 compliant */ /* Check that it is NSR02 compliant */
/* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
else {
block = udf_vrs(sb, silent); block = udf_vrs(sb, silent);
if (block == -1) { if (block == -1)
struct udf_sb_info *sbi = UDF_SB(sb);
udf_debug("Failed to read byte 32768. Assuming open " udf_debug("Failed to read byte 32768. Assuming open "
"disc. Skipping validity check\n"); "disc. Skipping validity check\n");
if (!sbi->s_last_block) if (block && !sbi->s_last_block)
sbi->s_last_block = udf_get_last_block(sb); sbi->s_last_block = udf_get_last_block(sb);
return 0;
} else
return !block; return !block;
}
} }
static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) static int udf_load_sequence(struct super_block *sb, kernel_lb_addr *fileset)
{ {
struct anchorVolDescPtr *anchor; struct anchorVolDescPtr *anchor;
uint16_t ident; uint16_t ident;
struct buffer_head *bh; struct buffer_head *bh;
long main_s, main_e, reserve_s, reserve_e; long main_s, main_e, reserve_s, reserve_e;
int i, j; int i;
struct udf_sb_info *sbi; struct udf_sb_info *sbi;
if (!sb) if (!sb)
...@@ -1515,6 +1705,7 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) ...@@ -1515,6 +1705,7 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) {
if (!sbi->s_anchor[i]) if (!sbi->s_anchor[i])
continue; continue;
bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i], bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i],
&ident); &ident);
if (!bh) if (!bh)
...@@ -1553,76 +1744,6 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) ...@@ -1553,76 +1744,6 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
} }
udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]); 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; return 0;
} }
...@@ -1630,51 +1751,49 @@ static void udf_open_lvid(struct super_block *sb) ...@@ -1630,51 +1751,49 @@ static void udf_open_lvid(struct super_block *sb)
{ {
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
struct buffer_head *bh = sbi->s_lvid_bh; struct buffer_head *bh = sbi->s_lvid_bh;
if (bh) { struct logicalVolIntegrityDesc *lvid;
kernel_timestamp cpu_time; struct logicalVolIntegrityDescImpUse *lvidiu;
struct logicalVolIntegrityDesc *lvid = if (!bh)
(struct logicalVolIntegrityDesc *)bh->b_data; return;
struct logicalVolIntegrityDescImpUse *lvidiu =
udf_sb_lvidiu(sbi); lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
lvidiu = udf_sb_lvidiu(sbi);
lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) udf_time_to_disk_stamp(&lvid->recordingDateAndTime,
lvid->recordingDateAndTime = cpu_to_lets(cpu_time); CURRENT_TIME);
lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN;
lvid->descTag.descCRC = cpu_to_le16( lvid->descTag.descCRC = cpu_to_le16(
udf_crc((char *)lvid + sizeof(tag), crc_itu_t(0, (char *)lvid + sizeof(tag),
le16_to_cpu(lvid->descTag.descCRCLength), le16_to_cpu(lvid->descTag.descCRCLength)));
0));
lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
}
} }
static void udf_close_lvid(struct super_block *sb) static void udf_close_lvid(struct super_block *sb)
{ {
kernel_timestamp cpu_time;
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
struct buffer_head *bh = sbi->s_lvid_bh; struct buffer_head *bh = sbi->s_lvid_bh;
struct logicalVolIntegrityDesc *lvid; struct logicalVolIntegrityDesc *lvid;
struct logicalVolIntegrityDescImpUse *lvidiu;
if (!bh) if (!bh)
return; return;
lvid = (struct logicalVolIntegrityDesc *)bh->b_data; lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
if (lvid->integrityType == LVID_INTEGRITY_TYPE_OPEN) { if (lvid->integrityType != LVID_INTEGRITY_TYPE_OPEN)
struct logicalVolIntegrityDescImpUse *lvidiu = return;
udf_sb_lvidiu(sbi);
lvidiu = udf_sb_lvidiu(sbi);
lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME);
lvid->recordingDateAndTime = cpu_to_lets(cpu_time);
if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev))
lvidiu->maxUDFWriteRev = lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION);
cpu_to_le16(UDF_MAX_WRITE_VERSION);
if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev))
lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev);
if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev))
...@@ -1682,13 +1801,11 @@ static void udf_close_lvid(struct super_block *sb) ...@@ -1682,13 +1801,11 @@ static void udf_close_lvid(struct super_block *sb)
lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
lvid->descTag.descCRC = cpu_to_le16( lvid->descTag.descCRC = cpu_to_le16(
udf_crc((char *)lvid + sizeof(tag), crc_itu_t(0, (char *)lvid + sizeof(tag),
le16_to_cpu(lvid->descTag.descCRCLength), le16_to_cpu(lvid->descTag.descCRCLength)));
0));
lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
}
} }
static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
...@@ -1708,22 +1825,35 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) ...@@ -1708,22 +1825,35 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
vfree(bitmap); vfree(bitmap);
} }
/* static void udf_free_partition(struct udf_part_map *map)
* udf_read_super {
* int i;
* PURPOSE struct udf_meta_data *mdata;
* Complete the specified super block.
* if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
* PRE-CONDITIONS iput(map->s_uspace.s_table);
* sb Pointer to superblock to complete - never NULL. if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
* sb->s_dev Device to read suberblock from. iput(map->s_fspace.s_table);
* options Pointer to mount options. if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
* silent Silent flag. udf_sb_free_bitmap(map->s_uspace.s_bitmap);
* if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
* HISTORY udf_sb_free_bitmap(map->s_fspace.s_bitmap);
* July 1, 1997 - Andrew E. Mileski if (map->s_partition_type == UDF_SPARABLE_MAP15)
* Written, tested, and released. 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;
}
}
static int udf_fill_super(struct super_block *sb, void *options, int silent) static int udf_fill_super(struct super_block *sb, void *options, int silent)
{ {
int i; int i;
...@@ -1776,8 +1906,11 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -1776,8 +1906,11 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
sbi->s_nls_map = uopt.nls_map; sbi->s_nls_map = uopt.nls_map;
/* Set the block size for all transfers */ /* Set the block size for all transfers */
if (!udf_set_blocksize(sb, uopt.blocksize)) 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);
goto error_out; goto error_out;
}
if (uopt.session == 0xFFFFFFFF) if (uopt.session == 0xFFFFFFFF)
sbi->s_session = udf_get_last_session(sb); sbi->s_session = udf_get_last_session(sb);
...@@ -1789,7 +1922,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -1789,7 +1922,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
sbi->s_last_block = uopt.lastblock; sbi->s_last_block = uopt.lastblock;
sbi->s_anchor[0] = sbi->s_anchor[1] = 0; sbi->s_anchor[0] = sbi->s_anchor[1] = 0;
sbi->s_anchor[2] = uopt.anchor; sbi->s_anchor[2] = uopt.anchor;
sbi->s_anchor[3] = 256;
if (udf_check_valid(sb, uopt.novrs, silent)) { if (udf_check_valid(sb, uopt.novrs, silent)) {
/* read volume recognition sequences */ /* read volume recognition sequences */
...@@ -1806,7 +1938,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -1806,7 +1938,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
sb->s_magic = UDF_SUPER_MAGIC; sb->s_magic = UDF_SUPER_MAGIC;
sb->s_time_gran = 1000; sb->s_time_gran = 1000;
if (udf_load_partition(sb, &fileset)) { if (udf_load_sequence(sb, &fileset)) {
printk(KERN_WARNING "UDF-fs: No partition found (1)\n"); printk(KERN_WARNING "UDF-fs: No partition found (1)\n");
goto error_out; goto error_out;
} }
...@@ -1856,12 +1988,12 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -1856,12 +1988,12 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
} }
if (!silent) { if (!silent) {
kernel_timestamp ts; timestamp ts;
udf_time_to_stamp(&ts, sbi->s_record_time); udf_time_to_disk_stamp(&ts, sbi->s_record_time);
udf_info("UDF: Mounting volume '%s', " udf_info("UDF: Mounting volume '%s', "
"timestamp %04u/%02u/%02u %02u:%02u (%x)\n", "timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
sbi->s_volume_ident, ts.year, ts.month, ts.day, sbi->s_volume_ident, le16_to_cpu(ts.year), ts.month, ts.day,
ts.hour, ts.minute, ts.typeAndTimezone); ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone));
} }
if (!(sb->s_flags & MS_RDONLY)) if (!(sb->s_flags & MS_RDONLY))
udf_open_lvid(sb); udf_open_lvid(sb);
...@@ -1890,21 +2022,9 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -1890,21 +2022,9 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
error_out: error_out:
if (sbi->s_vat_inode) if (sbi->s_vat_inode)
iput(sbi->s_vat_inode); iput(sbi->s_vat_inode);
if (sbi->s_partitions) { if (sbi->s_partitions)
struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition]; for (i = 0; i < sbi->s_partitions; i++)
if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) udf_free_partition(&sbi->s_partmaps[i]);
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 #ifdef CONFIG_UDF_NLS
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
unload_nls(sbi->s_nls_map); unload_nls(sbi->s_nls_map);
...@@ -1920,7 +2040,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -1920,7 +2040,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
return -EINVAL; return -EINVAL;
} }
void udf_error(struct super_block *sb, const char *function, static void udf_error(struct super_block *sb, const char *function,
const char *fmt, ...) const char *fmt, ...)
{ {
va_list args; va_list args;
...@@ -1948,19 +2068,6 @@ void udf_warning(struct super_block *sb, const char *function, ...@@ -1948,19 +2068,6 @@ void udf_warning(struct super_block *sb, const char *function,
sb->s_id, function, error_buf); 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) static void udf_put_super(struct super_block *sb)
{ {
int i; int i;
...@@ -1969,21 +2076,9 @@ static void udf_put_super(struct super_block *sb) ...@@ -1969,21 +2076,9 @@ static void udf_put_super(struct super_block *sb)
sbi = UDF_SB(sb); sbi = UDF_SB(sb);
if (sbi->s_vat_inode) if (sbi->s_vat_inode)
iput(sbi->s_vat_inode); iput(sbi->s_vat_inode);
if (sbi->s_partitions) { if (sbi->s_partitions)
struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition]; for (i = 0; i < sbi->s_partitions; i++)
if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) udf_free_partition(&sbi->s_partmaps[i]);
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 #ifdef CONFIG_UDF_NLS
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
unload_nls(sbi->s_nls_map); unload_nls(sbi->s_nls_map);
...@@ -1996,19 +2091,6 @@ static void udf_put_super(struct super_block *sb) ...@@ -1996,19 +2091,6 @@ static void udf_put_super(struct super_block *sb)
sb->s_fs_info = NULL; 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) static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
{ {
struct super_block *sb = dentry->d_sb; struct super_block *sb = dentry->d_sb;
...@@ -2035,10 +2117,6 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -2035,10 +2117,6 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0; 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, static unsigned int udf_count_free_bitmap(struct super_block *sb,
struct udf_bitmap *bitmap) struct udf_bitmap *bitmap)
{ {
...@@ -2048,7 +2126,6 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, ...@@ -2048,7 +2126,6 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
int block = 0, newblock; int block = 0, newblock;
kernel_lb_addr loc; kernel_lb_addr loc;
uint32_t bytes; uint32_t bytes;
uint8_t value;
uint8_t *ptr; uint8_t *ptr;
uint16_t ident; uint16_t ident;
struct spaceBitmapDesc *bm; struct spaceBitmapDesc *bm;
...@@ -2074,13 +2151,10 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, ...@@ -2074,13 +2151,10 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
ptr = (uint8_t *)bh->b_data; ptr = (uint8_t *)bh->b_data;
while (bytes > 0) { while (bytes > 0) {
while ((bytes > 0) && (index < sb->s_blocksize)) { u32 cur_bytes = min_t(u32, bytes, sb->s_blocksize - index);
value = ptr[index]; accum += bitmap_weight((const unsigned long *)(ptr + index),
accum += udf_bitmap_lookup[value & 0x0f]; cur_bytes * 8);
accum += udf_bitmap_lookup[value >> 4]; bytes -= cur_bytes;
index++;
bytes--;
}
if (bytes) { if (bytes) {
brelse(bh); brelse(bh);
newblock = udf_get_lb_pblock(sb, loc, ++block); newblock = udf_get_lb_pblock(sb, loc, ++block);
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/udf_fs.h>
#include <linux/time.h> #include <linux/time.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/stat.h> #include <linux/stat.h>
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include "udfdecl.h" #include "udfdecl.h"
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/udf_fs.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include "udf_i.h" #include "udf_i.h"
...@@ -180,6 +179,24 @@ void udf_discard_prealloc(struct inode *inode) ...@@ -180,6 +179,24 @@ void udf_discard_prealloc(struct inode *inode)
brelse(epos.bh); 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) void udf_truncate_extents(struct inode *inode)
{ {
struct extent_position epos; struct extent_position epos;
...@@ -187,7 +204,6 @@ void udf_truncate_extents(struct inode *inode) ...@@ -187,7 +204,6 @@ void udf_truncate_extents(struct inode *inode)
uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc; uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
int8_t etype; int8_t etype;
struct super_block *sb = inode->i_sb; 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; sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset;
loff_t byte_offset; loff_t byte_offset;
int adsize; int adsize;
...@@ -224,35 +240,15 @@ void udf_truncate_extents(struct inode *inode) ...@@ -224,35 +240,15 @@ void udf_truncate_extents(struct inode *inode)
if (indirect_ext_len) { if (indirect_ext_len) {
/* We managed to free all extents in the /* We managed to free all extents in the
* indirect extent - free it too */ * indirect extent - free it too */
if (!epos.bh) BUG_ON(!epos.bh);
BUG();
udf_free_blocks(sb, inode, epos.block, udf_free_blocks(sb, inode, epos.block,
0, indirect_ext_len); 0, indirect_ext_len);
} else { } else if (!epos.bh) {
if (!epos.bh) { iinfo->i_lenAlloc = lenalloc;
iinfo->i_lenAlloc =
lenalloc;
mark_inode_dirty(inode); mark_inode_dirty(inode);
} else { } else
struct allocExtDesc *aed = udf_update_alloc_ext_desc(inode,
(struct allocExtDesc *) &epos, lenalloc);
(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); brelse(epos.bh);
epos.offset = sizeof(struct allocExtDesc); epos.offset = sizeof(struct allocExtDesc);
epos.block = eloc; epos.block = eloc;
...@@ -272,29 +268,14 @@ void udf_truncate_extents(struct inode *inode) ...@@ -272,29 +268,14 @@ void udf_truncate_extents(struct inode *inode)
} }
if (indirect_ext_len) { if (indirect_ext_len) {
if (!epos.bh) BUG_ON(!epos.bh);
BUG();
udf_free_blocks(sb, inode, epos.block, 0, udf_free_blocks(sb, inode, epos.block, 0,
indirect_ext_len); indirect_ext_len);
} else { } else if (!epos.bh) {
if (!epos.bh) {
iinfo->i_lenAlloc = lenalloc; iinfo->i_lenAlloc = lenalloc;
mark_inode_dirty(inode); mark_inode_dirty(inode);
} else { } else
struct allocExtDesc *aed = udf_update_alloc_ext_desc(inode, &epos, lenalloc);
(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) { } else if (inode->i_size) {
if (byte_offset) { if (byte_offset) {
kernel_long_ad extent; kernel_long_ad extent;
......
#ifndef __LINUX_UDF_I_H #ifndef _UDF_I_H
#define __LINUX_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;
};
#include <linux/udf_fs_i.h>
static inline struct udf_inode_info *UDF_I(struct inode *inode) static inline struct udf_inode_info *UDF_I(struct inode *inode)
{ {
return list_entry(inode, struct udf_inode_info, vfs_inode); return list_entry(inode, struct udf_inode_info, vfs_inode);
} }
#endif /* !defined(_LINUX_UDF_I_H) */ #endif /* _UDF_I_H) */
#ifndef __LINUX_UDF_SB_H #ifndef __LINUX_UDF_SB_H
#define __LINUX_UDF_SB_H #define __LINUX_UDF_SB_H
#include <linux/mutex.h>
/* Since UDF 2.01 is ISO 13346 based... */ /* Since UDF 2.01 is ISO 13346 based... */
#define UDF_SUPER_MAGIC 0x15013346 #define UDF_SUPER_MAGIC 0x15013346
#define UDF_MAX_READ_VERSION 0x0201 #define UDF_MAX_READ_VERSION 0x0250
#define UDF_MAX_WRITE_VERSION 0x0201 #define UDF_MAX_WRITE_VERSION 0x0201
#define UDF_FLAG_USE_EXTENDED_FE 0 #define UDF_FLAG_USE_EXTENDED_FE 0
...@@ -38,6 +40,111 @@ ...@@ -38,6 +40,111 @@
#define UDF_PART_FLAG_REWRITABLE 0x0040 #define UDF_PART_FLAG_REWRITABLE 0x0040
#define UDF_PART_FLAG_OVERWRITABLE 0x0080 #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) static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
{ {
return sb->s_fs_info; return sb->s_fs_info;
......
#ifndef __UDF_DECL_H #ifndef __UDF_DECL_H
#define __UDF_DECL_H #define __UDF_DECL_H
#include <linux/udf_fs.h>
#include "ecma_167.h" #include "ecma_167.h"
#include "osta_udf.h" #include "osta_udf.h"
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/udf_fs_i.h>
#include <linux/udf_fs_sb.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/udf_fs_i.h>
#include "udf_sb.h"
#include "udfend.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_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) )
#define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) ) #define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) )
...@@ -23,16 +43,24 @@ ...@@ -23,16 +43,24 @@
#define UDF_NAME_LEN 256 #define UDF_NAME_LEN 256
#define UDF_PATH_LEN 1023 #define UDF_PATH_LEN 1023
#define udf_file_entry_alloc_offset(inode)\ static inline size_t udf_file_entry_alloc_offset(struct inode *inode)
(UDF_I(inode)->i_use ?\ {
sizeof(struct unallocSpaceEntry) :\ struct udf_inode_info *iinfo = UDF_I(inode);
((UDF_I(inode)->i_efe ?\ if (iinfo->i_use)
sizeof(struct extendedFileEntry) :\ return sizeof(struct unallocSpaceEntry);
sizeof(struct fileEntry)) + UDF_I(inode)->i_lenEAttr)) else if (iinfo->i_efe)
return sizeof(struct extendedFileEntry) + iinfo->i_lenEAttr;
#define udf_ext0_offset(inode)\ else
(UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ?\ return sizeof(struct fileEntry) + iinfo->i_lenEAttr;
udf_file_entry_alloc_offset(inode) : 0) }
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_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset)) #define udf_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset))
...@@ -83,7 +111,6 @@ struct extent_position { ...@@ -83,7 +111,6 @@ struct extent_position {
}; };
/* super.c */ /* super.c */
extern void udf_error(struct super_block *, const char *, const char *, ...);
extern void udf_warning(struct super_block *, const char *, const char *, ...); extern void udf_warning(struct super_block *, const char *, const char *, ...);
/* namei.c */ /* namei.c */
...@@ -150,6 +177,8 @@ extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t, ...@@ -150,6 +177,8 @@ extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t,
uint32_t); uint32_t);
extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t, extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t,
uint32_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 *); extern int udf_relocate_blocks(struct super_block *, long, long *);
/* unicode.c */ /* unicode.c */
...@@ -157,7 +186,7 @@ extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int); ...@@ -157,7 +186,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 *, extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *,
int); int);
extern int udf_build_ustr(struct ustr *, dstring *, int); extern int udf_build_ustr(struct ustr *, dstring *, int);
extern int udf_CS0toUTF8(struct ustr *, struct ustr *); extern int udf_CS0toUTF8(struct ustr *, const struct ustr *);
/* ialloc.c */ /* ialloc.c */
extern void udf_free_inode(struct inode *); extern void udf_free_inode(struct inode *);
...@@ -191,11 +220,9 @@ extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, ...@@ -191,11 +220,9 @@ extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize,
extern long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int); extern long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int);
extern short_ad *udf_get_fileshortad(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 */ /* udftime.c */
extern time_t *udf_stamp_to_time(time_t *, long *, kernel_timestamp); extern struct timespec *udf_disk_stamp_to_time(struct timespec *dest,
extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *, struct timespec); timestamp src);
extern timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec src);
#endif /* __UDF_DECL_H */ #endif /* __UDF_DECL_H */
...@@ -24,17 +24,6 @@ static inline lb_addr cpu_to_lelb(kernel_lb_addr in) ...@@ -24,17 +24,6 @@ static inline lb_addr cpu_to_lelb(kernel_lb_addr in)
return out; 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) static inline short_ad lesa_to_cpu(short_ad in)
{ {
short_ad out; short_ad out;
...@@ -85,15 +74,4 @@ static inline kernel_extent_ad leea_to_cpu(extent_ad in) ...@@ -85,15 +74,4 @@ static inline kernel_extent_ad leea_to_cpu(extent_ad in)
return out; 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 */ #endif /* __UDF_ENDIAN_H */
...@@ -85,39 +85,38 @@ extern struct timezone sys_tz; ...@@ -85,39 +85,38 @@ extern struct timezone sys_tz;
#define SECS_PER_HOUR (60 * 60) #define SECS_PER_HOUR (60 * 60)
#define SECS_PER_DAY (SECS_PER_HOUR * 24) #define SECS_PER_DAY (SECS_PER_HOUR * 24)
time_t *udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src) struct timespec *udf_disk_stamp_to_time(struct timespec *dest, timestamp src)
{ {
int yday; int yday;
uint8_t type = src.typeAndTimezone >> 12; u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone);
u16 year = le16_to_cpu(src.year);
uint8_t type = typeAndTimezone >> 12;
int16_t offset; int16_t offset;
if (type == 1) { if (type == 1) {
offset = src.typeAndTimezone << 4; offset = typeAndTimezone << 4;
/* sign extent offset */ /* sign extent offset */
offset = (offset >> 4); offset = (offset >> 4);
if (offset == -2047) /* unspecified offset */ if (offset == -2047) /* unspecified offset */
offset = 0; offset = 0;
} else { } else
offset = 0; offset = 0;
}
if ((src.year < EPOCH_YEAR) || if ((year < EPOCH_YEAR) ||
(src.year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) { (year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) {
*dest = -1;
*dest_usec = -1;
return NULL; return NULL;
} }
*dest = year_seconds[src.year - EPOCH_YEAR]; dest->tv_sec = year_seconds[year - EPOCH_YEAR];
*dest -= offset * 60; dest->tv_sec -= offset * 60;
yday = ((__mon_yday[__isleap(src.year)][src.month - 1]) + src.day - 1); yday = ((__mon_yday[__isleap(year)][src.month - 1]) + src.day - 1);
*dest += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second; dest->tv_sec += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second;
*dest_usec = src.centiseconds * 10000 + dest->tv_nsec = 1000 * (src.centiseconds * 10000 +
src.hundredsOfMicroseconds * 100 + src.microseconds; src.hundredsOfMicroseconds * 100 + src.microseconds);
return dest; return dest;
} }
kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts) timestamp *udf_time_to_disk_stamp(timestamp *dest, struct timespec ts)
{ {
long int days, rem, y; long int days, rem, y;
const unsigned short int *ip; const unsigned short int *ip;
...@@ -128,7 +127,7 @@ kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts) ...@@ -128,7 +127,7 @@ kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
if (!dest) if (!dest)
return NULL; return NULL;
dest->typeAndTimezone = 0x1000 | (offset & 0x0FFF); dest->typeAndTimezone = cpu_to_le16(0x1000 | (offset & 0x0FFF));
ts.tv_sec += offset * 60; ts.tv_sec += offset * 60;
days = ts.tv_sec / SECS_PER_DAY; days = ts.tv_sec / SECS_PER_DAY;
...@@ -151,7 +150,7 @@ kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts) ...@@ -151,7 +150,7 @@ kernel_timestamp *udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
- LEAPS_THRU_END_OF(y - 1)); - LEAPS_THRU_END_OF(y - 1));
y = yg; y = yg;
} }
dest->year = y; dest->year = cpu_to_le16(y);
ip = __mon_yday[__isleap(y)]; ip = __mon_yday[__isleap(y)];
for (y = 11; days < (long int)ip[y]; --y) for (y = 11; days < (long int)ip[y]; --y)
continue; continue;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/string.h> /* for memset */ #include <linux/string.h> /* for memset */
#include <linux/nls.h> #include <linux/nls.h>
#include <linux/udf_fs.h> #include <linux/crc-itu-t.h>
#include "udf_sb.h" #include "udf_sb.h"
...@@ -49,14 +49,16 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size) ...@@ -49,14 +49,16 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
{ {
int usesize; int usesize;
if ((!dest) || (!ptr) || (!size)) if (!dest || !ptr || !size)
return -1; return -1;
BUG_ON(size < 2);
memset(dest, 0, sizeof(struct ustr)); usesize = min_t(size_t, ptr[size - 1], sizeof(dest->u_name));
usesize = (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size; usesize = min(usesize, size - 2);
dest->u_cmpID = ptr[0]; dest->u_cmpID = ptr[0];
dest->u_len = ptr[size - 1]; dest->u_len = usesize;
memcpy(dest->u_name, ptr + 1, usesize - 1); memcpy(dest->u_name, ptr + 1, usesize);
memset(dest->u_name + usesize, 0, sizeof(dest->u_name) - usesize);
return 0; return 0;
} }
...@@ -83,9 +85,6 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) ...@@ -83,9 +85,6 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
* PURPOSE * PURPOSE
* Convert OSTA Compressed Unicode to the UTF-8 equivalent. * Convert OSTA Compressed Unicode to the UTF-8 equivalent.
* *
* DESCRIPTION
* This routine is only called by udf_filldir().
*
* PRE-CONDITIONS * PRE-CONDITIONS
* utf Pointer to UTF-8 output buffer. * utf Pointer to UTF-8 output buffer.
* ocu Pointer to OSTA Compressed Unicode input buffer * ocu Pointer to OSTA Compressed Unicode input buffer
...@@ -99,43 +98,39 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) ...@@ -99,43 +98,39 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
* November 12, 1997 - Andrew E. Mileski * November 12, 1997 - Andrew E. Mileski
* Written, tested, and released. * Written, tested, and released.
*/ */
int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i) int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
{ {
uint8_t *ocu; const uint8_t *ocu;
uint32_t c;
uint8_t cmp_id, ocu_len; uint8_t cmp_id, ocu_len;
int i; int i;
ocu = ocu_i->u_name;
ocu_len = ocu_i->u_len; ocu_len = ocu_i->u_len;
cmp_id = ocu_i->u_cmpID;
utf_o->u_len = 0;
if (ocu_len == 0) { if (ocu_len == 0) {
memset(utf_o, 0, sizeof(struct ustr)); memset(utf_o, 0, sizeof(struct ustr));
utf_o->u_cmpID = 0;
utf_o->u_len = 0;
return 0; return 0;
} }
if ((cmp_id != 8) && (cmp_id != 16)) { cmp_id = ocu_i->u_cmpID;
if (cmp_id != 8 && cmp_id != 16) {
memset(utf_o, 0, sizeof(struct ustr));
printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n",
cmp_id, ocu_i->u_name); cmp_id, ocu_i->u_name);
return 0; 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));) { for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
/* Expand OSTA compressed Unicode to Unicode */ /* Expand OSTA compressed Unicode to Unicode */
c = ocu[i++]; uint32_t c = ocu[i++];
if (cmp_id == 16) if (cmp_id == 16)
c = (c << 8) | ocu[i++]; c = (c << 8) | ocu[i++];
/* Compress Unicode to UTF-8 */ /* Compress Unicode to UTF-8 */
if (c < 0x80U) { if (c < 0x80U)
utf_o->u_name[utf_o->u_len++] = (uint8_t)c; 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++] = utf_o->u_name[utf_o->u_len++] =
(uint8_t)(0xc0 | (c >> 6)); (uint8_t)(0xc0 | (c >> 6));
utf_o->u_name[utf_o->u_len++] = utf_o->u_name[utf_o->u_len++] =
...@@ -255,35 +250,32 @@ static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) ...@@ -255,35 +250,32 @@ static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
} }
static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
struct ustr *ocu_i) const struct ustr *ocu_i)
{ {
uint8_t *ocu; const uint8_t *ocu;
uint32_t c;
uint8_t cmp_id, ocu_len; uint8_t cmp_id, ocu_len;
int i; int i;
ocu = ocu_i->u_name;
ocu_len = ocu_i->u_len; ocu_len = ocu_i->u_len;
cmp_id = ocu_i->u_cmpID;
utf_o->u_len = 0;
if (ocu_len == 0) { if (ocu_len == 0) {
memset(utf_o, 0, sizeof(struct ustr)); memset(utf_o, 0, sizeof(struct ustr));
utf_o->u_cmpID = 0;
utf_o->u_len = 0;
return 0; return 0;
} }
if ((cmp_id != 8) && (cmp_id != 16)) { cmp_id = ocu_i->u_cmpID;
if (cmp_id != 8 && cmp_id != 16) {
memset(utf_o, 0, sizeof(struct ustr));
printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n",
cmp_id, ocu_i->u_name); cmp_id, ocu_i->u_name);
return 0; 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));) { for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
/* Expand OSTA compressed Unicode to Unicode */ /* Expand OSTA compressed Unicode to Unicode */
c = ocu[i++]; uint32_t c = ocu[i++];
if (cmp_id == 16) if (cmp_id == 16)
c = (c << 8) | ocu[i++]; c = (c << 8) | ocu[i++];
...@@ -463,7 +455,7 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, ...@@ -463,7 +455,7 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName,
} else if (newIndex > 250) } else if (newIndex > 250)
newIndex = 250; newIndex = 250;
newName[newIndex++] = CRC_MARK; newName[newIndex++] = CRC_MARK;
valueCRC = udf_crc(fidName, fidNameLen, 0); valueCRC = crc_itu_t(0, fidName, fidNameLen);
newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8];
newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
......
...@@ -150,6 +150,7 @@ header-y += tiocl.h ...@@ -150,6 +150,7 @@ header-y += tiocl.h
header-y += tipc.h header-y += tipc.h
header-y += tipc_config.h header-y += tipc_config.h
header-y += toshiba.h header-y += toshiba.h
header-y += udf_fs_i.h
header-y += ultrasound.h header-y += ultrasound.h
header-y += un.h header-y += un.h
header-y += utime.h header-y += utime.h
...@@ -334,7 +335,6 @@ unifdef-y += time.h ...@@ -334,7 +335,6 @@ unifdef-y += time.h
unifdef-y += timex.h unifdef-y += timex.h
unifdef-y += tty.h unifdef-y += tty.h
unifdef-y += types.h unifdef-y += types.h
unifdef-y += udf_fs_i.h
unifdef-y += udp.h unifdef-y += udp.h
unifdef-y += uinput.h unifdef-y += uinput.h
unifdef-y += uio.h unifdef-y += uio.h
......
/*
* 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 */
...@@ -9,41 +9,10 @@ ...@@ -9,41 +9,10 @@
* ftp://prep.ai.mit.edu/pub/gnu/GPL * ftp://prep.ai.mit.edu/pub/gnu/GPL
* Each contributing author retains all rights to their own work. * Each contributing author retains all rights to their own work.
*/ */
#ifndef _UDF_FS_I_H #ifndef _UDF_FS_I_H
#define _UDF_FS_I_H 1 #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 */ /* exported IOCTLs, we have 'l', 0x40-0x7f */
#define UDF_GETEASIZE _IOR('l', 0x40, int) #define UDF_GETEASIZE _IOR('l', 0x40, int)
#define UDF_GETEABLOCK _IOR('l', 0x41, void *) #define UDF_GETEABLOCK _IOR('l', 0x41, void *)
#define UDF_GETVOLIDENT _IOR('l', 0x42, void *) #define UDF_GETVOLIDENT _IOR('l', 0x42, void *)
......
/*
* 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 <linux/mutex.h>
#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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment