| .. | .. | 
|---|
 | 1 | +// SPDX-License-Identifier: GPL-2.0-only  | 
|---|
| 1 | 2 |  /* | 
|---|
| 2 | 3 |   *  linux/fs/adfs/dir_f.c | 
|---|
| 3 | 4 |   * | 
|---|
| 4 | 5 |   * Copyright (C) 1997-1999 Russell King | 
|---|
| 5 | 6 |   * | 
|---|
| 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 |  | - *  | 
|---|
| 10 | 7 |   *  E and F format directory handling | 
|---|
| 11 | 8 |   */ | 
|---|
| 12 |  | -#include <linux/buffer_head.h>  | 
|---|
| 13 | 9 |  #include "adfs.h" | 
|---|
| 14 | 10 |  #include "dir_f.h" | 
|---|
| 15 |  | -  | 
|---|
| 16 |  | -static void adfs_f_free(struct adfs_dir *dir);  | 
|---|
| 17 | 11 |   | 
|---|
| 18 | 12 |  /* | 
|---|
| 19 | 13 |   * Read an (unaligned) value of length 1..4 bytes | 
|---|
| .. | .. | 
|---|
| 24 | 18 |   | 
|---|
| 25 | 19 |  	switch (len) { | 
|---|
| 26 | 20 |  	case 4:		val |= p[3] << 24; | 
|---|
 | 21 | +		fallthrough;  | 
|---|
| 27 | 22 |  	case 3:		val |= p[2] << 16; | 
|---|
 | 23 | +		fallthrough;  | 
|---|
| 28 | 24 |  	case 2:		val |= p[1] << 8; | 
|---|
 | 25 | +		fallthrough;  | 
|---|
| 29 | 26 |  	default:	val |= p[0]; | 
|---|
| 30 | 27 |  	} | 
|---|
| 31 | 28 |  	return val; | 
|---|
| .. | .. | 
|---|
| 35 | 32 |  { | 
|---|
| 36 | 33 |  	switch (len) { | 
|---|
| 37 | 34 |  	case 4:		p[3] = val >> 24; | 
|---|
 | 35 | +		fallthrough;  | 
|---|
| 38 | 36 |  	case 3:		p[2] = val >> 16; | 
|---|
 | 37 | +		fallthrough;  | 
|---|
| 39 | 38 |  	case 2:		p[1] = val >> 8; | 
|---|
 | 39 | +		fallthrough;  | 
|---|
| 40 | 40 |  	default:	p[0] = val; | 
|---|
| 41 | 41 |  	} | 
|---|
| 42 |  | -}  | 
|---|
| 43 |  | -  | 
|---|
| 44 |  | -static inline int adfs_readname(char *buf, char *ptr, int maxlen)  | 
|---|
| 45 |  | -{  | 
|---|
| 46 |  | -	char *old_buf = buf;  | 
|---|
| 47 |  | -  | 
|---|
| 48 |  | -	while ((unsigned char)*ptr >= ' ' && maxlen--) {  | 
|---|
| 49 |  | -		if (*ptr == '/')  | 
|---|
| 50 |  | -			*buf++ = '.';  | 
|---|
| 51 |  | -		else  | 
|---|
| 52 |  | -			*buf++ = *ptr;  | 
|---|
| 53 |  | -		ptr++;  | 
|---|
| 54 |  | -	}  | 
|---|
| 55 |  | -  | 
|---|
| 56 |  | -	return buf - old_buf;  | 
|---|
| 57 | 42 |  } | 
|---|
| 58 | 43 |   | 
|---|
| 59 | 44 |  #define ror13(v) ((v >> 13) | (v << 19)) | 
|---|
| .. | .. | 
|---|
| 73 | 58 |  #define bufoff(_bh,_idx)			\ | 
|---|
| 74 | 59 |  	({ int _buf = _idx >> blocksize_bits;	\ | 
|---|
| 75 | 60 |  	   int _off = _idx - (_buf << blocksize_bits);\ | 
|---|
| 76 |  | -	  (u8 *)(_bh[_buf]->b_data + _off);	\  | 
|---|
 | 61 | +	  (void *)(_bh[_buf]->b_data + _off);	\  | 
|---|
| 77 | 62 |  	}) | 
|---|
| 78 | 63 |   | 
|---|
| 79 | 64 |  /* | 
|---|
| .. | .. | 
|---|
| 136 | 121 |  	return (dircheck ^ (dircheck >> 8) ^ (dircheck >> 16) ^ (dircheck >> 24)) & 0xff; | 
|---|
| 137 | 122 |  } | 
|---|
| 138 | 123 |   | 
|---|
| 139 |  | -/*  | 
|---|
| 140 |  | - * Read and check that a directory is valid  | 
|---|
| 141 |  | - */  | 
|---|
| 142 |  | -static int  | 
|---|
| 143 |  | -adfs_dir_read(struct super_block *sb, unsigned long object_id,  | 
|---|
| 144 |  | -	      unsigned int size, struct adfs_dir *dir)  | 
|---|
 | 124 | +static int adfs_f_validate(struct adfs_dir *dir)  | 
