1/*
2 * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com
3 * All rights reserved. Distributed under the terms of the MIT License.
4 */
5
6
7#include "ShortDirectory.h"
8
9
10ShortDirectory::ShortDirectory(Inode* inode)
11	:
12	fInode(inode),
13	fTrack(0)
14{
15	fHeader = (ShortFormHeader*)(DIR_DFORK_PTR(fInode->Buffer(), fInode->CoreInodeSize()));
16	fLastEntryOffset = 0;
17}
18
19
20ShortDirectory::~ShortDirectory()
21{
22}
23
24
25uint8
26ShortDirectory::GetFileType(ShortFormEntry* entry)
27{
28	ASSERT(fInode->HasFileTypeField() == true);
29	return entry->name[entry->namelen];
30}
31
32
33ShortFormEntry*
34ShortDirectory::FirstEntry()
35{
36	return (ShortFormEntry*) ((char*) fHeader + HeaderSize());
37}
38
39
40size_t
41ShortDirectory::HeaderSize()
42{
43	if (fHeader->i8count)
44		return sizeof(ShortFormHeader);
45	else
46		return sizeof(ShortFormHeader) - sizeof(uint32);
47}
48
49
50xfs_ino_t
51ShortDirectory::GetIno(ShortFormInodeUnion* inum)
52{
53	if (fHeader->i8count)
54		return B_BENDIAN_TO_HOST_INT64(inum->i8);
55	else
56		return B_BENDIAN_TO_HOST_INT32(inum->i4);
57}
58
59
60xfs_ino_t
61ShortDirectory::GetEntryIno(ShortFormEntry* entry)
62{
63	if (fInode->HasFileTypeField())
64		return GetIno((ShortFormInodeUnion*)(entry->name
65				+ entry->namelen + sizeof(uint8)));
66	else
67		return GetIno((ShortFormInodeUnion*)(entry->name + entry->namelen));
68}
69
70
71size_t
72ShortDirectory::EntrySize(int namelen)
73{
74	return sizeof(ShortFormEntry) + namelen
75			+ (fInode->HasFileTypeField() ? sizeof(uint8) : 0)
76			+ (fHeader->i8count ? sizeof(uint64) : sizeof(uint32));
77}
78
79
80status_t
81ShortDirectory::Lookup(const char* name, size_t length, xfs_ino_t* ino)
82{
83	TRACE("ShortDirectory::Lookup\n");
84
85	if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
86		xfs_ino_t rootIno = fInode->GetVolume()->Root();
87		if (strcmp(name, ".") == 0 || (rootIno == fInode->ID())) {
88			*ino = fInode->ID();
89			TRACE("ShortDirectory:Lookup: name: \".\" ino: (%" B_PRIu64 ")\n", *ino);
90			return B_OK;
91		}
92		*ino = GetIno(&fHeader->parent);
93		TRACE("Parent: (%" B_PRIu64 ")\n", *ino);
94		return B_OK;
95	}
96
97	ShortFormEntry* entry = FirstEntry();
98	TRACE("Length of first entry: (%" B_PRIu8 "),offset of first entry:"
99		"(%" B_PRIu16 ")\n", entry->namelen, B_BENDIAN_TO_HOST_INT16(entry->offset.i));
100
101	int status;
102	for (int i = 0; i < fHeader->count; i++) {
103		status = strncmp(name, (char*)entry->name, entry->namelen);
104		if (status == 0) {
105			*ino = GetEntryIno(entry);
106			return B_OK;
107		}
108		entry = (ShortFormEntry*)
109			((char*) entry + EntrySize(entry->namelen));
110	}
111
112	return B_ENTRY_NOT_FOUND;
113}
114
115
116status_t
117ShortDirectory::GetNext(char* name, size_t* length, xfs_ino_t* ino)
118{
119	if (fTrack == 0) {
120		// Return '.'
121		if (*length < 2)
122			return B_BUFFER_OVERFLOW;
123		*length = 2;
124		strlcpy(name, ".", *length + 1);
125		*ino = fInode->ID();
126		fTrack = 1;
127		TRACE("ShortDirectory:GetNext: name: \".\" ino: (%" B_PRIu64 ")\n", *ino);
128		return B_OK;
129	}
130	if (fTrack == 1) {
131		// Return '..'
132		if (*length < 3)
133			return B_BUFFER_OVERFLOW;
134		*length = 3;
135		strlcpy(name, "..", *length + 1);
136		*ino = GetIno(&fHeader->parent);
137		fTrack = 2;
138		TRACE("ShortDirectory:GetNext: name: \"..\" ino: (%" B_PRIu64 ")\n", *ino);
139		return B_OK;
140	}
141
142	ShortFormEntry* entry = FirstEntry();
143	TRACE("Length of first entry: (%" B_PRIu8 "),offset of first entry:"
144		"(%" B_PRIu16 ")\n", entry->namelen, B_BENDIAN_TO_HOST_INT16(entry->offset.i));
145
146	for (int i = 0; i < fHeader->count; i++) {
147		uint16 curOffset = B_BENDIAN_TO_HOST_INT16(entry->offset.i);
148		if (curOffset > fLastEntryOffset) {
149
150			if ((size_t)(entry->namelen + 1) > *length)
151				return B_BUFFER_OVERFLOW;
152
153			fLastEntryOffset = curOffset;
154			memcpy(name, entry->name, entry->namelen);
155			name[entry->namelen] = '\0';
156			*length = entry->namelen + 1;
157			*ino = GetEntryIno(entry);
158			TRACE("Entry found. Name: (%s), Length: (%" B_PRIuSIZE "),ino: (%" B_PRIu64 ")\n",
159				name,*length, *ino);
160			return B_OK;
161		}
162		entry = (ShortFormEntry*)((char*)entry + EntrySize(entry->namelen));
163	}
164
165	return B_ENTRY_NOT_FOUND;
166}
167