1/*
2 * Copyright 2012, J��r��me Duval, korli@users.berlios.de.
3 * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@gmail.com.
4 * Copyright 2003, Tyler Dauwalder, tyler@dauwalder.net.
5 * Distributed under the terms of the MIT License.
6 */
7#ifndef _UDF_ICB_H
8#define _UDF_ICB_H
9
10/*! \file Icb.h */
11
12#include "UdfStructures.h"
13
14#include <util/kernel_cpp.h>
15#include <util/SinglyLinkedList.h>
16
17#include "CachedBlock.h"
18
19class DirectoryIterator;
20class Icb;
21class Volume;
22
23/*! \brief Abstract interface to file entry structure members
24	that are not commonly accessible through file_icb_entry().
25
26	This is necessary, since we can't use virtual functions in
27	the disk structure structs themselves, since we generally
28	don't create disk structure objects by calling new, but
29	rather just cast a chunk of memory read off disk to be
30	a pointer to the struct of interest (which works fine
31	for regular functions, but fails miserably for virtuals
32	due to the vtable not being setup properly).
33*/
34class AbstractFileEntry {
35public:
36	virtual uint8* 		AllocationDescriptors() = 0;
37	virtual uint32		AllocationDescriptorsLength() = 0;
38};
39
40
41template <class Descriptor>
42class FileEntry : public AbstractFileEntry {
43public:
44								FileEntry(CachedBlock *descriptorBlock = NULL);
45	void						SetTo(CachedBlock *descriptorBlock);
46	virtual uint8*				AllocationDescriptors();
47	virtual uint32				AllocationDescriptorsLength();
48
49private:
50	Descriptor					*_Descriptor();
51	CachedBlock					*fDescriptorBlock;
52};
53
54
55class DirectoryIterator : public SinglyLinkedListLinkImpl<DirectoryIterator> {
56public:
57
58	status_t						GetNextEntry(char *name, uint32 *length,
59										ino_t *id);
60
61	Icb								*Parent() { return fParent; }
62	const Icb						*Parent() const { return fParent; }
63
64	void							Rewind();
65
66private:
67friend class 						Icb;
68
69	/* The following is called by Icb::GetDirectoryIterator() */
70									DirectoryIterator(Icb *parent);
71	/* The following is called by Icb::~Icb() */
72	void							_Invalidate() { fParent = NULL; }
73
74	bool							fAtBeginning;
75	Icb								*fParent;
76	off_t							fPosition;
77};
78
79
80class Icb {
81public:
82								Icb(Volume *volume, long_address address);
83								~Icb();
84
85	status_t					InitCheck();
86	ino_t						Id() { return fId; }
87
88	// categorization
89	uint8						Type() { return _IcbTag().file_type(); }
90	bool						IsFile() { return Type() == ICB_TYPE_REGULAR_FILE; }
91	bool						IsDirectory() { return (Type() == ICB_TYPE_DIRECTORY
92									|| Type() == ICB_TYPE_STREAM_DIRECTORY); }
93
94	uint32						Uid() { return _FileEntry()->uid(); }
95	uint32						Gid() { return 0; }
96	uint16						FileLinkCount() { return _FileEntry()->file_link_count(); }
97	uint64						Length() { return _FileEntry()->information_length(); }
98	mode_t						Mode() { return (IsDirectory() ? S_IFDIR : S_IFREG)
99									| S_IRUSR | S_IRGRP | S_IROTH; }
100	void 						GetAccessTime(struct timespec &timespec) const;
101	void 						GetModificationTime(struct timespec &timespec) const;
102
103	uint8						*AllocationDescriptors()
104									{ return _AbstractEntry()->AllocationDescriptors(); }
105	uint32						AllocationDescriptorsSize()
106									{ return _AbstractEntry()->AllocationDescriptorsLength(); }
107
108	status_t					FindBlock(uint32 logicalBlock, off_t &block,
109									bool &recorded);
110	status_t					Read(off_t pos, void *buffer, size_t *length,
111									uint32 *block = NULL);
112
113	void *						FileCache() { return fFileCache; }
114	void *						FileMap() { return fFileMap; }
115
116	status_t					GetFileMap(off_t offset, size_t size,
117									struct file_io_vec *vecs, size_t *count);
118
119	// for directories only
120	status_t					GetDirectoryIterator(DirectoryIterator **iterator);
121	status_t					Find(const char *filename, ino_t *id);
122
123	Volume						*GetVolume() const { return fVolume; }
124
125private:
126	AbstractFileEntry			*_AbstractEntry() const { return (_Tag().id()
127									== TAGID_EXTENDED_FILE_ENTRY)
128									? (AbstractFileEntry *)&fExtendedEntry
129									: (AbstractFileEntry *)&fFileEntry; }
130
131	descriptor_tag				&_Tag() const { return ((icb_header *)fData.Block())->tag(); }
132	icb_entry_tag				&_IcbTag() const { return ((icb_header *)fData.Block())->icb_tag(); }
133	file_icb_entry				*_FileEntry() const
134		{ return (file_icb_entry *)fData.Block(); }
135	extended_file_icb_entry		*_ExtendedEntry() const
136		{ return (extended_file_icb_entry *)fData.Block(); }
137
138	template<class DescriptorList>
139	status_t					_GetFileMap(DescriptorList &list, off_t offset,
140									size_t size, struct file_io_vec *vecs,
141									size_t *count);
142	template<class DescriptorList>
143	status_t					_Read(DescriptorList &list, off_t pos,
144									void *buffer, size_t *length, uint32 *block);
145
146	Volume						*fVolume;
147	CachedBlock					fData;
148	status_t					fInitStatus;
149	ino_t						fId;
150	SinglyLinkedList<DirectoryIterator>		fIteratorList;
151	uint16						fPartition;
152	FileEntry<file_icb_entry> 				fFileEntry;
153	FileEntry<extended_file_icb_entry>		fExtendedEntry;
154	void *						fFileCache;
155	void *						fFileMap;
156};
157
158
159template <class Descriptor>
160FileEntry<Descriptor>::FileEntry(CachedBlock *descriptorBlock)
161	: fDescriptorBlock(descriptorBlock)
162{
163}
164
165
166template <class Descriptor>
167void
168FileEntry<Descriptor>::SetTo(CachedBlock *descriptorBlock)
169{
170	fDescriptorBlock = descriptorBlock;
171}
172
173
174template <class Descriptor>
175uint8*
176FileEntry<Descriptor>::AllocationDescriptors()
177{
178	Descriptor* descriptor = _Descriptor();
179	return descriptor ? descriptor->allocation_descriptors() : NULL;
180}
181
182
183template <class Descriptor>
184uint32
185FileEntry<Descriptor>::AllocationDescriptorsLength()
186{
187	Descriptor* descriptor = _Descriptor();
188	return descriptor ? descriptor->allocation_descriptors_length() : 0;
189}
190
191
192template <class Descriptor>
193Descriptor*
194FileEntry<Descriptor>::_Descriptor()
195{
196	return fDescriptorBlock
197		? (Descriptor *)fDescriptorBlock->Block() : NULL;
198}
199
200#endif	// _UDF_ICB_H
201