xref: /haiku/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp (revision 25f1ddecf7c81f9fd03fbd9463aa6566b8d01fc4)
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 
16 	fHeader = (ShortFormHeader*)(DIR_DFORK_PTR(fInode->Buffer()));
17 }
18 
19 
20 ShortDirectory::~ShortDirectory()
21 {
22 }
23 
24 
25 bool
26 ShortDirectory::HasFileTypeField()
27 {
28 	if (fInode->GetVolume()->SuperBlockFeatures2() & XFS_SB_VERSION2_FTYPE)
29 		return true;
30 	else
31 		return false;
32 }
33 
34 
35 uint8
36 ShortDirectory::GetFileType(ShortFormEntry* entry)
37 {
38 	ASSERT(HasFileTypeField() == true);
39 	return entry->name[entry->namelen];
40 }
41 
42 
43 ShortFormEntry*
44 ShortDirectory::FirstEntry()
45 {
46 	return (ShortFormEntry*) ((char*) fHeader + HeaderSize());
47 }
48 
49 
50 size_t
51 ShortDirectory::HeaderSize()
52 {
53 	if (fHeader->i8count)
54 		return sizeof(ShortFormHeader);
55 	else
56 		return sizeof(ShortFormHeader) - sizeof(uint32);
57 }
58 
59 
60 xfs_ino_t
61 ShortDirectory::GetIno(ShortFormInodeUnion* inum)
62 {
63 	if (fHeader->i8count)
64 		return B_BENDIAN_TO_HOST_INT64(inum->i8);
65 	else
66 		return B_BENDIAN_TO_HOST_INT32(inum->i4);
67 }
68 
69 
70 xfs_ino_t
71 ShortDirectory::GetEntryIno(ShortFormEntry* entry)
72 {
73 	if (HasFileTypeField())
74 		return GetIno((ShortFormInodeUnion*)(entry->name
75 				+ entry->namelen + sizeof(uint8)));
76 	else
77 		return GetIno((ShortFormInodeUnion*)(entry->name + entry->namelen));
78 }
79 
80 
81 size_t
82 ShortDirectory::EntrySize(int namelen)
83 {
84 	return sizeof(ShortFormEntry) + namelen
85 			+ (HasFileTypeField()? sizeof(uint8) : 0)
86 			+ (fHeader->i8count? sizeof(uint64):sizeof(uint32));
87 }
88 
89 
90 status_t
91 ShortDirectory::Lookup(const char* name, size_t length, xfs_ino_t* ino)
92 {
93 	TRACE("ShortDirectory::Lookup\n");
94 
95 	if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
96 		xfs_ino_t rootIno = fInode->GetVolume()->Root();
97 		if (strcmp(name, ".") == 0 || (rootIno == fInode->ID())) {
98 			*ino = fInode->ID();
99 			TRACE("ShortDirectory:Lookup: name: \".\" ino: (%d)\n", *ino);
100 			return B_OK;
101 		}
102 		*ino = GetIno(&fHeader->parent);
103 		TRACE("Parent: (%d)\n", *ino);
104 		return B_OK;
105 	}
106 
107 	ShortFormEntry* entry = FirstEntry();
108 	TRACE("Length of first entry: (%d),offset of first entry:"
109 		"(%d)\n", entry->namelen, B_BENDIAN_TO_HOST_INT16(entry->offset.i));
110 
111 	int status;
112 	for (int i = 0; i < fHeader->count; i++) {
113 		status = strncmp(name, (char*)entry->name, entry->namelen);
114 		if (status == 0) {
115 			*ino = GetEntryIno(entry);
116 			return B_OK;
117 		}
118 		entry = (ShortFormEntry*)
119 			((char*) entry + EntrySize(entry->namelen));
120 	}
121 
122 	return B_ENTRY_NOT_FOUND;
123 }
124 
125 
126 status_t
127 ShortDirectory::GetNext(char* name, size_t* length, xfs_ino_t* ino)
128 {
129 	if (fTrack == 0) {
130 		// Return '.'
131 		if (*length < 2)
132 			return B_BUFFER_OVERFLOW;
133 		*length = 2;
134 		strlcpy(name, ".", *length + 1);
135 		*ino = fInode->ID();
136 		fTrack = 1;
137 		TRACE("ShortDirectory:GetNext: name: \".\" ino: (%d)\n", *ino);
138 		return B_OK;
139 	}
140 	if (fTrack == 1) {
141 		// Return '..'
142 		if (*length < 3)
143 			return B_BUFFER_OVERFLOW;
144 		*length = 3;
145 		strlcpy(name, "..", *length + 1);
146 		*ino = GetIno(&fHeader->parent);
147 		fTrack = 2;
148 		TRACE("ShortDirectory:GetNext: name: \"..\" ino: (%d)\n", *ino);
149 		return B_OK;
150 	}
151 
152 	ShortFormEntry* entry = FirstEntry();
153 	TRACE("Length of first entry: (%d), offset of first entry:"
154 		"(%d)\n", entry->namelen, B_BENDIAN_TO_HOST_INT16(entry->offset.i));
155 
156 	for (int i = 0; i < fHeader->count; i++) {
157 		uint16 curOffset = B_BENDIAN_TO_HOST_INT16(entry->offset.i);
158 		if (curOffset > fLastEntryOffset) {
159 
160 			if (entry->namelen > *length)
161 				return B_BUFFER_OVERFLOW;
162 
163 			fLastEntryOffset = curOffset;
164 			memcpy(name, entry->name, entry->namelen);
165 			name[entry->namelen] = '\0';
166 			*length = entry->namelen + 1;
167 			*ino = GetEntryIno(entry);
168 
169 			TRACE("Entry found. Name: (%s), Length: (%ld),ino: (%ld)\n", name,
170 				*length, *ino);
171 			return B_OK;
172 		}
173 		entry = (ShortFormEntry*)((char*)entry + EntrySize(entry->namelen));
174 	}
175 
176 	return B_ENTRY_NOT_FOUND;
177 }
178