11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/adfs/dir_f.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1997-1999 Russell King 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 81da177e4SLinus Torvalds * published by the Free Software Foundation. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * E and F format directory handling 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds #include <linux/buffer_head.h> 131da177e4SLinus Torvalds #include "adfs.h" 141da177e4SLinus Torvalds #include "dir_f.h" 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds static void adfs_f_free(struct adfs_dir *dir); 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds /* 191da177e4SLinus Torvalds * Read an (unaligned) value of length 1..4 bytes 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds static inline unsigned int adfs_readval(unsigned char *p, int len) 221da177e4SLinus Torvalds { 231da177e4SLinus Torvalds unsigned int val = 0; 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds switch (len) { 261da177e4SLinus Torvalds case 4: val |= p[3] << 24; 271da177e4SLinus Torvalds case 3: val |= p[2] << 16; 281da177e4SLinus Torvalds case 2: val |= p[1] << 8; 291da177e4SLinus Torvalds default: val |= p[0]; 301da177e4SLinus Torvalds } 311da177e4SLinus Torvalds return val; 321da177e4SLinus Torvalds } 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds static inline void adfs_writeval(unsigned char *p, int len, unsigned int val) 351da177e4SLinus Torvalds { 361da177e4SLinus Torvalds switch (len) { 371da177e4SLinus Torvalds case 4: p[3] = val >> 24; 381da177e4SLinus Torvalds case 3: p[2] = val >> 16; 391da177e4SLinus Torvalds case 2: p[1] = val >> 8; 401da177e4SLinus Torvalds default: p[0] = val; 411da177e4SLinus Torvalds } 421da177e4SLinus Torvalds } 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds static inline int adfs_readname(char *buf, char *ptr, int maxlen) 451da177e4SLinus Torvalds { 461da177e4SLinus Torvalds char *old_buf = buf; 471da177e4SLinus Torvalds 483223ea8cSJames Bursa while ((unsigned char)*ptr >= ' ' && maxlen--) { 491da177e4SLinus Torvalds if (*ptr == '/') 501da177e4SLinus Torvalds *buf++ = '.'; 511da177e4SLinus Torvalds else 521da177e4SLinus Torvalds *buf++ = *ptr; 531da177e4SLinus Torvalds ptr++; 541da177e4SLinus Torvalds } 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds return buf - old_buf; 571da177e4SLinus Torvalds } 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds #define ror13(v) ((v >> 13) | (v << 19)) 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds #define dir_u8(idx) \ 621da177e4SLinus Torvalds ({ int _buf = idx >> blocksize_bits; \ 631da177e4SLinus Torvalds int _off = idx - (_buf << blocksize_bits);\ 641da177e4SLinus Torvalds *(u8 *)(bh[_buf]->b_data + _off); \ 651da177e4SLinus Torvalds }) 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds #define dir_u32(idx) \ 681da177e4SLinus Torvalds ({ int _buf = idx >> blocksize_bits; \ 691da177e4SLinus Torvalds int _off = idx - (_buf << blocksize_bits);\ 701da177e4SLinus Torvalds *(__le32 *)(bh[_buf]->b_data + _off); \ 711da177e4SLinus Torvalds }) 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds #define bufoff(_bh,_idx) \ 741da177e4SLinus Torvalds ({ int _buf = _idx >> blocksize_bits; \ 751da177e4SLinus Torvalds int _off = _idx - (_buf << blocksize_bits);\ 761da177e4SLinus Torvalds (u8 *)(_bh[_buf]->b_data + _off); \ 771da177e4SLinus Torvalds }) 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds /* 801da177e4SLinus Torvalds * There are some algorithms that are nice in 811da177e4SLinus Torvalds * assembler, but a bitch in C... This is one 821da177e4SLinus Torvalds * of them. 831da177e4SLinus Torvalds */ 841da177e4SLinus Torvalds static u8 851da177e4SLinus Torvalds adfs_dir_checkbyte(const struct adfs_dir *dir) 861da177e4SLinus Torvalds { 871da177e4SLinus Torvalds struct buffer_head * const *bh = dir->bh; 881da177e4SLinus Torvalds const int blocksize_bits = dir->sb->s_blocksize_bits; 891da177e4SLinus Torvalds union { __le32 *ptr32; u8 *ptr8; } ptr, end; 901da177e4SLinus Torvalds u32 dircheck = 0; 911da177e4SLinus Torvalds int last = 5 - 26; 921da177e4SLinus Torvalds int i = 0; 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds /* 951da177e4SLinus Torvalds * Accumulate each word up to the last whole 961da177e4SLinus Torvalds * word of the last directory entry. This 971da177e4SLinus Torvalds * can spread across several buffer heads. 981da177e4SLinus Torvalds */ 991da177e4SLinus Torvalds do { 1001da177e4SLinus Torvalds last += 26; 1011da177e4SLinus Torvalds do { 1021da177e4SLinus Torvalds dircheck = le32_to_cpu(dir_u32(i)) ^ ror13(dircheck); 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds i += sizeof(u32); 1051da177e4SLinus Torvalds } while (i < (last & ~3)); 1061da177e4SLinus Torvalds } while (dir_u8(last) != 0); 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds /* 1091da177e4SLinus Torvalds * Accumulate the last few bytes. These 1101da177e4SLinus Torvalds * bytes will be within the same bh. 1111da177e4SLinus Torvalds */ 1121da177e4SLinus Torvalds if (i != last) { 1131da177e4SLinus Torvalds ptr.ptr8 = bufoff(bh, i); 1141da177e4SLinus Torvalds end.ptr8 = ptr.ptr8 + last - i; 1151da177e4SLinus Torvalds 116e5949050SHarvey Harrison do { 1171da177e4SLinus Torvalds dircheck = *ptr.ptr8++ ^ ror13(dircheck); 118e5949050SHarvey Harrison } while (ptr.ptr8 < end.ptr8); 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds /* 1221da177e4SLinus Torvalds * The directory tail is in the final bh 1231da177e4SLinus Torvalds * Note that contary to the RISC OS PRMs, 1241da177e4SLinus Torvalds * the first few bytes are NOT included 1251da177e4SLinus Torvalds * in the check. All bytes are in the 1261da177e4SLinus Torvalds * same bh. 1271da177e4SLinus Torvalds */ 1281da177e4SLinus Torvalds ptr.ptr8 = bufoff(bh, 2008); 1291da177e4SLinus Torvalds end.ptr8 = ptr.ptr8 + 36; 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds do { 1321da177e4SLinus Torvalds __le32 v = *ptr.ptr32++; 1331da177e4SLinus Torvalds dircheck = le32_to_cpu(v) ^ ror13(dircheck); 1341da177e4SLinus Torvalds } while (ptr.ptr32 < end.ptr32); 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds return (dircheck ^ (dircheck >> 8) ^ (dircheck >> 16) ^ (dircheck >> 24)) & 0xff; 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds /* 1401da177e4SLinus Torvalds * Read and check that a directory is valid 1411da177e4SLinus Torvalds */ 1421da177e4SLinus Torvalds static int 1431da177e4SLinus Torvalds adfs_dir_read(struct super_block *sb, unsigned long object_id, 1441da177e4SLinus Torvalds unsigned int size, struct adfs_dir *dir) 1451da177e4SLinus Torvalds { 1461da177e4SLinus Torvalds const unsigned int blocksize_bits = sb->s_blocksize_bits; 1471da177e4SLinus Torvalds int blk = 0; 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds /* 1501da177e4SLinus Torvalds * Directories which are not a multiple of 2048 bytes 1511da177e4SLinus Torvalds * are considered bad v2 [3.6] 1521da177e4SLinus Torvalds */ 1531da177e4SLinus Torvalds if (size & 2047) 1541da177e4SLinus Torvalds goto bad_dir; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds size >>= blocksize_bits; 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds dir->nr_buffers = 0; 1591da177e4SLinus Torvalds dir->sb = sb; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds for (blk = 0; blk < size; blk++) { 1621da177e4SLinus Torvalds int phys; 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds phys = __adfs_block_map(sb, object_id, blk); 1651da177e4SLinus Torvalds if (!phys) { 1661da177e4SLinus Torvalds adfs_error(sb, "dir object %lX has a hole at offset %d", 1671da177e4SLinus Torvalds object_id, blk); 1681da177e4SLinus Torvalds goto release_buffers; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds dir->bh[blk] = sb_bread(sb, phys); 1721da177e4SLinus Torvalds if (!dir->bh[blk]) 1731da177e4SLinus Torvalds goto release_buffers; 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead)); 1771da177e4SLinus Torvalds memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail)); 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds if (dir->dirhead.startmasseq != dir->dirtail.new.endmasseq || 1801da177e4SLinus Torvalds memcmp(&dir->dirhead.startname, &dir->dirtail.new.endname, 4)) 1811da177e4SLinus Torvalds goto bad_dir; 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds if (memcmp(&dir->dirhead.startname, "Nick", 4) && 1841da177e4SLinus Torvalds memcmp(&dir->dirhead.startname, "Hugo", 4)) 1851da177e4SLinus Torvalds goto bad_dir; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds if (adfs_dir_checkbyte(dir) != dir->dirtail.new.dircheckbyte) 1881da177e4SLinus Torvalds goto bad_dir; 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds dir->nr_buffers = blk; 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds return 0; 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds bad_dir: 1951da177e4SLinus Torvalds adfs_error(sb, "corrupted directory fragment %lX", 1961da177e4SLinus Torvalds object_id); 1971da177e4SLinus Torvalds release_buffers: 1981da177e4SLinus Torvalds for (blk -= 1; blk >= 0; blk -= 1) 1991da177e4SLinus Torvalds brelse(dir->bh[blk]); 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds dir->sb = NULL; 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds return -EIO; 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds /* 2071da177e4SLinus Torvalds * convert a disk-based directory entry to a Linux ADFS directory entry 2081da177e4SLinus Torvalds */ 2091da177e4SLinus Torvalds static inline void 210da23ef05SStuart Swales adfs_dir2obj(struct adfs_dir *dir, struct object_info *obj, 211da23ef05SStuart Swales struct adfs_direntry *de) 2121da177e4SLinus Torvalds { 2131da177e4SLinus Torvalds obj->name_len = adfs_readname(obj->name, de->dirobname, ADFS_F_NAME_LEN); 2141da177e4SLinus Torvalds obj->file_id = adfs_readval(de->dirinddiscadd, 3); 2151da177e4SLinus Torvalds obj->loadaddr = adfs_readval(de->dirload, 4); 2161da177e4SLinus Torvalds obj->execaddr = adfs_readval(de->direxec, 4); 2171da177e4SLinus Torvalds obj->size = adfs_readval(de->dirlen, 4); 2181da177e4SLinus Torvalds obj->attr = de->newdiratts; 219da23ef05SStuart Swales 220411c49bcSRussell King adfs_object_fixup(dir, obj); 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds /* 2241da177e4SLinus Torvalds * convert a Linux ADFS directory entry to a disk-based directory entry 2251da177e4SLinus Torvalds */ 2261da177e4SLinus Torvalds static inline void 2271da177e4SLinus Torvalds adfs_obj2dir(struct adfs_direntry *de, struct object_info *obj) 2281da177e4SLinus Torvalds { 2291da177e4SLinus Torvalds adfs_writeval(de->dirinddiscadd, 3, obj->file_id); 2301da177e4SLinus Torvalds adfs_writeval(de->dirload, 4, obj->loadaddr); 2311da177e4SLinus Torvalds adfs_writeval(de->direxec, 4, obj->execaddr); 2321da177e4SLinus Torvalds adfs_writeval(de->dirlen, 4, obj->size); 2331da177e4SLinus Torvalds de->newdiratts = obj->attr; 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds /* 2371da177e4SLinus Torvalds * get a directory entry. Note that the caller is responsible 2381da177e4SLinus Torvalds * for holding the relevant locks. 2391da177e4SLinus Torvalds */ 2401da177e4SLinus Torvalds static int 2411da177e4SLinus Torvalds __adfs_dir_get(struct adfs_dir *dir, int pos, struct object_info *obj) 2421da177e4SLinus Torvalds { 2431da177e4SLinus Torvalds struct super_block *sb = dir->sb; 2441da177e4SLinus Torvalds struct adfs_direntry de; 2451da177e4SLinus Torvalds int thissize, buffer, offset; 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds buffer = pos >> sb->s_blocksize_bits; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds if (buffer > dir->nr_buffers) 2501da177e4SLinus Torvalds return -EINVAL; 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds offset = pos & (sb->s_blocksize - 1); 2531da177e4SLinus Torvalds thissize = sb->s_blocksize - offset; 2541da177e4SLinus Torvalds if (thissize > 26) 2551da177e4SLinus Torvalds thissize = 26; 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds memcpy(&de, dir->bh[buffer]->b_data + offset, thissize); 2581da177e4SLinus Torvalds if (thissize != 26) 2591da177e4SLinus Torvalds memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data, 2601da177e4SLinus Torvalds 26 - thissize); 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds if (!de.dirobname[0]) 2631da177e4SLinus Torvalds return -ENOENT; 2641da177e4SLinus Torvalds 265da23ef05SStuart Swales adfs_dir2obj(dir, obj, &de); 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds return 0; 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds static int 2711da177e4SLinus Torvalds __adfs_dir_put(struct adfs_dir *dir, int pos, struct object_info *obj) 2721da177e4SLinus Torvalds { 2731da177e4SLinus Torvalds struct super_block *sb = dir->sb; 2741da177e4SLinus Torvalds struct adfs_direntry de; 2751da177e4SLinus Torvalds int thissize, buffer, offset; 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds buffer = pos >> sb->s_blocksize_bits; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds if (buffer > dir->nr_buffers) 2801da177e4SLinus Torvalds return -EINVAL; 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds offset = pos & (sb->s_blocksize - 1); 2831da177e4SLinus Torvalds thissize = sb->s_blocksize - offset; 2841da177e4SLinus Torvalds if (thissize > 26) 2851da177e4SLinus Torvalds thissize = 26; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds /* 2881da177e4SLinus Torvalds * Get the entry in total 2891da177e4SLinus Torvalds */ 2901da177e4SLinus Torvalds memcpy(&de, dir->bh[buffer]->b_data + offset, thissize); 2911da177e4SLinus Torvalds if (thissize != 26) 2921da177e4SLinus Torvalds memcpy(((char *)&de) + thissize, dir->bh[buffer + 1]->b_data, 2931da177e4SLinus Torvalds 26 - thissize); 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds /* 2961da177e4SLinus Torvalds * update it 2971da177e4SLinus Torvalds */ 2981da177e4SLinus Torvalds adfs_obj2dir(&de, obj); 2991da177e4SLinus Torvalds 3001da177e4SLinus Torvalds /* 3011da177e4SLinus Torvalds * Put the new entry back 3021da177e4SLinus Torvalds */ 3031da177e4SLinus Torvalds memcpy(dir->bh[buffer]->b_data + offset, &de, thissize); 3041da177e4SLinus Torvalds if (thissize != 26) 3051da177e4SLinus Torvalds memcpy(dir->bh[buffer + 1]->b_data, ((char *)&de) + thissize, 3061da177e4SLinus Torvalds 26 - thissize); 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds return 0; 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds /* 3121da177e4SLinus Torvalds * the caller is responsible for holding the necessary 3131da177e4SLinus Torvalds * locks. 3141da177e4SLinus Torvalds */ 3151da177e4SLinus Torvalds static int 3161da177e4SLinus Torvalds adfs_dir_find_entry(struct adfs_dir *dir, unsigned long object_id) 3171da177e4SLinus Torvalds { 3181da177e4SLinus Torvalds int pos, ret; 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds ret = -ENOENT; 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds for (pos = 5; pos < ADFS_NUM_DIR_ENTRIES * 26 + 5; pos += 26) { 3231da177e4SLinus Torvalds struct object_info obj; 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds if (!__adfs_dir_get(dir, pos, &obj)) 3261da177e4SLinus Torvalds break; 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds if (obj.file_id == object_id) { 3291da177e4SLinus Torvalds ret = pos; 3301da177e4SLinus Torvalds break; 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds return ret; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds static int 3381da177e4SLinus Torvalds adfs_f_read(struct super_block *sb, unsigned int id, unsigned int sz, struct adfs_dir *dir) 3391da177e4SLinus Torvalds { 3401da177e4SLinus Torvalds int ret; 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds if (sz != ADFS_NEWDIR_SIZE) 3431da177e4SLinus Torvalds return -EIO; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds ret = adfs_dir_read(sb, id, sz, dir); 3461da177e4SLinus Torvalds if (ret) 3471da177e4SLinus Torvalds adfs_error(sb, "unable to read directory"); 3481da177e4SLinus Torvalds else 3491da177e4SLinus Torvalds dir->parent_id = adfs_readval(dir->dirtail.new.dirparent, 3); 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds return ret; 3521da177e4SLinus Torvalds } 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds static int 3551da177e4SLinus Torvalds adfs_f_setpos(struct adfs_dir *dir, unsigned int fpos) 3561da177e4SLinus Torvalds { 3571da177e4SLinus Torvalds if (fpos >= ADFS_NUM_DIR_ENTRIES) 3581da177e4SLinus Torvalds return -ENOENT; 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds dir->pos = 5 + fpos * 26; 3611da177e4SLinus Torvalds return 0; 3621da177e4SLinus Torvalds } 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds static int 3651da177e4SLinus Torvalds adfs_f_getnext(struct adfs_dir *dir, struct object_info *obj) 3661da177e4SLinus Torvalds { 3671da177e4SLinus Torvalds unsigned int ret; 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds ret = __adfs_dir_get(dir, dir->pos, obj); 3701da177e4SLinus Torvalds if (ret == 0) 3711da177e4SLinus Torvalds dir->pos += 26; 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds return ret; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds static int 3771da177e4SLinus Torvalds adfs_f_update(struct adfs_dir *dir, struct object_info *obj) 3781da177e4SLinus Torvalds { 3791da177e4SLinus Torvalds struct super_block *sb = dir->sb; 3801da177e4SLinus Torvalds int ret, i; 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds ret = adfs_dir_find_entry(dir, obj->file_id); 3831da177e4SLinus Torvalds if (ret < 0) { 3841da177e4SLinus Torvalds adfs_error(dir->sb, "unable to locate entry to update"); 3851da177e4SLinus Torvalds goto out; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds __adfs_dir_put(dir, ret, obj); 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds /* 3911da177e4SLinus Torvalds * Increment directory sequence number 3921da177e4SLinus Torvalds */ 3931da177e4SLinus Torvalds dir->bh[0]->b_data[0] += 1; 3941da177e4SLinus Torvalds dir->bh[dir->nr_buffers - 1]->b_data[sb->s_blocksize - 6] += 1; 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds ret = adfs_dir_checkbyte(dir); 3971da177e4SLinus Torvalds /* 3981da177e4SLinus Torvalds * Update directory check byte 3991da177e4SLinus Torvalds */ 4001da177e4SLinus Torvalds dir->bh[dir->nr_buffers - 1]->b_data[sb->s_blocksize - 1] = ret; 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds #if 1 4031da177e4SLinus Torvalds { 4041da177e4SLinus Torvalds const unsigned int blocksize_bits = sb->s_blocksize_bits; 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds memcpy(&dir->dirhead, bufoff(dir->bh, 0), sizeof(dir->dirhead)); 4071da177e4SLinus Torvalds memcpy(&dir->dirtail, bufoff(dir->bh, 2007), sizeof(dir->dirtail)); 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds if (dir->dirhead.startmasseq != dir->dirtail.new.endmasseq || 4101da177e4SLinus Torvalds memcmp(&dir->dirhead.startname, &dir->dirtail.new.endname, 4)) 4111da177e4SLinus Torvalds goto bad_dir; 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds if (memcmp(&dir->dirhead.startname, "Nick", 4) && 4141da177e4SLinus Torvalds memcmp(&dir->dirhead.startname, "Hugo", 4)) 4151da177e4SLinus Torvalds goto bad_dir; 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds if (adfs_dir_checkbyte(dir) != dir->dirtail.new.dircheckbyte) 4181da177e4SLinus Torvalds goto bad_dir; 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds #endif 4211da177e4SLinus Torvalds for (i = dir->nr_buffers - 1; i >= 0; i--) 4221da177e4SLinus Torvalds mark_buffer_dirty(dir->bh[i]); 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds ret = 0; 4251da177e4SLinus Torvalds out: 4261da177e4SLinus Torvalds return ret; 4271da177e4SLinus Torvalds #if 1 4281da177e4SLinus Torvalds bad_dir: 4291da177e4SLinus Torvalds adfs_error(dir->sb, "whoops! I broke a directory!"); 4301da177e4SLinus Torvalds return -EIO; 4311da177e4SLinus Torvalds #endif 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds 434ffdc9064SAl Viro static int 435ffdc9064SAl Viro adfs_f_sync(struct adfs_dir *dir) 436ffdc9064SAl Viro { 437ffdc9064SAl Viro int err = 0; 438ffdc9064SAl Viro int i; 439ffdc9064SAl Viro 440ffdc9064SAl Viro for (i = dir->nr_buffers - 1; i >= 0; i--) { 441ffdc9064SAl Viro struct buffer_head *bh = dir->bh[i]; 442ffdc9064SAl Viro sync_dirty_buffer(bh); 443ffdc9064SAl Viro if (buffer_req(bh) && !buffer_uptodate(bh)) 444ffdc9064SAl Viro err = -EIO; 445ffdc9064SAl Viro } 446ffdc9064SAl Viro 447ffdc9064SAl Viro return err; 448ffdc9064SAl Viro } 449ffdc9064SAl Viro 4501da177e4SLinus Torvalds static void 4511da177e4SLinus Torvalds adfs_f_free(struct adfs_dir *dir) 4521da177e4SLinus Torvalds { 4531da177e4SLinus Torvalds int i; 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds for (i = dir->nr_buffers - 1; i >= 0; i--) { 4561da177e4SLinus Torvalds brelse(dir->bh[i]); 4571da177e4SLinus Torvalds dir->bh[i] = NULL; 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds dir->nr_buffers = 0; 4611da177e4SLinus Torvalds dir->sb = NULL; 4621da177e4SLinus Torvalds } 4631da177e4SLinus Torvalds 4640125f504SJulia Lawall const struct adfs_dir_ops adfs_f_dir_ops = { 4651da177e4SLinus Torvalds .read = adfs_f_read, 4661da177e4SLinus Torvalds .setpos = adfs_f_setpos, 4671da177e4SLinus Torvalds .getnext = adfs_f_getnext, 4681da177e4SLinus Torvalds .update = adfs_f_update, 469ffdc9064SAl Viro .sync = adfs_f_sync, 4701da177e4SLinus Torvalds .free = adfs_f_free 4711da177e4SLinus Torvalds }; 472