|---|
 | 125 | +{  | 
|---|
 | 126 | +	struct adfs_dirheader *head = dir->dirhead;  | 
|---|
 | 127 | +	struct adfs_newdirtail *tail = dir->newtail;  | 
|---|
 | 128 | +  | 
|---|
 | 129 | +	if (head->startmasseq != tail->endmasseq ||  | 
|---|
 | 130 | +	    tail->dirlastmask || tail->reserved[0] || tail->reserved[1] ||  | 
|---|
 | 131 | +	    (memcmp(&head->startname, "Nick", 4) &&  | 
|---|
 | 132 | +	     memcmp(&head->startname, "Hugo", 4)) ||  | 
|---|
 | 133 | +	    memcmp(&head->startname, &tail->endname, 4) ||  | 
|---|
 | 134 | +	    adfs_dir_checkbyte(dir) != tail->dircheckbyte)  | 
|---|
 | 135 | +		return -EIO;  | 
|---|
 | 136 | +  | 
|---|
 | 137 | +	return 0;  | 
|---|
 | 138 | +}  | 
|---|
 | 139 | +  | 
|---|
 | 140 | +/* Read and check that a directory is valid */  | 
|---|
 | 141 | +static int adfs_f_read(struct super_block *sb, u32 indaddr, unsigned int size,  | 
|---|
 | 142 | +		       struct adfs_dir *dir)  | 
