1 module tagion.tools.ifiler.ifiler;
2 import std.process;
3 import std.stdio : writeln, writefln;
4 import core.sys.linux.sys.inotify;
5 import core.sys.posix.unistd;
6 import core.stdc.stdio;
7 import core.stdc.stdlib;
8 import std.stdio;
9 import std.algorithm;
10 import tools = tagion.tools.toolsexception;
11 import tagion.tools.Basic;
12 import std.string : representation;
13 import std.getopt;
14 import tagion.tools.revision;
15 import std.format;
16 import std.array;
17 
18 mixin Main!_main;
19 
20 struct Inotify {
21     protected {
22         ubyte[] buffer;
23         int fd;
24         int wd;
25         inotify_event* event;
26         bool _empty;
27     }
28     enum EVENT_BUF_LEN = 0x100 * (inotify_event.sizeof + size_t.sizeof);
29     this(string file_name, uint mask, const size_t buf_size = EVENT_BUF_LEN) nothrow @trusted {
30         buffer.length = EVENT_BUF_LEN;
31         file_name ~= '\0';
32         fd = inotify_init();
33         wd = inotify_add_watch(fd, &file_name[0], mask);
34         event = cast(inotify_event*)&buffer[0];
35     }
36 
37     const(inotify_event*) wait() nothrow {
38         const length = read(fd, &buffer[0], cast(int) buffer.length);
39         /*checking for error*/
40         if (length < 0) {
41             enum error_text = "# inotify error #".representation;
42             event.len = cast(uint) error_text.length;
43             auto error = buffer[inotify_event.sizeof .. $];
44             error[0 .. error_text.length] = error_text;
45         }
46         return event;
47     }
48 
49     void close() nothrow @nogc {
50         inotify_rm_watch(fd, wd);
51 
52         
53 
54         .close(fd);
55     }
56 
57     const pure {
58         const(char[]) name() const pure @trusted @nogc {
59 
60             const result = (cast(char*) event.name.ptr)[0 .. event.len];
61             const len = result.countUntil(0);
62             return result[0 .. len];
63         }
64     }
65 }
66 
67 import tagion.dart.BlockFile : truncate;
68 
69 void icopy(string src, string dest, const size_t block_size) {
70     import std.file;
71     import std.path;
72 
73     tools.check(src.exists, format("%s should exist", src));
74     tools.check(src.isFile, format("%s should be a file", src));
75     tools.check(dest.extension.empty && dest.exists && dest.isDir,
76             format("%s path does not exists", dest));
77     if (dest.exists && dest.isDir) {
78         dest = buildPath(dest, src.baseName);
79     }
80     File fin, fout;
81     scope (exit) {
82         fout.flush;
83         fout.close;
84         fin.close;
85     }
86     enum one_MiB = 1 << 20;
87 
88     size_t block_count;
89     ubyte[] fin_buf;
90     ubyte[] fout_buf;
91     fin_buf.length = fout_buf.length = block_size;
92     fin = File(src, "r");
93     if (dest.exists) {
94 
95         fout = File(dest, "r+");
96         while (!fin.eof) {
97             verbose("Verify block %d %f.6MiB", block_count, double(fin.tell) / one_MiB);
98             const fin_tell = fin.tell;
99             const fin_current = fin.rawRead(fin_buf);
100             const fout_tell = fout.tell;
101             const fout_current = fout.rawRead(fout_buf);
102             if (fin_current != fout_current) {
103                 fin.seek(fin_tell);
104                 fout.seek(fin_tell);
105                 break;
106             }
107             block_count++;
108         }
109     }
110     else {
111         fout = File(dest, "w");
112     }
113     while (!fin.eof) {
114         verbose("Update block %d %f.6MiB", block_count, double(fin.tell) / one_MiB);
115         const fin_tell = fin.tell;
116         const fout_tell = fout.tell;
117         const fin_current = fin.rawRead(fin_buf);
118         fout.rawWrite(fin_current);
119         block_count++;
120     }
121     fout.flush;
122     auto inotify = Inotify(src, IN_CLOSE_WRITE | IN_MODIFY);
123     for (;;) {
124         const event = inotify.wait;
125         const fin_tell = fin.tell;
126         fin.reopen(null, "r");
127         fin.seek(fin_tell);
128         verbose("Reopen %s %d", src, fin.tell);
129         while (!fin.eof) {
130             verbose("Copy block %d %f.6MiB", block_count, double(fin.tell) / one_MiB);
131             const fout_tell = fout.tell;
132             const fin_current = fin.rawRead(fin_buf);
133             fout.rawWrite(fin_current);
134             fout.flush;
135             block_count++;
136         }
137         if ((event.mask & IN_MODIFY) == 0) {
138             verbose("CLosed");
139             break;
140         }
141     }
142 
143 }
144 
145 int _main(string[] args) {
146     immutable program = args[0];
147     bool version_switch;
148     size_t block_size = 0x400;
149     //    auto logo = import("logo.txt");
150     GetoptResult main_args;
151     try {
152         main_args = getopt(args,
153                 std.getopt.config.caseSensitive,
154                 std.getopt.config.bundling,
155                 "version", "display the version", &version_switch,
156                 "v|verbose", "Prints more debug information", &__verbose_switch,
157                 "b|block", "Set the block size (Default %s)", &block_size,
158         );
159         if (version_switch) {
160             revision_text.writeln;
161             return 0;
162         }
163 
164         if (main_args.helpWanted) {
165             //            writeln(logo);
166             defaultGetoptPrinter(
167                     [
168                     "Documentation: https://tagion.org/",
169                     "",
170                     "Usage:",
171                     format("%s [<option>...] <src-file> <dst-file> ", program),
172                     "",
173 
174                     "<option>:",
175 
176                     ].join("\n"),
177                     main_args.options);
178             return 0;
179         }
180         tools.check(args.length == 3, format("%s should have two arguments", program));
181         icopy(args[1], args[2], block_size);
182     }
183     catch (Exception e) {
184         error(e);
185         return 1;
186     }
187     return 0;
188 }