1/*
2 * 	Copyright 2008, Salvatore Benedetto, salvatore.benedetto@gmail.com
3 * 	Copyright 2003, Tyler Dauwalder, tyler@dauwalder.net
4 * 	Copyright 2002-2020, Axel D��rfler, axeld@pinc-software.de
5 * 	Distributed under the terms of the MIT License.
6 */
7#ifndef _UDF_CACHED_BLOCK_H
8#define _UDF_CACHED_BLOCK_H
9
10/*! \file CachedBlock.h
11
12	Based on the CachedBlock class from BFS, written by
13	Axel D��rfler, axeld@pinc-software.de
14*/
15
16#include <fs_cache.h>
17#include <util/kernel_cpp.h>
18
19#include "UdfDebug.h"
20#include "UdfStructures.h"
21#include "Volume.h"
22
23
24class CachedBlock {
25public:
26								CachedBlock(Volume *volume);
27								CachedBlock(CachedBlock *cached);
28								~CachedBlock();
29
30	uint8						*Block() const { return fBlock; }
31	off_t						BlockNumber() const { return fBlockNumber; }
32	uint32						BlockSize() const { return fVolume->BlockSize(); }
33	uint32						BlockShift() const { return fVolume->BlockShift(); }
34
35	inline void					Keep();
36	inline void					Unset();
37
38	inline status_t				SetTo(off_t block);
39	inline status_t				SetTo(off_t block, off_t base, size_t length);
40	inline status_t				SetTo(long_address address);
41	template <class Accessor, class Descriptor>
42	inline status_t				SetTo(Accessor &accessor,
43									Descriptor &descriptor);
44
45protected:
46	uint8						*fBlock;
47	off_t						fBlockNumber;
48	Volume						*fVolume;
49};
50
51
52inline
53CachedBlock::CachedBlock(Volume *volume)
54	:
55	fBlock(NULL),
56	fBlockNumber(0),
57	fVolume(volume)
58{
59}
60
61
62inline
63CachedBlock::CachedBlock(CachedBlock *cached)
64	:
65	fBlock(cached->fBlock),
66	fBlockNumber(cached->BlockNumber()),
67	fVolume(cached->fVolume)
68{
69	cached->Keep();
70}
71
72
73inline
74CachedBlock::~CachedBlock()
75{
76	Unset();
77}
78
79
80inline void
81CachedBlock::Keep()
82{
83	fBlock = NULL;
84}
85
86
87inline void
88CachedBlock::Unset()
89{
90	if (fBlock != NULL) {
91		block_cache_put(fVolume->BlockCache(), fBlockNumber);
92		fBlock = NULL;
93	}
94}
95
96
97inline status_t
98CachedBlock::SetTo(off_t block)
99{
100	return SetTo(block, block, 1);
101}
102
103
104inline status_t
105CachedBlock::SetTo(off_t block, off_t base, size_t length)
106{
107	Unset();
108	fBlockNumber = block;
109	return block_cache_get_etc(fVolume->BlockCache(), block, base, length,
110		(const void**)&fBlock);
111}
112
113
114inline status_t
115CachedBlock::SetTo(long_address address)
116{
117	off_t block;
118	if (fVolume->MapBlock(address, &block) == B_OK)
119		return SetTo(block, block, 1);
120
121	return B_BAD_VALUE;
122}
123
124
125template <class Accessor, class Descriptor>
126inline status_t
127CachedBlock::SetTo(Accessor &accessor, Descriptor &descriptor)
128{
129	// Make a long_address out of the descriptor and call it a day
130	long_address address;
131	address.set_to(accessor.GetBlock(descriptor),
132		accessor.GetPartition(descriptor));
133    return SetTo(address);
134}
135
136
137#endif	// _UDF_CACHED_BLOCK_H
138