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