| .. | .. | 
|---|
 | 1 | +// SPDX-License-Identifier: GPL-2.0-only  | 
|---|
| 1 | 2 |  /* | 
|---|
| 2 | 3 |   *  linux/fs/adfs/inode.c | 
|---|
| 3 | 4 |   * | 
|---|
| 4 | 5 |   *  Copyright (C) 1997-1999 Russell King | 
|---|
| 5 |  | - *  | 
|---|
| 6 |  | - * This program is free software; you can redistribute it and/or modify  | 
|---|
| 7 |  | - * it under the terms of the GNU General Public License version 2 as  | 
|---|
| 8 |  | - * published by the Free Software Foundation.  | 
|---|
| 9 | 6 |   */ | 
|---|
| 10 | 7 |  #include <linux/buffer_head.h> | 
|---|
| 11 | 8 |  #include <linux/writeback.h> | 
|---|
| .. | .. | 
|---|
| 23 | 20 |  		if (block >= inode->i_blocks) | 
|---|
| 24 | 21 |  			goto abort_toobig; | 
|---|
| 25 | 22 |   | 
|---|
| 26 |  | -		block = __adfs_block_map(inode->i_sb, inode->i_ino, block);  | 
|---|
 | 23 | +		block = __adfs_block_map(inode->i_sb, ADFS_I(inode)->indaddr,  | 
|---|
 | 24 | +					 block);  | 
