vrfileman

diff src/fs.cc @ 2:282da6123fd4

lalalala
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 01 Feb 2015 12:51:10 +0200
parents 9e3d77dad51b
children d487181ee1d9
line diff
     1.1 --- a/src/fs.cc	Sat Jan 31 20:01:35 2015 +0200
     1.2 +++ b/src/fs.cc	Sun Feb 01 12:51:10 2015 +0200
     1.3 @@ -2,13 +2,17 @@
     1.4  #include <string.h>
     1.5  #include <ctype.h>
     1.6  #include <errno.h>
     1.7 +#include <algorithm>
     1.8  #include <alloca.h>
     1.9  #include <unistd.h>
    1.10  #include <dirent.h>
    1.11 +#include <sys/stat.h>
    1.12  #include "fs.h"
    1.13  
    1.14 +static bool childcmpless(const FSNode *aptr, const FSNode *bptr);
    1.15  static char *clean_path(char *path);
    1.16  static char *filename(char *path);
    1.17 +static FSNode::Type st_mode_to_type(mode_t mode);
    1.18  
    1.19  FSNode::FSNode()
    1.20  {
    1.21 @@ -25,7 +29,9 @@
    1.22  	path = name = 0;
    1.23  	parent = 0;
    1.24  	expanded = false;
    1.25 +	sorted = true;
    1.26  	uid = gid = mode = 0;
    1.27 +	type = UNKNOWN;
    1.28  }
    1.29  
    1.30  void FSNode::destroy()
    1.31 @@ -44,6 +50,32 @@
    1.32  	destroy();
    1.33  }
    1.34  
    1.35 +void FSNode::set_type(Type type)
    1.36 +{
    1.37 +	this->type = type;
    1.38 +}
    1.39 +
    1.40 +FSNode::Type FSNode::get_type() const
    1.41 +{
    1.42 +	return type;
    1.43 +}
    1.44 +
    1.45 +bool FSNode::is_file() const
    1.46 +{
    1.47 +	return type != DIRECTORY;
    1.48 +}
    1.49 +
    1.50 +bool FSNode::is_directory() const
    1.51 +{
    1.52 +	return type == DIRECTORY;
    1.53 +}
    1.54 +
    1.55 +void FSNode::sort_children()
    1.56 +{
    1.57 +	std::sort(children.begin(), children.end(), childcmpless);
    1.58 +	sorted = true;
    1.59 +}
    1.60 +
    1.61  void FSNode::set_path(const char *path)
    1.62  {
    1.63  	delete [] this->path;
    1.64 @@ -77,25 +109,146 @@
    1.65  	}
    1.66  }
    1.67  
    1.68 -#if 0
    1.69 -FSDir *create_fsdir(const char *path)
    1.70 +const char *FSNode::get_path() const
    1.71  {
    1.72 -	char *pathbuf;
    1.73 +	return path;
    1.74 +}
    1.75  
    1.76 -	FSDir *node = new FSDir;
    1.77 -	node->name = std::string(filename(path));
    1.78 +const char *FSNode::get_name() const
    1.79 +{
    1.80 +	return name;
    1.81 +}
    1.82 +
    1.83 +bool FSNode::add_child(FSNode *node)
    1.84 +{
    1.85 +	if(node->parent == this) {
    1.86 +		return true;
    1.87 +	}
    1.88 +
    1.89 +	if(node->parent) {
    1.90 +		node->parent->remove_child(node);
    1.91 +	}
    1.92 +	node->parent = this;
    1.93 +
    1.94 +	try {
    1.95 +		children.push_back(node);
    1.96 +	}
    1.97 +	catch(...) {
    1.98 +		return false;
    1.99 +	}
   1.100 +
   1.101 +	sorted = false;
   1.102 +	return true;
   1.103 +}
   1.104 +
   1.105 +bool FSNode::remove_child(FSNode *node)
   1.106 +{
   1.107 +	int cidx = find_child(node);
   1.108 +	if(cidx == -1) {
   1.109 +		return false;
   1.110 +	}
   1.111 +	children.erase(children.begin() + cidx);
   1.112 +
   1.113 +	if(node->parent != this) {
   1.114 +		fprintf(stderr, "FSNode::remove_child(): target node doesn't have this node as parent\n");
   1.115 +		// let's not touch it if this happens...
   1.116 +	} else {
   1.117 +		node->parent = 0;
   1.118 +	}
   1.119 +	return true;
   1.120 +}
   1.121 +
   1.122 +int FSNode::find_child(FSNode *node) const
   1.123 +{
   1.124 +	for(size_t i=0; i<children.size(); i++) {
   1.125 +		if(children[i] == node) {
   1.126 +			return i;
   1.127 +		}
   1.128 +	}
   1.129 +	return -1;
   1.130 +}
   1.131 +
   1.132 +int FSNode::find_child(const char *name) const
   1.133 +{
   1.134 +	FSNode key;
   1.135 +	key.name = (char*)name;
   1.136 +
   1.137 +	if(!sorted) {
   1.138 +		((FSNode*)this)->sort_children();
   1.139 +	}
   1.140 +
   1.141 +	std::vector<FSNode*>::const_iterator it;
   1.142 +	it = std::lower_bound(children.begin(), children.end(), &key, childcmpless);
   1.143 +	if(it == children.end() || strcmp((*it)->name, name) != 0) {
   1.144 +		return -1;
   1.145 +	}
   1.146 +	return std::distance(children.begin(), it);
   1.147 +}
   1.148 +
   1.149 +FSNode *FSNode::get_parent()
   1.150 +{
   1.151 +	return parent;
   1.152 +}
   1.153 +
   1.154 +const FSNode *FSNode::get_parent() const
   1.155 +{
   1.156 +	return parent;
   1.157 +}
   1.158 +
   1.159 +int FSNode::get_child_count() const
   1.160 +{
   1.161 +	return (int)children.size();
   1.162 +}
   1.163 +
   1.164 +FSNode *FSNode::get_child(int n)
   1.165 +{
   1.166 +	if(!sorted) {
   1.167 +		sort_children();
   1.168 +	}
   1.169 +	return children[n];
   1.170 +}
   1.171 +
   1.172 +const FSNode *FSNode::get_child(int n) const
   1.173 +{
   1.174 +	if(!sorted) {
   1.175 +		((FSNode*)this)->sort_children();
   1.176 +	}
   1.177 +	return children[n];
   1.178 +}
   1.179 +
   1.180 +bool FSNode::expand()
   1.181 +{
   1.182 +	expanded = true;
   1.183 +	return true;
   1.184 +}
   1.185 +
   1.186 +bool FSNode::is_expanded() const
   1.187 +{
   1.188 +	return expanded;
   1.189 +}
   1.190 +
   1.191 +
   1.192 +// ---- FSDir ----
   1.193 +FSDir::FSDir()
   1.194 +{
   1.195 +	type = DIRECTORY;
   1.196 +}
   1.197 +
   1.198 +bool FSDir::expand()
   1.199 +{
   1.200 +	if(expanded) return true;
   1.201  
   1.202  	DIR *dir = opendir(path);
   1.203  	if(!dir) {
   1.204 -		fprintf(stderr, "failed to open dir: %s: %s\n", path, strerror(errno));
   1.205 -		return 0;
   1.206 +		fprintf(stderr, "FSDir::expand() failed to open dir: %s: %s\n", path, strerror(errno));
   1.207 +		return false;
   1.208  	}
   1.209  
   1.210 -	pathbuf = (char*)alloca(strlen(path) + NAME_MAX + 2);
   1.211 +	char *pathbuf = (char*)alloca(strlen(path) + NAME_MAX + 2);
   1.212  
   1.213  	struct dirent *ent;
   1.214  	while((ent = readdir(dir))) {
   1.215 -		sprintf(pathbuf, "%s/%s", path, ent->d_ent);
   1.216 +		sprintf(pathbuf, "%s/%s", path, ent->d_name);
   1.217  
   1.218  		struct stat st;
   1.219  		if(stat(pathbuf, &st) == -1) {
   1.220 @@ -103,18 +256,49 @@
   1.221  			continue;
   1.222  		}
   1.223  
   1.224 -		if(S_ISDIR(st.st_type)) {
   1.225 -			FSDir *subdir = new FSDir;
   1.226 -			subdir->name = std::string(ent->d_ent);
   1.227 -			add_subdir(node, subdir);
   1.228 +		FSNode *child;
   1.229 +		if(S_ISDIR(st.st_mode)) {
   1.230 +			child = new FSDir;
   1.231  		} else {
   1.232 -			FSFile *file =  new FSFile;
   1.233 -			file->name = std::string(ent->d_ent);
   1.234 -			file->parent = node;
   1.235 +			FSFile *file = new FSFile;
   1.236 +			file->set_size(st.st_size);
   1.237 +			file->set_type(st_mode_to_type(st.st_mode));
   1.238 +			child = file;
   1.239  		}
   1.240 +		add_child(child);
   1.241 +		child->set_name(ent->d_name);
   1.242  	}
   1.243 +
   1.244 +	closedir(dir);
   1.245 +
   1.246 +	expanded = true;
   1.247 +	return true;
   1.248  }
   1.249 -#endif
   1.250 +
   1.251 +// ---- FSFile ----
   1.252 +
   1.253 +FSFile::FSFile()
   1.254 +{
   1.255 +	type = UNKNOWN;
   1.256 +	size = 0;
   1.257 +}
   1.258 +
   1.259 +void FSFile::set_size(unsigned long s)
   1.260 +{
   1.261 +	size = s;
   1.262 +}
   1.263 +
   1.264 +unsigned long FSFile::get_size() const
   1.265 +{
   1.266 +	return size;
   1.267 +}
   1.268 +
   1.269 +// ---- static helpers ----
   1.270 +
   1.271 +static bool childcmpless(const FSNode *aptr, const FSNode *bptr)
   1.272 +{
   1.273 +	return strcmp(aptr->get_name(), bptr->get_name()) < 0;
   1.274 +}
   1.275  
   1.276  static char *clean_path(char *path)
   1.277  {
   1.278 @@ -144,3 +328,25 @@
   1.279  	}
   1.280  	return path;
   1.281  }
   1.282 +
   1.283 +static FSNode::Type st_mode_to_type(mode_t mode)
   1.284 +{
   1.285 +	switch(mode & S_IFMT) {
   1.286 +	case S_IFDIR:
   1.287 +		return FSNode::DIRECTORY;
   1.288 +	case S_IFREG:
   1.289 +		return FSNode::REGFILE;
   1.290 +	case S_IFLNK:
   1.291 +		return FSNode::LINK;
   1.292 +	case S_IFBLK:
   1.293 +	case S_IFCHR:
   1.294 +		return FSNode::DEVICE;
   1.295 +	case S_IFSOCK:
   1.296 +		return FSNode::SOCKET;
   1.297 +	case S_IFIFO:
   1.298 +		return FSNode::FIFO;
   1.299 +	default:
   1.300 +		break;
   1.301 +	}
   1.302 +	return FSNode::UNKNOWN;
   1.303 +}