xref: /haiku/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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 
10 ShortDirectory::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 
20 ShortDirectory::~ShortDirectory()
21 {
22 }
23 
24 
25 uint8
26 ShortDirectory::GetFileType(ShortFormEntry* entry)
27 {
28 	ASSERT(fInode->HasFileTypeField() == true);
29 	return entry->name[entry->namelen];
30 }
31 
32 
33 ShortFormEntry*
34 ShortDirectory::FirstEntry()
35 {
36 	return (ShortFormEntry*) ((char*) fHeader + HeaderSize());
37 }
38 
39 
40 size_t
41 ShortDirectory::HeaderSize()
42 {
43 	if (fHeader->i8count)
44 		return sizeof(ShortFormHeader);
45 	else
46 		return sizeof(ShortFormHeader) - sizeof(uint32);
47 }
48 
49 
50 xfs_ino_t
51 ShortDirectory::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 
60 xfs_ino_t
61 ShortDirectory::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 
71 size_t
72 ShortDirectory::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 
80 status_t
81 ShortDirectory::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 
116 status_t
117 ShortDirectory::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