11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/ufs/ufs_dir.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1996 51da177e4SLinus Torvalds * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) 61da177e4SLinus Torvalds * Laboratory for Computer Science Research Computing Facility 71da177e4SLinus Torvalds * Rutgers, The State University of New Jersey 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * swab support by Francois-Rene Rideau <fare@tunes.org> 19970406 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * 4.4BSD (FreeBSD) support added on February 1st 1998 by 121da177e4SLinus Torvalds * Niels Kristian Bech Jensen <nkbj@image.dk> partially based 131da177e4SLinus Torvalds * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>. 141da177e4SLinus Torvalds */ 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds #include <linux/time.h> 171da177e4SLinus Torvalds #include <linux/fs.h> 181da177e4SLinus Torvalds #include <linux/ufs_fs.h> 191da177e4SLinus Torvalds #include <linux/smp_lock.h> 201da177e4SLinus Torvalds #include <linux/buffer_head.h> 211da177e4SLinus Torvalds #include <linux/sched.h> 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #include "swab.h" 241da177e4SLinus Torvalds #include "util.h" 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #undef UFS_DIR_DEBUG 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #ifdef UFS_DIR_DEBUG 291da177e4SLinus Torvalds #define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; 301da177e4SLinus Torvalds #else 311da177e4SLinus Torvalds #define UFSD(x) 321da177e4SLinus Torvalds #endif 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds static int 351da177e4SLinus Torvalds ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *, 361da177e4SLinus Torvalds struct buffer_head *, unsigned long); 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /* 401da177e4SLinus Torvalds * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure. 411da177e4SLinus Torvalds * 421da177e4SLinus Torvalds * len <= UFS_MAXNAMLEN and de != NULL are guaranteed by caller. 431da177e4SLinus Torvalds */ 441da177e4SLinus Torvalds static inline int ufs_match(struct super_block *sb, int len, 451da177e4SLinus Torvalds const char * const name, struct ufs_dir_entry * de) 461da177e4SLinus Torvalds { 471da177e4SLinus Torvalds if (len != ufs_get_de_namlen(sb, de)) 481da177e4SLinus Torvalds return 0; 491da177e4SLinus Torvalds if (!de->d_ino) 501da177e4SLinus Torvalds return 0; 511da177e4SLinus Torvalds return !memcmp(name, de->d_name, len); 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds /* 551da177e4SLinus Torvalds * This is blatantly stolen from ext2fs 561da177e4SLinus Torvalds */ 571da177e4SLinus Torvalds static int 581da177e4SLinus Torvalds ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) 591da177e4SLinus Torvalds { 601da177e4SLinus Torvalds struct inode *inode = filp->f_dentry->d_inode; 611da177e4SLinus Torvalds int error = 0; 621da177e4SLinus Torvalds unsigned long offset, lblk; 631da177e4SLinus Torvalds int i, stored; 641da177e4SLinus Torvalds struct buffer_head * bh; 651da177e4SLinus Torvalds struct ufs_dir_entry * de; 661da177e4SLinus Torvalds struct super_block * sb; 671da177e4SLinus Torvalds int de_reclen; 681da177e4SLinus Torvalds unsigned flags; 691da177e4SLinus Torvalds u64 blk= 0L; 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds lock_kernel(); 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds sb = inode->i_sb; 741da177e4SLinus Torvalds flags = UFS_SB(sb)->s_flags; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds UFSD(("ENTER, ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos)) 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds stored = 0; 791da177e4SLinus Torvalds bh = NULL; 801da177e4SLinus Torvalds offset = filp->f_pos & (sb->s_blocksize - 1); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds while (!error && !stored && filp->f_pos < inode->i_size) { 831da177e4SLinus Torvalds lblk = (filp->f_pos) >> sb->s_blocksize_bits; 841da177e4SLinus Torvalds blk = ufs_frag_map(inode, lblk); 851da177e4SLinus Torvalds if (!blk || !(bh = sb_bread(sb, blk))) { 861da177e4SLinus Torvalds /* XXX - error - skip to the next block */ 871da177e4SLinus Torvalds printk("ufs_readdir: " 881da177e4SLinus Torvalds "dir inode %lu has a hole at offset %lu\n", 891da177e4SLinus Torvalds inode->i_ino, (unsigned long int)filp->f_pos); 901da177e4SLinus Torvalds filp->f_pos += sb->s_blocksize - offset; 911da177e4SLinus Torvalds continue; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds revalidate: 951da177e4SLinus Torvalds /* If the dir block has changed since the last call to 961da177e4SLinus Torvalds * readdir(2), then we might be pointing to an invalid 971da177e4SLinus Torvalds * dirent right now. Scan from the start of the block 981da177e4SLinus Torvalds * to make sure. */ 991da177e4SLinus Torvalds if (filp->f_version != inode->i_version) { 1001da177e4SLinus Torvalds for (i = 0; i < sb->s_blocksize && i < offset; ) { 1011da177e4SLinus Torvalds de = (struct ufs_dir_entry *)(bh->b_data + i); 1021da177e4SLinus Torvalds /* It's too expensive to do a full 1031da177e4SLinus Torvalds * dirent test each time round this 1041da177e4SLinus Torvalds * loop, but we do have to test at 1051da177e4SLinus Torvalds * least that it is non-zero. A 1061da177e4SLinus Torvalds * failure will be detected in the 1071da177e4SLinus Torvalds * dirent test below. */ 1081da177e4SLinus Torvalds de_reclen = fs16_to_cpu(sb, de->d_reclen); 1091da177e4SLinus Torvalds if (de_reclen < 1) 1101da177e4SLinus Torvalds break; 1111da177e4SLinus Torvalds i += de_reclen; 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds offset = i; 1141da177e4SLinus Torvalds filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) 1151da177e4SLinus Torvalds | offset; 1161da177e4SLinus Torvalds filp->f_version = inode->i_version; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds while (!error && filp->f_pos < inode->i_size 1201da177e4SLinus Torvalds && offset < sb->s_blocksize) { 1211da177e4SLinus Torvalds de = (struct ufs_dir_entry *) (bh->b_data + offset); 1221da177e4SLinus Torvalds /* XXX - put in a real ufs_check_dir_entry() */ 1231da177e4SLinus Torvalds if ((de->d_reclen == 0) || (ufs_get_de_namlen(sb, de) == 0)) { 1241da177e4SLinus Torvalds filp->f_pos = (filp->f_pos & 1251da177e4SLinus Torvalds (sb->s_blocksize - 1)) + 1261da177e4SLinus Torvalds sb->s_blocksize; 1271da177e4SLinus Torvalds brelse(bh); 1281da177e4SLinus Torvalds unlock_kernel(); 1291da177e4SLinus Torvalds return stored; 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds if (!ufs_check_dir_entry ("ufs_readdir", inode, de, 1321da177e4SLinus Torvalds bh, offset)) { 1331da177e4SLinus Torvalds /* On error, skip the f_pos to the 1341da177e4SLinus Torvalds next block. */ 1351da177e4SLinus Torvalds filp->f_pos = (filp->f_pos | 1361da177e4SLinus Torvalds (sb->s_blocksize - 1)) + 1371da177e4SLinus Torvalds 1; 1381da177e4SLinus Torvalds brelse (bh); 1391da177e4SLinus Torvalds unlock_kernel(); 1401da177e4SLinus Torvalds return stored; 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds offset += fs16_to_cpu(sb, de->d_reclen); 1431da177e4SLinus Torvalds if (de->d_ino) { 1441da177e4SLinus Torvalds /* We might block in the next section 1451da177e4SLinus Torvalds * if the data destination is 1461da177e4SLinus Torvalds * currently swapped out. So, use a 1471da177e4SLinus Torvalds * version stamp to detect whether or 1481da177e4SLinus Torvalds * not the directory has been modified 1491da177e4SLinus Torvalds * during the copy operation. */ 1501da177e4SLinus Torvalds unsigned long version = filp->f_version; 1511da177e4SLinus Torvalds unsigned char d_type = DT_UNKNOWN; 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds UFSD(("filldir(%s,%u)\n", de->d_name, 1541da177e4SLinus Torvalds fs32_to_cpu(sb, de->d_ino))) 1551da177e4SLinus Torvalds UFSD(("namlen %u\n", ufs_get_de_namlen(sb, de))) 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds if ((flags & UFS_DE_MASK) == UFS_DE_44BSD) 1581da177e4SLinus Torvalds d_type = de->d_u.d_44.d_type; 1591da177e4SLinus Torvalds error = filldir(dirent, de->d_name, 1601da177e4SLinus Torvalds ufs_get_de_namlen(sb, de), filp->f_pos, 1611da177e4SLinus Torvalds fs32_to_cpu(sb, de->d_ino), d_type); 1621da177e4SLinus Torvalds if (error) 1631da177e4SLinus Torvalds break; 1641da177e4SLinus Torvalds if (version != filp->f_version) 1651da177e4SLinus Torvalds goto revalidate; 1661da177e4SLinus Torvalds stored ++; 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds filp->f_pos += fs16_to_cpu(sb, de->d_reclen); 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds offset = 0; 1711da177e4SLinus Torvalds brelse (bh); 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds unlock_kernel(); 1741da177e4SLinus Torvalds return 0; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds /* 1781da177e4SLinus Torvalds * define how far ahead to read directories while searching them. 1791da177e4SLinus Torvalds */ 1801da177e4SLinus Torvalds #define NAMEI_RA_CHUNKS 2 1811da177e4SLinus Torvalds #define NAMEI_RA_BLOCKS 4 1821da177e4SLinus Torvalds #define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) 1831da177e4SLinus Torvalds #define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds /* 1861da177e4SLinus Torvalds * ufs_find_entry() 1871da177e4SLinus Torvalds * 1881da177e4SLinus Torvalds * finds an entry in the specified directory with the wanted name. It 1891da177e4SLinus Torvalds * returns the cache buffer in which the entry was found, and the entry 1901da177e4SLinus Torvalds * itself (as a parameter - res_bh). It does NOT read the inode of the 1911da177e4SLinus Torvalds * entry - you'll have to do that yourself if you want to. 1921da177e4SLinus Torvalds */ 1931da177e4SLinus Torvalds struct ufs_dir_entry * ufs_find_entry (struct dentry *dentry, 1941da177e4SLinus Torvalds struct buffer_head ** res_bh) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds struct super_block * sb; 1971da177e4SLinus Torvalds struct buffer_head * bh_use[NAMEI_RA_SIZE]; 1981da177e4SLinus Torvalds struct buffer_head * bh_read[NAMEI_RA_SIZE]; 1991da177e4SLinus Torvalds unsigned long offset; 2001da177e4SLinus Torvalds int block, toread, i, err; 2011da177e4SLinus Torvalds struct inode *dir = dentry->d_parent->d_inode; 2021da177e4SLinus Torvalds const char *name = dentry->d_name.name; 2031da177e4SLinus Torvalds int namelen = dentry->d_name.len; 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen)) 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds *res_bh = NULL; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds sb = dir->i_sb; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds if (namelen > UFS_MAXNAMLEN) 2121da177e4SLinus Torvalds return NULL; 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds memset (bh_use, 0, sizeof (bh_use)); 2151da177e4SLinus Torvalds toread = 0; 2161da177e4SLinus Torvalds for (block = 0; block < NAMEI_RA_SIZE; ++block) { 2171da177e4SLinus Torvalds struct buffer_head * bh; 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds if ((block << sb->s_blocksize_bits) >= dir->i_size) 2201da177e4SLinus Torvalds break; 2211da177e4SLinus Torvalds bh = ufs_getfrag (dir, block, 0, &err); 2221da177e4SLinus Torvalds bh_use[block] = bh; 2231da177e4SLinus Torvalds if (bh && !buffer_uptodate(bh)) 2241da177e4SLinus Torvalds bh_read[toread++] = bh; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds for (block = 0, offset = 0; offset < dir->i_size; block++) { 2281da177e4SLinus Torvalds struct buffer_head * bh; 2291da177e4SLinus Torvalds struct ufs_dir_entry * de; 2301da177e4SLinus Torvalds char * dlimit; 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds if ((block % NAMEI_RA_BLOCKS) == 0 && toread) { 2331da177e4SLinus Torvalds ll_rw_block (READ, toread, bh_read); 2341da177e4SLinus Torvalds toread = 0; 2351da177e4SLinus Torvalds } 2361da177e4SLinus Torvalds bh = bh_use[block % NAMEI_RA_SIZE]; 2371da177e4SLinus Torvalds if (!bh) { 2381da177e4SLinus Torvalds ufs_error (sb, "ufs_find_entry", 2391da177e4SLinus Torvalds "directory #%lu contains a hole at offset %lu", 2401da177e4SLinus Torvalds dir->i_ino, offset); 2411da177e4SLinus Torvalds offset += sb->s_blocksize; 2421da177e4SLinus Torvalds continue; 2431da177e4SLinus Torvalds } 2441da177e4SLinus Torvalds wait_on_buffer (bh); 2451da177e4SLinus Torvalds if (!buffer_uptodate(bh)) { 2461da177e4SLinus Torvalds /* 2471da177e4SLinus Torvalds * read error: all bets are off 2481da177e4SLinus Torvalds */ 2491da177e4SLinus Torvalds break; 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 2531da177e4SLinus Torvalds dlimit = bh->b_data + sb->s_blocksize; 2541da177e4SLinus Torvalds while ((char *) de < dlimit && offset < dir->i_size) { 2551da177e4SLinus Torvalds /* this code is executed quadratically often */ 2561da177e4SLinus Torvalds /* do minimal checking by hand */ 2571da177e4SLinus Torvalds int de_len; 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds if ((char *) de + namelen <= dlimit && 2601da177e4SLinus Torvalds ufs_match(sb, namelen, name, de)) { 2611da177e4SLinus Torvalds /* found a match - 2621da177e4SLinus Torvalds just to be sure, do a full check */ 2631da177e4SLinus Torvalds if (!ufs_check_dir_entry("ufs_find_entry", 2641da177e4SLinus Torvalds dir, de, bh, offset)) 2651da177e4SLinus Torvalds goto failed; 2661da177e4SLinus Torvalds for (i = 0; i < NAMEI_RA_SIZE; ++i) { 2671da177e4SLinus Torvalds if (bh_use[i] != bh) 2681da177e4SLinus Torvalds brelse (bh_use[i]); 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds *res_bh = bh; 2711da177e4SLinus Torvalds return de; 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds /* prevent looping on a bad block */ 2741da177e4SLinus Torvalds de_len = fs16_to_cpu(sb, de->d_reclen); 2751da177e4SLinus Torvalds if (de_len <= 0) 2761da177e4SLinus Torvalds goto failed; 2771da177e4SLinus Torvalds offset += de_len; 2781da177e4SLinus Torvalds de = (struct ufs_dir_entry *) ((char *) de + de_len); 2791da177e4SLinus Torvalds } 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds brelse (bh); 2821da177e4SLinus Torvalds if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >= 2831da177e4SLinus Torvalds dir->i_size) 2841da177e4SLinus Torvalds bh = NULL; 2851da177e4SLinus Torvalds else 2861da177e4SLinus Torvalds bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err); 2871da177e4SLinus Torvalds bh_use[block % NAMEI_RA_SIZE] = bh; 2881da177e4SLinus Torvalds if (bh && !buffer_uptodate(bh)) 2891da177e4SLinus Torvalds bh_read[toread++] = bh; 2901da177e4SLinus Torvalds } 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds failed: 2931da177e4SLinus Torvalds for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]); 2941da177e4SLinus Torvalds UFSD(("EXIT\n")) 2951da177e4SLinus Torvalds return NULL; 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds static int 2991da177e4SLinus Torvalds ufs_check_dir_entry (const char *function, struct inode *dir, 3001da177e4SLinus Torvalds struct ufs_dir_entry *de, struct buffer_head *bh, 3011da177e4SLinus Torvalds unsigned long offset) 3021da177e4SLinus Torvalds { 3031da177e4SLinus Torvalds struct super_block *sb = dir->i_sb; 3041da177e4SLinus Torvalds const char *error_msg = NULL; 3051da177e4SLinus Torvalds int rlen = fs16_to_cpu(sb, de->d_reclen); 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds if (rlen < UFS_DIR_REC_LEN(1)) 3081da177e4SLinus Torvalds error_msg = "reclen is smaller than minimal"; 3091da177e4SLinus Torvalds else if (rlen % 4 != 0) 3101da177e4SLinus Torvalds error_msg = "reclen % 4 != 0"; 3111da177e4SLinus Torvalds else if (rlen < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))) 3121da177e4SLinus Torvalds error_msg = "reclen is too small for namlen"; 3131da177e4SLinus Torvalds else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize) 3141da177e4SLinus Torvalds error_msg = "directory entry across blocks"; 3151da177e4SLinus Torvalds else if (fs32_to_cpu(sb, de->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg * 3161da177e4SLinus Torvalds UFS_SB(sb)->s_uspi->s_ncg)) 3171da177e4SLinus Torvalds error_msg = "inode out of bounds"; 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds if (error_msg != NULL) 3201da177e4SLinus Torvalds ufs_error (sb, function, "bad entry in directory #%lu, size %Lu: %s - " 3211da177e4SLinus Torvalds "offset=%lu, inode=%lu, reclen=%d, namlen=%d", 3221da177e4SLinus Torvalds dir->i_ino, dir->i_size, error_msg, offset, 3231da177e4SLinus Torvalds (unsigned long)fs32_to_cpu(sb, de->d_ino), 3241da177e4SLinus Torvalds rlen, ufs_get_de_namlen(sb, de)); 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds return (error_msg == NULL ? 1 : 0); 3271da177e4SLinus Torvalds } 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct buffer_head **p) 3301da177e4SLinus Torvalds { 3311da177e4SLinus Torvalds int err; 3321da177e4SLinus Torvalds struct buffer_head *bh = ufs_bread (dir, 0, 0, &err); 3331da177e4SLinus Torvalds struct ufs_dir_entry *res = NULL; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds if (bh) { 3361da177e4SLinus Torvalds res = (struct ufs_dir_entry *) bh->b_data; 3371da177e4SLinus Torvalds res = (struct ufs_dir_entry *)((char *)res + 3381da177e4SLinus Torvalds fs16_to_cpu(dir->i_sb, res->d_reclen)); 3391da177e4SLinus Torvalds } 3401da177e4SLinus Torvalds *p = bh; 3411da177e4SLinus Torvalds return res; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds ino_t ufs_inode_by_name(struct inode * dir, struct dentry *dentry) 3441da177e4SLinus Torvalds { 3451da177e4SLinus Torvalds ino_t res = 0; 3461da177e4SLinus Torvalds struct ufs_dir_entry * de; 3471da177e4SLinus Torvalds struct buffer_head *bh; 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds de = ufs_find_entry (dentry, &bh); 3501da177e4SLinus Torvalds if (de) { 3511da177e4SLinus Torvalds res = fs32_to_cpu(dir->i_sb, de->d_ino); 3521da177e4SLinus Torvalds brelse(bh); 3531da177e4SLinus Torvalds } 3541da177e4SLinus Torvalds return res; 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, 3581da177e4SLinus Torvalds struct buffer_head *bh, struct inode *inode) 3591da177e4SLinus Torvalds { 3601da177e4SLinus Torvalds dir->i_version++; 3611da177e4SLinus Torvalds de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino); 3621da177e4SLinus Torvalds mark_buffer_dirty(bh); 3631da177e4SLinus Torvalds if (IS_DIRSYNC(dir)) 3641da177e4SLinus Torvalds sync_dirty_buffer(bh); 3651da177e4SLinus Torvalds brelse (bh); 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds /* 3691da177e4SLinus Torvalds * ufs_add_entry() 3701da177e4SLinus Torvalds * 3711da177e4SLinus Torvalds * adds a file entry to the specified directory, using the same 3721da177e4SLinus Torvalds * semantics as ufs_find_entry(). It returns NULL if it failed. 3731da177e4SLinus Torvalds */ 3741da177e4SLinus Torvalds int ufs_add_link(struct dentry *dentry, struct inode *inode) 3751da177e4SLinus Torvalds { 3761da177e4SLinus Torvalds struct super_block * sb; 3771da177e4SLinus Torvalds struct ufs_sb_private_info * uspi; 3781da177e4SLinus Torvalds unsigned long offset; 3791da177e4SLinus Torvalds unsigned fragoff; 3801da177e4SLinus Torvalds unsigned short rec_len; 3811da177e4SLinus Torvalds struct buffer_head * bh; 3821da177e4SLinus Torvalds struct ufs_dir_entry * de, * de1; 3831da177e4SLinus Torvalds struct inode *dir = dentry->d_parent->d_inode; 3841da177e4SLinus Torvalds const char *name = dentry->d_name.name; 3851da177e4SLinus Torvalds int namelen = dentry->d_name.len; 3861da177e4SLinus Torvalds int err; 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds UFSD(("ENTER, name %s, namelen %u\n", name, namelen)) 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds sb = dir->i_sb; 3911da177e4SLinus Torvalds uspi = UFS_SB(sb)->s_uspi; 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds if (!namelen) 3941da177e4SLinus Torvalds return -EINVAL; 3951da177e4SLinus Torvalds bh = ufs_bread (dir, 0, 0, &err); 3961da177e4SLinus Torvalds if (!bh) 3971da177e4SLinus Torvalds return err; 3981da177e4SLinus Torvalds rec_len = UFS_DIR_REC_LEN(namelen); 3991da177e4SLinus Torvalds offset = 0; 4001da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 4011da177e4SLinus Torvalds while (1) { 4021da177e4SLinus Torvalds if ((char *)de >= UFS_SECTOR_SIZE + bh->b_data) { 4031da177e4SLinus Torvalds fragoff = offset & ~uspi->s_fmask; 4041da177e4SLinus Torvalds if (fragoff != 0 && fragoff != UFS_SECTOR_SIZE) 4051da177e4SLinus Torvalds ufs_error (sb, "ufs_add_entry", "internal error" 4061da177e4SLinus Torvalds " fragoff %u", fragoff); 4071da177e4SLinus Torvalds if (!fragoff) { 4081da177e4SLinus Torvalds brelse (bh); 4091da177e4SLinus Torvalds bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, &err); 4101da177e4SLinus Torvalds if (!bh) 4111da177e4SLinus Torvalds return err; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds if (dir->i_size <= offset) { 4141da177e4SLinus Torvalds if (dir->i_size == 0) { 4151da177e4SLinus Torvalds brelse(bh); 4161da177e4SLinus Torvalds return -ENOENT; 4171da177e4SLinus Torvalds } 4181da177e4SLinus Torvalds de = (struct ufs_dir_entry *) (bh->b_data + fragoff); 4191da177e4SLinus Torvalds de->d_ino = 0; 4201da177e4SLinus Torvalds de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE); 4211da177e4SLinus Torvalds ufs_set_de_namlen(sb, de, 0); 4221da177e4SLinus Torvalds dir->i_size = offset + UFS_SECTOR_SIZE; 4231da177e4SLinus Torvalds mark_inode_dirty(dir); 4241da177e4SLinus Torvalds } else { 4251da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 4261da177e4SLinus Torvalds } 4271da177e4SLinus Torvalds } 4281da177e4SLinus Torvalds if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) { 4291da177e4SLinus Torvalds brelse (bh); 4301da177e4SLinus Torvalds return -ENOENT; 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds if (ufs_match(sb, namelen, name, de)) { 4331da177e4SLinus Torvalds brelse (bh); 4341da177e4SLinus Torvalds return -EEXIST; 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds if (de->d_ino == 0 && fs16_to_cpu(sb, de->d_reclen) >= rec_len) 4371da177e4SLinus Torvalds break; 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds if (fs16_to_cpu(sb, de->d_reclen) >= 4401da177e4SLinus Torvalds UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)) + rec_len) 4411da177e4SLinus Torvalds break; 4421da177e4SLinus Torvalds offset += fs16_to_cpu(sb, de->d_reclen); 4431da177e4SLinus Torvalds de = (struct ufs_dir_entry *) ((char *) de + fs16_to_cpu(sb, de->d_reclen)); 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds if (de->d_ino) { 4471da177e4SLinus Torvalds de1 = (struct ufs_dir_entry *) ((char *) de + 4481da177e4SLinus Torvalds UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))); 4491da177e4SLinus Torvalds de1->d_reclen = 4501da177e4SLinus Torvalds cpu_to_fs16(sb, fs16_to_cpu(sb, de->d_reclen) - 4511da177e4SLinus Torvalds UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))); 4521da177e4SLinus Torvalds de->d_reclen = 4531da177e4SLinus Torvalds cpu_to_fs16(sb, UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))); 4541da177e4SLinus Torvalds de = de1; 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds de->d_ino = 0; 4571da177e4SLinus Torvalds ufs_set_de_namlen(sb, de, namelen); 4581da177e4SLinus Torvalds memcpy (de->d_name, name, namelen + 1); 4591da177e4SLinus Torvalds de->d_ino = cpu_to_fs32(sb, inode->i_ino); 4601da177e4SLinus Torvalds ufs_set_de_type(sb, de, inode->i_mode); 4611da177e4SLinus Torvalds mark_buffer_dirty(bh); 4621da177e4SLinus Torvalds if (IS_DIRSYNC(dir)) 4631da177e4SLinus Torvalds sync_dirty_buffer(bh); 4641da177e4SLinus Torvalds brelse (bh); 4651da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 4661da177e4SLinus Torvalds dir->i_version++; 4671da177e4SLinus Torvalds mark_inode_dirty(dir); 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds UFSD(("EXIT\n")) 4701da177e4SLinus Torvalds return 0; 4711da177e4SLinus Torvalds } 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds /* 4741da177e4SLinus Torvalds * ufs_delete_entry deletes a directory entry by merging it with the 4751da177e4SLinus Torvalds * previous entry. 4761da177e4SLinus Torvalds */ 4771da177e4SLinus Torvalds int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir, 4781da177e4SLinus Torvalds struct buffer_head * bh ) 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds { 4811da177e4SLinus Torvalds struct super_block * sb; 4821da177e4SLinus Torvalds struct ufs_dir_entry * de, * pde; 4831da177e4SLinus Torvalds unsigned i; 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds UFSD(("ENTER\n")) 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds sb = inode->i_sb; 4881da177e4SLinus Torvalds i = 0; 4891da177e4SLinus Torvalds pde = NULL; 4901da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 4911da177e4SLinus Torvalds 4921da177e4SLinus Torvalds UFSD(("ino %u, reclen %u, namlen %u, name %s\n", 4931da177e4SLinus Torvalds fs32_to_cpu(sb, de->d_ino), 494221fc10eSEvgeniy fs16_to_cpu(sb, de->d_reclen), 4951da177e4SLinus Torvalds ufs_get_de_namlen(sb, de), de->d_name)) 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds while (i < bh->b_size) { 4981da177e4SLinus Torvalds if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i)) { 4991da177e4SLinus Torvalds brelse(bh); 5001da177e4SLinus Torvalds return -EIO; 5011da177e4SLinus Torvalds } 5021da177e4SLinus Torvalds if (de == dir) { 5031da177e4SLinus Torvalds if (pde) 5041da177e4SLinus Torvalds fs16_add(sb, &pde->d_reclen, 5051da177e4SLinus Torvalds fs16_to_cpu(sb, dir->d_reclen)); 5061da177e4SLinus Torvalds dir->d_ino = 0; 5071da177e4SLinus Torvalds inode->i_version++; 5081da177e4SLinus Torvalds inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; 5091da177e4SLinus Torvalds mark_inode_dirty(inode); 5101da177e4SLinus Torvalds mark_buffer_dirty(bh); 5111da177e4SLinus Torvalds if (IS_DIRSYNC(inode)) 5121da177e4SLinus Torvalds sync_dirty_buffer(bh); 5131da177e4SLinus Torvalds brelse(bh); 5141da177e4SLinus Torvalds UFSD(("EXIT\n")) 5151da177e4SLinus Torvalds return 0; 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds i += fs16_to_cpu(sb, de->d_reclen); 5181da177e4SLinus Torvalds if (i == UFS_SECTOR_SIZE) pde = NULL; 5191da177e4SLinus Torvalds else pde = de; 5201da177e4SLinus Torvalds de = (struct ufs_dir_entry *) 5211da177e4SLinus Torvalds ((char *) de + fs16_to_cpu(sb, de->d_reclen)); 5221da177e4SLinus Torvalds if (i == UFS_SECTOR_SIZE && de->d_reclen == 0) 5231da177e4SLinus Torvalds break; 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds UFSD(("EXIT\n")) 5261da177e4SLinus Torvalds brelse(bh); 5271da177e4SLinus Torvalds return -ENOENT; 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds int ufs_make_empty(struct inode * inode, struct inode *dir) 5311da177e4SLinus Torvalds { 5321da177e4SLinus Torvalds struct super_block * sb = dir->i_sb; 5331da177e4SLinus Torvalds struct buffer_head * dir_block; 5341da177e4SLinus Torvalds struct ufs_dir_entry * de; 5351da177e4SLinus Torvalds int err; 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds dir_block = ufs_bread (inode, 0, 1, &err); 5381da177e4SLinus Torvalds if (!dir_block) 5391da177e4SLinus Torvalds return err; 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds inode->i_blocks = sb->s_blocksize / UFS_SECTOR_SIZE; 5421da177e4SLinus Torvalds de = (struct ufs_dir_entry *) dir_block->b_data; 5431da177e4SLinus Torvalds de->d_ino = cpu_to_fs32(sb, inode->i_ino); 5441da177e4SLinus Torvalds ufs_set_de_type(sb, de, inode->i_mode); 5451da177e4SLinus Torvalds ufs_set_de_namlen(sb, de, 1); 5461da177e4SLinus Torvalds de->d_reclen = cpu_to_fs16(sb, UFS_DIR_REC_LEN(1)); 5471da177e4SLinus Torvalds strcpy (de->d_name, "."); 5481da177e4SLinus Torvalds de = (struct ufs_dir_entry *) 5491da177e4SLinus Torvalds ((char *)de + fs16_to_cpu(sb, de->d_reclen)); 5501da177e4SLinus Torvalds de->d_ino = cpu_to_fs32(sb, dir->i_ino); 5511da177e4SLinus Torvalds ufs_set_de_type(sb, de, dir->i_mode); 5521da177e4SLinus Torvalds de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1)); 5531da177e4SLinus Torvalds ufs_set_de_namlen(sb, de, 2); 5541da177e4SLinus Torvalds strcpy (de->d_name, ".."); 5551da177e4SLinus Torvalds mark_buffer_dirty(dir_block); 5561da177e4SLinus Torvalds brelse (dir_block); 5571da177e4SLinus Torvalds mark_inode_dirty(inode); 5581da177e4SLinus Torvalds return 0; 5591da177e4SLinus Torvalds } 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds /* 5621da177e4SLinus Torvalds * routine to check that the specified directory is empty (for rmdir) 5631da177e4SLinus Torvalds */ 5641da177e4SLinus Torvalds int ufs_empty_dir (struct inode * inode) 5651da177e4SLinus Torvalds { 5661da177e4SLinus Torvalds struct super_block * sb; 5671da177e4SLinus Torvalds unsigned long offset; 5681da177e4SLinus Torvalds struct buffer_head * bh; 5691da177e4SLinus Torvalds struct ufs_dir_entry * de, * de1; 5701da177e4SLinus Torvalds int err; 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds sb = inode->i_sb; 5731da177e4SLinus Torvalds 5741da177e4SLinus Torvalds if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) || 5751da177e4SLinus Torvalds !(bh = ufs_bread (inode, 0, 0, &err))) { 5761da177e4SLinus Torvalds ufs_warning (inode->i_sb, "empty_dir", 5771da177e4SLinus Torvalds "bad directory (dir #%lu) - no data block", 5781da177e4SLinus Torvalds inode->i_ino); 5791da177e4SLinus Torvalds return 1; 5801da177e4SLinus Torvalds } 5811da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 5821da177e4SLinus Torvalds de1 = (struct ufs_dir_entry *) 5831da177e4SLinus Torvalds ((char *)de + fs16_to_cpu(sb, de->d_reclen)); 5841da177e4SLinus Torvalds if (fs32_to_cpu(sb, de->d_ino) != inode->i_ino || de1->d_ino == 0 || 5851da177e4SLinus Torvalds strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) { 5861da177e4SLinus Torvalds ufs_warning (inode->i_sb, "empty_dir", 5871da177e4SLinus Torvalds "bad directory (dir #%lu) - no `.' or `..'", 5881da177e4SLinus Torvalds inode->i_ino); 5891da177e4SLinus Torvalds return 1; 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds offset = fs16_to_cpu(sb, de->d_reclen) + fs16_to_cpu(sb, de1->d_reclen); 5921da177e4SLinus Torvalds de = (struct ufs_dir_entry *) 5931da177e4SLinus Torvalds ((char *)de1 + fs16_to_cpu(sb, de1->d_reclen)); 5941da177e4SLinus Torvalds while (offset < inode->i_size ) { 5951da177e4SLinus Torvalds if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) { 5961da177e4SLinus Torvalds brelse (bh); 5971da177e4SLinus Torvalds bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err); 5981da177e4SLinus Torvalds if (!bh) { 5991da177e4SLinus Torvalds ufs_error (sb, "empty_dir", 6001da177e4SLinus Torvalds "directory #%lu contains a hole at offset %lu", 6011da177e4SLinus Torvalds inode->i_ino, offset); 6021da177e4SLinus Torvalds offset += sb->s_blocksize; 6031da177e4SLinus Torvalds continue; 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds if (!ufs_check_dir_entry ("empty_dir", inode, de, bh, offset)) { 6081da177e4SLinus Torvalds brelse (bh); 6091da177e4SLinus Torvalds return 1; 6101da177e4SLinus Torvalds } 6111da177e4SLinus Torvalds if (de->d_ino) { 6121da177e4SLinus Torvalds brelse (bh); 6131da177e4SLinus Torvalds return 0; 6141da177e4SLinus Torvalds } 6151da177e4SLinus Torvalds offset += fs16_to_cpu(sb, de->d_reclen); 6161da177e4SLinus Torvalds de = (struct ufs_dir_entry *) 6171da177e4SLinus Torvalds ((char *)de + fs16_to_cpu(sb, de->d_reclen)); 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds brelse (bh); 6201da177e4SLinus Torvalds return 1; 6211da177e4SLinus Torvalds } 6221da177e4SLinus Torvalds 623*4b6f5d20SArjan van de Ven const struct file_operations ufs_dir_operations = { 6241da177e4SLinus Torvalds .read = generic_read_dir, 6251da177e4SLinus Torvalds .readdir = ufs_readdir, 6261da177e4SLinus Torvalds .fsync = file_fsync, 6271da177e4SLinus Torvalds }; 628