1 module unde.file_manager.change_rights;
2 
3 import unde.global_state;
4 import unde.lsblk;
5 import unde.lib;
6 import unde.scan;
7 import unde.path_mnt;
8 
9 import std.stdio;
10 import std.conv;
11 import core.stdc.stdlib;
12 import std.math;
13 import berkeleydb.all;
14 import std.stdint;
15 import core.stdc.stdlib;
16 import std..string;
17 import std.algorithm.sorting;
18 import std.utf;
19 import std.process;
20 import std.concurrency;
21 import core.time;
22 import core.thread;
23 import core.stdc.errno;
24 import core.stdc..string;
25 import std.datetime;
26 import std.regex;
27 import std.algorithm.sorting;
28 
29 import derelict.sdl2.sdl;
30 
31 import std.file;
32 import core.sys.posix.sys.stat;
33 
34 version(Posix)
35 {
36 enum DirOrFile
37 {
38     All,
39     Dir,
40     File
41 }
42 
43 private void
44 save_errors(FMGlobalState cgs, PathMnt path, string e)
45 {
46     DbTxn txn = null;
47     Dbt key, data;
48     string path0 = path.get_key(cgs.lsblk);
49     key = path0;
50     auto res = cgs.db_map.get(txn, &key, &data);
51 
52     RectSize rectsize;
53     if (res == 0)
54         rectsize = data.to!(RectSize);
55 
56     ulong curr_time = Clock.currTime().toUnixTime();
57     rectsize.msg = to_char_array!80(strip_error(e));
58     rectsize.msg_time = curr_time;
59     rectsize.msg_color = 0x80FF8080; // ARGB
60 
61     data = rectsize;
62     //writefln("WRITE - %s - %s", path0, rectsize);
63     res = cgs.db_map.put(txn, &key, &data);
64     if (res != 0)
65         throw new Exception("Path info to map-db not written");
66 
67     ssize_t first, last;
68     first = path0.indexOf("\0");
69     while (first != last)
70     {
71         last = path0.lastIndexOf("\0");
72         if (last > first)
73             path0 = path0[0..last];
74         else
75             path0 = path0[0..first+1];
76         key = path0;
77         res = cgs.db_map.get(txn, &key, &data);
78         if (res == 0)
79         {
80             rectsize = data.to!(RectSize);
81 
82             if (curr_time > rectsize.newest_msg_time)
83             {
84                 rectsize.newest_msg_time = curr_time;
85 
86                 data = rectsize;
87                 //writefln("WRITE - %s - %s", path0, rectsize);
88                 res = cgs.db_map.put(txn, &key, &data);
89                 if (res != 0)
90                     throw new Exception("Path info to map-db not written");
91             }
92         }
93     }
94 }
95 
96 private void
97 change_rights_ang_save_errors(FMGlobalState cgs, PathMnt path, mode_t mode)
98 {
99     //writefln("%s: %s", path, mode_to_string(mode));
100     int res = chmod(toStringz(path), mode);
101     if (res < 0)
102     {
103         save_errors(cgs, path, fromStringz(strerror(errno)).idup());
104     }
105 }
106 
107 private void
108 change_rights_private(FMGlobalState cgs, PathMnt path, bool set, int bit, DirOrFile dof, bool recursive)
109 {
110     //writefln("remove_path(%s)", path);
111     // exits on exits of parent
112     receiveTimeout( 0.seconds, 
113             (OwnerTerminated ot) {
114                 writefln("Abort removing due stopping parent");
115                 cgs.finish = true;
116             } );
117 
118     if (cgs.finish)
119         return;
120 
121     DirEntry de;
122     mode_t mode;
123     try
124     {
125         path.update(cgs.lsblk);
126         de = DirEntry(path);
127 
128         mode = de.statBuf.st_mode;
129         final switch(dof)
130         {
131             case DirOrFile.Dir:
132                 if (!de.isSymlink && de.isDir)
133                 {
134                     goto case DirOrFile.All;
135                 }
136                 break;
137             case DirOrFile.File:
138                 if (de.isSymlink || de.isFile)
139                 {
140                     goto case DirOrFile.All;
141                 }
142                 break;
143             case DirOrFile.All:
144                 if (set)
145                     mode |= 1 << (11-bit);
146                 else
147                     mode &= ~(1 << (11-bit));
148                 break;
149         }
150     }
151     catch (Exception e)
152     {
153         save_errors(cgs, path, e.msg);
154     }
155 
156     try
157     {
158         if (de.isSymlink)
159         {
160             change_rights_ang_save_errors(cgs, path, mode);
161             return;
162         }
163         else if (de.isDir)
164         {
165             if (recursive)
166             {
167                 string[] paths;
168                 try
169                 {
170                     foreach (string name; dirEntries(path, SpanMode.shallow))
171                     {
172                         paths ~= name;
173                     }
174                 }
175                 catch (Exception e)
176                 {
177                     return;
178                 }
179 
180                 sort!("a < b")(paths);
181 
182                 foreach (string name; paths)
183                 {
184                     if (name != path)
185                     {
186                         change_rights_private(cgs, path.next(name), set, bit, dof, recursive);
187                     }
188                 }
189             }
190 
191             change_rights_ang_save_errors(cgs, path, mode);
192             return;
193         }
194         else if (de.isFile)
195         {
196             change_rights_ang_save_errors(cgs, path, mode);
197             return;
198         }
199         else 
200         {
201             change_rights_ang_save_errors(cgs, path, mode);
202             return;
203         }
204     }
205     catch (Exception e)
206     {
207         save_errors(cgs, path, e.msg);
208     }
209 }
210 
211 private void
212 start_change_rights(shared LsblkInfo[string] lsblk, immutable string[] paths, 
213         bool set, int bit, DirOrFile dof, bool recursive, Tid tid)
214 {
215     writefln("Start change rights %s", paths);
216 
217     try {
218         FMGlobalState cgs = new FMGlobalState();
219         scope(exit)
220         {
221             destroy(cgs);
222         }
223 
224         cgs.lsblk = to!(LsblkInfo[string])(lsblk);
225 
226         DbTxn txn = null;//dbenv.txn_begin(null);
227         string[] paths_dup = paths.dup;
228         sort!("a < b")(paths_dup);
229         foreach(path; paths_dup)
230         {
231             change_rights_private(cgs, PathMnt(cgs.lsblk, path), set, bit, dof, recursive);
232         }
233         //txn.commit();
234     } catch (shared(Throwable) exc) {
235         send(tid, exc);
236     }
237 
238     writefln("Finish change rights %s", paths);
239     send(tid, thisTid);
240 }
241 
242 int change_rights(GlobalState gs, immutable string[] paths, bool set, int bit, 
243         DirOrFile dof, bool recursive)
244 {
245     foreach(tid, paths2; gs.changers_rights)
246     {
247         if (paths2 == paths)
248         {
249             string msg = format("Wait till finished previous task on change rights");
250             gs.messages ~= ConsoleMessage(
251                     SDL_Color(0xFF, 0x00, 0x00, 0xFF),
252                     msg,
253                     SDL_GetTicks()
254                     );
255             writeln(msg);
256             return -1;
257         }
258     }
259 
260     shared LsblkInfo[string] lsblk = to!(shared LsblkInfo[string])(gs.lsblk);
261     auto tid = spawn(&start_change_rights, lsblk, paths, set, bit, dof, 
262                         recursive, thisTid);
263     gs.changers_rights[tid] = paths.dup();
264     return 0;
265 }
266 
267 void check_changer_rights(GlobalState gs)
268 {
269     // Look check_scanners
270 }
271 }