vrfileman

annotate src/fs.cc @ 6:b041bc1c38ad

layout
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 03 Feb 2015 15:42:03 +0200
parents d487181ee1d9
children
rev   line source
nuclear@1 1 #include <stdio.h>
nuclear@1 2 #include <string.h>
nuclear@1 3 #include <ctype.h>
nuclear@1 4 #include <errno.h>
nuclear@2 5 #include <algorithm>
nuclear@1 6 #include <alloca.h>
nuclear@1 7 #include <unistd.h>
nuclear@1 8 #include <dirent.h>
nuclear@2 9 #include <sys/stat.h>
nuclear@1 10 #include "fs.h"
nuclear@1 11
nuclear@2 12 static bool childcmpless(const FSNode *aptr, const FSNode *bptr);
nuclear@1 13 static char *clean_path(char *path);
nuclear@1 14 static char *filename(char *path);
nuclear@2 15 static FSNode::Type st_mode_to_type(mode_t mode);
nuclear@1 16
nuclear@1 17 FSNode::FSNode()
nuclear@1 18 {
nuclear@1 19 init();
nuclear@1 20 }
nuclear@1 21
nuclear@1 22 FSNode::~FSNode()
nuclear@1 23 {
nuclear@1 24 destroy();
nuclear@1 25 }
nuclear@1 26
nuclear@1 27 void FSNode::init()
nuclear@1 28 {
nuclear@1 29 path = name = 0;
nuclear@1 30 parent = 0;
nuclear@1 31 expanded = false;
nuclear@2 32 sorted = true;
nuclear@1 33 uid = gid = mode = 0;
nuclear@2 34 type = UNKNOWN;
nuclear@1 35 }
nuclear@1 36
nuclear@1 37 void FSNode::destroy()
nuclear@1 38 {
nuclear@1 39 delete [] path;
nuclear@1 40 children.clear();
nuclear@1 41 init();
nuclear@1 42 }
nuclear@1 43
nuclear@1 44 void FSNode::destroy_tree()
nuclear@1 45 {
nuclear@1 46 for(size_t i=0; i<children.size(); i++) {
nuclear@1 47 children[i]->destroy_tree();
nuclear@1 48 delete children[i];
nuclear@1 49 }
nuclear@1 50 destroy();
nuclear@1 51 }
nuclear@1 52
nuclear@2 53 void FSNode::set_type(Type type)
nuclear@2 54 {
nuclear@2 55 this->type = type;
nuclear@2 56 }
nuclear@2 57
nuclear@2 58 FSNode::Type FSNode::get_type() const
nuclear@2 59 {
nuclear@2 60 return type;
nuclear@2 61 }
nuclear@2 62
nuclear@2 63 bool FSNode::is_file() const
nuclear@2 64 {
nuclear@2 65 return type != DIRECTORY;
nuclear@2 66 }
nuclear@2 67
nuclear@2 68 bool FSNode::is_directory() const
nuclear@2 69 {
nuclear@2 70 return type == DIRECTORY;
nuclear@2 71 }
nuclear@2 72
nuclear@2 73 void FSNode::sort_children()
nuclear@2 74 {
nuclear@2 75 std::sort(children.begin(), children.end(), childcmpless);
nuclear@2 76 sorted = true;
nuclear@2 77 }
nuclear@2 78
nuclear@1 79 void FSNode::set_path(const char *path)
nuclear@1 80 {
nuclear@1 81 delete [] this->path;
nuclear@1 82
nuclear@1 83 char *buf = new char[strlen(path) + 1];
nuclear@1 84 strcpy(buf, path);
nuclear@1 85
nuclear@1 86 char *tmp = clean_path(buf);
nuclear@1 87 if(tmp == buf) {
nuclear@1 88 this->path = tmp;
nuclear@1 89 } else {
nuclear@1 90 this->path = new char[strlen(tmp) + 1];
nuclear@1 91 strcpy(this->path, tmp);
nuclear@1 92 delete [] buf;
nuclear@1 93 }
nuclear@1 94
nuclear@1 95 name = filename(this->path);
nuclear@1 96 }
nuclear@1 97
nuclear@1 98 void FSNode::set_name(const char *name)
nuclear@1 99 {
nuclear@1 100 delete [] path;
nuclear@1 101
nuclear@1 102 if(parent) {
nuclear@1 103 char *path = new char[strlen(name) + strlen(parent->path) + 2];
nuclear@1 104 sprintf(path, "%s/%s", parent->path, name);
nuclear@1 105 set_path(path);
nuclear@1 106 } else {
nuclear@1 107 path = this->name = new char[strlen(name) + 1];
nuclear@1 108 strcpy(path, name);
nuclear@1 109 }
nuclear@1 110 }
nuclear@1 111
nuclear@2 112 const char *FSNode::get_path() const
nuclear@1 113 {
nuclear@2 114 return path;
nuclear@2 115 }
nuclear@1 116
nuclear@2 117 const char *FSNode::get_name() const
nuclear@2 118 {
nuclear@2 119 return name;
nuclear@2 120 }
nuclear@2 121
nuclear@2 122 bool FSNode::add_child(FSNode *node)
nuclear@2 123 {
nuclear@2 124 if(node->parent == this) {
nuclear@2 125 return true;
nuclear@2 126 }
nuclear@2 127
nuclear@2 128 if(node->parent) {
nuclear@2 129 node->parent->remove_child(node);
nuclear@2 130 }
nuclear@2 131 node->parent = this;
nuclear@2 132
nuclear@2 133 try {
nuclear@2 134 children.push_back(node);
nuclear@2 135 }
nuclear@2 136 catch(...) {
nuclear@2 137 return false;
nuclear@2 138 }
nuclear@2 139
nuclear@2 140 sorted = false;
nuclear@2 141 return true;
nuclear@2 142 }
nuclear@2 143
nuclear@2 144 bool FSNode::remove_child(FSNode *node)
nuclear@2 145 {
nuclear@2 146 int cidx = find_child(node);
nuclear@2 147 if(cidx == -1) {
nuclear@2 148 return false;
nuclear@2 149 }
nuclear@2 150 children.erase(children.begin() + cidx);
nuclear@2 151
nuclear@2 152 if(node->parent != this) {
nuclear@2 153 fprintf(stderr, "FSNode::remove_child(): target node doesn't have this node as parent\n");
nuclear@2 154 // let's not touch it if this happens...
nuclear@2 155 } else {
nuclear@2 156 node->parent = 0;
nuclear@2 157 }
nuclear@2 158 return true;
nuclear@2 159 }
nuclear@2 160
nuclear@2 161 int FSNode::find_child(FSNode *node) const
nuclear@2 162 {
nuclear@2 163 for(size_t i=0; i<children.size(); i++) {
nuclear@2 164 if(children[i] == node) {
nuclear@2 165 return i;
nuclear@2 166 }
nuclear@2 167 }
nuclear@2 168 return -1;
nuclear@2 169 }
nuclear@2 170
nuclear@2 171 int FSNode::find_child(const char *name) const
nuclear@2 172 {
nuclear@2 173 FSNode key;
nuclear@2 174 key.name = (char*)name;
nuclear@2 175
nuclear@2 176 if(!sorted) {
nuclear@2 177 ((FSNode*)this)->sort_children();
nuclear@2 178 }
nuclear@2 179
nuclear@2 180 std::vector<FSNode*>::const_iterator it;
nuclear@2 181 it = std::lower_bound(children.begin(), children.end(), &key, childcmpless);
nuclear@2 182 if(it == children.end() || strcmp((*it)->name, name) != 0) {
nuclear@2 183 return -1;
nuclear@2 184 }
nuclear@2 185 return std::distance(children.begin(), it);
nuclear@2 186 }
nuclear@2 187
nuclear@2 188 FSNode *FSNode::get_parent()
nuclear@2 189 {
nuclear@2 190 return parent;
nuclear@2 191 }
nuclear@2 192
nuclear@2 193 const FSNode *FSNode::get_parent() const
nuclear@2 194 {
nuclear@2 195 return parent;
nuclear@2 196 }
nuclear@2 197
nuclear@2 198 int FSNode::get_child_count() const
nuclear@2 199 {
nuclear@2 200 return (int)children.size();
nuclear@2 201 }
nuclear@2 202
nuclear@2 203 FSNode *FSNode::get_child(int n)
nuclear@2 204 {
nuclear@2 205 if(!sorted) {
nuclear@2 206 sort_children();
nuclear@2 207 }
nuclear@2 208 return children[n];
nuclear@2 209 }
nuclear@2 210
nuclear@2 211 const FSNode *FSNode::get_child(int n) const
nuclear@2 212 {
nuclear@2 213 if(!sorted) {
nuclear@2 214 ((FSNode*)this)->sort_children();
nuclear@2 215 }
nuclear@2 216 return children[n];
nuclear@2 217 }
nuclear@2 218
nuclear@2 219 bool FSNode::expand()
nuclear@2 220 {
nuclear@2 221 expanded = true;
nuclear@2 222 return true;
nuclear@2 223 }
nuclear@2 224
nuclear@2 225 bool FSNode::is_expanded() const
nuclear@2 226 {
nuclear@2 227 return expanded;
nuclear@2 228 }
nuclear@2 229
nuclear@2 230
nuclear@2 231 // ---- FSDir ----
nuclear@2 232 FSDir::FSDir()
nuclear@2 233 {
nuclear@2 234 type = DIRECTORY;
nuclear@2 235 }
nuclear@2 236
nuclear@2 237 bool FSDir::expand()
nuclear@2 238 {
nuclear@2 239 if(expanded) return true;
nuclear@1 240
nuclear@1 241 DIR *dir = opendir(path);
nuclear@1 242 if(!dir) {
nuclear@2 243 fprintf(stderr, "FSDir::expand() failed to open dir: %s: %s\n", path, strerror(errno));
nuclear@2 244 return false;
nuclear@1 245 }
nuclear@1 246
nuclear@2 247 char *pathbuf = (char*)alloca(strlen(path) + NAME_MAX + 2);
nuclear@1 248
nuclear@1 249 struct dirent *ent;
nuclear@1 250 while((ent = readdir(dir))) {
nuclear@2 251 sprintf(pathbuf, "%s/%s", path, ent->d_name);
nuclear@1 252
nuclear@1 253 struct stat st;
nuclear@1 254 if(stat(pathbuf, &st) == -1) {
nuclear@1 255 fprintf(stderr, "failed to stat: %s: %s\n", pathbuf, strerror(errno));
nuclear@1 256 continue;
nuclear@1 257 }
nuclear@1 258
nuclear@2 259 FSNode *child;
nuclear@2 260 if(S_ISDIR(st.st_mode)) {
nuclear@2 261 child = new FSDir;
nuclear@1 262 } else {
nuclear@2 263 FSFile *file = new FSFile;
nuclear@2 264 file->set_size(st.st_size);
nuclear@2 265 file->set_type(st_mode_to_type(st.st_mode));
nuclear@2 266 child = file;
nuclear@1 267 }
nuclear@2 268 add_child(child);
nuclear@2 269 child->set_name(ent->d_name);
nuclear@1 270 }
nuclear@2 271
nuclear@2 272 closedir(dir);
nuclear@2 273
nuclear@2 274 expanded = true;
nuclear@2 275 return true;
nuclear@1 276 }
nuclear@2 277
nuclear@2 278 // ---- FSFile ----
nuclear@2 279
nuclear@2 280 FSFile::FSFile()
nuclear@2 281 {
nuclear@2 282 type = UNKNOWN;
nuclear@2 283 size = 0;
nuclear@2 284 }
nuclear@2 285
nuclear@2 286 void FSFile::set_size(unsigned long s)
nuclear@2 287 {
nuclear@2 288 size = s;
nuclear@2 289 }
nuclear@2 290
nuclear@2 291 unsigned long FSFile::get_size() const
nuclear@2 292 {
nuclear@2 293 return size;
nuclear@2 294 }
nuclear@2 295
nuclear@2 296 // ---- static helpers ----
nuclear@2 297
nuclear@2 298 static bool childcmpless(const FSNode *aptr, const FSNode *bptr)
nuclear@2 299 {
nuclear@2 300 return strcmp(aptr->get_name(), bptr->get_name()) < 0;
nuclear@2 301 }
nuclear@1 302
nuclear@1 303 static char *clean_path(char *path)
nuclear@1 304 {
nuclear@1 305 while(*path && isspace(*path)) {
nuclear@1 306 path++;
nuclear@1 307 }
nuclear@1 308
nuclear@1 309 char *end = path + strlen(path) - 1;
nuclear@1 310 while(end >= path && isspace(*end)) {
nuclear@1 311 *end-- = 0;
nuclear@1 312 }
nuclear@1 313
nuclear@1 314 char *ptr = path - 1;
nuclear@1 315 while(*++ptr) {
nuclear@1 316 if(*ptr == '\\') {
nuclear@1 317 *ptr = '/';
nuclear@1 318 }
nuclear@1 319 }
nuclear@1 320 return path;
nuclear@1 321 }
nuclear@1 322
nuclear@1 323 static char *filename(char *path)
nuclear@1 324 {
nuclear@1 325 char *ptr = strrchr(path, '/');
nuclear@1 326 if(ptr) {
nuclear@1 327 return ptr + 1;
nuclear@1 328 }
nuclear@1 329 return path;
nuclear@1 330 }
nuclear@2 331
nuclear@2 332 static FSNode::Type st_mode_to_type(mode_t mode)
nuclear@2 333 {
nuclear@2 334 switch(mode & S_IFMT) {
nuclear@2 335 case S_IFDIR:
nuclear@2 336 return FSNode::DIRECTORY;
nuclear@2 337 case S_IFREG:
nuclear@2 338 return FSNode::REGFILE;
nuclear@2 339 case S_IFLNK:
nuclear@2 340 return FSNode::LINK;
nuclear@2 341 case S_IFBLK:
nuclear@2 342 case S_IFCHR:
nuclear@2 343 return FSNode::DEVICE;
nuclear@2 344 case S_IFSOCK:
nuclear@2 345 return FSNode::SOCKET;
nuclear@2 346 case S_IFIFO:
nuclear@2 347 return FSNode::FIFO;
nuclear@2 348 default:
nuclear@2 349 break;
nuclear@2 350 }
nuclear@2 351 return FSNode::UNKNOWN;
nuclear@2 352 }