예제 #1
0
static errcode_t orphan_dir_check(ocfs2_filesys *fs,
				  uint16_t new_slots)
{
	errcode_t ret = 0;
	uint64_t blkno;
	int i, has_orphan = 0;
	uint16_t max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;

	for (i = new_slots ; i < max_slots; ++i) {
		ret = ocfs2_lookup_system_inode(fs, ORPHAN_DIR_SYSTEM_INODE,
						i, &blkno);
		if (ret) {
			verbosef(VL_APP,
				 "%s while looking up orphan dir for "
				 "slot %u during orphan dir check\n",
				 error_message(ret), i);
			break;
		}

		ret = ocfs2_dir_iterate(fs, blkno,
					OCFS2_DIRENT_FLAG_EXCLUDE_DOTS, NULL,
					orphan_iterate, &has_orphan);

		if (has_orphan) {
			ret = TUNEFS_ET_ORPHAN_DIR_NOT_EMPTY;
			verbosef(VL_APP,
				 "Entries found in orphan dir for slot %u\n",
				 i);
			break;
		}
	}

	return ret;
}
예제 #2
0
static PyObject *
fs_dir_iterate (Filesystem *self,
                PyObject   *args,
                PyObject   *kwargs)
{
  errcode_t  ret;
  WalkData   wdata;
  PyObject  *py_func, *py_data = NULL, *py_dir = NULL;
  uint64_t   dir;
  int        flags = OCFS2_DIRENT_FLAG_EXCLUDE_DOTS;

  static char *kwlist[] = { "callback", "data", "dir", "flags", NULL };

  if (!PyArg_ParseTupleAndKeywords (args, kwargs,
				    "O|OOi:dir_iterate", kwlist,
				    &py_func, &py_data, &py_dir, &flags))
    return NULL;

  if (!PyCallable_Check (py_func))
    {
      PyErr_SetString (PyExc_TypeError, "callback must be a callable object");
      return NULL;
    }

  if (py_dir == NULL || py_dir == Py_None)
    dir = self->fs->fs_root_blkno;
  else if (DirEntry_Check (py_dir))
    dir = ((DirEntry *) py_dir)->dentry.inode;
  else if (PyInt_Check (py_dir))
    dir = PyInt_AsUnsignedLongMask (py_dir);
  else if (PyLong_Check (py_dir))
    dir = PyLong_AsUnsignedLongLongMask (py_dir);
  else
    {
      PyErr_SetString (PyExc_TypeError, "dir must be DirEntry or integer");
      return NULL;
    }

  Py_INCREF (py_func);
  wdata.func = py_func;

  Py_XINCREF (py_data);
  wdata.data = py_data;

  wdata.fs = self;

  /* XXX: handle errors */
  ret = ocfs2_dir_iterate (self->fs, dir, flags, NULL, walk_dirs, &wdata);

  Py_DECREF (py_func);
  Py_XDECREF (py_data);

  Py_INCREF (Py_None);
  return Py_None;
}
예제 #3
0
static errcode_t remove_slot_entry(ocfs2_filesys *fs, uint16_t removed_slot)
{
	struct remove_slot_ctxt ctxt = {
		.fs = fs,
		.removed_slot = removed_slot,
		.errcode = 0
	};

	ocfs2_dir_iterate(fs, fs->fs_sysdir_blkno,
			  OCFS2_DIRENT_FLAG_EXCLUDE_DOTS, NULL,
			  remove_slot_iterate, &ctxt);

	return ctxt.errcode;
}

