1 /* 2 * Copyright 2003-2013, 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 14 #include <string.h> 15 #include <unistd.h> 16 17 18 // temp. private VFS API 19 extern Node *get_node_from(int fd); 20 21 22 namespace BFS { 23 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(nothrow) 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) 174 == B_OK) { 175 if (fStream.Mode() & (S_ATTR_DIR | S_INDEX_DIR)) 176 return false; 177 178 if (++count > 2 || (strcmp(".", name) && strcmp("..", name))) 179 return false; 180 } 181 return true; 182 } 183 184 185 status_t 186 Directory::GetName(char *name, size_t size) const 187 { 188 if (fStream.inode_num == fStream.GetVolume().Root()) { 189 strlcpy(name, fStream.GetVolume().SuperBlock().name, size); 190 return B_OK; 191 } 192 193 return fStream.GetName(name, size); 194 } 195 196 197 ino_t 198 Directory::Inode() const 199 { 200 return fStream.ID(); 201 } 202 203 204 } // namespace BFS 205