/*
 * Copyright 2012 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Paweł Dziepak, pdziepak@quarnos.org
 */
 
 
#include "RootInode.h"
 
#include <string.h>
 
#include "MetadataCache.h"
#include "Request.h"
 
 
RootInode::RootInode()
	:
	fInfoCacheExpire(0),
	fName(NULL),
	fIOSize(0)
{
	mutex_init(&fInfoCacheLock, NULL);
}
 
 
RootInode::~RootInode()
{
	free(const_cast<char*>(fName));
	mutex_destroy(&fInfoCacheLock);
}
 
 
status_t
RootInode::ReadInfo(struct fs_info* info)
{
	ASSERT(info != NULL);
 
	status_t result = _UpdateInfo();
	if (result != B_OK)
		return result;
 
	memcpy(info, &fInfoCache, sizeof(struct fs_info));
 
	return B_OK;
}
 
 
status_t
RootInode::_UpdateInfo(bool force)
{
	if (!force && fInfoCacheExpire > time(NULL))
		return B_OK;
 
	MutexLocker _(fInfoCacheLock);
 
	if (fInfoCacheExpire > time(NULL))
		return B_OK;
 
	uint32 attempt = 0;
	do {
		RPC::Server* server = fFileSystem->Server();
		Request request(server, fFileSystem);
		RequestBuilder& req = request.Builder();
 
		req.PutFH(fInfo.fHandle);
		Attribute attr[] = { FATTR4_FILES_FREE, FATTR4_FILES_TOTAL,
			FATTR4_MAXREAD, FATTR4_MAXWRITE, FATTR4_SPACE_FREE,
			FATTR4_SPACE_TOTAL };
		req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
 
		status_t result = request.Send();
		if (result != B_OK)
			return result;
 
		ReplyInterpreter& reply = request.Reply();
 
		if (HandleErrors(attempt, reply.NFS4Error(), server))
			continue;
 
		reply.PutFH();
 
		AttrValue* values;
		uint32 count, next = 0;
		result = reply.GetAttr(&values, &count);
		if (result != B_OK)
			return result;
 
		if (count >= next && values[next].fAttribute == FATTR4_FILES_FREE) {
			fInfoCache.free_nodes = values[next].fData.fValue64;
			next++;
		}
 
		if (count >= next && values[next].fAttribute == FATTR4_FILES_TOTAL) {
			fInfoCache.total_nodes = values[next].fData.fValue64;
			next++;
		}
 
		uint64 ioSize = LONGLONG_MAX;
		if (count >= next && values[next].fAttribute == FATTR4_MAXREAD) {
			ioSize = min_c(ioSize, values[next].fData.fValue64);
			next++;
		}
 
		if (count >= next && values[next].fAttribute == FATTR4_MAXWRITE) {
			ioSize = min_c(ioSize, values[next].fData.fValue64);
			next++;
		}
 
		if (ioSize == LONGLONG_MAX)
			ioSize = 32768;
		if (ioSize == 0)
			ioSize = 4096;
		fInfoCache.io_size = ioSize;
		fInfoCache.block_size = ioSize;
		fIOSize = ioSize;
 
		if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) {
			fInfoCache.free_blocks = values[next].fData.fValue64 / ioSize;
			next++;
		}
 
		if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) {
			fInfoCache.total_blocks = values[next].fData.fValue64 / ioSize;
			next++;
		}
 
		delete[] values;
 
		break;
	} while (true);
 
	fInfoCache.flags = 	B_FS_IS_PERSISTENT | B_FS_IS_SHARED
		| B_FS_SUPPORTS_NODE_MONITORING;
 
	if (fFileSystem->NamedAttrs()
		|| fFileSystem->GetConfiguration().fEmulateNamedAttrs)
		fInfoCache.flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR;
 
	strlcpy(fInfoCache.volume_name, fName, sizeof(fInfoCache.volume_name));
 
	fInfoCacheExpire = time(NULL) + MetadataCache::kExpirationTime;
 
	return B_OK;
}
 
 
bool
RootInode::ProbeMigration()
{
	uint32 attempt = 0;
	do {
		RPC::Server* server = fFileSystem->Server();
		Request request(server, fFileSystem);
		RequestBuilder& req = request.Builder();
 
		req.PutFH(fInfo.fHandle);
		req.Access();
 
		status_t result = request.Send();
		if (result != B_OK)
			continue;
 
		ReplyInterpreter& reply = request.Reply();
 
		if (reply.NFS4Error() == NFS4ERR_MOVED)
			return true;
 
		if (HandleErrors(attempt, reply.NFS4Error(), server))
			continue;
 
		return false;
	} while (true);
}
 
 
status_t
RootInode::GetLocations(AttrValue** attrv)
{
	ASSERT(attrv != NULL);
 
	uint32 attempt = 0;
	do {
		RPC::Server* server = fFileSystem->Server();
		Request request(server, fFileSystem);
		RequestBuilder& req = request.Builder();
 
		req.PutFH(fInfo.fHandle);
		Attribute attr[] = { FATTR4_FS_LOCATIONS };
		req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
 
		status_t result = request.Send();
		if (result != B_OK)
			return result;
 
		ReplyInterpreter& reply = request.Reply();
 
		if (HandleErrors(attempt, reply.NFS4Error(), server))
			continue;
 
		reply.PutFH();
 
		uint32 count;
		result = reply.GetAttr(attrv, &count);
		if (result != B_OK)
			return result;
		if (count < 1) {
			delete[] *attrv;
			return B_ERROR;
		}
 
		return B_OK;
	} while (true);
 
	return B_OK;
}
 
 
const char*
RootInode::Name() const
{
	ASSERT(fName != NULL);
	return fName;
}
 

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fInfoCache.