1 module unde.path_mnt;
2 
3 import unde.global_state;
4 import unde.lib;
5 import unde.lsblk;
6 import unde.slash;
7 
8 import std.stdio;
9 import std..string;
10 import std.format;
11 
12 import std.file;
13 import core.sys.posix.sys.types;
14 
15 version (Windows)
16 {
17 import berkeleydb.all: ssize_t;
18 }
19 
20 struct PathMnt
21 {
22     string path;
23     string _next;
24     string mnt;
25     version (Windows)
26     {
27 	alias char dev_t;
28     }
29     dev_t dev;
30     alias _next this;
31 
32     this(string p)
33     {
34         path = p;
35         mnt = p;
36         _next = p;
37 
38 	version(Posix)
39 	{
40         DirEntry de = DirEntry(p);
41         dev = de.statBuf.st_dev;
42 	}
43 	else version(Windows)
44 	{
45 	dev=p[0];
46 	//assert(p[1] == ':');
47 	}
48     }
49 
50     this(ref LsblkInfo[string] lsblk, string path)
51     out
52     {
53         assert(this.path == path, 
54                 format("this.path=%s, path=%s", this.path, path));
55     }
56     body
57     {
58     if (path.length > 1 && path[0] == path[1] && path[0] == SL[0])
59         path = path[1..$];
60 	version(Windows)
61 	{
62 	if (path.length > 1 && path[1] == ':')
63 		this(path[0..2]);
64 	else
65 		this(SL);
66 	}
67 	else
68 	{
69 	this(SL);
70 	}
71         string wrkpath = this.path;
72         while (wrkpath < path)
73         {
74 	    bool found = false;
75 	    version (Windows)
76 	    {
77 		    if (wrkpath == SL && path[1] == ':')
78 		    {
79 			    wrkpath = path[0..2];
80 			    found = true;
81 		    }
82 	    }
83 	    if (!found)
84 	    {
85 		    string after = path[wrkpath.length+1 .. $];
86                     if (wrkpath[$-1] == SL[0]) after = path[wrkpath.length .. $];
87 		    //writefln("wrkpath=%s, path=%s, after=%s", wrkpath, path, after);
88 		    ssize_t i = after.indexOf(SL);
89 		    if (i < 0) i = after.length;
90 		    ssize_t new_len = wrkpath.length + i + 1;
91 		    if (wrkpath[$-1] == SL[0]) new_len--;
92 		    wrkpath = path[0..new_len];
93 		    //writefln("wrkpath=%s", wrkpath);
94 	    }
95 
96             _next = wrkpath;
97             update(lsblk);
98         }
99     }
100 
101     this(string path, string mnt, dev_t dev)
102     {
103         this.path = path;
104         this.mnt = mnt;
105         this.next = path;
106         this.dev = dev;
107     }
108 
109     PathMnt next(string next)
110     {
111         PathMnt new_path = this;
112         new_path._next = next;
113         return new_path;
114     }
115 
116     string get_key(in LsblkInfo[string] lsblk)
117     {
118         string key;
119 
120         LsblkInfo info = lsblk[mnt];
121 
122         string subpath = subpath(_next, mnt);
123         string path0 = info.uuid ~ subpath.replace(SL, "\0");
124         return path0;
125     }
126 
127     void update(ref LsblkInfo[string] lsblkinfo)
128     in
129     {
130         size_t i = path.length;
131 	version(Windows)
132 	{
133 		if (path != "\\")
134 		{
135 			assert(_next[0..i] == path, _next[0..i]~" == "~path);
136 			if (_next != path)
137 			{
138 			    assert(_next[i] == SL[0] || path == SL, format("path=%s, _next=%s", path, _next));
139 			    assert(_next[i+1..$].indexOf(SL) < 0, format("path=%s, _next=%s", path, _next));
140 			}
141 		}
142 	}
143 	else
144 	{
145 		assert(_next[0..i] == path, _next[0..i]~" == "~path);
146 		if (_next != path)
147 		{
148 		    assert(_next[i] == SL[0] || path == SL, format("path=%s, _next=%s", path, _next));
149 		    assert(_next[i+1..$].indexOf(SL) < 0, format("path=%s, _next=%s", path, _next));
150 		}
151 	}
152     }
153     out
154     {
155         assert(path == _next);
156     }
157     body
158     {
159         if (_next == path) return;
160 
161         DirEntry de;
162         bool direntry_success = true;
163 	version(Posix)
164 	{
165         try
166         {
167             de = DirEntry(_next);
168         }
169         catch (FileException e)
170         {
171             direntry_success = false;
172         }
173 
174 	bool not_the_same_filesystem = direntry_success && !de.isSymlink && de.statBuf.st_dev != dev;
175 	}
176 	else version(Windows)
177 	{
178 	bool not_the_same_filesystem = _next[0] != dev;
179 	}
180         if (not_the_same_filesystem)
181         {
182 	    version(Posix)
183 	    {
184             dev = de.statBuf.st_dev;
185 	    }
186 	    else
187 	    {
188 	    dev = _next[0];
189 	    }
190             char major = (dev & 0xFF00) >> 8;
191             if ( (major == 7 ||  major == 8 || major == 179) && 
192                     path !in lsblkinfo )
193             {
194                 lsblk(lsblkinfo);
195                 assert(_next in lsblkinfo, "Path "~path~" not in lsblk");
196             }
197         }
198 
199         if (_next in lsblkinfo)
200         {
201             mnt = _next;
202         }
203         path = _next;
204     }
205 }