static errcode_t decrease_link_count(ocfs2_filesys *fs, uint16_t blkno)
{
	errcode_t ret;
	char *buf = NULL;
	struct ocfs2_dinode *di  = NULL;

	ret = ocfs2_malloc_block(fs->fs_io, &buf);
	if (ret)
		goto bail;

	ret = ocfs2_read_inode(fs, blkno, buf);
	if (ret)
		goto bail;

	di = (struct ocfs2_dinode *)buf;

	if (di->i_links_count > 0)
		di->i_links_count--;
	else {
		ret = OCFS2_ET_INODE_NOT_VALID;
		goto bail;
	}

	ret = ocfs2_write_inode(fs, blkno, buf);
bail:
	if (buf)
		ocfs2_free(&buf);
	return ret;
}
예제 #4
0
파일: pass3.c 프로젝트: pepe5/ocfs2-tools
static void fix_dot_dot(o2fsck_state *ost, o2fsck_dir_parent *dir)
{
	errcode_t ret;

	struct fix_dot_dot_args args = {
		.ost = ost,
		.parent = dir->dp_dirent,
		.fixed = 0,
	};

	ret = ocfs2_dir_iterate(ost->ost_fs, dir->dp_ino, 
				OCFS2_DIRENT_FLAG_INCLUDE_EMPTY, NULL,
				fix_dot_dot_dirent, &args);
	if (ret) {
		com_err("fix_dot_dot", ret, "while iterating through dir "
			"inode %"PRIu64"'s directory entries.", dir->dp_dirent);
		/* XXX mark fs invalid */
		return;
	}

	if (!args.fixed) {
		fprintf(stderr, "Didn't find a '..' entry to fix.\n");
		/* XXX mark fs invalid */
		return;
	}

	dir->dp_dot_dot = dir->dp_dirent;
}

/* add a directory entry that points to a given inode in lost+found. */
void o2fsck_reconnect_file(o2fsck_state *ost, uint64_t inode)
{
	static char iname[NAME_MAX + 1];
	char name[] = "lost+found";
	int namelen = sizeof(name) - 1;
	o2fsck_dir_parent *dp;
	errcode_t ret;
	uint8_t type;
	int len;

	if (ost->ost_lostfound_ino == 0) {
		ret = ocfs2_lookup(ost->ost_fs, ost->ost_fs->fs_root_blkno,
				   name, namelen, NULL,
				   &ost->ost_lostfound_ino);
		if (ret) {
			com_err(whoami, ret, "while trying to find the "
				"/lost+found directory so that inode "
				"%"PRIu64" could be moved there.", inode);
			goto out;
		}
	}

	len = snprintf(iname, sizeof(iname), "#%"PRIu64, inode);
	if (len <= 0) {
		ret = OCFS2_ET_NO_MEMORY;
		com_err(whoami, ret, "while trying to build a new file name "
			"for inode %"PRIu64" to use in /lost+found", inode);
		goto out;
	}

	ret = o2fsck_type_from_dinode(ost, inode, &type);
	if (ret)
		goto out;

	ret = ocfs2_link(ost->ost_fs, ost->ost_lostfound_ino, iname, inode,
			 type);
	if (ret) {
		com_err(whoami, ret, "while trying to link inode %"PRIu64" "
			"into /lost+found", inode);
		goto out;
	}

	/* add another ref to account for this new dirent */
	o2fsck_icount_delta(ost->ost_icount_refs, inode, 1);

	/* if we just added a directory to l+f we need to track that 
	 * the new dirent points to the dir.  we leave the dot_dot tracking
	 * intact because we didn't change that in the dirblock.. */
	if (type == OCFS2_FT_DIR) {
		dp = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, inode);
		if (dp == NULL) {
			ret = OCFS2_ET_INTERNAL_FAILURE;
			com_err(whoami, ret, "while looking up the directory "
				"parent structure for inode %"PRIu64, inode);
			goto out;
		}
		dp->dp_dirent = ost->ost_lostfound_ino;
	}

out:
	return;
}

static uint64_t loop_no = 0;