|---|
| 145 | 143 |  { | 
|---|
| 146 | 144 |  	const unsigned int blocksize_bits = sb->s_blocksize_bits; | 
|---|
| 147 |  | -	int blk = 0;  | 
|---|
 | 145 | +	int ret;  | 
|---|
| 148 | 146 |   | 
|---|
| 149 |  | -	/*  | 
|---|
| 150 |  | -	 * Directories which are not a multiple of 2048 bytes  | 
|---|
| 151 |  | -	 * are considered bad v2 [3.6]  | 
|---|
| 152 |  | -	 */  | 
|---|
| 153 |  | -	if (size & 2047)  | 
|---|
 | 147 | +	if (size && size != ADFS_NEWDIR_SIZE)  | 
|---|
 | 148 | +		return -EIO;  | 
|---|
 | 149 | +  | 
|---|
 | 150 | +	ret = adfs_dir_read_buffers(sb, indaddr, ADFS_NEWDIR_SIZE, dir);  | 
|---|
 | 151 | +	if (ret)  | 
|---|
 | 152 | +		return ret;  | 
|---|
 | 153 | +  | 
|---|
 | 154 | +	dir->dirhead = bufoff(dir->bh, 0);  | 
|---|
 | 155 | +	dir->newtail = bufoff(dir->bh, 2007);  | 
|---|
 | 156 | +  | 
|---|
 | 157 | +	if (adfs_f_validate(dir))  | 
|---|
| 154 | 158 |  		goto bad_dir; | 
|---|
| 155 | 159 |   | 
|---|
| 156 |  | -	size >>= blocksize_bits;  | 
|---|
| 157 |  | -  | 
|---|
| 158 |  | -	dir->nr_buffers = 0;  | 
|---|
| 159 |  | -	dir->sb = sb;  | 
|---|
| 160 |  | -  | 
|---|
| 161 |  | -	for (blk = 0; blk < size; blk++) {  | 
|---|
| 162 |  | -		int phys;  | 
|---|
| 163 |  | -  | 
|---|
| 164 |  | -		phys = __adfs_block_map(sb, object_id, blk);  | 
|---|
| 165 |  | -		if (!phys) {  | 
|---|
| 166 |  | -			adfs_error(sb, "dir object %lX has a hole at offset %d",  | 
|---|
| 167 |  | -				   object_id, blk);  | 
|---|
| 168 |  | -			goto release_buffers;  | 
|---|
| 169 |  | -		}  | 
|---|
| 170 |  | -  | 
|---|
| 171 |  | -		dir->bh[blk] = sb_bread(sb, phys);  | 
|---|
| 172 |  | -		if (!dir->bh[blk])  | 
|---|
| 173 |  | -			goto release_buffers;  | 
|---|
| 174 |  | -	}  | 
|---|
| 175 |  | -  | 
|---|
| 176 |  | -	memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead));  | 
|---|
| 177 |  | -	memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail));  | 
|---|
| 178 |  | -  | 
|---|
| 179 |  | -	if (dir->dirhead.startmasseq != dir->dirtail.new.endmasseq ||  | 
|---|
| 180 |  | -	    memcmp(&dir->dirhead.startname, &dir->dirtail.new.endname, 4))  | 
|---|
| 181 |  | -		goto bad_dir;  | 
|---|
| 182 |  | -  | 
|---|
| 183 |  | -	if (memcmp(&dir->dirhead.startname, "Nick", 4) &&  | 
|---|
| 184 |  | -	    memcmp(&dir->dirhead.startname, "Hugo", 4))  | 
|---|
| 185 |  | -		goto bad_dir;  | 
|---|
| 186 |  | -  | 
|---|
| 187 |  | -	if (adfs_dir_checkbyte(dir) != dir->dirtail.new.dircheckbyte)  | 
|---|
| 188 |  | -		goto bad_dir;  | 
|---|
| 189 |  | -  | 
|---|
| 190 |  | -	dir->nr_buffers = blk;  | 
|---|
 | 160 | +	dir->parent_id = adfs_readval(dir->newtail->dirparent, 3);  | 
|---|
| 191 | 161 |   | 
|---|
| 192 | 162 |  	return 0; | 
|---|
| 193 | 163 |   | 
|---|
| 194 | 164 |  bad_dir: | 
|---|
| 195 |  | -	adfs_error(sb, "corrupted directory fragment %lX",  | 
|---|
| 196 |  | -		   object_id);  | 
|---|
| 197 |  | -release_buffers:  | 
|---|
| 198 |  | -	for (blk -= 1; blk >= 0; blk -= 1)  | 
|---|
| 199 |  | -		brelse(dir->bh[blk]);  | 
|---|
| 200 |  | -  | 
|---|
| 201 |  | -	dir->sb = NULL;  | 
|---|
 | 165 | +	adfs_error(sb, "dir %06x is corrupted", indaddr);  | 
|---|
 | 166 | +	adfs_dir_relse(dir);  | 
