/*
 * This file is part of DesktopBSD, see the README file.
 *
 * Author: Peter Hofer <ph@desktopbsd.net>
 *			(C) 2004, 2005
 *
 * Copyright: BSD, see the COPYING file included in this distribution
 *
 */

#include <chunk.h>

#include <executor.h>


/** @return TRUE when this object is valid,
  *			otherwise false.
  * @sa Disk::Chunk
  */
bool  Disk::Chunk::isValid()  const {
	return  (cnk != NULL  &&  parent != NULL);
}

/** @return FALSE when unused, otherwise TRUE. */
bool  Disk::Chunk::inUse() const {
	if(!isValid())
		return false;

	return cnk->type != unused;
}

/** Private because only "Disk" should be
  * allowed to instantiate this class.
  */
Disk::Chunk::Chunk(chunk *c, Disk *d)
		  : FSDevice(c->name),

		  parent(d),
		  cnk(c)
{
	switch(c->type) {
	case whole:
		fstype = Whole; break;

	case unused:
		fstype = Unused; break;

	default:
		fstype = typeFromSysId(cnk->subtype);
	}

	/*
	switch (c->type) {
	case whole:
		fstype = Whole;
		break;

	case mbr:
		fstype = typeFromSysId(cnk->subtype);
		break;

	case fat:
		fstype = FAT;
		break;

	case freebsd:
		switch (cnk->subtype) {
		case 165: fstype = UFS; break;
		default:  fstype = Unknown; break;
		} break;

	case unused:
		fstype = Unused;
		break;

	default:
		fstype = Unknown;
	}
	*/

	size = Size(cnk->size, Size::Blocks);
}


/** Creates a new slice in this chunk with the
  * given file system.
  *
  * Fails if the chunk is in use.
  *
  * This doesn't prepare the file system in any
  * form (e.g. formatting).
  */
bool  Disk::Chunk::create(FSType fs, const Size & size) {
	int sysid;
	if(!isValid() || cnk->type != unused || (sysid = sysIdFromType(fs)) == 0)
		return false;

	chunk_e ptype;
	if(fs == UFS)
		ptype = freebsd;
	else if(fs == FAT)
		ptype = fat;
	else
		ptype = mbr;

	bool ret = !Create_Chunk(parent->dsk, cnk->offset, size.get(Size::Blocks),
									 ptype, sysid, cnk->flags & CHUNK_ALIGN, "");
	parent->update();
	cnk = NULL;
	return ret;
}


/** Deletes this chunk.
  * Fails if the chunk is already unused.
  */
bool  Disk::Chunk::free() {
	bool ret = false;
	if(isValid() && cnk->type != unused) {
		ret = !Delete_Chunk(parent->dsk, cnk);
		parent->update();
		cnk = NULL;
	}

	return ret;
}


/** Creates a new file system in this chunk. This
  * works only with unused chunks.
  *
  * At the moment, only UFS and FAT are supported.
  *
  * If the new file system is UFS, this also writes
  * a disk label that uses all the space for one partition.
  *
  * @attention
  * All pending changes are written in the process.
  * Make sure you re-read the disk after performing
  * calling this method (the chunk also doesn't get
  * invalid afterwards automatically)
  *
  * @returns TRUE when the disk changes were written
  *			 successfully and newfs (and bsdlabel if
  *			 using UFS) were successfully, otherwise
  *			 FALSE.
  */
bool  Disk::Chunk::newFS() {
	if(isValid() && (fstype == UFS || fstype == FAT)) {
		if(!parent->writeChanges())
			return false;

		QString name = getName();
		if(fstype == UFS) {
			QString labelCmd = "/sbin/bsdlabel -w '%1'";
			QString newfsCmd = "/sbin/newfs -U '%1'";

			return (Executor::exec(labelCmd.arg(name)) == Executor::NoError) &&
					 (Executor::exec(newfsCmd.arg(name)) == Executor::NoError);
		} else if(fstype == FAT) {
			QString newfsCmd = "/sbin/newfs_msdos '%1'";
			return Executor::exec(newfsCmd.arg(name)) == Executor::NoError;
		}
	}

	return false;
}