static errcode_t connect_directory(o2fsck_state *ost,
				   o2fsck_dir_parent *dir)
{
	o2fsck_dir_parent *dp = dir, *par;
	errcode_t ret = 0;
	int fix;

	verbosef("checking dir inode %"PRIu64" parent %"PRIu64" dot_dot "
		"%"PRIu64"\n", dir->dp_ino, dp->dp_dirent, dp->dp_dot_dot);

	loop_no++;

	while(!dp->dp_connected) {

		/* we either will ascend to a parent that is connected or
		 * we'll graft the subtree with this directory on to lost
		 * and found. */ 
		dp->dp_connected = 1;

		/* move on to the parent dir only if it exists and we haven't
		 * already traversed it in this instance of parent walking */
		if (dp->dp_dirent) {
			par = o2fsck_dir_parent_lookup(&ost->ost_dir_parents, 
							dp->dp_dirent);
			if (par == NULL) {
				ret = OCFS2_ET_INTERNAL_FAILURE;
				com_err(whoami, ret, "no dir info for parent "
					"%"PRIu64, dp->dp_dirent);
				goto out;
			}
			if (par->dp_loop_no != loop_no) {
				par->dp_loop_no = loop_no;
				dp = par;
				continue;
			}
		}

		/* ok, we hit an orphan subtree with no parent or are at 
		 * the dir in a subtree that is the first to try to reference
		 * a dir in its children */
		fix = prompt(ost, PY, PR_DIR_NOT_CONNECTED,
			     "Directory inode %"PRIu64" isn't "
			     "connected to the filesystem.  Move it to "
			     "lost+found?", dp->dp_ino);
		if (fix)
			o2fsck_reconnect_file(ost, dp->dp_ino);

		break;
	}

	/* 
	 * orphan dirs are a magically awesome special case.  they have
	 * their i_link_count increased when subdirs are added but
	 * the subdirs '..' entry isn't updated to point to the orphan
	 * dir.  we alter our book-keeping to it look like the '..'
	 * was reasonable on disk.
	 */
	if (dir->dp_in_orphan_dir) {
		/* previous '..' entry is garbage */
		if (dir->dp_dot_dot)
			o2fsck_icount_delta(ost->ost_icount_refs,
					    dir->dp_dot_dot, -1);
		/* pretend '..' pointed to the orphan dir */
		dir->dp_dot_dot = dir->dp_dirent;
		o2fsck_icount_delta(ost->ost_icount_refs, dir->dp_dot_dot, 1);
	}
	if (dir->dp_dirent != dir->dp_dot_dot) {
		fix = prompt(ost, PY, PR_DIR_DOTDOT,
			     "Directory inode %"PRIu64" is "
			     "referenced by a dirent in directory %"PRIu64" "
			     "but its '..' entry points to inode %"PRIu64". "
			     "Fix the '..' entry to reference %"PRIu64"?", 
			     dir->dp_ino, dir->dp_dirent, dir->dp_dot_dot, 
			     dir->dp_dirent);
		if (fix)
			fix_dot_dot(ost, dir);
	}
out:
	return ret;
}
예제 #5
0
static int walk_tree_func(struct ocfs2_dir_entry *dentry,
			  int offset,
			  int blocksize,
			  char *buf,
			  void *priv_data)
{
	errcode_t ret;
	int len, oldval;
	int reti = 0;
	char *old_path, *path;
	struct walk_path *wp = priv_data;

	if (!strncmp(dentry->name, ".", dentry->name_len) ||
	    !strncmp(dentry->name, "..", dentry->name_len))
		return 0;

	len = strlen(wp->path);

	if (len + dentry->name_len > 4095) {
		fprintf(stderr, "name is too long in %s\n", wp->path);
		return OCFS2_DIRENT_ABORT;
	}

	ret = ocfs2_malloc0(4096, &path);
	if (ret) {
		com_err(wp->argv0, ret,
			"while allocating path memory in %s\n",
			wp->path);
		return OCFS2_DIRENT_ABORT;
	}
	
	memcpy(path, wp->path, len);
	memcpy(path + len, dentry->name, dentry->name_len);
	if (dentry->file_type == OCFS2_FT_DIR)
		path[len + dentry->name_len] = '/';

	if (wp->check_dups) {
		ret = ocfs2_bitmap_test(wp->dup_map, dentry->inode,
					&oldval);
		if (oldval) {
			fprintf(stdout, "Dup! %20"PRIu64" %s\n",
				(uint64_t)dentry->inode, path);
		}
		goto out;
	}

	oldval = 0;
	ret = ocfs2_bitmap_set(wp->inode_map, dentry->inode, &oldval);
	if (ret) {
		com_err(wp->argv0, ret,
			"while setting bitmap bit %"PRIu64"\n",
			(uint64_t)dentry->inode);
		reti = OCFS2_DIRENT_ABORT;
		goto out;
	}

	if (oldval) {
		wp->has_dups = 1;
		ret = ocfs2_bitmap_set(wp->dup_map, dentry->inode,
				       NULL);
		if (ret) {
			com_err(wp->argv0, ret,
				"while setting dup bit %"PRIu64"\n",
				(uint64_t)dentry->inode);
			reti = OCFS2_DIRENT_ABORT;
			goto out;
		}
	}

	if (!wp->quiet)
		fprintf(stdout, "%20"PRIu64" %s\n",
			(uint64_t)dentry->inode, path);

	if (dentry->file_type == OCFS2_FT_DIR) {
		old_path = wp->path;
		wp->path = path;
		ret = ocfs2_dir_iterate(wp->fs, dentry->inode, 0, NULL,
					walk_tree_func, wp);
		if (ret) {
			com_err(wp->argv0, ret,
				"while walking %s", wp->path);
			reti = OCFS2_DIRENT_ABORT;
		}
		wp->path = old_path;
	}

out:
	ocfs2_free(&path);

	return reti;
}
예제 #6
0
int main(int argc, char *argv[])
{
	errcode_t ret;
	uint64_t blkno;
	char *filename;
	ocfs2_filesys *fs;
	struct walk_path wp;

	blkno = OCFS2_SUPER_BLOCK_BLKNO;

	initialize_ocfs_error_table();

	wp.argv0 = argv[0];
	wp.quiet = 0;
	wp.has_dups = 0;
	wp.check_dups = 0;
	if (argc < 2) {
		fprintf(stderr, "Missing filename\n");
		print_usage();
		return 1;
	}
	filename = argv[1];

	if (argc > 2) {
		if (!strcmp(argv[2], "-q"))
			wp.quiet = 1;
	}
	
	ret = ocfs2_open(filename, OCFS2_FLAG_RO, 0, 0, &fs);
	if (ret) {
		com_err(argv[0], ret,
			"while opening file \"%s\"", filename);
		goto out;
	}
	wp.fs = fs;

	ret = ocfs2_block_bitmap_new(fs, "Inode bitmap", &wp.inode_map);
	if (ret) {
		com_err(argv[0], ret,
			"while creating the inode bitmap");
		goto out_close;
	}

	ret = ocfs2_block_bitmap_new(fs, "Duplicate inode bitmap",
				     &wp.dup_map);
	if (ret) {
		com_err(argv[0], ret,
			"while creating the duplicate inode bitmap");
		goto out_close;
	}

	ocfs2_bitmap_set(wp.inode_map,
			 OCFS2_RAW_SB(fs->fs_super)->s_system_dir_blkno,
			 NULL);
	ocfs2_bitmap_set(wp.inode_map,
			 OCFS2_RAW_SB(fs->fs_super)->s_root_blkno,
			 NULL);

	fprintf(stdout, "Walking system directory...\n");
	wp.path = "<system_dir>/";
	ret = ocfs2_dir_iterate(fs,
				OCFS2_RAW_SB(fs->fs_super)->s_system_dir_blkno,
				0, NULL, walk_tree_func, &wp);
	if (ret) {
		com_err(argv[0], ret,
			"while walking sysdm dir inode %"PRIu64" on \"%s\"\n",
			blkno, filename);
		goto out_close;
	}
	wp.path = "/";
	fprintf(stdout, "Walking root directory...\n");
	ret = ocfs2_dir_iterate(fs,
				OCFS2_RAW_SB(fs->fs_super)->s_root_blkno,
				0, NULL, walk_tree_func, &wp);
	if (ret) {
		com_err(argv[0], ret,
			"while walking root inode %"PRIu64" on \"%s\"\n",
			blkno, filename);
		goto out_close;
	}

	if (wp.has_dups) {
		fprintf(stdout, "Hardlinks found\n");

		wp.check_dups = 1;
		fprintf(stdout, "Scanning system directory for dups...\n");
		wp.path = "<system_dir>/";
		ret = ocfs2_dir_iterate(fs,
					OCFS2_RAW_SB(fs->fs_super)->s_system_dir_blkno,
					0, NULL, walk_tree_func, &wp);
		if (ret) {
			com_err(argv[0], ret,
				"while dup scanning sysdm dir inode %"PRIu64
			        " on \"%s\"\n",
				blkno, filename);
			goto out_close;
		}
		wp.path = "/";
		fprintf(stdout, "Scanning root directory for dups...\n");
		ret = ocfs2_dir_iterate(fs,
					OCFS2_RAW_SB(fs->fs_super)->s_root_blkno,
					0, NULL, walk_tree_func, &wp);
		if (ret) {
			com_err(argv[0], ret,
				"while dup scanning root inode %"PRIu64
			       	" on \"%s\"\n",
				blkno, filename);
			goto out_close;
		}
	}

out_close:
	ret = ocfs2_close(fs);
	if (ret) {
		com_err(argv[0], ret,
			"while closing file \"%s\"", filename);
	}

out:
	return 0;
}
예제 #7
0
static errcode_t remove_quota_files(ocfs2_filesys *fs, int type,
				    struct tools_progress *prog)
{
	struct remove_quota_files_ctxt ctxt = {
		.fs = fs,
		.type = type,
		.err = 0,
	};

