1 module unde.file_manager.find_path;
2
3 import unde.global_state;
4 import unde.lib;
5 import unde.lsblk;
6 import unde.path_mnt;
7 import unde.slash;
8
9 import berkeleydb.all;
10
11 import std.stdio;
12 import std..string;
13
14 import std.file;
15
16 version (Windows)
17 {
18 import unde.scan;
19 }
20
21 enum unDE_Path_Finder_Flags {
22 Go_Up,
23 Go_Down,
24 Out,
25 Try_Other_Directory
26 }
27
28 private unDE_Path_Finder_Flags
29 what_to_do_with_path_by_rectangle(GlobalState gs,
30 in ref DRect surf_rect, in ref RectSize rectsize,
31 in PathMnt path, DRect apply_rect, in SortType sort,
32 in int level = 0)
33 {
34 if (level == 0)
35 {
36 if (rectsize.rect(sort).In(surf_rect))
37 {
38 if (path > gs.main_path)
39 {
40 if (gs.path != SL)
41 {
42 return unDE_Path_Finder_Flags.Go_Up;
43 }
44 else
45 {
46 return unDE_Path_Finder_Flags.Try_Other_Directory;
47 }
48 }
49 }
50 }
51
52 /*writefln("!%s", path);
53 writefln("R %s, %s, %s, %s", rectsize.rect(sort).x,
54 rectsize.rect(sort).x+rectsize.rect(sort).w,
55 rectsize.rect(sort).y,
56 rectsize.rect(sort).y+rectsize.rect(sort).h);
57 writefln("S %s, %s, %s, %s", surf_rect.x, surf_rect.x+surf_rect.w,
58 surf_rect.y, surf_rect.y+surf_rect.h);*/
59
60 if (surf_rect.In(rectsize.rect(sort)))
61 {
62 gs.path = path;
63 gs.apply_rect = apply_rect;
64 gs.sort = sort;
65 //writefln("path=%s, apply_rect=%s, sort=%s",
66 // gs.path, gs.apply_rect, gs.sort);
67 }
68
69 //writefln("rectsize=%s, surf_rect=%s", rectsize.rect(sort), surf_rect);
70 if (rectsize.rect(sort).In(surf_rect))
71 return unDE_Path_Finder_Flags.Out;
72
73 if (rectsize.rect(sort).NotIntersect(surf_rect))
74 return unDE_Path_Finder_Flags.Try_Other_Directory;
75
76 return unDE_Path_Finder_Flags.Go_Down;
77 }
78
79 version(Windows)
80 {
81 public DRect
82 get_drect_of_drives(GlobalState gs, string drive)
83 {
84 DRect full_rect = DRect(0, 0, 1024*1024, 1024*1024);
85 RectSize rectsize = RectSize(full_rect, full_rect, full_rect);
86
87 int ret = 0;
88
89 string[] paths;
90
91 foreach(char c; 'A'..'Z'+1)
92 {
93 string disk = c ~ ":";
94 if ( disk in gs.lsblk )
95 {
96 paths ~= disk;
97 }
98 }
99
100 int levels = 0;
101 long l = paths.length;
102 /*if (l > 0)
103 {
104 l--;
105 }*/
106 for (long i=12; i < l; i=i*2+12)
107 {
108 l -= i;
109 levels++;
110 }
111 if (l > 0) levels++;
112
113 immutable long entries_on_last_level = l;
114
115 //RectSize[string] rect_sizes;
116
117 //writefln("levels = %s", levels);
118 long[] coords = new long[levels+1];
119 long i = 0;
120 size_t lev = 1;
121 bool first = true;
122 foreach (string name; paths)
123 {
124 DRect rect;
125 calculate_rect(full_rect, rect, coords, lev);
126
127 if (name == drive) return rect;
128
129 calculate_coords(coords, lev, i, levels, entries_on_last_level);
130 first = false;
131 }
132
133 return full_rect;
134 }
135 }
136
137 /* EN: This function make selection of directory by surface rectangle
138 So gs.path must specify the most deep directory which still
139 include surface rectangle.
140
141 RU: Эта функция выбирает директорию в соответствии с прямоугольником,
142 который занимает surface. После выполнения этой функции gs.path
143 должен указывать на самую глубокую директорию которая ещё включает
144 прямоугольник surface.
145 */
146 unDE_Path_Finder_Flags
147 find_path(GlobalState gs, DbTxn txn, CoordinatesPlusScale surf, PathMnt path,
148 DRect apply_rect, SortType sort = SortType.ByName,
149 in int level = 0)
150 {
151 DRect surf_rect = surf.getRect();
152
153 go_up:
154 bool up = false;
155 Dbt key, data;
156
157 DirEntry de;
158 try
159 {
160 de = DirEntry(path);
161 }
162 catch (FileException e)
163 {
164 return unDE_Path_Finder_Flags.Try_Other_Directory;
165 }
166
167 if (path in gs.lsblk)
168 {
169 string path0 = path.get_key(gs.lsblk);
170 key = path0;
171 auto res = gs.db_map.get(txn, &key, &data);
172 if (res == 0)
173 {
174 RectSize rectsize;
175 rectsize = data.to!(RectSize);
176 apply_rect = rectsize.rect(sort).apply(apply_rect);
177 }
178 else
179 {
180 version(Windows)
181 {
182 if (path.length == 2)
183 {
184 DRect rect = get_drect_of_drives(gs, path);
185 apply_rect = rect.apply(apply_rect);
186 }
187 }
188
189 {
190 // TODO: Created mount point, rescan up path
191 }
192 }
193 }
194
195 try
196 {
197 path.update(gs.lsblk);
198 }
199 catch (Exception e)
200 {
201 return unDE_Path_Finder_Flags.Out;
202 }
203
204 string path0 = path.get_key(gs.lsblk);
205 key = path0;
206 auto res = gs.db_map.get(txn, &key, &data);
207 version(Windows)
208 {
209 if (path == SL) res = 0;
210 }
211
212 if (res == 0)
213 {
214 up = false;
215 RectSize rectsize;
216 version(Windows)
217 {
218 if (path == SL)
219 {
220 DRect full_rect = DRect(0, 0, 1024*1024, 1024*1024);
221 rectsize = RectSize(full_rect, full_rect, full_rect);
222 }
223 else
224 rectsize = data.to!(RectSize);
225 }
226 else
227 {
228 rectsize = data.to!(RectSize);
229 }
230 rectsize.rect(sort) = rectsize.rect(sort).apply(apply_rect);
231 auto wtdwpbr = what_to_do_with_path_by_rectangle(gs, surf_rect,
232 rectsize, path, apply_rect, sort, level);
233 //writefln("%s - %s", path, wtdwpbr);
234 final switch (wtdwpbr)
235 {
236 case unDE_Path_Finder_Flags.Go_Up:
237 path = gs.path = PathMnt(SL);
238 apply_rect = gs.apply_rect = DRect(0, 0, 1024*1024, 1024*1024);
239 gs.sort = SortType.ByName;
240 goto go_up;
241
242 case unDE_Path_Finder_Flags.Go_Down:
243 if (!de.isSymlink && de.isDir)
244 {
245 string[] paths;
246
247 try
248 {
249 //writefln("Go Down?");
250 bool done = false;
251 version(Windows)
252 {
253 if (path == SL)
254 {
255 //writefln("This way?");
256 foreach(char c; 'A'..'Z'+1)
257 {
258 string name = c ~ ":";
259 if ( name in gs.lsblk )
260 {
261 auto r = find_path(gs, txn, surf, path.next(name),
262 rectsize.rect(sort), rectsize.sort, level+1);
263 if (r == unDE_Path_Finder_Flags.Out) return r;
264 }
265 }
266 done = true;
267 }
268 }
269
270 if (!done)
271 {
272 //writefln("This way!");
273 foreach (string name;
274 dirEntries(path, SpanMode.shallow))
275 {
276 auto r = find_path(gs, txn, surf, path.next(name),
277 rectsize.rect(sort), rectsize.sort, level+1);
278 if (r == unDE_Path_Finder_Flags.Out) return r;
279 }
280 }
281 } catch (FileException e)
282 {
283 }
284 }
285 break;
286
287 case unDE_Path_Finder_Flags.Out:
288 if (level == 0 && path != SL)
289 goto case unDE_Path_Finder_Flags.Go_Up;
290 return unDE_Path_Finder_Flags.Out;
291
292 case unDE_Path_Finder_Flags.Try_Other_Directory:
293 if (level == 0 && path != SL)
294 goto case unDE_Path_Finder_Flags.Go_Up;
295 return unDE_Path_Finder_Flags.Try_Other_Directory;
296 }
297 }
298 else
299 {
300 //throw new Exception("No " ~ path ~ " entry");
301 }
302
303 return unDE_Path_Finder_Flags.Try_Other_Directory;
304 }