1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * linux/fs/ufs/ufs_dir.c 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Copyright (C) 1996 5*1da177e4SLinus Torvalds * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu) 6*1da177e4SLinus Torvalds * Laboratory for Computer Science Research Computing Facility 7*1da177e4SLinus Torvalds * Rutgers, The State University of New Jersey 8*1da177e4SLinus Torvalds * 9*1da177e4SLinus Torvalds * swab support by Francois-Rene Rideau <fare@tunes.org> 19970406 10*1da177e4SLinus Torvalds * 11*1da177e4SLinus Torvalds * 4.4BSD (FreeBSD) support added on February 1st 1998 by 12*1da177e4SLinus Torvalds * Niels Kristian Bech Jensen <nkbj@image.dk> partially based 13*1da177e4SLinus Torvalds * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>. 14*1da177e4SLinus Torvalds */ 15*1da177e4SLinus Torvalds 16*1da177e4SLinus Torvalds #include <linux/time.h> 17*1da177e4SLinus Torvalds #include <linux/fs.h> 18*1da177e4SLinus Torvalds #include <linux/ufs_fs.h> 19*1da177e4SLinus Torvalds #include <linux/smp_lock.h> 20*1da177e4SLinus Torvalds #include <linux/buffer_head.h> 21*1da177e4SLinus Torvalds #include <linux/sched.h> 22*1da177e4SLinus Torvalds 23*1da177e4SLinus Torvalds #include "swab.h" 24*1da177e4SLinus Torvalds #include "util.h" 25*1da177e4SLinus Torvalds 26*1da177e4SLinus Torvalds #undef UFS_DIR_DEBUG 27*1da177e4SLinus Torvalds 28*1da177e4SLinus Torvalds #ifdef UFS_DIR_DEBUG 29*1da177e4SLinus Torvalds #define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; 30*1da177e4SLinus Torvalds #else 31*1da177e4SLinus Torvalds #define UFSD(x) 32*1da177e4SLinus Torvalds #endif 33*1da177e4SLinus Torvalds 34*1da177e4SLinus Torvalds static int 35*1da177e4SLinus Torvalds ufs_check_dir_entry (const char *, struct inode *, struct ufs_dir_entry *, 36*1da177e4SLinus Torvalds struct buffer_head *, unsigned long); 37*1da177e4SLinus Torvalds 38*1da177e4SLinus Torvalds 39*1da177e4SLinus Torvalds /* 40*1da177e4SLinus Torvalds * NOTE! unlike strncmp, ufs_match returns 1 for success, 0 for failure. 41*1da177e4SLinus Torvalds * 42*1da177e4SLinus Torvalds * len <= UFS_MAXNAMLEN and de != NULL are guaranteed by caller. 43*1da177e4SLinus Torvalds */ 44*1da177e4SLinus Torvalds static inline int ufs_match(struct super_block *sb, int len, 45*1da177e4SLinus Torvalds const char * const name, struct ufs_dir_entry * de) 46*1da177e4SLinus Torvalds { 47*1da177e4SLinus Torvalds if (len != ufs_get_de_namlen(sb, de)) 48*1da177e4SLinus Torvalds return 0; 49*1da177e4SLinus Torvalds if (!de->d_ino) 50*1da177e4SLinus Torvalds return 0; 51*1da177e4SLinus Torvalds return !memcmp(name, de->d_name, len); 52*1da177e4SLinus Torvalds } 53*1da177e4SLinus Torvalds 54*1da177e4SLinus Torvalds /* 55*1da177e4SLinus Torvalds * This is blatantly stolen from ext2fs 56*1da177e4SLinus Torvalds */ 57*1da177e4SLinus Torvalds static int 58*1da177e4SLinus Torvalds ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) 59*1da177e4SLinus Torvalds { 60*1da177e4SLinus Torvalds struct inode *inode = filp->f_dentry->d_inode; 61*1da177e4SLinus Torvalds int error = 0; 62*1da177e4SLinus Torvalds unsigned long offset, lblk; 63*1da177e4SLinus Torvalds int i, stored; 64*1da177e4SLinus Torvalds struct buffer_head * bh; 65*1da177e4SLinus Torvalds struct ufs_dir_entry * de; 66*1da177e4SLinus Torvalds struct super_block * sb; 67*1da177e4SLinus Torvalds int de_reclen; 68*1da177e4SLinus Torvalds unsigned flags; 69*1da177e4SLinus Torvalds u64 blk= 0L; 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds lock_kernel(); 72*1da177e4SLinus Torvalds 73*1da177e4SLinus Torvalds sb = inode->i_sb; 74*1da177e4SLinus Torvalds flags = UFS_SB(sb)->s_flags; 75*1da177e4SLinus Torvalds 76*1da177e4SLinus Torvalds UFSD(("ENTER, ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos)) 77*1da177e4SLinus Torvalds 78*1da177e4SLinus Torvalds stored = 0; 79*1da177e4SLinus Torvalds bh = NULL; 80*1da177e4SLinus Torvalds offset = filp->f_pos & (sb->s_blocksize - 1); 81*1da177e4SLinus Torvalds 82*1da177e4SLinus Torvalds while (!error && !stored && filp->f_pos < inode->i_size) { 83*1da177e4SLinus Torvalds lblk = (filp->f_pos) >> sb->s_blocksize_bits; 84*1da177e4SLinus Torvalds blk = ufs_frag_map(inode, lblk); 85*1da177e4SLinus Torvalds if (!blk || !(bh = sb_bread(sb, blk))) { 86*1da177e4SLinus Torvalds /* XXX - error - skip to the next block */ 87*1da177e4SLinus Torvalds printk("ufs_readdir: " 88*1da177e4SLinus Torvalds "dir inode %lu has a hole at offset %lu\n", 89*1da177e4SLinus Torvalds inode->i_ino, (unsigned long int)filp->f_pos); 90*1da177e4SLinus Torvalds filp->f_pos += sb->s_blocksize - offset; 91*1da177e4SLinus Torvalds continue; 92*1da177e4SLinus Torvalds } 93*1da177e4SLinus Torvalds 94*1da177e4SLinus Torvalds revalidate: 95*1da177e4SLinus Torvalds /* If the dir block has changed since the last call to 96*1da177e4SLinus Torvalds * readdir(2), then we might be pointing to an invalid 97*1da177e4SLinus Torvalds * dirent right now. Scan from the start of the block 98*1da177e4SLinus Torvalds * to make sure. */ 99*1da177e4SLinus Torvalds if (filp->f_version != inode->i_version) { 100*1da177e4SLinus Torvalds for (i = 0; i < sb->s_blocksize && i < offset; ) { 101*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *)(bh->b_data + i); 102*1da177e4SLinus Torvalds /* It's too expensive to do a full 103*1da177e4SLinus Torvalds * dirent test each time round this 104*1da177e4SLinus Torvalds * loop, but we do have to test at 105*1da177e4SLinus Torvalds * least that it is non-zero. A 106*1da177e4SLinus Torvalds * failure will be detected in the 107*1da177e4SLinus Torvalds * dirent test below. */ 108*1da177e4SLinus Torvalds de_reclen = fs16_to_cpu(sb, de->d_reclen); 109*1da177e4SLinus Torvalds if (de_reclen < 1) 110*1da177e4SLinus Torvalds break; 111*1da177e4SLinus Torvalds i += de_reclen; 112*1da177e4SLinus Torvalds } 113*1da177e4SLinus Torvalds offset = i; 114*1da177e4SLinus Torvalds filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) 115*1da177e4SLinus Torvalds | offset; 116*1da177e4SLinus Torvalds filp->f_version = inode->i_version; 117*1da177e4SLinus Torvalds } 118*1da177e4SLinus Torvalds 119*1da177e4SLinus Torvalds while (!error && filp->f_pos < inode->i_size 120*1da177e4SLinus Torvalds && offset < sb->s_blocksize) { 121*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) (bh->b_data + offset); 122*1da177e4SLinus Torvalds /* XXX - put in a real ufs_check_dir_entry() */ 123*1da177e4SLinus Torvalds if ((de->d_reclen == 0) || (ufs_get_de_namlen(sb, de) == 0)) { 124*1da177e4SLinus Torvalds filp->f_pos = (filp->f_pos & 125*1da177e4SLinus Torvalds (sb->s_blocksize - 1)) + 126*1da177e4SLinus Torvalds sb->s_blocksize; 127*1da177e4SLinus Torvalds brelse(bh); 128*1da177e4SLinus Torvalds unlock_kernel(); 129*1da177e4SLinus Torvalds return stored; 130*1da177e4SLinus Torvalds } 131*1da177e4SLinus Torvalds if (!ufs_check_dir_entry ("ufs_readdir", inode, de, 132*1da177e4SLinus Torvalds bh, offset)) { 133*1da177e4SLinus Torvalds /* On error, skip the f_pos to the 134*1da177e4SLinus Torvalds next block. */ 135*1da177e4SLinus Torvalds filp->f_pos = (filp->f_pos | 136*1da177e4SLinus Torvalds (sb->s_blocksize - 1)) + 137*1da177e4SLinus Torvalds 1; 138*1da177e4SLinus Torvalds brelse (bh); 139*1da177e4SLinus Torvalds unlock_kernel(); 140*1da177e4SLinus Torvalds return stored; 141*1da177e4SLinus Torvalds } 142*1da177e4SLinus Torvalds offset += fs16_to_cpu(sb, de->d_reclen); 143*1da177e4SLinus Torvalds if (de->d_ino) { 144*1da177e4SLinus Torvalds /* We might block in the next section 145*1da177e4SLinus Torvalds * if the data destination is 146*1da177e4SLinus Torvalds * currently swapped out. So, use a 147*1da177e4SLinus Torvalds * version stamp to detect whether or 148*1da177e4SLinus Torvalds * not the directory has been modified 149*1da177e4SLinus Torvalds * during the copy operation. */ 150*1da177e4SLinus Torvalds unsigned long version = filp->f_version; 151*1da177e4SLinus Torvalds unsigned char d_type = DT_UNKNOWN; 152*1da177e4SLinus Torvalds 153*1da177e4SLinus Torvalds UFSD(("filldir(%s,%u)\n", de->d_name, 154*1da177e4SLinus Torvalds fs32_to_cpu(sb, de->d_ino))) 155*1da177e4SLinus Torvalds UFSD(("namlen %u\n", ufs_get_de_namlen(sb, de))) 156*1da177e4SLinus Torvalds 157*1da177e4SLinus Torvalds if ((flags & UFS_DE_MASK) == UFS_DE_44BSD) 158*1da177e4SLinus Torvalds d_type = de->d_u.d_44.d_type; 159*1da177e4SLinus Torvalds error = filldir(dirent, de->d_name, 160*1da177e4SLinus Torvalds ufs_get_de_namlen(sb, de), filp->f_pos, 161*1da177e4SLinus Torvalds fs32_to_cpu(sb, de->d_ino), d_type); 162*1da177e4SLinus Torvalds if (error) 163*1da177e4SLinus Torvalds break; 164*1da177e4SLinus Torvalds if (version != filp->f_version) 165*1da177e4SLinus Torvalds goto revalidate; 166*1da177e4SLinus Torvalds stored ++; 167*1da177e4SLinus Torvalds } 168*1da177e4SLinus Torvalds filp->f_pos += fs16_to_cpu(sb, de->d_reclen); 169*1da177e4SLinus Torvalds } 170*1da177e4SLinus Torvalds offset = 0; 171*1da177e4SLinus Torvalds brelse (bh); 172*1da177e4SLinus Torvalds } 173*1da177e4SLinus Torvalds unlock_kernel(); 174*1da177e4SLinus Torvalds return 0; 175*1da177e4SLinus Torvalds } 176*1da177e4SLinus Torvalds 177*1da177e4SLinus Torvalds /* 178*1da177e4SLinus Torvalds * define how far ahead to read directories while searching them. 179*1da177e4SLinus Torvalds */ 180*1da177e4SLinus Torvalds #define NAMEI_RA_CHUNKS 2 181*1da177e4SLinus Torvalds #define NAMEI_RA_BLOCKS 4 182*1da177e4SLinus Torvalds #define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) 183*1da177e4SLinus Torvalds #define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) 184*1da177e4SLinus Torvalds 185*1da177e4SLinus Torvalds /* 186*1da177e4SLinus Torvalds * ufs_find_entry() 187*1da177e4SLinus Torvalds * 188*1da177e4SLinus Torvalds * finds an entry in the specified directory with the wanted name. It 189*1da177e4SLinus Torvalds * returns the cache buffer in which the entry was found, and the entry 190*1da177e4SLinus Torvalds * itself (as a parameter - res_bh). It does NOT read the inode of the 191*1da177e4SLinus Torvalds * entry - you'll have to do that yourself if you want to. 192*1da177e4SLinus Torvalds */ 193*1da177e4SLinus Torvalds struct ufs_dir_entry * ufs_find_entry (struct dentry *dentry, 194*1da177e4SLinus Torvalds struct buffer_head ** res_bh) 195*1da177e4SLinus Torvalds { 196*1da177e4SLinus Torvalds struct super_block * sb; 197*1da177e4SLinus Torvalds struct buffer_head * bh_use[NAMEI_RA_SIZE]; 198*1da177e4SLinus Torvalds struct buffer_head * bh_read[NAMEI_RA_SIZE]; 199*1da177e4SLinus Torvalds unsigned long offset; 200*1da177e4SLinus Torvalds int block, toread, i, err; 201*1da177e4SLinus Torvalds struct inode *dir = dentry->d_parent->d_inode; 202*1da177e4SLinus Torvalds const char *name = dentry->d_name.name; 203*1da177e4SLinus Torvalds int namelen = dentry->d_name.len; 204*1da177e4SLinus Torvalds 205*1da177e4SLinus Torvalds UFSD(("ENTER, dir_ino %lu, name %s, namlen %u\n", dir->i_ino, name, namelen)) 206*1da177e4SLinus Torvalds 207*1da177e4SLinus Torvalds *res_bh = NULL; 208*1da177e4SLinus Torvalds 209*1da177e4SLinus Torvalds sb = dir->i_sb; 210*1da177e4SLinus Torvalds 211*1da177e4SLinus Torvalds if (namelen > UFS_MAXNAMLEN) 212*1da177e4SLinus Torvalds return NULL; 213*1da177e4SLinus Torvalds 214*1da177e4SLinus Torvalds memset (bh_use, 0, sizeof (bh_use)); 215*1da177e4SLinus Torvalds toread = 0; 216*1da177e4SLinus Torvalds for (block = 0; block < NAMEI_RA_SIZE; ++block) { 217*1da177e4SLinus Torvalds struct buffer_head * bh; 218*1da177e4SLinus Torvalds 219*1da177e4SLinus Torvalds if ((block << sb->s_blocksize_bits) >= dir->i_size) 220*1da177e4SLinus Torvalds break; 221*1da177e4SLinus Torvalds bh = ufs_getfrag (dir, block, 0, &err); 222*1da177e4SLinus Torvalds bh_use[block] = bh; 223*1da177e4SLinus Torvalds if (bh && !buffer_uptodate(bh)) 224*1da177e4SLinus Torvalds bh_read[toread++] = bh; 225*1da177e4SLinus Torvalds } 226*1da177e4SLinus Torvalds 227*1da177e4SLinus Torvalds for (block = 0, offset = 0; offset < dir->i_size; block++) { 228*1da177e4SLinus Torvalds struct buffer_head * bh; 229*1da177e4SLinus Torvalds struct ufs_dir_entry * de; 230*1da177e4SLinus Torvalds char * dlimit; 231*1da177e4SLinus Torvalds 232*1da177e4SLinus Torvalds if ((block % NAMEI_RA_BLOCKS) == 0 && toread) { 233*1da177e4SLinus Torvalds ll_rw_block (READ, toread, bh_read); 234*1da177e4SLinus Torvalds toread = 0; 235*1da177e4SLinus Torvalds } 236*1da177e4SLinus Torvalds bh = bh_use[block % NAMEI_RA_SIZE]; 237*1da177e4SLinus Torvalds if (!bh) { 238*1da177e4SLinus Torvalds ufs_error (sb, "ufs_find_entry", 239*1da177e4SLinus Torvalds "directory #%lu contains a hole at offset %lu", 240*1da177e4SLinus Torvalds dir->i_ino, offset); 241*1da177e4SLinus Torvalds offset += sb->s_blocksize; 242*1da177e4SLinus Torvalds continue; 243*1da177e4SLinus Torvalds } 244*1da177e4SLinus Torvalds wait_on_buffer (bh); 245*1da177e4SLinus Torvalds if (!buffer_uptodate(bh)) { 246*1da177e4SLinus Torvalds /* 247*1da177e4SLinus Torvalds * read error: all bets are off 248*1da177e4SLinus Torvalds */ 249*1da177e4SLinus Torvalds break; 250*1da177e4SLinus Torvalds } 251*1da177e4SLinus Torvalds 252*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 253*1da177e4SLinus Torvalds dlimit = bh->b_data + sb->s_blocksize; 254*1da177e4SLinus Torvalds while ((char *) de < dlimit && offset < dir->i_size) { 255*1da177e4SLinus Torvalds /* this code is executed quadratically often */ 256*1da177e4SLinus Torvalds /* do minimal checking by hand */ 257*1da177e4SLinus Torvalds int de_len; 258*1da177e4SLinus Torvalds 259*1da177e4SLinus Torvalds if ((char *) de + namelen <= dlimit && 260*1da177e4SLinus Torvalds ufs_match(sb, namelen, name, de)) { 261*1da177e4SLinus Torvalds /* found a match - 262*1da177e4SLinus Torvalds just to be sure, do a full check */ 263*1da177e4SLinus Torvalds if (!ufs_check_dir_entry("ufs_find_entry", 264*1da177e4SLinus Torvalds dir, de, bh, offset)) 265*1da177e4SLinus Torvalds goto failed; 266*1da177e4SLinus Torvalds for (i = 0; i < NAMEI_RA_SIZE; ++i) { 267*1da177e4SLinus Torvalds if (bh_use[i] != bh) 268*1da177e4SLinus Torvalds brelse (bh_use[i]); 269*1da177e4SLinus Torvalds } 270*1da177e4SLinus Torvalds *res_bh = bh; 271*1da177e4SLinus Torvalds return de; 272*1da177e4SLinus Torvalds } 273*1da177e4SLinus Torvalds /* prevent looping on a bad block */ 274*1da177e4SLinus Torvalds de_len = fs16_to_cpu(sb, de->d_reclen); 275*1da177e4SLinus Torvalds if (de_len <= 0) 276*1da177e4SLinus Torvalds goto failed; 277*1da177e4SLinus Torvalds offset += de_len; 278*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) ((char *) de + de_len); 279*1da177e4SLinus Torvalds } 280*1da177e4SLinus Torvalds 281*1da177e4SLinus Torvalds brelse (bh); 282*1da177e4SLinus Torvalds if (((block + NAMEI_RA_SIZE) << sb->s_blocksize_bits ) >= 283*1da177e4SLinus Torvalds dir->i_size) 284*1da177e4SLinus Torvalds bh = NULL; 285*1da177e4SLinus Torvalds else 286*1da177e4SLinus Torvalds bh = ufs_getfrag (dir, block + NAMEI_RA_SIZE, 0, &err); 287*1da177e4SLinus Torvalds bh_use[block % NAMEI_RA_SIZE] = bh; 288*1da177e4SLinus Torvalds if (bh && !buffer_uptodate(bh)) 289*1da177e4SLinus Torvalds bh_read[toread++] = bh; 290*1da177e4SLinus Torvalds } 291*1da177e4SLinus Torvalds 292*1da177e4SLinus Torvalds failed: 293*1da177e4SLinus Torvalds for (i = 0; i < NAMEI_RA_SIZE; ++i) brelse (bh_use[i]); 294*1da177e4SLinus Torvalds UFSD(("EXIT\n")) 295*1da177e4SLinus Torvalds return NULL; 296*1da177e4SLinus Torvalds } 297*1da177e4SLinus Torvalds 298*1da177e4SLinus Torvalds static int 299*1da177e4SLinus Torvalds ufs_check_dir_entry (const char *function, struct inode *dir, 300*1da177e4SLinus Torvalds struct ufs_dir_entry *de, struct buffer_head *bh, 301*1da177e4SLinus Torvalds unsigned long offset) 302*1da177e4SLinus Torvalds { 303*1da177e4SLinus Torvalds struct super_block *sb = dir->i_sb; 304*1da177e4SLinus Torvalds const char *error_msg = NULL; 305*1da177e4SLinus Torvalds int rlen = fs16_to_cpu(sb, de->d_reclen); 306*1da177e4SLinus Torvalds 307*1da177e4SLinus Torvalds if (rlen < UFS_DIR_REC_LEN(1)) 308*1da177e4SLinus Torvalds error_msg = "reclen is smaller than minimal"; 309*1da177e4SLinus Torvalds else if (rlen % 4 != 0) 310*1da177e4SLinus Torvalds error_msg = "reclen % 4 != 0"; 311*1da177e4SLinus Torvalds else if (rlen < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))) 312*1da177e4SLinus Torvalds error_msg = "reclen is too small for namlen"; 313*1da177e4SLinus Torvalds else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize) 314*1da177e4SLinus Torvalds error_msg = "directory entry across blocks"; 315*1da177e4SLinus Torvalds else if (fs32_to_cpu(sb, de->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg * 316*1da177e4SLinus Torvalds UFS_SB(sb)->s_uspi->s_ncg)) 317*1da177e4SLinus Torvalds error_msg = "inode out of bounds"; 318*1da177e4SLinus Torvalds 319*1da177e4SLinus Torvalds if (error_msg != NULL) 320*1da177e4SLinus Torvalds ufs_error (sb, function, "bad entry in directory #%lu, size %Lu: %s - " 321*1da177e4SLinus Torvalds "offset=%lu, inode=%lu, reclen=%d, namlen=%d", 322*1da177e4SLinus Torvalds dir->i_ino, dir->i_size, error_msg, offset, 323*1da177e4SLinus Torvalds (unsigned long)fs32_to_cpu(sb, de->d_ino), 324*1da177e4SLinus Torvalds rlen, ufs_get_de_namlen(sb, de)); 325*1da177e4SLinus Torvalds 326*1da177e4SLinus Torvalds return (error_msg == NULL ? 1 : 0); 327*1da177e4SLinus Torvalds } 328*1da177e4SLinus Torvalds 329*1da177e4SLinus Torvalds struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct buffer_head **p) 330*1da177e4SLinus Torvalds { 331*1da177e4SLinus Torvalds int err; 332*1da177e4SLinus Torvalds struct buffer_head *bh = ufs_bread (dir, 0, 0, &err); 333*1da177e4SLinus Torvalds struct ufs_dir_entry *res = NULL; 334*1da177e4SLinus Torvalds 335*1da177e4SLinus Torvalds if (bh) { 336*1da177e4SLinus Torvalds res = (struct ufs_dir_entry *) bh->b_data; 337*1da177e4SLinus Torvalds res = (struct ufs_dir_entry *)((char *)res + 338*1da177e4SLinus Torvalds fs16_to_cpu(dir->i_sb, res->d_reclen)); 339*1da177e4SLinus Torvalds } 340*1da177e4SLinus Torvalds *p = bh; 341*1da177e4SLinus Torvalds return res; 342*1da177e4SLinus Torvalds } 343*1da177e4SLinus Torvalds ino_t ufs_inode_by_name(struct inode * dir, struct dentry *dentry) 344*1da177e4SLinus Torvalds { 345*1da177e4SLinus Torvalds ino_t res = 0; 346*1da177e4SLinus Torvalds struct ufs_dir_entry * de; 347*1da177e4SLinus Torvalds struct buffer_head *bh; 348*1da177e4SLinus Torvalds 349*1da177e4SLinus Torvalds de = ufs_find_entry (dentry, &bh); 350*1da177e4SLinus Torvalds if (de) { 351*1da177e4SLinus Torvalds res = fs32_to_cpu(dir->i_sb, de->d_ino); 352*1da177e4SLinus Torvalds brelse(bh); 353*1da177e4SLinus Torvalds } 354*1da177e4SLinus Torvalds return res; 355*1da177e4SLinus Torvalds } 356*1da177e4SLinus Torvalds 357*1da177e4SLinus Torvalds void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, 358*1da177e4SLinus Torvalds struct buffer_head *bh, struct inode *inode) 359*1da177e4SLinus Torvalds { 360*1da177e4SLinus Torvalds dir->i_version++; 361*1da177e4SLinus Torvalds de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino); 362*1da177e4SLinus Torvalds mark_buffer_dirty(bh); 363*1da177e4SLinus Torvalds if (IS_DIRSYNC(dir)) 364*1da177e4SLinus Torvalds sync_dirty_buffer(bh); 365*1da177e4SLinus Torvalds brelse (bh); 366*1da177e4SLinus Torvalds } 367*1da177e4SLinus Torvalds 368*1da177e4SLinus Torvalds /* 369*1da177e4SLinus Torvalds * ufs_add_entry() 370*1da177e4SLinus Torvalds * 371*1da177e4SLinus Torvalds * adds a file entry to the specified directory, using the same 372*1da177e4SLinus Torvalds * semantics as ufs_find_entry(). It returns NULL if it failed. 373*1da177e4SLinus Torvalds */ 374*1da177e4SLinus Torvalds int ufs_add_link(struct dentry *dentry, struct inode *inode) 375*1da177e4SLinus Torvalds { 376*1da177e4SLinus Torvalds struct super_block * sb; 377*1da177e4SLinus Torvalds struct ufs_sb_private_info * uspi; 378*1da177e4SLinus Torvalds unsigned long offset; 379*1da177e4SLinus Torvalds unsigned fragoff; 380*1da177e4SLinus Torvalds unsigned short rec_len; 381*1da177e4SLinus Torvalds struct buffer_head * bh; 382*1da177e4SLinus Torvalds struct ufs_dir_entry * de, * de1; 383*1da177e4SLinus Torvalds struct inode *dir = dentry->d_parent->d_inode; 384*1da177e4SLinus Torvalds const char *name = dentry->d_name.name; 385*1da177e4SLinus Torvalds int namelen = dentry->d_name.len; 386*1da177e4SLinus Torvalds int err; 387*1da177e4SLinus Torvalds 388*1da177e4SLinus Torvalds UFSD(("ENTER, name %s, namelen %u\n", name, namelen)) 389*1da177e4SLinus Torvalds 390*1da177e4SLinus Torvalds sb = dir->i_sb; 391*1da177e4SLinus Torvalds uspi = UFS_SB(sb)->s_uspi; 392*1da177e4SLinus Torvalds 393*1da177e4SLinus Torvalds if (!namelen) 394*1da177e4SLinus Torvalds return -EINVAL; 395*1da177e4SLinus Torvalds bh = ufs_bread (dir, 0, 0, &err); 396*1da177e4SLinus Torvalds if (!bh) 397*1da177e4SLinus Torvalds return err; 398*1da177e4SLinus Torvalds rec_len = UFS_DIR_REC_LEN(namelen); 399*1da177e4SLinus Torvalds offset = 0; 400*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 401*1da177e4SLinus Torvalds while (1) { 402*1da177e4SLinus Torvalds if ((char *)de >= UFS_SECTOR_SIZE + bh->b_data) { 403*1da177e4SLinus Torvalds fragoff = offset & ~uspi->s_fmask; 404*1da177e4SLinus Torvalds if (fragoff != 0 && fragoff != UFS_SECTOR_SIZE) 405*1da177e4SLinus Torvalds ufs_error (sb, "ufs_add_entry", "internal error" 406*1da177e4SLinus Torvalds " fragoff %u", fragoff); 407*1da177e4SLinus Torvalds if (!fragoff) { 408*1da177e4SLinus Torvalds brelse (bh); 409*1da177e4SLinus Torvalds bh = ufs_bread (dir, offset >> sb->s_blocksize_bits, 1, &err); 410*1da177e4SLinus Torvalds if (!bh) 411*1da177e4SLinus Torvalds return err; 412*1da177e4SLinus Torvalds } 413*1da177e4SLinus Torvalds if (dir->i_size <= offset) { 414*1da177e4SLinus Torvalds if (dir->i_size == 0) { 415*1da177e4SLinus Torvalds brelse(bh); 416*1da177e4SLinus Torvalds return -ENOENT; 417*1da177e4SLinus Torvalds } 418*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) (bh->b_data + fragoff); 419*1da177e4SLinus Torvalds de->d_ino = 0; 420*1da177e4SLinus Torvalds de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE); 421*1da177e4SLinus Torvalds ufs_set_de_namlen(sb, de, 0); 422*1da177e4SLinus Torvalds dir->i_size = offset + UFS_SECTOR_SIZE; 423*1da177e4SLinus Torvalds mark_inode_dirty(dir); 424*1da177e4SLinus Torvalds } else { 425*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 426*1da177e4SLinus Torvalds } 427*1da177e4SLinus Torvalds } 428*1da177e4SLinus Torvalds if (!ufs_check_dir_entry ("ufs_add_entry", dir, de, bh, offset)) { 429*1da177e4SLinus Torvalds brelse (bh); 430*1da177e4SLinus Torvalds return -ENOENT; 431*1da177e4SLinus Torvalds } 432*1da177e4SLinus Torvalds if (ufs_match(sb, namelen, name, de)) { 433*1da177e4SLinus Torvalds brelse (bh); 434*1da177e4SLinus Torvalds return -EEXIST; 435*1da177e4SLinus Torvalds } 436*1da177e4SLinus Torvalds if (de->d_ino == 0 && fs16_to_cpu(sb, de->d_reclen) >= rec_len) 437*1da177e4SLinus Torvalds break; 438*1da177e4SLinus Torvalds 439*1da177e4SLinus Torvalds if (fs16_to_cpu(sb, de->d_reclen) >= 440*1da177e4SLinus Torvalds UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de)) + rec_len) 441*1da177e4SLinus Torvalds break; 442*1da177e4SLinus Torvalds offset += fs16_to_cpu(sb, de->d_reclen); 443*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) ((char *) de + fs16_to_cpu(sb, de->d_reclen)); 444*1da177e4SLinus Torvalds } 445*1da177e4SLinus Torvalds 446*1da177e4SLinus Torvalds if (de->d_ino) { 447*1da177e4SLinus Torvalds de1 = (struct ufs_dir_entry *) ((char *) de + 448*1da177e4SLinus Torvalds UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))); 449*1da177e4SLinus Torvalds de1->d_reclen = 450*1da177e4SLinus Torvalds cpu_to_fs16(sb, fs16_to_cpu(sb, de->d_reclen) - 451*1da177e4SLinus Torvalds UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))); 452*1da177e4SLinus Torvalds de->d_reclen = 453*1da177e4SLinus Torvalds cpu_to_fs16(sb, UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, de))); 454*1da177e4SLinus Torvalds de = de1; 455*1da177e4SLinus Torvalds } 456*1da177e4SLinus Torvalds de->d_ino = 0; 457*1da177e4SLinus Torvalds ufs_set_de_namlen(sb, de, namelen); 458*1da177e4SLinus Torvalds memcpy (de->d_name, name, namelen + 1); 459*1da177e4SLinus Torvalds de->d_ino = cpu_to_fs32(sb, inode->i_ino); 460*1da177e4SLinus Torvalds ufs_set_de_type(sb, de, inode->i_mode); 461*1da177e4SLinus Torvalds mark_buffer_dirty(bh); 462*1da177e4SLinus Torvalds if (IS_DIRSYNC(dir)) 463*1da177e4SLinus Torvalds sync_dirty_buffer(bh); 464*1da177e4SLinus Torvalds brelse (bh); 465*1da177e4SLinus Torvalds dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 466*1da177e4SLinus Torvalds dir->i_version++; 467*1da177e4SLinus Torvalds mark_inode_dirty(dir); 468*1da177e4SLinus Torvalds 469*1da177e4SLinus Torvalds UFSD(("EXIT\n")) 470*1da177e4SLinus Torvalds return 0; 471*1da177e4SLinus Torvalds } 472*1da177e4SLinus Torvalds 473*1da177e4SLinus Torvalds /* 474*1da177e4SLinus Torvalds * ufs_delete_entry deletes a directory entry by merging it with the 475*1da177e4SLinus Torvalds * previous entry. 476*1da177e4SLinus Torvalds */ 477*1da177e4SLinus Torvalds int ufs_delete_entry (struct inode * inode, struct ufs_dir_entry * dir, 478*1da177e4SLinus Torvalds struct buffer_head * bh ) 479*1da177e4SLinus Torvalds 480*1da177e4SLinus Torvalds { 481*1da177e4SLinus Torvalds struct super_block * sb; 482*1da177e4SLinus Torvalds struct ufs_dir_entry * de, * pde; 483*1da177e4SLinus Torvalds unsigned i; 484*1da177e4SLinus Torvalds 485*1da177e4SLinus Torvalds UFSD(("ENTER\n")) 486*1da177e4SLinus Torvalds 487*1da177e4SLinus Torvalds sb = inode->i_sb; 488*1da177e4SLinus Torvalds i = 0; 489*1da177e4SLinus Torvalds pde = NULL; 490*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 491*1da177e4SLinus Torvalds 492*1da177e4SLinus Torvalds UFSD(("ino %u, reclen %u, namlen %u, name %s\n", 493*1da177e4SLinus Torvalds fs32_to_cpu(sb, de->d_ino), 494*1da177e4SLinus Torvalds fs16to_cpu(sb, de->d_reclen), 495*1da177e4SLinus Torvalds ufs_get_de_namlen(sb, de), de->d_name)) 496*1da177e4SLinus Torvalds 497*1da177e4SLinus Torvalds while (i < bh->b_size) { 498*1da177e4SLinus Torvalds if (!ufs_check_dir_entry ("ufs_delete_entry", inode, de, bh, i)) { 499*1da177e4SLinus Torvalds brelse(bh); 500*1da177e4SLinus Torvalds return -EIO; 501*1da177e4SLinus Torvalds } 502*1da177e4SLinus Torvalds if (de == dir) { 503*1da177e4SLinus Torvalds if (pde) 504*1da177e4SLinus Torvalds fs16_add(sb, &pde->d_reclen, 505*1da177e4SLinus Torvalds fs16_to_cpu(sb, dir->d_reclen)); 506*1da177e4SLinus Torvalds dir->d_ino = 0; 507*1da177e4SLinus Torvalds inode->i_version++; 508*1da177e4SLinus Torvalds inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; 509*1da177e4SLinus Torvalds mark_inode_dirty(inode); 510*1da177e4SLinus Torvalds mark_buffer_dirty(bh); 511*1da177e4SLinus Torvalds if (IS_DIRSYNC(inode)) 512*1da177e4SLinus Torvalds sync_dirty_buffer(bh); 513*1da177e4SLinus Torvalds brelse(bh); 514*1da177e4SLinus Torvalds UFSD(("EXIT\n")) 515*1da177e4SLinus Torvalds return 0; 516*1da177e4SLinus Torvalds } 517*1da177e4SLinus Torvalds i += fs16_to_cpu(sb, de->d_reclen); 518*1da177e4SLinus Torvalds if (i == UFS_SECTOR_SIZE) pde = NULL; 519*1da177e4SLinus Torvalds else pde = de; 520*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) 521*1da177e4SLinus Torvalds ((char *) de + fs16_to_cpu(sb, de->d_reclen)); 522*1da177e4SLinus Torvalds if (i == UFS_SECTOR_SIZE && de->d_reclen == 0) 523*1da177e4SLinus Torvalds break; 524*1da177e4SLinus Torvalds } 525*1da177e4SLinus Torvalds UFSD(("EXIT\n")) 526*1da177e4SLinus Torvalds brelse(bh); 527*1da177e4SLinus Torvalds return -ENOENT; 528*1da177e4SLinus Torvalds } 529*1da177e4SLinus Torvalds 530*1da177e4SLinus Torvalds int ufs_make_empty(struct inode * inode, struct inode *dir) 531*1da177e4SLinus Torvalds { 532*1da177e4SLinus Torvalds struct super_block * sb = dir->i_sb; 533*1da177e4SLinus Torvalds struct buffer_head * dir_block; 534*1da177e4SLinus Torvalds struct ufs_dir_entry * de; 535*1da177e4SLinus Torvalds int err; 536*1da177e4SLinus Torvalds 537*1da177e4SLinus Torvalds dir_block = ufs_bread (inode, 0, 1, &err); 538*1da177e4SLinus Torvalds if (!dir_block) 539*1da177e4SLinus Torvalds return err; 540*1da177e4SLinus Torvalds 541*1da177e4SLinus Torvalds inode->i_blocks = sb->s_blocksize / UFS_SECTOR_SIZE; 542*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) dir_block->b_data; 543*1da177e4SLinus Torvalds de->d_ino = cpu_to_fs32(sb, inode->i_ino); 544*1da177e4SLinus Torvalds ufs_set_de_type(sb, de, inode->i_mode); 545*1da177e4SLinus Torvalds ufs_set_de_namlen(sb, de, 1); 546*1da177e4SLinus Torvalds de->d_reclen = cpu_to_fs16(sb, UFS_DIR_REC_LEN(1)); 547*1da177e4SLinus Torvalds strcpy (de->d_name, "."); 548*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) 549*1da177e4SLinus Torvalds ((char *)de + fs16_to_cpu(sb, de->d_reclen)); 550*1da177e4SLinus Torvalds de->d_ino = cpu_to_fs32(sb, dir->i_ino); 551*1da177e4SLinus Torvalds ufs_set_de_type(sb, de, dir->i_mode); 552*1da177e4SLinus Torvalds de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1)); 553*1da177e4SLinus Torvalds ufs_set_de_namlen(sb, de, 2); 554*1da177e4SLinus Torvalds strcpy (de->d_name, ".."); 555*1da177e4SLinus Torvalds mark_buffer_dirty(dir_block); 556*1da177e4SLinus Torvalds brelse (dir_block); 557*1da177e4SLinus Torvalds mark_inode_dirty(inode); 558*1da177e4SLinus Torvalds return 0; 559*1da177e4SLinus Torvalds } 560*1da177e4SLinus Torvalds 561*1da177e4SLinus Torvalds /* 562*1da177e4SLinus Torvalds * routine to check that the specified directory is empty (for rmdir) 563*1da177e4SLinus Torvalds */ 564*1da177e4SLinus Torvalds int ufs_empty_dir (struct inode * inode) 565*1da177e4SLinus Torvalds { 566*1da177e4SLinus Torvalds struct super_block * sb; 567*1da177e4SLinus Torvalds unsigned long offset; 568*1da177e4SLinus Torvalds struct buffer_head * bh; 569*1da177e4SLinus Torvalds struct ufs_dir_entry * de, * de1; 570*1da177e4SLinus Torvalds int err; 571*1da177e4SLinus Torvalds 572*1da177e4SLinus Torvalds sb = inode->i_sb; 573*1da177e4SLinus Torvalds 574*1da177e4SLinus Torvalds if (inode->i_size < UFS_DIR_REC_LEN(1) + UFS_DIR_REC_LEN(2) || 575*1da177e4SLinus Torvalds !(bh = ufs_bread (inode, 0, 0, &err))) { 576*1da177e4SLinus Torvalds ufs_warning (inode->i_sb, "empty_dir", 577*1da177e4SLinus Torvalds "bad directory (dir #%lu) - no data block", 578*1da177e4SLinus Torvalds inode->i_ino); 579*1da177e4SLinus Torvalds return 1; 580*1da177e4SLinus Torvalds } 581*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 582*1da177e4SLinus Torvalds de1 = (struct ufs_dir_entry *) 583*1da177e4SLinus Torvalds ((char *)de + fs16_to_cpu(sb, de->d_reclen)); 584*1da177e4SLinus Torvalds if (fs32_to_cpu(sb, de->d_ino) != inode->i_ino || de1->d_ino == 0 || 585*1da177e4SLinus Torvalds strcmp (".", de->d_name) || strcmp ("..", de1->d_name)) { 586*1da177e4SLinus Torvalds ufs_warning (inode->i_sb, "empty_dir", 587*1da177e4SLinus Torvalds "bad directory (dir #%lu) - no `.' or `..'", 588*1da177e4SLinus Torvalds inode->i_ino); 589*1da177e4SLinus Torvalds return 1; 590*1da177e4SLinus Torvalds } 591*1da177e4SLinus Torvalds offset = fs16_to_cpu(sb, de->d_reclen) + fs16_to_cpu(sb, de1->d_reclen); 592*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) 593*1da177e4SLinus Torvalds ((char *)de1 + fs16_to_cpu(sb, de1->d_reclen)); 594*1da177e4SLinus Torvalds while (offset < inode->i_size ) { 595*1da177e4SLinus Torvalds if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) { 596*1da177e4SLinus Torvalds brelse (bh); 597*1da177e4SLinus Torvalds bh = ufs_bread (inode, offset >> sb->s_blocksize_bits, 1, &err); 598*1da177e4SLinus Torvalds if (!bh) { 599*1da177e4SLinus Torvalds ufs_error (sb, "empty_dir", 600*1da177e4SLinus Torvalds "directory #%lu contains a hole at offset %lu", 601*1da177e4SLinus Torvalds inode->i_ino, offset); 602*1da177e4SLinus Torvalds offset += sb->s_blocksize; 603*1da177e4SLinus Torvalds continue; 604*1da177e4SLinus Torvalds } 605*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) bh->b_data; 606*1da177e4SLinus Torvalds } 607*1da177e4SLinus Torvalds if (!ufs_check_dir_entry ("empty_dir", inode, de, bh, offset)) { 608*1da177e4SLinus Torvalds brelse (bh); 609*1da177e4SLinus Torvalds return 1; 610*1da177e4SLinus Torvalds } 611*1da177e4SLinus Torvalds if (de->d_ino) { 612*1da177e4SLinus Torvalds brelse (bh); 613*1da177e4SLinus Torvalds return 0; 614*1da177e4SLinus Torvalds } 615*1da177e4SLinus Torvalds offset += fs16_to_cpu(sb, de->d_reclen); 616*1da177e4SLinus Torvalds de = (struct ufs_dir_entry *) 617*1da177e4SLinus Torvalds ((char *)de + fs16_to_cpu(sb, de->d_reclen)); 618*1da177e4SLinus Torvalds } 619*1da177e4SLinus Torvalds brelse (bh); 620*1da177e4SLinus Torvalds return 1; 621*1da177e4SLinus Torvalds } 622*1da177e4SLinus Torvalds 623*1da177e4SLinus Torvalds struct file_operations ufs_dir_operations = { 624*1da177e4SLinus Torvalds .read = generic_read_dir, 625*1da177e4SLinus Torvalds .readdir = ufs_readdir, 626*1da177e4SLinus Torvalds .fsync = file_fsync, 627*1da177e4SLinus Torvalds }; 628