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 20 extern Node *get_node_from(int fd); 21 22 23 namespace BFS { 24 25 26 Directory::Directory(Volume &volume, block_run run) 27 : 28 fStream(volume, run), 29 fTree(&fStream) 30 { 31 } 32 33 34 Directory::Directory(Volume &volume, off_t id) 35 : 36 fStream(volume, id), 37 fTree(&fStream) 38 { 39 } 40 41 42 Directory::Directory(const Stream &stream) 43 : 44 fStream(stream), 45 fTree(&fStream) 46 { 47 } 48 49 50 Directory::~Directory() 51 { 52 } 53 54 55 status_t 56 Directory::InitCheck() 57 { 58 return fStream.InitCheck(); 59 } 60 61 62 status_t 63 Directory::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 75 status_t 76 Directory::Close(void *cookie) 77 { 78 _inherited::Close(cookie); 79 80 delete (TreeIterator *)cookie; 81 return B_OK; 82 } 83 84 85 Node * 86 Directory::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 121 status_t 122 Directory::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 132 status_t 133 Directory::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 152 status_t 153 Directory::Rewind(void *cookie) 154 { 155 TreeIterator *iterator = (TreeIterator *)cookie; 156 157 return iterator->Rewind(); 158 } 159 160 161 bool 162 Directory::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 186 status_t 187 Directory::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 198 ino_t 199 Directory::Inode() const 200 { 201 return fStream.ID(); 202 } 203 204 205 } // namespace BFS 206