18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#include <linux/fs.h>
38c2ecf20Sopenharmony_ci#include <linux/buffer_head.h>
48c2ecf20Sopenharmony_ci#include <linux/exportfs.h>
58c2ecf20Sopenharmony_ci#include <linux/iso_fs.h>
68c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_cienum isofs_file_format {
98c2ecf20Sopenharmony_ci	isofs_file_normal = 0,
108c2ecf20Sopenharmony_ci	isofs_file_sparse = 1,
118c2ecf20Sopenharmony_ci	isofs_file_compressed = 2,
128c2ecf20Sopenharmony_ci};
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/*
158c2ecf20Sopenharmony_ci * iso fs inode data in memory
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_cistruct iso_inode_info {
188c2ecf20Sopenharmony_ci	unsigned long i_iget5_block;
198c2ecf20Sopenharmony_ci	unsigned long i_iget5_offset;
208c2ecf20Sopenharmony_ci	unsigned int i_first_extent;
218c2ecf20Sopenharmony_ci	unsigned char i_file_format;
228c2ecf20Sopenharmony_ci	unsigned char i_format_parm[3];
238c2ecf20Sopenharmony_ci	unsigned long i_next_section_block;
248c2ecf20Sopenharmony_ci	unsigned long i_next_section_offset;
258c2ecf20Sopenharmony_ci	off_t i_section_size;
268c2ecf20Sopenharmony_ci	struct inode vfs_inode;
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/*
308c2ecf20Sopenharmony_ci * iso9660 super-block data in memory
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_cistruct isofs_sb_info {
338c2ecf20Sopenharmony_ci	unsigned long s_ninodes;
348c2ecf20Sopenharmony_ci	unsigned long s_nzones;
358c2ecf20Sopenharmony_ci	unsigned long s_firstdatazone;
368c2ecf20Sopenharmony_ci	unsigned long s_log_zone_size;
378c2ecf20Sopenharmony_ci	unsigned long s_max_size;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	int           s_rock_offset; /* offset of SUSP fields within SU area */
408c2ecf20Sopenharmony_ci	s32           s_sbsector;
418c2ecf20Sopenharmony_ci	unsigned char s_joliet_level;
428c2ecf20Sopenharmony_ci	unsigned char s_mapping;
438c2ecf20Sopenharmony_ci	unsigned char s_check;
448c2ecf20Sopenharmony_ci	unsigned char s_session;
458c2ecf20Sopenharmony_ci	unsigned int  s_high_sierra:1;
468c2ecf20Sopenharmony_ci	unsigned int  s_rock:2;
478c2ecf20Sopenharmony_ci	unsigned int  s_cruft:1; /* Broken disks with high byte of length
488c2ecf20Sopenharmony_ci				  * containing junk */
498c2ecf20Sopenharmony_ci	unsigned int  s_nocompress:1;
508c2ecf20Sopenharmony_ci	unsigned int  s_hide:1;
518c2ecf20Sopenharmony_ci	unsigned int  s_showassoc:1;
528c2ecf20Sopenharmony_ci	unsigned int  s_overriderockperm:1;
538c2ecf20Sopenharmony_ci	unsigned int  s_uid_set:1;
548c2ecf20Sopenharmony_ci	unsigned int  s_gid_set:1;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	umode_t s_fmode;
578c2ecf20Sopenharmony_ci	umode_t s_dmode;
588c2ecf20Sopenharmony_ci	kgid_t s_gid;
598c2ecf20Sopenharmony_ci	kuid_t s_uid;
608c2ecf20Sopenharmony_ci	struct nls_table *s_nls_iocharset; /* Native language support table */
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#define ISOFS_INVALID_MODE ((umode_t) -1)
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic inline struct isofs_sb_info *ISOFS_SB(struct super_block *sb)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	return sb->s_fs_info;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic inline struct iso_inode_info *ISOFS_I(struct inode *inode)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	return container_of(inode, struct iso_inode_info, vfs_inode);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic inline int isonum_711(u8 *p)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	return *p;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_cistatic inline int isonum_712(s8 *p)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	return *p;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_cistatic inline unsigned int isonum_721(u8 *p)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	return get_unaligned_le16(p);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_cistatic inline unsigned int isonum_722(u8 *p)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	return get_unaligned_be16(p);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_cistatic inline unsigned int isonum_723(u8 *p)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	/* Ignore bigendian datum due to broken mastering programs */
948c2ecf20Sopenharmony_ci	return get_unaligned_le16(p);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_cistatic inline unsigned int isonum_731(u8 *p)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	return get_unaligned_le32(p);
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_cistatic inline unsigned int isonum_732(u8 *p)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	return get_unaligned_be32(p);
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_cistatic inline unsigned int isonum_733(u8 *p)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	/* Ignore bigendian datum due to broken mastering programs */
1078c2ecf20Sopenharmony_ci	return get_unaligned_le32(p);
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ciextern int iso_date(u8 *, int);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistruct inode;		/* To make gcc happy */
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ciextern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *, int relocated);
1148c2ecf20Sopenharmony_ciextern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
1158c2ecf20Sopenharmony_ciextern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ciint get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *);
1188c2ecf20Sopenharmony_ciint get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ciextern struct dentry *isofs_lookup(struct inode *, struct dentry *, unsigned int flags);
1218c2ecf20Sopenharmony_ciextern struct buffer_head *isofs_bread(struct inode *, sector_t);
1228c2ecf20Sopenharmony_ciextern int isofs_get_blocks(struct inode *, sector_t, struct buffer_head **, unsigned long);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistruct inode *__isofs_iget(struct super_block *sb,
1258c2ecf20Sopenharmony_ci			   unsigned long block,
1268c2ecf20Sopenharmony_ci			   unsigned long offset,
1278c2ecf20Sopenharmony_ci			   int relocated);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic inline struct inode *isofs_iget(struct super_block *sb,
1308c2ecf20Sopenharmony_ci				       unsigned long block,
1318c2ecf20Sopenharmony_ci				       unsigned long offset)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	return __isofs_iget(sb, block, offset, 0);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic inline struct inode *isofs_iget_reloc(struct super_block *sb,
1378c2ecf20Sopenharmony_ci					     unsigned long block,
1388c2ecf20Sopenharmony_ci					     unsigned long offset)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	return __isofs_iget(sb, block, offset, 1);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/* Because the inode number is no longer relevant to finding the
1448c2ecf20Sopenharmony_ci * underlying meta-data for an inode, we are free to choose a more
1458c2ecf20Sopenharmony_ci * convenient 32-bit number as the inode number.  The inode numbering
1468c2ecf20Sopenharmony_ci * scheme was recommended by Sergey Vlasov and Eric Lammerts. */
1478c2ecf20Sopenharmony_cistatic inline unsigned long isofs_get_ino(unsigned long block,
1488c2ecf20Sopenharmony_ci					  unsigned long offset,
1498c2ecf20Sopenharmony_ci					  unsigned long bufbits)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	return (block << (bufbits - 5)) | (offset >> 5);
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci/* Every directory can have many redundant directory entries scattered
1558c2ecf20Sopenharmony_ci * throughout the directory tree.  First there is the directory entry
1568c2ecf20Sopenharmony_ci * with the name of the directory stored in the parent directory.
1578c2ecf20Sopenharmony_ci * Then, there is the "." directory entry stored in the directory
1588c2ecf20Sopenharmony_ci * itself.  Finally, there are possibly many ".." directory entries
1598c2ecf20Sopenharmony_ci * stored in all the subdirectories.
1608c2ecf20Sopenharmony_ci *
1618c2ecf20Sopenharmony_ci * In order for the NFS get_parent() method to work and for the
1628c2ecf20Sopenharmony_ci * general consistency of the dcache, we need to make sure the
1638c2ecf20Sopenharmony_ci * "i_iget5_block" and "i_iget5_offset" all point to exactly one of
1648c2ecf20Sopenharmony_ci * the many redundant entries for each directory.  We normalize the
1658c2ecf20Sopenharmony_ci * block and offset by always making them point to the "."  directory.
1668c2ecf20Sopenharmony_ci *
1678c2ecf20Sopenharmony_ci * Notice that we do not use the entry for the directory with the name
1688c2ecf20Sopenharmony_ci * that is located in the parent directory.  Even though choosing this
1698c2ecf20Sopenharmony_ci * first directory is more natural, it is much easier to find the "."
1708c2ecf20Sopenharmony_ci * entry in the NFS get_parent() method because it is implicitly
1718c2ecf20Sopenharmony_ci * encoded in the "extent + ext_attr_length" fields of _all_ the
1728c2ecf20Sopenharmony_ci * redundant entries for the directory.  Thus, it can always be
1738c2ecf20Sopenharmony_ci * reached regardless of which directory entry you have in hand.
1748c2ecf20Sopenharmony_ci *
1758c2ecf20Sopenharmony_ci * This works because the "." entry is simply the first directory
1768c2ecf20Sopenharmony_ci * record when you start reading the file that holds all the directory
1778c2ecf20Sopenharmony_ci * records, and this file starts at "extent + ext_attr_length" blocks.
1788c2ecf20Sopenharmony_ci * Because the "." entry is always the first entry listed in the
1798c2ecf20Sopenharmony_ci * directories file, the normalized "offset" value is always 0.
1808c2ecf20Sopenharmony_ci *
1818c2ecf20Sopenharmony_ci * You should pass the directory entry in "de".  On return, "block"
1828c2ecf20Sopenharmony_ci * and "offset" will hold normalized values.  Only directories are
1838c2ecf20Sopenharmony_ci * affected making it safe to call even for non-directory file
1848c2ecf20Sopenharmony_ci * types. */
1858c2ecf20Sopenharmony_cistatic inline void
1868c2ecf20Sopenharmony_ciisofs_normalize_block_and_offset(struct iso_directory_record* de,
1878c2ecf20Sopenharmony_ci				 unsigned long *block,
1888c2ecf20Sopenharmony_ci				 unsigned long *offset)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	/* Only directories are normalized. */
1918c2ecf20Sopenharmony_ci	if (de->flags[0] & 2) {
1928c2ecf20Sopenharmony_ci		*offset = 0;
1938c2ecf20Sopenharmony_ci		*block = (unsigned long)isonum_733(de->extent)
1948c2ecf20Sopenharmony_ci			+ (unsigned long)isonum_711(de->ext_attr_length);
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ciextern const struct inode_operations isofs_dir_inode_operations;
1998c2ecf20Sopenharmony_ciextern const struct file_operations isofs_dir_operations;
2008c2ecf20Sopenharmony_ciextern const struct address_space_operations isofs_symlink_aops;
2018c2ecf20Sopenharmony_ciextern const struct export_operations isofs_export_ops;
202