vrfileman

annotate src/fs.cc @ 5:d487181ee1d9

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