|---|
| 202 | 167 |   | 
|---|
| 203 | 168 |  	return -EIO; | 
|---|
| 204 | 169 |  } | 
|---|
| .. | .. | 
|---|
| 210 | 175 |  adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj, | 
|---|
| 211 | 176 |  	struct adfs_direntry *de) | 
|---|
| 212 | 177 |  { | 
|---|
| 213 |  | -	obj->name_len =	adfs_readname(obj->name, de->dirobname, ADFS_F_NAME_LEN);  | 
|---|
| 214 |  | -	obj->file_id  = adfs_readval(de->dirinddiscadd, 3);  | 
|---|
 | 178 | +	unsigned int name_len;  | 
|---|
 | 179 | +  | 
|---|
 | 180 | +	for (name_len = 0; name_len < ADFS_F_NAME_LEN; name_len++) {  | 
|---|
 | 181 | +		if (de->dirobname[name_len] < ' ')  | 
|---|
 | 182 | +			break;  | 
|---|
 | 183 | +  | 
|---|
 | 184 | +		obj->name[name_len] = de->dirobname[name_len];  | 
|---|
 | 185 | +	}  | 
|---|
 | 186 | +  | 
|---|
 | 187 | +	obj->name_len =	name_len;  | 
|---|
 | 188 | +	obj->indaddr  = adfs_readval(de->dirinddiscadd, 3);  | 
|---|
| 215 | 189 |  	obj->loadaddr = adfs_readval(de->dirload, 4); | 
|---|
| 216 | 190 |  	obj->execaddr = adfs_readval(de->direxec, 4); | 
|---|
| 217 | 191 |  	obj->size     = adfs_readval(de->dirlen,  4); | 
|---|
| 218 | 192 |  	obj->attr     = de->newdiratts; | 
|---|
| 219 |  | -	obj->filetype = -1;  | 
|---|
| 220 | 193 |   | 
|---|
| 221 |  | -	/*  | 
|---|
| 222 |  | -	 * object is a file and is filetyped and timestamped?  | 
|---|
| 223 |  | -	 * RISC OS 12-bit filetype is stored in load_address[19:8]  | 
|---|
| 224 |  | -	 */  | 
|---|
| 225 |  | -	if ((0 == (obj->attr & ADFS_NDA_DIRECTORY)) &&  | 
|---|
| 226 |  | -		(0xfff00000 == (0xfff00000 & obj->loadaddr))) {  | 
|---|
| 227 |  | -		obj->filetype = (__u16) ((0x000fff00 & obj->loadaddr) >> 8);  | 
|---|
| 228 |  | -  | 
|---|
| 229 |  | -		/* optionally append the ,xyz hex filetype suffix */  | 
|---|
| 230 |  | -		if (ADFS_SB(dir->sb)->s_ftsuffix)  | 
|---|
| 231 |  | -			obj->name_len +=  | 
|---|
| 232 |  | -				append_filetype_suffix(  | 
|---|
| 233 |  | -					&obj->name[obj->name_len],  | 
|---|
| 234 |  | -					obj->filetype);  | 
|---|
| 235 |  | -	}  | 
|---|
 | 194 | +	adfs_object_fixup(dir, obj);  | 
|---|
| 236 | 195 |  } | 
|---|
| 237 | 196 |   | 
|---|
| 238 | 197 |  /* | 
|---|
| .. | .. | 
|---|
| 241 | 200 |  static inline void | 
|---|
| 242 | 201 |  adfs_obj2dir(struct adfs_direntry *de, struct object_info *obj) | 
|---|
| 243 | 202 |  { | 
|---|
| 244 |  | -	adfs_writeval(de->dirinddiscadd, 3, obj->file_id);  | 
|---|
 | 203 | +	adfs_writeval(de->dirinddiscadd, 3, obj->indaddr);  | 
|---|
| 245 | 204 |  	adfs_writeval(de->dirload, 4, obj->loadaddr); | 
|---|
| 246 | 205 |  	adfs_writeval(de->direxec, 4, obj->execaddr); | 
|---|
| 247 | 206 |  	adfs_writeval(de->dirlen,  4, obj->size); | 
|---|
| .. | .. | 
|---|
| 255 | 214 |  static int | 
|---|
| 256 | 215 |  __adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj) | 
|---|
| 257 | 216 |  { | 
|---|
| 258 |  | -	struct super_block *sb = dir->sb;  | 
|---|
| 259 | 217 |  	struct adfs_direntry de; | 
|---|
| 260 |  | -	int thissize, buffer, offset;  | 
|---|
 | 218 | +	int ret;  | 
|---|
| 261 | 219 |   | 
|---|
| 262 |  | -	buffer = pos >> sb->s_blocksize_bits;  | 
|---|
| 263 |  | -  | 
|---|
| 264 |  | -	if (buffer > dir->nr_buffers)  | 
|---|
| 265 |  | -		return -EINVAL;  | 
|---|
| 266 |  | -  | 
|---|
| 267 |  | -	offset = pos & (sb->s_blocksize - 1);  | 
|---|
| 268 |  | -	thissize = sb->s_blocksize - offset;  | 
|---|
| 269 |  | -	if (thissize > 26)  | 
|---|
| 270 |  | -		thissize = 26;  | 
|---|
| 271 |  | -  | 
|---|
| 272 |  | -	memcpy(&de, dir->bh[buffer]->b_data + offset, thissize);  | 
|---|
| 273 |  | -	if (thissize != 26)  | 
|---|
| 274 |  | -		memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data,  | 
|---|
| 275 |  | -		       26 - thissize);  | 
|---|
 | 220 | +	ret = adfs_dir_copyfrom(&de, dir, pos, 26);  | 
|---|
 | 221 | +	if (ret)  | 
|---|
 | 222 | +		return ret;  | 
|---|
| 276 | 223 |   | 
|---|
| 277 | 224 |  	if (!de.dirobname[0]) | 
|---|
| 278 | 225 |  		return -ENOENT; | 
|---|
| .. | .. | 
|---|
| 280 | 227 |  	adfs_dir2obj(dir, obj, &de); | 
|---|
| 281 | 228 |   | 
|---|
| 282 | 229 |  	return 0; | 
|---|
| 283 |  | -}  | 
|---|
| 284 |  | -  | 
|---|
| 285 |  | -static int  | 
|---|
| 286 |  | -__adfs_dir_put(struct adfs_dir *dir, int pos, struct object_info *obj)  | 
|---|
| 287 |  | -{  | 
|---|
| 288 |  | -	struct super_block *sb = dir->sb;  | 
|---|
| 289 |  | -	struct adfs_direntry de;  | 
|---|
| 290 |  | -	int thissize, buffer, offset;  | 
|---|
| 291 |  | -  | 
|---|
| 292 |  | -	buffer = pos >> sb->s_blocksize_bits;  | 
|---|
| 293 |  | -  | 
|---|
| 294 |  | -	if (buffer > dir->nr_buffers)  | 
|---|
| 295 |  | -		return -EINVAL;  | 
|---|
| 296 |  | -  | 
|---|
| 297 |  | -	offset = pos & (sb->s_blocksize - 1);  | 
|---|
| 298 |  | -	thissize = sb->s_blocksize - offset;  | 
|---|
| 299 |  | -	if (thissize > 26)  | 
|---|
| 300 |  | -		thissize = 26;  | 
|---|
| 301 |  | -  | 
|---|
| 302 |  | -	/*  | 
|---|
| 303 |  | -	 * Get the entry in total  | 
|---|
| 304 |  | -	 */  | 
|---|
| 305 |  | -	memcpy(&de, dir->bh[buffer]->b_data + offset, thissize);  | 
|---|
| 306 |  | -	if (thissize != 26)  | 
|---|
| 307 |  | -		memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data,  | 
|---|
| 308 |  | -		       26 - thissize);  | 
|---|
| 309 |  | -  | 
|---|
| 310 |  | -	/*  | 
|---|
| 311 |  | -	 * update it  | 
|---|
| 312 |  | -	 */  | 
|---|
| 313 |  | -	adfs_obj2dir(&de, obj);  | 
|---|
| 314 |  | -  | 
|---|
| 315 |  | -	/*  | 
|---|
| 316 |  | -	 * Put the new entry back  | 
|---|
| 317 |  | -	 */  | 
|---|
| 318 |  | -	memcpy(dir->bh[buffer]->b_data + offset, &de, thissize);  | 
|---|
| 319 |  | -	if (thissize != 26)  | 
|---|
| 320 |  | -		memcpy(dir->bh[buffer + 1]->b_data, ((char *)&de) + thissize,  | 
|---|
| 321 |  | -		       26 - thissize);  | 
|---|
| 322 |  | -  | 
|---|
| 323 |  | -	return 0;  | 
|---|
| 324 |  | -}  | 
|---|
| 325 |  | -  | 
|---|
| 326 |  | -/*  | 
|---|
| 327 |  | - * the caller is responsible for holding the necessary  | 
|---|
| 328 |  | - * locks.  | 
|---|
| 329 |  | - */  | 
|---|
| 330 |  | -static int  | 
|---|
| 331 |  | -adfs_dir_find_entry(struct adfs_dir *dir, unsigned long object_id)  | 
|---|
| 332 |  | -{  | 
|---|
| 333 |  | -	int pos, ret;  | 
|---|
| 334 |  | -  | 
|---|
| 335 |  | -	ret = -ENOENT;  | 
|---|
| 336 |  | -  | 
|---|
| 337 |  | -	for (pos = 5; pos < ADFS_NUM_DIR_ENTRIES * 26 + 5; pos += 26) {  | 
|---|
| 338 |  | -		struct object_info obj;  | 
|---|
| 339 |  | -  | 
|---|
| 340 |  | -		if (!__adfs_dir_get(dir, pos, &obj))  | 
|---|
| 341 |  | -			break;  | 
|---|
| 342 |  | -  | 
|---|
| 343 |  | -		if (obj.file_id == object_id) {  | 
|---|
| 344 |  | -			ret = pos;  | 
|---|
| 345 |  | -			break;  | 
|---|
| 346 |  | -		}  | 
|---|
| 347 |  | -	}  | 
|---|
| 348 |  | -  | 
|---|
| 349 |  | -	return ret;  | 
|---|
| 350 |  | -}  | 
|---|
| 351 |  | -  | 
|---|
| 352 |  | -static int  | 
|---|
| 353 |  | -adfs_f_read(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir)  | 
|---|
| 354 |  | -{  | 
|---|
| 355 |  | -	int ret;  | 
|---|
| 356 |  | -  | 
|---|
| 357 |  | -	if (sz != ADFS_NEWDIR_SIZE)  | 
|---|
| 358 |  | -		return -EIO;  | 
|---|
| 359 |  | -  | 
|---|
| 360 |  | -	ret = adfs_dir_read(sb, id, sz, dir);  | 
|---|
| 361 |  | -	if (ret)  | 
|---|
| 362 |  | -		adfs_error(sb, "unable to read directory");  | 
|---|
| 363 |  | -	else  | 
|---|
| 364 |  | -		dir->parent_id = adfs_readval(dir->dirtail.new.dirparent, 3);  | 
|---|
| 365 |  | -  | 
|---|
| 366 |  | -	return ret;  | 
|---|
| 367 | 230 |  } | 
|---|
| 368 | 231 |   | 
|---|
| 369 | 232 |  static int | 
|---|
| .. | .. | 
|---|
| 388 | 251 |  	return ret; | 
|---|
| 389 | 252 |  } | 
|---|
| 390 | 253 |   | 
|---|
| 391 |  | -static int  | 
|---|
| 392 |  | -adfs_f_update(struct adfs_dir *dir, struct object_info *obj)  | 
|---|
 | 254 | +static int adfs_f_iterate(struct adfs_dir *dir, struct dir_context *ctx)  | 
