1 module beangle.fs.file;
2 
3 import std.stdio;
4 import std.file;
5 import std.zip;
6 import std..string;
7 import std.conv;
8 import vibe.core.log;
9 
10 uint unzip(string zipfile,string base,string innerDir=null){
11   string prefix=innerDir;
12   if (null!=prefix && !prefix.endsWith( "/")){
13     prefix ~="/";
14   }
15   uint count=0;
16   if (exists( zipfile)){
17     auto zip = new ZipArchive( read( zipfile));
18     mkdirRecurse( base);
19     foreach (name, am; zip.directory)   {
20       if (null==prefix  || name.startsWith( prefix)){
21         auto targetName=name;
22         if (null!=prefix && name.startsWith( prefix)){
23           targetName =targetName[prefix.length .. $];
24         }
25         if (targetName.endsWith( "/")){
26           mkdirRecurse( base~"/"~targetName);
27         } else if (targetName.length>0) {
28           auto lastSlash=targetName.lastIndexOf( "/");
29           if (lastSlash>0){
30             mkdirRecurse( base~"/"~ targetName[0..lastSlash]);
31           }
32           zip.expand( am);
33           assert(am.expandedData.length == am.expandedSize);
34           std.file.write( base~"/"~targetName,am.expandedData);
35           count +=1;
36         }
37       }
38     }
39   }
40   return count;
41 }
42 
43 uint refreshUnzip(string zipfile,string base,string innerDir=null){
44   string prefix=innerDir;
45   if (null!=prefix && !prefix.endsWith( "/")){
46     prefix ~="/";
47   }
48   uint count=0;
49   if (exists( zipfile)){
50     auto zip = new ZipArchive( read( zipfile));
51     mkdirRecurse( base);
52     foreach (name, am; zip.directory)   {
53       if (null==prefix  || name.startsWith( prefix)){
54         auto targetName=name;
55         if (null!=prefix && name.startsWith( prefix)){
56           targetName =targetName[prefix.length .. $];
57         }
58         if (targetName.endsWith( "/")){
59           mkdirRecurse( base~"/"~targetName);
60         } else if (targetName.length>0) {
61           auto lastSlash=targetName.lastIndexOf( "/");
62           if (lastSlash>0){
63             mkdirRecurse( base~"/"~ targetName[0..lastSlash]);
64           }
65           auto targetFile = base~"/"~targetName;
66           bool  spawn=true;
67           if (exists( targetFile) && getSize( targetFile) == am.expandedSize){
68             spawn=false;
69           }
70           if (spawn){
71             zip.expand( am);
72             assert(am.expandedData.length == am.expandedSize);
73             std.file.write( targetFile,am.expandedData);
74           }
75           count +=1;
76         }
77       }
78     }
79   }
80   return count;
81 }
82 
83 void setReadOnly(string dir){
84   if (!exists( dir)){
85     return ;
86   }
87   doSetReadOnly( dir);
88 }
89 
90 private void doSetReadOnly(string dir){
91   if (dir.isDir){
92     dir.setAttributes( octal!555);
93     foreach (d; dirEntries( dir, SpanMode.shallow)) {
94       if (!d.isSymlink){
95         if (d.isDir) {
96           doSetReadOnly( d);
97         }else {
98           d.setAttributes( octal!444);
99         }
100       }
101     }
102   }else {
103     dir.setAttributes( octal!444);
104   }
105 }
106 
107 void setWritable(string dir){
108   if (!exists( dir)){
109     return ;
110   }
111   doSetWritable( dir);
112 }
113 
114 private void doSetWritable(string dir){
115   if (dir.isDir){
116     dir.setAttributes( dir.getAttributes | octal!700);
117     foreach (d; dirEntries( dir, SpanMode.breadth)) {
118       if (!d.isSymlink){
119         if (d.isDir) {
120           doSetWritable( d);
121         }else {
122           d.setAttributes( d.getAttributes | octal!200);
123         }
124       }
125     }
126   }else {
127     dir.setAttributes( dir.getAttributes | octal!600);
128   }
129 }
130 
131 unittest{
132   import std.file : read;
133   import std.stdio;
134   auto zipPath="/tmp/beangle-bundles-bui-0.2.1.jar";
135   if (exists( zipPath)){
136     auto base="/tmp/beangle-bundles-bui-0.2.1";
137     unzip( zipPath,base,"META-INF/resources/bui");
138     setReadOnly( base);
139     setWritable( base);
140     base.rmdirRecurse();
141   }
142 }