1//----------------------------------------------------------------------
2//  This software is part of the OpenBeOS distribution and is covered
3//  by the OpenBeOS license.
4//
5//  Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
6//---------------------------------------------------------------------
7#include "Icb.h"
8
9#include "time.h"
10
11#include "AllocationDescriptorList.h"
12#include "DirectoryIterator.h"
13#include "Utils.h"
14#include "Volume.h"
15
16using namespace Udf;
17
18Icb::Icb(Volume *volume, long_address address)
19	: fVolume(volume)
20	, fData(volume)
21	, fInitStatus(B_NO_INIT)
22	, fId(to_vnode_id(address))
23	, fFileEntry(&fData)
24	, fExtendedEntry(&fData)
25{
26	DEBUG_INIT_ETC("Icb", ("volume: %p, address(block: %ld, "
27	               "partition: %d, length: %ld)", volume, address.block(),
28	               address.partition(), address.length()));
29	status_t error = volume ? B_OK : B_BAD_VALUE;
30	if (!error) {
31		off_t block;
32		error = fVolume->MapBlock(address, &block);
33		if (!error) {
34			icb_header *header = reinterpret_cast<icb_header*>(fData.SetTo(block));
35			if (header->tag().id() == TAGID_FILE_ENTRY) {
36				file_icb_entry *entry = reinterpret_cast<file_icb_entry*>(header);
37				PDUMP(entry);
38				(void)entry;	// warning death
39			} else if (header->tag().id() == TAGID_EXTENDED_FILE_ENTRY) {
40				extended_file_icb_entry *entry = reinterpret_cast<extended_file_icb_entry*>(header);
41				PDUMP(entry);
42				(void)entry;	// warning death
43			} else {
44				PDUMP(header);
45			}
46			error = header->tag().init_check(address.block());
47		}
48	}
49	fInitStatus = error;
50	PRINT(("result: 0x%lx, `%s'\n", error, strerror(error)));
51}
52
53status_t
54Icb::InitCheck()
55{
56	return fInitStatus;
57}
58
59time_t
60Icb::AccessTime()
61{
62	return make_time(FileEntry()->access_date_and_time());
63}
64
65time_t
66Icb::ModificationTime()
67{
68	return make_time(FileEntry()->modification_date_and_time());
69}
70
71status_t
72Icb::Read(off_t pos, void *buffer, size_t *length, uint32 *block)
73{
74	DEBUG_INIT_ETC("Icb",
75	               ("pos: %Ld, buffer: %p, length: (%p)->%ld", pos, buffer, length, (length ? *length : 0)));
76
77	if (!buffer || !length || pos < 0)
78		RETURN(B_BAD_VALUE);
79
80	if (uint64(pos) >= Length()) {
81		*length = 0;
82		return B_OK;
83	}
84
85	switch (IcbTag().descriptor_flags()) {
86		case ICB_DESCRIPTOR_TYPE_SHORT: {
87			PRINT(("descriptor type: short\n"));
88			AllocationDescriptorList<ShortDescriptorAccessor> list(this, ShortDescriptorAccessor(0));
89			RETURN(_Read(list, pos, buffer, length, block));
90			break;
91		}
92
93		case ICB_DESCRIPTOR_TYPE_LONG: {
94			PRINT(("descriptor type: long\n"));
95			AllocationDescriptorList<LongDescriptorAccessor> list(this);
96			RETURN(_Read(list, pos, buffer, length, block));
97			break;
98		}
99
100		case ICB_DESCRIPTOR_TYPE_EXTENDED: {
101			PRINT(("descriptor type: extended\n"));
102//			AllocationDescriptorList<ExtendedDescriptorAccessor> list(this, ExtendedDescriptorAccessor(0));
103//			RETURN(_Read(list, pos, buffer, length, block));
104			RETURN(B_ERROR);
105			break;
106		}
107
108		case ICB_DESCRIPTOR_TYPE_EMBEDDED: {
109			PRINT(("descriptor type: embedded\n"));
110			RETURN(B_ERROR);
111			break;
112		}
113
114		default:
115			PRINT(("Invalid icb descriptor flags! (flags = %d)\n", IcbTag().descriptor_flags()));
116			RETURN(B_BAD_VALUE);
117			break;
118	}
119}
120
121status_t
122Icb::GetDirectoryIterator(DirectoryIterator **iterator)
123{
124	status_t error = iterator ? B_OK : B_BAD_VALUE;
125
126	if (!error) {
127		*iterator = new(nothrow) DirectoryIterator(this);
128		if (*iterator) {
129			error = fIteratorList.PushBack(*iterator);
130		} else {
131			error = B_NO_MEMORY;
132		}
133	}
134
135	return error;
136}
137
138status_t
139Icb::Find(const char *filename, vnode_id *id)
140{
141	DEBUG_INIT_ETC("Icb",
142	               ("filename: `%s', id: %p", filename, id));
143
144	if (!filename || !id)
145		RETURN(B_BAD_VALUE);
146
147	DirectoryIterator *i;
148	status_t error = GetDirectoryIterator(&i);
149	if (!error) {
150		vnode_id entryId;
151		uint32 length = B_FILE_NAME_LENGTH;
152		char name[B_FILE_NAME_LENGTH];
153
154		bool foundIt = false;
155		while (i->GetNextEntry(name, &length, &entryId) == B_OK)
156		{
157	    	if (strcmp(filename, name) == 0) {
158	    		foundIt = true;
159	    		break;
160	    	}
161		}
162
163		if (foundIt) {
164			*id = entryId;
165		} else {
166			error = B_ENTRY_NOT_FOUND;
167		}
168	}
169
170	RETURN(error);
171}
172