⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dir.c

📁 ocfs1.2.7 源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * dir.c * * Creates, reads, walks and deletes directory-nodes * * Copyright (C) 2002, 2004 Oracle.  All rights reserved. * *  Portions of this code from linux/fs/ext3/dir.c * *  Copyright (C) 1992, 1993, 1994, 1995 *  Remy Card (card@masi.ibp.fr) *  Laboratoire MASI - Institut Blaise pascal *  Universite Pierre et Marie Curie (Paris VI) * *   from * *   linux/fs/minix/dir.c * *   Copyright (C) 1991, 1992 Linux Torvalds * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */#include <linux/fs.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/highmem.h>#define MLOG_MASK_PREFIX ML_NAMEI#include <cluster/masklog.h>#include "ocfs2.h"#include "alloc.h"#include "dir.h"#include "dlmglue.h"#include "extent_map.h"#include "file.h"#include "inode.h"#include "journal.h"#include "namei.h"#include "suballoc.h"#include "uptodate.h"#include "buffer_head_io.h"static unsigned char ocfs2_filetype_table[] = {	DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK};static int ocfs2_extend_dir(struct ocfs2_super *osb,			    struct inode *dir,			    struct buffer_head *parent_fe_bh,			    struct buffer_head **new_de_bh);/* * ocfs2_readdir() * */int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir){	int error = 0;	unsigned long offset, blk;	int i, num, stored;	struct buffer_head * bh, * tmp;	struct ocfs2_dir_entry * de;	int err;	struct inode *inode = filp->f_dentry->d_inode;	struct super_block * sb = inode->i_sb;	int have_disk_lock = 0;	mlog_entry("dirino=%"MLFu64"\n", OCFS2_I(inode)->ip_blkno);	stored = 0;	bh = NULL;	error = ocfs2_meta_lock(inode, NULL, NULL, 0);	if (error < 0) {		if (error != -ENOENT)			mlog_errno(error);		/* we haven't got any yet, so propagate the error. */		stored = error;		goto bail;	}	have_disk_lock = 1;	offset = filp->f_pos & (sb->s_blocksize - 1);	while (!error && !stored && filp->f_pos < i_size_read(inode)) {		blk = (filp->f_pos) >> sb->s_blocksize_bits;		bh = ocfs2_bread(inode, blk, &err, 0);		if (!bh) {			mlog(ML_ERROR, "directory #%"MLFu64" contains a hole "				       "at offset %lld\n",			     OCFS2_I(inode)->ip_blkno,			     filp->f_pos);			filp->f_pos += sb->s_blocksize - offset;			continue;		}		/*		 * Do the readahead (8k)		 */		if (!offset) {			for (i = 16 >> (sb->s_blocksize_bits - 9), num = 0;			     i > 0; i--) {				tmp = ocfs2_bread(inode, ++blk, &err, 1);				if (tmp)					brelse(tmp);			}		}revalidate:		/* If the dir block has changed since the last call to		 * readdir(2), then we might be pointing to an invalid		 * dirent right now.  Scan from the start of the block		 * to make sure. */		if (filp->f_version != inode->i_version) {			for (i = 0; i < sb->s_blocksize && i < offset; ) {				de = (struct ocfs2_dir_entry *) (bh->b_data + i);				/* It's too expensive to do a full				 * dirent test each time round this				 * loop, but we do have to test at				 * least that it is non-zero.  A				 * failure will be detected in the				 * dirent test below. */				if (le16_to_cpu(de->rec_len) <				    OCFS2_DIR_REC_LEN(1))					break;				i += le16_to_cpu(de->rec_len);			}			offset = i;			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))				| offset;			filp->f_version = inode->i_version;		}		while (!error && filp->f_pos < i_size_read(inode)		       && offset < sb->s_blocksize) {			de = (struct ocfs2_dir_entry *) (bh->b_data + offset);			if (!ocfs2_check_dir_entry(inode, de, bh, offset)) {				/* On error, skip the f_pos to the				   next block. */				filp->f_pos = (filp->f_pos |					       (sb->s_blocksize - 1)) + 1;				brelse(bh);				goto bail;			}			offset += le16_to_cpu(de->rec_len);			if (le64_to_cpu(de->inode)) {				/* We might block in the next section				 * if the data destination is				 * currently swapped out.  So, use a				 * version stamp to detect whether or				 * not the directory has been modified				 * during the copy operation.				 */				unsigned long version = filp->f_version;				unsigned char d_type = DT_UNKNOWN;				if (de->file_type < OCFS2_FT_MAX)					d_type = ocfs2_filetype_table[de->file_type];				error = filldir(dirent, de->name,						de->name_len,						filp->f_pos,						ino_from_blkno(sb, le64_to_cpu(de->inode)),						d_type);				if (error)					break;				if (version != filp->f_version)					goto revalidate;				stored ++;			}			filp->f_pos += le16_to_cpu(de->rec_len);		}		offset = 0;		brelse(bh);	}	stored = 0;bail:	if (have_disk_lock)		ocfs2_meta_unlock(inode, 0);	mlog_exit(stored);	return stored;}/* * NOTE: this should always be called with parent dir i_mutex taken. */int ocfs2_find_files_on_disk(const char *name,			     int namelen,			     u64 *blkno,			     struct inode *inode,			     struct buffer_head **dirent_bh,			     struct ocfs2_dir_entry **dirent){	int status = -ENOENT;	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);	mlog_entry("(osb=%p, parent=%"MLFu64", name='%.*s', blkno=%p, "		   "inode=%p)\n",		   osb, OCFS2_I(inode)->ip_blkno, namelen, name, blkno, inode);	*dirent_bh = ocfs2_find_entry(name, namelen, inode, dirent);	if (!*dirent_bh || !*dirent) {		status = -ENOENT;		goto leave;	}	*blkno = le64_to_cpu((*dirent)->inode);	status = 0;leave:	if (status < 0) {		*dirent = NULL;		if (*dirent_bh) {			brelse(*dirent_bh);			*dirent_bh = NULL;		}	}	mlog_exit(status);	return status;}/* Check for a name within a directory. * * Return 0 if the name does not exist * Return -EEXIST if the directory contains the name * * Callers should have i_mutex + a cluster lock on dir */int ocfs2_check_dir_for_entry(struct inode *dir,			      const char *name,			      int namelen){	int ret;	struct buffer_head *dirent_bh = NULL;	struct ocfs2_dir_entry *dirent = NULL;	mlog_entry("dir %"MLFu64", name '%.*s'\n", OCFS2_I(dir)->ip_blkno,		   namelen, name);	ret = -EEXIST;	dirent_bh = ocfs2_find_entry(name, namelen, dir, &dirent);	if (dirent_bh)		goto bail;	ret = 0;bail:	if (dirent_bh)		brelse(dirent_bh);	mlog_exit(ret);	return ret;}/* * routine to check that the specified directory is empty (for rmdir) */int ocfs2_empty_dir(struct inode *inode){	unsigned long offset;	struct buffer_head * bh;	struct ocfs2_dir_entry * de, * de1;	struct super_block * sb;	int err;	sb = inode->i_sb;	if ((i_size_read(inode) <	     (OCFS2_DIR_REC_LEN(1) + OCFS2_DIR_REC_LEN(2))) ||	    !(bh = ocfs2_bread(inode, 0, &err, 0))) {	    	mlog(ML_ERROR, "bad directory (dir #%"MLFu64") - "			       "no data block\n",		     OCFS2_I(inode)->ip_blkno);		return 1;	}	de = (struct ocfs2_dir_entry *) bh->b_data;	de1 = (struct ocfs2_dir_entry *)			((char *)de + le16_to_cpu(de->rec_len));	if ((le64_to_cpu(de->inode) != OCFS2_I(inode)->ip_blkno) ||			!le64_to_cpu(de1->inode) ||			strcmp(".", de->name) ||			strcmp("..", de1->name)) {	    	mlog(ML_ERROR, "bad directory (dir #%"MLFu64") - "			       "no `.' or `..'\n",		     OCFS2_I(inode)->ip_blkno);		brelse(bh);		return 1;	}	offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);	de = (struct ocfs2_dir_entry *)((char *)de1 + le16_to_cpu(de1->rec_len));	while (offset < i_size_read(inode) ) {		if (!bh || (void *)de >= (void *)(bh->b_data + sb->s_blocksize)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -