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