|---|
| 27 | 25 |  		if (block) | 
|---|
| 28 | 26 |  			map_bh(bh, inode->i_sb, block); | 
|---|
| 29 | 27 |  		return 0; | 
|---|
| .. | .. | 
|---|
| 97 | 95 |  		return S_IFDIR | S_IXUGO | mode; | 
|---|
| 98 | 96 |  	} | 
|---|
| 99 | 97 |   | 
|---|
| 100 |  | -	switch (ADFS_I(inode)->filetype) {  | 
|---|
 | 98 | +	switch (adfs_filetype(ADFS_I(inode)->loadaddr)) {  | 
|---|
| 101 | 99 |  	case 0xfc0:	/* LinkFS */ | 
|---|
| 102 | 100 |  		return S_IFLNK|S_IRWXUGO; | 
|---|
| 103 | 101 |   | 
|---|
| .. | .. | 
|---|
| 129 | 127 |   * Convert Linux permission to ADFS attribute.  We try to do the reverse | 
|---|
| 130 | 128 |   * of atts2mode, but there is not a 1:1 translation. | 
|---|
| 131 | 129 |   */ | 
|---|
| 132 |  | -static int  | 
|---|
| 133 |  | -adfs_mode2atts(struct super_block *sb, struct inode *inode)  | 
|---|
 | 130 | +static int adfs_mode2atts(struct super_block *sb, struct inode *inode,  | 
|---|
 | 131 | +			  umode_t ia_mode)  | 
|---|
| 134 | 132 |  { | 
|---|
 | 133 | +	struct adfs_sb_info *asb = ADFS_SB(sb);  | 
|---|
| 135 | 134 |  	umode_t mode; | 
|---|
| 136 | 135 |  	int attr; | 
|---|
| 137 |  | -	struct adfs_sb_info *asb = ADFS_SB(sb);  | 
|---|
| 138 | 136 |   | 
|---|
| 139 | 137 |  	/* FIXME: should we be able to alter a link? */ | 
|---|
| 140 | 138 |  	if (S_ISLNK(inode->i_mode)) | 
|---|
| 141 | 139 |  		return ADFS_I(inode)->attr; | 
|---|
| 142 | 140 |   | 
|---|
 | 141 | +	/* Directories do not have read/write permissions on the media */  | 
|---|
| 143 | 142 |  	if (S_ISDIR(inode->i_mode)) | 
|---|
| 144 |  | -		attr = ADFS_NDA_DIRECTORY;  | 
|---|
| 145 |  | -	else  | 
|---|
| 146 |  | -		attr = 0;  | 
|---|
 | 143 | +		return ADFS_NDA_DIRECTORY;  | 
|---|
| 147 | 144 |   | 
|---|
| 148 |  | -	mode = inode->i_mode & asb->s_owner_mask;  | 
|---|
 | 145 | +	attr = 0;  | 
|---|
 | 146 | +	mode = ia_mode & asb->s_owner_mask;  | 
|---|
| 149 | 147 |  	if (mode & S_IRUGO) | 
|---|
| 150 | 148 |  		attr |= ADFS_NDA_OWNER_READ; | 
|---|
| 151 | 149 |  	if (mode & S_IWUGO) | 
|---|
| 152 | 150 |  		attr |= ADFS_NDA_OWNER_WRITE; | 
|---|
| 153 | 151 |   | 
|---|
| 154 |  | -	mode = inode->i_mode & asb->s_other_mask;  | 
|---|
 | 152 | +	mode = ia_mode & asb->s_other_mask;  | 
|---|
| 155 | 153 |  	mode &= ~asb->s_owner_mask; | 
|---|
| 156 | 154 |  	if (mode & S_IRUGO) | 
|---|
| 157 | 155 |  		attr |= ADFS_NDA_PUBLIC_READ; | 
|---|
| .. | .. | 
|---|
| 160 | 158 |   | 
|---|
| 161 | 159 |  	return attr; | 
|---|
| 162 | 160 |  } | 
|---|
 | 161 | +  | 
|---|
 | 162 | +static const s64 nsec_unix_epoch_diff_risc_os_epoch = 2208988800000000000LL;  | 
|---|
| 163 | 163 |   | 
|---|
| 164 | 164 |  /* | 
|---|
| 165 | 165 |   * Convert an ADFS time to Unix time.  ADFS has a 40-bit centi-second time | 
|---|
| .. | .. | 
|---|
| 173 | 173 |  	/* 01 Jan 1970 00:00:00 (Unix epoch) as nanoseconds since | 
|---|
| 174 | 174 |  	 * 01 Jan 1900 00:00:00 (RISC OS epoch) | 
|---|
| 175 | 175 |  	 */ | 
|---|
| 176 |  | -	static const s64 nsec_unix_epoch_diff_risc_os_epoch =  | 
|---|
| 177 |  | -							2208988800000000000LL;  | 
|---|
| 178 | 176 |  	s64 nsec; | 
|---|
| 179 | 177 |   | 
|---|
| 180 |  | -	if (ADFS_I(inode)->stamped == 0)  | 
|---|
 | 178 | +	if (!adfs_inode_is_stamped(inode))  | 
|---|
| 181 | 179 |  		goto cur_time; | 
|---|
| 182 | 180 |   | 
|---|
| 183 | 181 |  	high = ADFS_I(inode)->loadaddr & 0xFF; /* top 8 bits of timestamp */ | 
|---|
| .. | .. | 
|---|
| 207 | 205 |  	return; | 
|---|
| 208 | 206 |  } | 
|---|
| 209 | 207 |   | 
|---|
| 210 |  | -/*  | 
|---|
| 211 |  | - * Convert an Unix time to ADFS time.  We only do this if the entry has a  | 
|---|
| 212 |  | - * time/date stamp already.  | 
|---|
| 213 |  | - */  | 
|---|
| 214 |  | -static void  | 
|---|
| 215 |  | -adfs_unix2adfs_time(struct inode *inode, unsigned int secs)  | 
|---|
 | 208 | +/* Convert an Unix time to ADFS time for an entry that is already stamped. */  | 
|---|
 | 209 | +static void adfs_unix2adfs_time(struct inode *inode,  | 
|---|
 | 210 | +				const struct timespec64 *ts)  | 
|---|
| 216 | 211 |  { | 
|---|
| 217 |  | -	unsigned int high, low;  | 
|---|
 | 212 | +	s64 cs, nsec = timespec64_to_ns(ts);  | 
|---|
| 218 | 213 |   | 
|---|
| 219 |  | -	if (ADFS_I(inode)->stamped) {  | 
|---|
| 220 |  | -		/* convert 32-bit seconds to 40-bit centi-seconds */  | 
|---|
| 221 |  | -		low  = (secs & 255) * 100;  | 
|---|
| 222 |  | -		high = (secs / 256) * 100 + (low >> 8) + 0x336e996a;  | 
|---|
 | 214 | +	/* convert from Unix to RISC OS epoch */  | 
|---|
 | 215 | +	nsec += nsec_unix_epoch_diff_risc_os_epoch;  | 
|---|
| 223 | 216 |   | 
|---|
| 224 |  | -		ADFS_I(inode)->loadaddr = (high >> 24) |  | 
|---|
| 225 |  | -				(ADFS_I(inode)->loadaddr & ~0xff);  | 
|---|
| 226 |  | -		ADFS_I(inode)->execaddr = (low & 255) | (high << 8);  | 
|---|
| 227 |  | -	}  | 
|---|
 | 217 | +	/* convert from nanoseconds to centiseconds */  | 
|---|
 | 218 | +	cs = div_s64(nsec, 10000000);  | 
|---|
 | 219 | +  | 
|---|
 | 220 | +	cs = clamp_t(s64, cs, 0, 0xffffffffff);  | 
|---|
 | 221 | +  | 
|---|
 | 222 | +	ADFS_I(inode)->loadaddr &= ~0xff;  | 
|---|
 | 223 | +	ADFS_I(inode)->loadaddr |= (cs >> 32) & 0xff;  | 
|---|
 | 224 | +	ADFS_I(inode)->execaddr = cs;  | 
|---|
| 228 | 225 |  } | 
|---|
| 229 | 226 |   | 
|---|
| 230 | 227 |  /* | 
|---|
| .. | .. | 
|---|
| 250 | 247 |   | 
|---|
| 251 | 248 |  	inode->i_uid	 = ADFS_SB(sb)->s_uid; | 
|---|
| 252 | 249 |  	inode->i_gid	 = ADFS_SB(sb)->s_gid; | 
|---|
| 253 |  | -	inode->i_ino	 = obj->file_id;  | 
|---|
 | 250 | +	inode->i_ino	 = obj->indaddr;  | 
|---|
| 254 | 251 |  	inode->i_size	 = obj->size; | 
|---|
| 255 | 252 |  	set_nlink(inode, 2); | 
|---|
| 256 | 253 |  	inode->i_blocks	 = (inode->i_size + sb->s_blocksize - 1) >> | 
|---|
| .. | .. | 
|---|
| 263 | 260 |  	 * for cross-directory renames. | 
|---|
| 264 | 261 |  	 */ | 
|---|
| 265 | 262 |  	ADFS_I(inode)->parent_id = obj->parent_id; | 
|---|
 | 263 | +	ADFS_I(inode)->indaddr   = obj->indaddr;  | 
|---|
| 266 | 264 |  	ADFS_I(inode)->loadaddr  = obj->loadaddr; | 
|---|
| 267 | 265 |  	ADFS_I(inode)->execaddr  = obj->execaddr; | 
|---|
| 268 | 266 |  	ADFS_I(inode)->attr      = obj->attr; | 
|---|
| 269 |  | -	ADFS_I(inode)->filetype  = obj->filetype;  | 
|---|
| 270 |  | -	ADFS_I(inode)->stamped   = ((obj->loadaddr & 0xfff00000) == 0xfff00000);  | 
|---|
| 271 | 267 |   | 
|---|
| 272 | 268 |  	inode->i_mode	 = adfs_atts2mode(sb, inode); | 
|---|
| 273 | 269 |  	adfs_adfs2unix_time(&inode->i_mtime, inode); | 
|---|
| .. | .. | 
|---|
| 320 | 316 |  	if (ia_valid & ATTR_SIZE) | 
|---|
| 321 | 317 |  		truncate_setsize(inode, attr->ia_size); | 
|---|
| 322 | 318 |   | 
|---|
| 323 |  | -	if (ia_valid & ATTR_MTIME) {  | 
|---|
| 324 |  | -		inode->i_mtime = attr->ia_mtime;  | 
|---|
| 325 |  | -		adfs_unix2adfs_time(inode, attr->ia_mtime.tv_sec);  | 
|---|
 | 319 | +	if (ia_valid & ATTR_MTIME && adfs_inode_is_stamped(inode)) {  | 
|---|
 | 320 | +		adfs_unix2adfs_time(inode, &attr->ia_mtime);  | 
|---|
 | 321 | +		adfs_adfs2unix_time(&inode->i_mtime, inode);  | 
|---|
| 326 | 322 |  	} | 
|---|
 | 323 | +  | 
|---|
| 327 | 324 |  	/* | 
|---|
| 328 | 325 |  	 * FIXME: should we make these == to i_mtime since we don't | 
|---|
| 329 | 326 |  	 * have the ability to represent them in our filesystem? | 
|---|
| .. | .. | 
|---|
| 333 | 330 |  	if (ia_valid & ATTR_CTIME) | 
|---|
| 334 | 331 |  		inode->i_ctime = attr->ia_ctime; | 
|---|
| 335 | 332 |  	if (ia_valid & ATTR_MODE) { | 
|---|
| 336 |  | -		ADFS_I(inode)->attr = adfs_mode2atts(sb, inode);  | 
|---|
 | 333 | +		ADFS_I(inode)->attr = adfs_mode2atts(sb, inode, attr->ia_mode);  | 
|---|
| 337 | 334 |  		inode->i_mode = adfs_atts2mode(sb, inode); | 
|---|
| 338 | 335 |  	} | 
|---|
| 339 | 336 |   | 
|---|
| .. | .. | 
|---|
| 358 | 355 |  	struct object_info obj; | 
|---|
| 359 | 356 |  	int ret; | 
|---|
| 360 | 357 |   | 
|---|
| 361 |  | -	obj.file_id	= inode->i_ino;  | 
|---|
 | 358 | +	obj.indaddr	= ADFS_I(inode)->indaddr;  | 
|---|
| 362 | 359 |  	obj.name_len	= 0; | 
|---|
| 363 | 360 |  	obj.parent_id	= ADFS_I(inode)->parent_id; | 
|---|
| 364 | 361 |  	obj.loadaddr	= ADFS_I(inode)->loadaddr; | 
|---|