cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

directory.c (5920B)


      1/*
      2 * directory.c
      3 *
      4 * PURPOSE
      5 *	Directory related functions
      6 *
      7 * COPYRIGHT
      8 *	This file is distributed under the terms of the GNU General Public
      9 *	License (GPL). Copies of the GPL can be obtained from:
     10 *		ftp://prep.ai.mit.edu/pub/gnu/GPL
     11 *	Each contributing author retains all rights to their own work.
     12 */
     13
     14#include "udfdecl.h"
     15#include "udf_i.h"
     16
     17#include <linux/fs.h>
     18#include <linux/string.h>
     19#include <linux/bio.h>
     20
     21struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
     22					 struct udf_fileident_bh *fibh,
     23					 struct fileIdentDesc *cfi,
     24					 struct extent_position *epos,
     25					 struct kernel_lb_addr *eloc, uint32_t *elen,
     26					 sector_t *offset)
     27{
     28	struct fileIdentDesc *fi;
     29	int i, num;
     30	udf_pblk_t block;
     31	struct buffer_head *tmp, *bha[16];
     32	struct udf_inode_info *iinfo = UDF_I(dir);
     33
     34	fibh->soffset = fibh->eoffset;
     35
     36	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
     37		fi = udf_get_fileident(iinfo->i_data -
     38				       (iinfo->i_efe ?
     39					sizeof(struct extendedFileEntry) :
     40					sizeof(struct fileEntry)),
     41				       dir->i_sb->s_blocksize,
     42				       &(fibh->eoffset));
     43		if (!fi)
     44			return NULL;
     45
     46		*nf_pos += fibh->eoffset - fibh->soffset;
     47
     48		memcpy((uint8_t *)cfi, (uint8_t *)fi,
     49		       sizeof(struct fileIdentDesc));
     50
     51		return fi;
     52	}
     53
     54	if (fibh->eoffset == dir->i_sb->s_blocksize) {
     55		uint32_t lextoffset = epos->offset;
     56		unsigned char blocksize_bits = dir->i_sb->s_blocksize_bits;
     57
     58		if (udf_next_aext(dir, epos, eloc, elen, 1) !=
     59		    (EXT_RECORDED_ALLOCATED >> 30))
     60			return NULL;
     61
     62		block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
     63
     64		(*offset)++;
     65
     66		if ((*offset << blocksize_bits) >= *elen)
     67			*offset = 0;
     68		else
     69			epos->offset = lextoffset;
     70
     71		brelse(fibh->sbh);
     72		fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
     73		if (!fibh->sbh)
     74			return NULL;
     75		fibh->soffset = fibh->eoffset = 0;
     76
     77		if (!(*offset & ((16 >> (blocksize_bits - 9)) - 1))) {
     78			i = 16 >> (blocksize_bits - 9);
     79			if (i + *offset > (*elen >> blocksize_bits))
     80				i = (*elen >> blocksize_bits)-*offset;
     81			for (num = 0; i > 0; i--) {
     82				block = udf_get_lb_pblock(dir->i_sb, eloc,
     83							  *offset + i);
     84				tmp = udf_tgetblk(dir->i_sb, block);
     85				if (tmp && !buffer_uptodate(tmp) &&
     86						!buffer_locked(tmp))
     87					bha[num++] = tmp;
     88				else
     89					brelse(tmp);
     90			}
     91			if (num) {
     92				ll_rw_block(REQ_OP_READ, REQ_RAHEAD, num, bha);
     93				for (i = 0; i < num; i++)
     94					brelse(bha[i]);
     95			}
     96		}
     97	} else if (fibh->sbh != fibh->ebh) {
     98		brelse(fibh->sbh);
     99		fibh->sbh = fibh->ebh;
    100	}
    101
    102	fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
    103			       &(fibh->eoffset));
    104
    105	if (!fi)
    106		return NULL;
    107
    108	*nf_pos += fibh->eoffset - fibh->soffset;
    109
    110	if (fibh->eoffset <= dir->i_sb->s_blocksize) {
    111		memcpy((uint8_t *)cfi, (uint8_t *)fi,
    112		       sizeof(struct fileIdentDesc));
    113	} else if (fibh->eoffset > dir->i_sb->s_blocksize) {
    114		uint32_t lextoffset = epos->offset;
    115
    116		if (udf_next_aext(dir, epos, eloc, elen, 1) !=
    117		    (EXT_RECORDED_ALLOCATED >> 30))
    118			return NULL;
    119
    120		block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
    121
    122		(*offset)++;
    123
    124		if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
    125			*offset = 0;
    126		else
    127			epos->offset = lextoffset;
    128
    129		fibh->soffset -= dir->i_sb->s_blocksize;
    130		fibh->eoffset -= dir->i_sb->s_blocksize;
    131
    132		fibh->ebh = udf_tread(dir->i_sb, block);
    133		if (!fibh->ebh)
    134			return NULL;
    135
    136		if (sizeof(struct fileIdentDesc) > -fibh->soffset) {
    137			int fi_len;
    138
    139			memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset);
    140			memcpy((uint8_t *)cfi - fibh->soffset,
    141			       fibh->ebh->b_data,
    142			       sizeof(struct fileIdentDesc) + fibh->soffset);
    143
    144			fi_len = udf_dir_entry_len(cfi);
    145			*nf_pos += fi_len - (fibh->eoffset - fibh->soffset);
    146			fibh->eoffset = fibh->soffset + fi_len;
    147		} else {
    148			memcpy((uint8_t *)cfi, (uint8_t *)fi,
    149			       sizeof(struct fileIdentDesc));
    150		}
    151	}
    152	/* Got last entry outside of dir size - fs is corrupted! */
    153	if (*nf_pos > dir->i_size)
    154		return NULL;
    155	return fi;
    156}
    157
    158struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset)
    159{
    160	struct fileIdentDesc *fi;
    161	int lengthThisIdent;
    162	uint8_t *ptr;
    163	int padlen;
    164
    165	if ((!buffer) || (!offset)) {
    166		udf_debug("invalidparms, buffer=%p, offset=%p\n",
    167			  buffer, offset);
    168		return NULL;
    169	}
    170
    171	ptr = buffer;
    172
    173	if ((*offset > 0) && (*offset < bufsize))
    174		ptr += *offset;
    175	fi = (struct fileIdentDesc *)ptr;
    176	if (fi->descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) {
    177		udf_debug("0x%x != TAG_IDENT_FID\n",
    178			  le16_to_cpu(fi->descTag.tagIdent));
    179		udf_debug("offset: %d sizeof: %lu bufsize: %d\n",
    180			  *offset, (unsigned long)sizeof(struct fileIdentDesc),
    181			  bufsize);
    182		return NULL;
    183	}
    184	if ((*offset + sizeof(struct fileIdentDesc)) > bufsize)
    185		lengthThisIdent = sizeof(struct fileIdentDesc);
    186	else
    187		lengthThisIdent = sizeof(struct fileIdentDesc) +
    188			fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
    189
    190	/* we need to figure padding, too! */
    191	padlen = lengthThisIdent % UDF_NAME_PAD;
    192	if (padlen)
    193		lengthThisIdent += (UDF_NAME_PAD - padlen);
    194	*offset = *offset + lengthThisIdent;
    195
    196	return fi;
    197}
    198
    199struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset,
    200			      int inc)
    201{
    202	struct short_ad *sa;
    203
    204	if ((!ptr) || (!offset)) {
    205		pr_err("%s: invalidparms\n", __func__);
    206		return NULL;
    207	}
    208
    209	if ((*offset + sizeof(struct short_ad)) > maxoffset)
    210		return NULL;
    211	else {
    212		sa = (struct short_ad *)ptr;
    213		if (sa->extLength == 0)
    214			return NULL;
    215	}
    216
    217	if (inc)
    218		*offset += sizeof(struct short_ad);
    219	return sa;
    220}
    221
    222struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc)
    223{
    224	struct long_ad *la;
    225
    226	if ((!ptr) || (!offset)) {
    227		pr_err("%s: invalidparms\n", __func__);
    228		return NULL;
    229	}
    230
    231	if ((*offset + sizeof(struct long_ad)) > maxoffset)
    232		return NULL;
    233	else {
    234		la = (struct long_ad *)ptr;
    235		if (la->extLength == 0)
    236			return NULL;
    237	}
    238
    239	if (inc)
    240		*offset += sizeof(struct long_ad);
    241	return la;
    242}