	ocfs2_dir_iterate(fs, fs->fs_sysdir_blkno,
			  OCFS2_DIRENT_FLAG_EXCLUDE_DOTS, NULL,
			  remove_quota_files_iterate, &ctxt);
	tools_progress_step(prog, 1);
	return ctxt.err;
}

static int enable_usrquota(ocfs2_filesys *fs, int flags)
{
	struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
	errcode_t ret;
	struct tools_progress *prog = NULL;

	if (OCFS2_HAS_RO_COMPAT_FEATURE(super,
	    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
		verbosef(VL_APP, "User quotas are already enabled; "
			 "nothing to enable\n");
		return 0;
	}

	if (!tools_interact("Enable user quota feature on device "
			    "\"%s\"? ",
			    fs->fs_devname))
		return 0;

	prog = tools_progress_start("Enabling user quota", "usrquota", 6);
	if (!prog) {
		ret = TUNEFS_ET_NO_MEMORY;
		tcom_err(ret, "while initializing progress display");
		return ret;
	}
	tunefs_block_signals();
	ret = create_quota_files(fs, USRQUOTA, prog);
	if (ret) {
		tcom_err(ret, "while creating user quota files");
		goto bail;
	}
	OCFS2_SET_RO_COMPAT_FEATURE(super,
				    OCFS2_FEATURE_RO_COMPAT_USRQUOTA);
	ret = ocfs2_write_super(fs);
	tools_progress_step(prog, 1);
bail:
	tunefs_unblock_signals();
	tools_progress_stop(prog);
	return ret;
}

static int disable_usrquota(ocfs2_filesys *fs, int flags)
{
	errcode_t ret;
	struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
	struct tools_progress *prog = NULL;

	if (!OCFS2_HAS_RO_COMPAT_FEATURE(super,
	    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
		verbosef(VL_APP, "User quotas are already disabled; "
			 "nothing to disable\n");
		return 0;
	}

	if (!tools_interact("Disable user quota feature on device "
			    "\"%s\"? ",
			    fs->fs_devname))
		return 0;

	prog = tools_progress_start("Disabling user quota", "nousrquota", 2);
	if (!prog) {
		ret = TUNEFS_ET_NO_MEMORY;
		tcom_err(ret, "while initializing progress display");
		return ret;
	}
	tunefs_block_signals();
	ret = remove_quota_files(fs, USRQUOTA, prog);
	if (ret) {
		tcom_err(ret, "while removing user quota files");
		goto bail;
	}
	OCFS2_CLEAR_RO_COMPAT_FEATURE(super,
				      OCFS2_FEATURE_RO_COMPAT_USRQUOTA);
	ret = ocfs2_write_super(fs);
	tools_progress_step(prog, 1);
bail:
	tunefs_unblock_signals();
	tools_progress_stop(prog);
	return ret;
}