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