1/* 2 * Copyright 2003-2010, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include "Directory.h" 8#include "File.h" 9#include "Link.h" 10 11#include <StorageDefs.h> 12#include <KernelExport.h> 13#include <util/kernel_cpp.h> 14 15#include <string.h> 16#include <unistd.h> 17 18 19// temp. private VFS API 20extern Node *get_node_from(int fd); 21 22 23namespace BFS { 24 25 26Directory::Directory(Volume &volume, block_run run) 27 : 28 fStream(volume, run), 29 fTree(&fStream) 30{ 31} 32 33 34Directory::Directory(Volume &volume, off_t id) 35 : 36 fStream(volume, id), 37 fTree(&fStream) 38{ 39} 40 41 42Directory::Directory(const Stream &stream) 43 : 44 fStream(stream), 45 fTree(&fStream) 46{ 47} 48 49 50Directory::~Directory() 51{ 52} 53 54 55status_t 56Directory::InitCheck() 57{ 58 return fStream.InitCheck(); 59} 60 61 62status_t 63Directory::Open(void **_cookie, int mode) 64{ 65 _inherited::Open(_cookie, mode); 66 67 *_cookie = (void *)new(nothrow) TreeIterator(&fTree); 68 if (*_cookie == NULL) 69 return B_NO_MEMORY; 70 71 return B_OK; 72} 73 74 75status_t 76Directory::Close(void *cookie) 77{ 78 _inherited::Close(cookie); 79 80 delete (TreeIterator *)cookie; 81 return B_OK; 82} 83 84 85Node * 86Directory::Lookup(const char *name, bool traverseLinks) 87{ 88 off_t id; 89 if (fTree.Find((uint8 *)name, strlen(name), &id) < B_OK) 90 return NULL; 91 92 Node *node = Stream::NodeFactory(fStream.GetVolume(), id); 93 if (!node) 94 return NULL; 95 96 if (S_ISLNK(node->Type())) { 97 // the node is a symbolic link, so we have to resolve the path 98 char linkPath[B_PATH_NAME_LENGTH]; 99 ((Link *)node)->ReadLink(linkPath, sizeof(linkPath)); 100 101 delete node; 102 // we don't need this one anymore 103 104 int fd = open_from(this, linkPath, O_RDONLY); 105 if (fd >= 0) { 106 node = get_node_from(fd); 107 if (node != NULL) 108 node->Acquire(); 109 110 close(fd); 111 return node; 112 } 113 114 return NULL; 115 } 116 117 return node; 118} 119 120 121status_t 122Directory::GetNextEntry(void *cookie, char *name, size_t size) 123{ 124 TreeIterator *iterator = (TreeIterator *)cookie; 125 uint16 length; 126 off_t id; 127 128 return iterator->GetNextEntry(name, &length, size, &id); 129} 130 131 132status_t 133Directory::GetNextNode(void *cookie, Node **_node) 134{ 135 TreeIterator *iterator = (TreeIterator *)cookie; 136 char name[B_FILE_NAME_LENGTH]; 137 uint16 length; 138 off_t id; 139 140 status_t status = iterator->GetNextEntry(name, &length, sizeof(name), &id); 141 if (status != B_OK) 142 return status; 143 144 *_node = Stream::NodeFactory(fStream.GetVolume(), id); 145 if (*_node == NULL) 146 return B_ERROR; 147 148 return B_OK; 149} 150 151 152status_t 153Directory::Rewind(void *cookie) 154{ 155 TreeIterator *iterator = (TreeIterator *)cookie; 156 157 return iterator->Rewind(); 158} 159 160 161bool 162Directory::IsEmpty() 163{ 164 TreeIterator iterator(&fTree); 165 166 // index and attribute directories are really empty when they are 167 // empty - directories for standard files always contain ".", and 168 // "..", so we need to ignore those two 169 170 uint32 count = 0; 171 char name[BPLUSTREE_MAX_KEY_LENGTH]; 172 uint16 length; 173 off_t id; 174 while (iterator.GetNextEntry(name, &length, B_FILE_NAME_LENGTH, &id) 175 == B_OK) { 176 if (fStream.Mode() & (S_ATTR_DIR | S_INDEX_DIR)) 177 return false; 178 179 if (++count > 2 || (strcmp(".", name) && strcmp("..", name))) 180 return false; 181 } 182 return true; 183} 184 185 186status_t 187Directory::GetName(char *name, size_t size) const 188{ 189 if (fStream.inode_num == fStream.GetVolume().Root()) { 190 strlcpy(name, fStream.GetVolume().SuperBlock().name, size); 191 return B_OK; 192 } 193 194 return fStream.GetName(name, size); 195} 196 197 198ino_t 199Directory::Inode() const 200{ 201 return fStream.ID(); 202} 203 204 205} // namespace BFS 206