|---|
| 393 | 255 |  { | 
|---|
| 394 |  | -	struct super_block *sb = dir->sb;  | 
|---|
| 395 |  | -	int ret, i;  | 
|---|
 | 256 | +	struct object_info obj;  | 
|---|
 | 257 | +	int pos = 5 + (ctx->pos - 2) * 26;  | 
|---|
| 396 | 258 |   | 
|---|
| 397 |  | -	ret = adfs_dir_find_entry(dir, obj->file_id);  | 
|---|
| 398 |  | -	if (ret < 0) {  | 
|---|
| 399 |  | -		adfs_error(dir->sb, "unable to locate entry to update");  | 
|---|
| 400 |  | -		goto out;  | 
|---|
 | 259 | +	while (ctx->pos < 2 + ADFS_NUM_DIR_ENTRIES) {  | 
|---|
 | 260 | +		if (__adfs_dir_get(dir, pos, &obj))  | 
|---|
 | 261 | +			break;  | 
|---|
 | 262 | +		if (!dir_emit(ctx, obj.name, obj.name_len,  | 
|---|
 | 263 | +			      obj.indaddr, DT_UNKNOWN))  | 
|---|
 | 264 | +			break;  | 
|---|
 | 265 | +		pos += 26;  | 
|---|
 | 266 | +		ctx->pos++;  | 
|---|
| 401 | 267 |  	} | 
|---|
 | 268 | +	return 0;  | 
|---|
 | 269 | +}  | 
|---|
| 402 | 270 |   | 
|---|
| 403 |  | -	__adfs_dir_put(dir, ret, obj);  | 
|---|
| 404 |  | -   | 
|---|
| 405 |  | -	/*  | 
|---|
| 406 |  | -	 * Increment directory sequence number  | 
|---|
| 407 |  | -	 */  | 
|---|
| 408 |  | -	dir->bh[0]->b_data[0] += 1;  | 
|---|
| 409 |  | -	dir->bh[dir->nr_buffers - 1]->b_data[sb->s_blocksize - 6] += 1;  | 
|---|
 | 271 | +static int adfs_f_update(struct adfs_dir *dir, struct object_info *obj)  | 
|---|
 | 272 | +{  | 
|---|
 | 273 | +	struct adfs_direntry de;  | 
|---|
 | 274 | +	int offset, ret;  | 
|---|
| 410 | 275 |   | 
|---|
| 411 |  | -	ret = adfs_dir_checkbyte(dir);  | 
|---|
| 412 |  | -	/*  | 
|---|
| 413 |  | -	 * Update directory check byte  | 
|---|
| 414 |  | -	 */  | 
|---|
| 415 |  | -	dir->bh[dir->nr_buffers - 1]->b_data[sb->s_blocksize - 1] = ret;  | 
|---|
 | 276 | +	offset = 5 - (int)sizeof(de);  | 
|---|
| 416 | 277 |   | 
|---|
| 417 |  | -#if 1  | 
|---|
| 418 |  | -	{  | 
|---|
| 419 |  | -	const unsigned int blocksize_bits = sb->s_blocksize_bits;  | 
|---|
 | 278 | +	do {  | 
|---|
 | 279 | +		offset += sizeof(de);  | 
|---|
 | 280 | +		ret = adfs_dir_copyfrom(&de, dir, offset, sizeof(de));  | 
|---|
 | 281 | +		if (ret) {  | 
|---|
 | 282 | +			adfs_error(dir->sb, "error reading directory entry");  | 
|---|
 | 283 | +			return -ENOENT;  | 
|---|
 | 284 | +		}  | 
|---|
 | 285 | +		if (!de.dirobname[0]) {  | 
|---|
 | 286 | +			adfs_error(dir->sb, "unable to locate entry to update");  | 
|---|
 | 287 | +			return -ENOENT;  | 
|---|
 | 288 | +		}  | 
|---|
 | 289 | +	} while (adfs_readval(de.dirinddiscadd, 3) != obj->indaddr);  | 
|---|
| 420 | 290 |   | 
|---|
| 421 |  | -	memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead));  | 
|---|
| 422 |  | -	memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail));  | 
|---|
 | 291 | +	/* Update the directory entry with the new object state */  | 
