xref: /haiku/src/add-ons/kernel/file_systems/udf/Icb.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
1 //----------------------------------------------------------------------
2 //  This software is part of the Haiku distribution and is covered
3 //  by the MIT 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 "Utils.h"
13 #include "Volume.h"
14 
15 
16 status_t
17 DirectoryIterator::GetNextEntry(char *name, uint32 *length, ino_t *id)
18 {
19 	if (!id || !name || !length)
20 		return B_BAD_VALUE;
21 
22 	TRACE(("DirectoryIterator::GetNextEntry: name = %s, length = %ld, "
23 		"id = %p, position = %Ld, parent length = %Ld\n", name, *length, id,
24 		fPosition, Parent()->Length()));
25 
26 	status_t status = B_OK;
27 	if (fAtBeginning) {
28 		TRACE(("DirectoryIterator::GetNextEntry: .\n"));
29 		sprintf(name, ".");
30 		*length = 2;
31 		*id = Parent()->Id();
32 		fAtBeginning = false;
33 	} else {
34 		if (uint64(fPosition) >= Parent()->Length())
35 			return B_ENTRY_NOT_FOUND;
36 
37 		uint8 data[kMaxFileIdSize];
38 		file_id_descriptor *entry = (file_id_descriptor *)data;
39 
40 		uint32 block = 0;
41 		off_t offset = fPosition;
42 
43 		size_t entryLength = kMaxFileIdSize;
44 		// First read in the static portion of the file id descriptor,
45 		// then, based on the information therein, read in the variable
46 		// length tail portion as well.
47 		status = Parent()->Read(offset, entry, &entryLength, &block);
48 		if (!status && entryLength >= sizeof(file_id_descriptor)
49 			&& entry->tag().init_check(block) == B_OK) {
50 			PDUMP(entry);
51 			offset += entry->total_length();
52 
53 			if (entry->is_parent()) {
54 				TRACE(("DirectoryIterator::GetNextEntry: ..\n"));
55 				sprintf(name, "..");
56 				*length = 3;
57 			} else {
58 				UdfString string(entry->id(), entry->id_length());
59 				TRACE(("DirectoryIterator::GetNextEntry: UfdString id == `%s', "
60 				"length = %lu\n", string.Utf8(), string.Utf8Length()));
61 				DUMP(entry->icb());
62 				sprintf(name, "%s", string.Utf8());
63 				*length = string.Utf8Length();
64 			}
65 			*id = to_vnode_id(entry->icb());
66 		}
67 
68 		if (!status)
69 			fPosition = offset;
70 	}
71 
72  	return status;
73 }
74 
75 
76 /*	\brief Rewinds the iterator to point to the first entry in the directory. */
77 void
78 DirectoryIterator::Rewind()
79 {
80 	fAtBeginning = true;
81 	fPosition = 0;
82 }
83 
84 
85 //	#pragma - Private methods
86 
87 
88 DirectoryIterator::DirectoryIterator(Icb *parent)
89 	:
90 	fAtBeginning(true),
91 	fParent(parent),
92 	fPosition(0)
93 {
94 }
95 
96 Icb::Icb(Volume *volume, long_address address)
97 	:
98 	fVolume(volume),
99 	fData(volume),
100 	fInitStatus(B_NO_INIT),
101 	fId(to_vnode_id(address)),
102 	fFileEntry(&fData),
103 	fExtendedEntry(&fData)
104 {
105 	TRACE(("Icb::Icb: volume = %p, address(block = %ld, partition = %d, "
106 		"length = %ld)\n", volume, address.block(), address.partition(),
107 		address.length()));
108 
109 	if (volume == NULL)
110 		fInitStatus = B_BAD_VALUE;
111 
112 	off_t block;
113 	status_t status = fVolume->MapBlock(address, &block);
114 	if (!status) {
115 		icb_header *header = (icb_header *)fData.SetTo(block);
116 		if (header->tag().id() == TAGID_FILE_ENTRY) {
117 			file_icb_entry *entry = (file_icb_entry *)header;
118 			PDUMP(entry);
119 			(void)entry;	// warning death
120 		} else if (header->tag().id() == TAGID_EXTENDED_FILE_ENTRY) {
121 			extended_file_icb_entry *entry = (extended_file_icb_entry *)header;
122 			PDUMP(entry);
123 			(void)entry;	// warning death
124 		} else {
125 			PDUMP(header);
126 		}
127 		status = header->tag().init_check(address.block());
128 	}
129 
130 	fInitStatus = status;
131 	TRACE(("Icb::Icb: status = 0x%lx, `%s'\n", status, strerror(status)));
132 }
133 
134 
135 status_t
136 Icb::GetDirectoryIterator(DirectoryIterator **iterator)
137 {
138 	status_t error = iterator ? B_OK : B_BAD_VALUE;
139 
140 	if (!error) {
141 		*iterator = new(std::nothrow) DirectoryIterator(this);
142 		if (*iterator)
143 		 	fIteratorList.Add(*iterator);
144 		else
145 			error = B_NO_MEMORY;
146 	}
147 
148 	return error;
149 }
150 
151 
152 status_t
153 Icb::InitCheck()
154 {
155 	return fInitStatus;
156 }
157 
158 
159 time_t
160 Icb::AccessTime()
161 {
162 	return make_time(_FileEntry()->access_date_and_time());
163 }
164 
165 
166 time_t
167 Icb::ModificationTime()
168 {
169 	return make_time(_FileEntry()->modification_date_and_time());
170 }
171 
172 
173 status_t
174 Icb::Read(off_t pos, void *buffer, size_t *length, uint32 *block)
175 {
176 	TRACE(("Icb::Read: pos = %Ld, buffer = %p, length = (%p)->%ld\n",
177 		pos, buffer, length, (length ? *length : 0)));
178 
179 	if (!buffer || !length || pos < 0)
180 		return B_BAD_VALUE;
181 
182 	if (uint64(pos) >= Length()) {
183 		*length = 0;
184 		return B_OK;
185 	}
186 
187 	switch (_IcbTag().descriptor_flags()) {
188 		case ICB_DESCRIPTOR_TYPE_SHORT: {
189 			TRACE(("Icb::Read: descriptor type -> short\n"));
190 			AllocationDescriptorList<ShortDescriptorAccessor> list(this, ShortDescriptorAccessor(0));
191 			RETURN(_Read(list, pos, buffer, length, block));
192 			break;
193 		}
194 
195 		case ICB_DESCRIPTOR_TYPE_LONG: {
196 			TRACE(("Icb::Read: descriptor type -> long\n"));
197 			AllocationDescriptorList<LongDescriptorAccessor> list(this);
198 			RETURN(_Read(list, pos, buffer, length, block));
199 			break;
200 		}
201 
202 		case ICB_DESCRIPTOR_TYPE_EXTENDED: {
203 			TRACE(("Icb::Read: descriptor type -> extended\n"));
204 //			AllocationDescriptorList<ExtendedDescriptorAccessor> list(this, ExtendedDescriptorAccessor(0));
205 //			RETURN(_Read(list, pos, buffer, length, block));
206 			RETURN(B_ERROR);
207 			break;
208 		}
209 
210 		case ICB_DESCRIPTOR_TYPE_EMBEDDED: {
211 			TRACE(("Icb::Read: descriptor type: embedded\n"));
212 			RETURN(B_ERROR);
213 			break;
214 		}
215 
216 		default:
217 			TRACE(("Icb::Read: invalid icb descriptor flags! (flags = %d)\n",
218 				_IcbTag().descriptor_flags()));
219 			RETURN(B_BAD_VALUE);
220 			break;
221 	}
222 }
223 
224 
225 status_t
226 Icb::Find(const char *filename, ino_t *id)
227 {
228 	TRACE(("Icb::Find: filename = `%s', id = %p\n", filename, id));
229 
230 	if (!filename || !id)
231 		RETURN(B_BAD_VALUE);
232 
233 	DirectoryIterator *i;
234 	status_t status = GetDirectoryIterator(&i);
235 	if (status != B_OK)
236 		return status;
237 
238 	ino_t entryId;
239 	uint32 length = B_FILE_NAME_LENGTH;
240 	char name[B_FILE_NAME_LENGTH];
241 
242 	bool foundIt = false;
243 	while (i->GetNextEntry(name, &length, &entryId) == B_OK) {
244     	if (strcmp(filename, name) == 0) {
245     		foundIt = true;
246     		break;
247     	}
248 	}
249 
250 	if (foundIt)
251 		*id = entryId;
252 	else
253 		status = B_ENTRY_NOT_FOUND;
254 
255 	return status;
256 }
257