|---|
 | 292 | +	adfs_obj2dir(&de, obj);  | 
|---|
| 423 | 293 |   | 
|---|
| 424 |  | -	if (dir->dirhead.startmasseq != dir->dirtail.new.endmasseq ||  | 
|---|
| 425 |  | -	    memcmp(&dir->dirhead.startname, &dir->dirtail.new.endname, 4))  | 
|---|
| 426 |  | -		goto bad_dir;  | 
|---|
 | 294 | +	/* Write the directory entry back to the directory */  | 
|---|
 | 295 | +	return adfs_dir_copyto(dir, offset, &de, 26);  | 
|---|
 | 296 | +}  | 
|---|
| 427 | 297 |   | 
|---|
| 428 |  | -	if (memcmp(&dir->dirhead.startname, "Nick", 4) &&  | 
|---|
| 429 |  | -	    memcmp(&dir->dirhead.startname, "Hugo", 4))  | 
|---|
| 430 |  | -		goto bad_dir;  | 
|---|
 | 298 | +static int adfs_f_commit(struct adfs_dir *dir)  | 
|---|
 | 299 | +{  | 
|---|
 | 300 | +	int ret;  | 
|---|
| 431 | 301 |   | 
|---|
| 432 |  | -	if (adfs_dir_checkbyte(dir) != dir->dirtail.new.dircheckbyte)  | 
|---|
| 433 |  | -		goto bad_dir;  | 
|---|
| 434 |  | -	}  | 
|---|
| 435 |  | -#endif  | 
|---|
| 436 |  | -	for (i = dir->nr_buffers - 1; i >= 0; i--)  | 
|---|
| 437 |  | -		mark_buffer_dirty(dir->bh[i]);  | 
|---|
 | 302 | +	/* Increment directory sequence number */  | 
|---|
 | 303 | +	dir->dirhead->startmasseq += 1;  | 
|---|
 | 304 | +	dir->newtail->endmasseq += 1;  | 
|---|
| 438 | 305 |   | 
|---|
| 439 |  | -	ret = 0;  | 
|---|
| 440 |  | -out:  | 
|---|
 | 306 | +	/* Update directory check byte */  | 
|---|
 | 307 | +	dir->newtail->dircheckbyte = adfs_dir_checkbyte(dir);  | 
|---|
 | 308 | +  | 
|---|
 | 309 | +	/* Make sure the directory still validates correctly */  | 
|---|
 | 310 | +	ret = adfs_f_validate(dir);  | 
|---|
 | 311 | +	if (ret)  | 
|---|
 | 312 | +		adfs_msg(dir->sb, KERN_ERR, "error: update broke directory");  | 
|---|
 | 313 | +  | 
|---|
| 441 | 314 |  	return ret; | 
|---|
| 442 |  | -#if 1  | 
|---|
| 443 |  | -bad_dir:  | 
|---|
| 444 |  | -	adfs_error(dir->sb, "whoops!  I broke a directory!");  | 
|---|
| 445 |  | -	return -EIO;  | 
|---|
| 446 |  | -#endif  | 
|---|
| 447 |  | -}  | 
|---|
| 448 |  | -  | 
|---|
| 449 |  | -static int  | 
|---|
| 450 |  | -adfs_f_sync(struct adfs_dir *dir)  | 
|---|
| 451 |  | -{  | 
|---|
| 452 |  | -	int err = 0;  | 
|---|
| 453 |  | -	int i;  | 
|---|
| 454 |  | -  | 
|---|
| 455 |  | -	for (i = dir->nr_buffers - 1; i >= 0; i--) {  | 
|---|
| 456 |  | -		struct buffer_head *bh = dir->bh[i];  | 
|---|
| 457 |  | -		sync_dirty_buffer(bh);  | 
|---|
| 458 |  | -		if (buffer_req(bh) && !buffer_uptodate(bh))  | 
|---|
| 459 |  | -			err = -EIO;  | 
|---|
| 460 |  | -	}  | 
|---|
| 461 |  | -  | 
|---|
| 462 |  | -	return err;  | 
|---|
| 463 |  | -}  | 
|---|
| 464 |  | -  | 
|---|
| 465 |  | -static void  | 
|---|
| 466 |  | -adfs_f_free(struct adfs_dir *dir)  | 
|---|
| 467 |  | -{  | 
|---|
| 468 |  | -	int i;  | 
|---|
| 469 |  | -  | 
|---|
| 470 |  | -	for (i = dir->nr_buffers - 1; i >= 0; i--) {  | 
|---|
| 471 |  | -		brelse(dir->bh[i]);  | 
|---|
| 472 |  | -		dir->bh[i] = NULL;  | 
|---|
| 473 |  | -	}  | 
|---|
| 474 |  | -  | 
|---|
| 475 |  | -	dir->nr_buffers = 0;  | 
|---|
| 476 |  | -	dir->sb = NULL;  | 
|---|
| 477 | 315 |  } | 
|---|
| 478 | 316 |   | 
|---|
| 479 | 317 |  const struct adfs_dir_ops adfs_f_dir_ops = { | 
|---|
| 480 | 318 |  	.read		= adfs_f_read, | 
|---|
 | 319 | +	.iterate	= adfs_f_iterate,  | 
|---|
| 481 | 320 |  	.setpos		= adfs_f_setpos, | 
|---|
| 482 | 321 |  	.getnext	= adfs_f_getnext, | 
|---|
| 483 | 322 |  	.update		= adfs_f_update, | 
|---|
| 484 |  | -	.sync		= adfs_f_sync,  | 
|---|
| 485 |  | -	.free		= adfs_f_free  | 
|---|
 | 323 | +	.commit		= adfs_f_commit,  | 
|---|
| 486 | 324 |  }; | 
|---|