1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00

Sqlite: Add option for read-only detection [#509]

This commit is contained in:
gnosygnu
2019-07-19 07:14:24 -04:00
parent 7f76d8128d
commit 989ccde83a
28 changed files with 669 additions and 168 deletions

View File

@@ -14,7 +14,8 @@ GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx;
import gplx.core.primitives.*; import gplx.core.ios.*; /*IoItmFil, IoItmDir..*/ import gplx.core.ios.streams.*; import gplx.core.ios.loaders.*;
import gplx.core.primitives.*;
import gplx.core.ios.*; /*IoItmFil, IoItmDir..*/ import gplx.core.ios.streams.*; import gplx.core.ios.loaders.*; import gplx.core.ios.atrs.*;
public class Io_mgr implements Gfo_evt_mgr_owner { // exists primarily to gather all cmds under gplx namespace; otherwise need to use gplx.core.ios whenever copying/deleting file
public Io_mgr() {evt_mgr = new Gfo_evt_mgr(this);}
public Gfo_evt_mgr Evt_mgr() {return evt_mgr;} private final Gfo_evt_mgr evt_mgr;
@@ -57,6 +58,7 @@ public class Io_mgr implements Gfo_evt_mgr_owner { // exists primarily to gather
}
public Io_url[] QueryDir_fils(Io_url dir) {return QueryDir_args(dir).ExecAsUrlAry();}
public IoEngine_xrg_queryDir QueryDir_args(Io_url dir) {return IoEngine_xrg_queryDir.new_(dir);}
public Io_itm_atr_req Query_itm_atrs(Io_url url, Io_itm_atr_req req) {return IoEnginePool.Instance.Get_by(url.Info().EngineKey()).Query_itm_atrs(url, req);}
public void DeleteDirSubs(Io_url url) {IoEngine_xrg_deleteDir.new_(url).Exec();}
public IoEngine_xrg_deleteDir DeleteDir_cmd(Io_url url) {return IoEngine_xrg_deleteDir.new_(url);}
public void DeleteDirDeep(Io_url url) {IoEngine_xrg_deleteDir.new_(url).Recur_().Exec();}
@@ -149,11 +151,13 @@ public class Io_mgr implements Gfo_evt_mgr_owner { // exists primarily to gather
}
public boolean DownloadFil(String src, Io_url trg) {return IoEngine_xrg_downloadFil.new_(src, trg).Exec();}
public IoEngine_xrg_downloadFil DownloadFil_args(String src, Io_url trg) {return IoEngine_xrg_downloadFil.new_(src, trg);}
public boolean Query_read_only(Io_url url, int read_only_type) {return IoEngineUtl.Query_read_only(IoEnginePool.Instance.Get_by(url.Info().EngineKey()), url, read_only_type);}
public static final Io_mgr Instance = new Io_mgr();
public static final int Len_kb = 1024, Len_mb = 1048576, Len_gb = 1073741824, Len_gb_2 = 2147483647;
public static final long Len_mb_long = Len_mb;
public static final long Len_null = -1;
public static final String Evt__fil_created = "fil_created";
public static final int Read_only__basic__file = 1, Read_only__basic__file_and_dirs = 2, Read_only__perms__file = 3;
}
class Io_mgr_ {
public static int Delete_dir_empty(Io_url url) {

View File

@@ -21,14 +21,14 @@ public class Ordered_hash_base extends Hash_adp_base implements Ordered_hash, Gf
@Override protected void Add_base(Object key, Object val) {
super.Add_base(key, val);
ordered.Add(val);
AssertCounts();
AssertCounts("Add_base", key);
}
@Override public void Del(Object key) {
if (!this.Has_base(key)) return;
Object val = this.Fetch_base(key);
this.Del_base(key);
ordered.Del(val);
AssertCounts();
AssertCounts("Del", key);
}
protected Object Get_at_base(int index) {return ordered.Get_at(index);}
protected int IndexOf_base(Object obj) {return ordered.Idx_of(obj);}
@@ -50,7 +50,7 @@ public class Ordered_hash_base extends Hash_adp_base implements Ordered_hash, Gf
if (locked) Lock_fail();
super.Add_base(key, val);
ordered.Add_at(i, val);
AssertCounts();
AssertCounts("Add_at", key);
}
public Ordered_hash Add_many_str(String... ary) {
int ary_len = ary.length;
@@ -61,8 +61,8 @@ public class Ordered_hash_base extends Hash_adp_base implements Ordered_hash, Gf
}
return this;
}
void AssertCounts() {
if (super.Count() != ordered.Count()) throw Err_.new_wo_type("counts do not match", "hash", super.Count(), "list", ordered.Count());
private void AssertCounts(String proc, Object key) {
if (super.Count() != ordered.Count()) throw Err_.new_wo_type("counts do not match; same key is either added twice, or delete failed", "proc", proc, "key", Object_.Xto_str_strict_or_null_mark(key), "hash", super.Count(), "list", ordered.Count());
}
public void Resize_bounds(int i) {if (locked) Lock_fail(); ordered.Resize_bounds(i);}
public void Lock() {locked = true;} private boolean locked = false;

View File

@@ -0,0 +1,147 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.caches; import gplx.*; import gplx.core.*;
public class Lru_cache {
private final Hash_adp map = Hash_adp_.New();
private Lru_node head, tail;
private long cur, min, max, evicts;
public Lru_cache(boolean auto_reg, String key, long min, long max) {
this.key = key;
this.min = min;
this.max = max;
if (auto_reg) Lru_cache_root.Instance.Add(this);
}
public String Key() {return key;} private final String key;
public long Evicts() {return evicts;}
public long Cur() {return cur;}
public void Min_max_(long min, long max) {
this.min = min;
this.max = max;
}
public Object Get_or_null(Object key) {
Lru_node nde = (Lru_node)map.Get_by(key);
if (nde == null) {
return null;
}
Del_node_from_linked_list(nde);
Add_to_tail(nde);
return nde.Val();
}
public void Set(Object key, Object val, long size) {
Lru_node nde = (Lru_node)map.Get_by(key);
if (nde != null) {
nde.Val_(val);
Del_node_from_linked_list(nde);
Add_to_tail(nde);
}
else {
this.Clear_min(size);
nde = new Lru_node(key, val, size);
Add_to_tail(nde);
map.Add(key, nde);
cur += size;
}
}
public void Del(Object key) {
Lru_node nde = (Lru_node)map.Get_by(key);
if (nde != null) {
Del_node_from_this(nde);
}
}
public void Clear_all() {
map.Clear();
head = null;
tail = null;
cur = 0;
}
public void Clear_min(long size) {
long threshold = min >= 0 ? min : max;
while (cur + size > threshold) {
Del_node_from_this(head);
evicts++;
}
}
private void Del_node_from_this(Lru_node nde) {
map.Del(nde.Key());
cur -= nde.Size();
Del_node_from_linked_list(nde);
}
private void Del_node_from_linked_list(Lru_node nde) {
if (nde.Prv() == null)
head = nde.Nxt();
else
nde.Prv().Nxt_(nde.Nxt());
if (nde.Nxt() == null)
tail = nde.Prv();
else
nde.Nxt().Prv_(nde.Prv());
}
private void Add_to_tail(Lru_node nde) {
if (tail != null)
tail.Nxt_(nde);
nde.Prv_(tail);
nde.Nxt_(null);
tail = nde;
if (head == null)
head = tail;
}
public void To_str(Bry_bfr bfr, boolean grps_only_or_both) {
bfr.Add_str_a7("g");
bfr.Add_byte_pipe().Add_str_u8(key);
bfr.Add_byte_pipe().Add_long_variable(cur);
bfr.Add_byte_pipe().Add_long_variable(min);
bfr.Add_byte_pipe().Add_long_variable(max);
bfr.Add_byte_nl();
if (grps_only_or_both) {
Lru_node nde = head;
while (nde != null) {
nde.To_str(bfr);
nde = nde.Nxt();
}
}
}
}
class Lru_node {
private final Object key;
private Object val;
private final long size;
private Lru_node prv;
private Lru_node nxt;
public Lru_node(Object key, Object val, long size) {
this.key = key;
this.val = val;
this.size = size;
}
public Object Key() {return key;}
public Object Val() {return val;} public void Val_(Object v) {this.val = v;}
public long Size() {return size;}
public Lru_node Prv() {return prv;} public void Prv_(Lru_node v) {this.prv = v;}
public Lru_node Nxt() {return nxt;} public void Nxt_(Lru_node v) {this.nxt = v;}
public void To_str(Bry_bfr bfr) {
bfr.Add_str_a7("i");
bfr.Add_byte_pipe().Add_str_u8(Object_.Xto_str_strict_or_null_mark(key));
bfr.Add_byte_pipe().Add_long_variable(size);
bfr.Add_byte_nl();
}
}

View File

@@ -0,0 +1,50 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.caches; import gplx.*; import gplx.core.*;
public class Lru_cache_root {
private final Ordered_hash hash = Ordered_hash_.New();
public Lru_cache Get_by_key(String key) {return (Lru_cache)hash.Get_by(key);}
public void Add(Lru_cache grp) {
hash.Add(grp.Key(), grp);
}
public void Del(String key) {
hash.Del(key);
}
public void Clear_caches_all() {
int len = hash.Len();
for (int i = 0; i < len; i++) {
Lru_cache grp = (Lru_cache)hash.Get_at(i);
grp.Clear_all();
}
}
public void Clear_caches_min() {
int len = hash.Len();
for (int i = 0; i < len; i++) {
Lru_cache grp = (Lru_cache)hash.Get_at(i);
grp.Clear_min(0);
}
}
public String Print_contents(boolean grps_only_or_both) {
Bry_bfr bfr = Bry_bfr_.New();
int len = hash.Len();
for (int i = 0; i < len; i++) {
Lru_cache grp = (Lru_cache)hash.Get_at(i);
grp.To_str(bfr, grps_only_or_both);
}
return bfr.To_str_and_clear();
}
public static final Lru_cache_root Instance = new Lru_cache_root();
}

View File

@@ -0,0 +1,104 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.caches; import gplx.*; import gplx.core.*;
import org.junit.*; import gplx.core.tests.*;
public class Lru_cache_tst {
private final Lru_cache_fxt fxt = new Lru_cache_fxt();
@Test public void Get_one() {
fxt.Exec__set("a", 5);
fxt.Test__get_y("a");
}
@Test public void Pop_one() {
fxt.Exec__set("a", 10);
fxt.Exec__set("b", 10);
fxt.Test__get_n("a");
fxt.Test__get_y("b");
}
@Test public void Add_many() {
fxt.Exec__set("a", 4);
fxt.Exec__set("b", 3);
fxt.Exec__set("c", 2);
fxt.Exec__set("d", 1);
fxt.Test__get_y("a", "b", "c", "d");
}
@Test public void Pop_many() {
fxt.Exec__set("a", 4);
fxt.Exec__set("b", 3);
fxt.Exec__set("c", 2);
fxt.Exec__set("d", 1);
fxt.Exec__set("e", 6);
fxt.Test__get_y("c", "d", "e");
fxt.Test__get_n("a", "b");
}
@Test public void Set_repeatedly() {
fxt.Exec__set("a", "a1", 10);
fxt.Exec__set("a", "a2", 10);
fxt.Exec__set("a", "a3", 10);
fxt.Test__get_val("a", "a3");
}
@Test public void Set_bumps_priority() {
fxt.Exec__set("a", 2);
fxt.Exec__set("b", 3);
fxt.Exec__set("c", 2);
fxt.Exec__set("a", 2);
fxt.Exec__set("d", 7);
fxt.Test__get_y("a", "d");
fxt.Test__get_n("b", "c");
}
@Test public void Del() {
fxt.Exec__set("a", 2);
fxt.Exec__set("b", 2);
fxt.Exec__del("b");
fxt.Test__get_y("a");
fxt.Test__get_n("b");
}
@Test public void Clear() {
fxt.Exec__set("a", 2);
fxt.Exec__set("b", 2);
fxt.Exec__clear();
fxt.Test__get_n("a", "b");
}
}
class Lru_cache_fxt {
private final Lru_cache cache = new Lru_cache(Bool_.N, "test", -1, 10);
public void Exec__set(String key, long size) {
cache.Set(key, key, size);
}
public void Exec__set(String key, String val, long size) {
cache.Set(key, val, size);
}
public void Exec__del(String key) {
cache.Del(key);
}
public void Exec__clear() {
cache.Clear_all();
}
public void Test__get_y(String... keys) {
for (String key : keys)
Test__get(key, key);
}
public void Test__get_n(String... keys) {
for (String key : keys)
Test__get(key, null);
}
public void Test__get_val(String key, String val) {
Test__get(key, val);
}
private void Test__get(String key, String expd) {
Object actl = cache.Get_or_null(key);
Gftest.Eq__obj_or_null(expd, actl);
}
}

View File

@@ -15,7 +15,7 @@ Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.ios; import gplx.*; import gplx.core.*;
import gplx.core.consoles.*; import gplx.core.criterias.*;
import gplx.core.ios.streams.*;
import gplx.core.ios.streams.*; import gplx.core.ios.atrs.*;
public interface IoEngine {
String Key();
boolean ExistsFil_api(Io_url url);
@@ -32,6 +32,7 @@ public interface IoEngine {
void XferFil(IoEngine_xrg_xferFil args);
void RecycleFil(IoEngine_xrg_recycleFil xrg);
boolean Truncate_fil(Io_url url, long size);
Io_itm_atr_req Query_itm_atrs(Io_url url, Io_itm_atr_req req);
boolean ExistsDir(Io_url url);
void CreateDir(Io_url url); // creates all folder levels (EX: C:\a\b\c\ will create C:\a\ and C:\a\b\). will not fail if called on already existing folders.
@@ -47,108 +48,3 @@ public interface IoEngine {
boolean DownloadFil(IoEngine_xrg_downloadFil xrg);
Io_stream_rdr DownloadFil_as_rdr(IoEngine_xrg_downloadFil xrg);
}
class IoEngineUtl {
public int BufferLength() {return bufferLength;} public void BufferLength_set(int v) {bufferLength = v;} int bufferLength = 4096; // 0x1000
public void DeleteRecycleGplx(IoEngine engine, IoEngine_xrg_recycleFil xrg) {
Io_url recycleUrl = xrg.RecycleUrl();
if (recycleUrl.Type_fil())
engine.MoveFil(IoEngine_xrg_xferFil.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true));
else
engine.MoveDirDeep(IoEngine_xrg_xferDir.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true));
}
public void DeleteDirDeep(IoEngine engine, Io_url dirUrl, IoEngine_xrg_deleteDir args) {
Console_adp usrDlg = args.UsrDlg();
IoItmDir dir = engine.QueryDir(dirUrl); if (!dir.Exists()) return;
for (Object subDirObj : dir.SubDirs()) {
IoItmDir subDir = (IoItmDir)subDirObj;
if (!args.SubDirScanCrt().Matches(subDir)) continue;
if (args.Recur()) DeleteDirDeep(engine, subDir.Url(), args);
}
for (Object subFilObj : dir.SubFils()) {
IoItmFil subFil = (IoItmFil)subFilObj;
if (!args.MatchCrt().Matches(subFil)) continue;
Io_url subFilUrl = subFil.Url();
try {engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(subFilUrl).ReadOnlyFails_(args.ReadOnlyFails()));}
catch (Exception exc) {usrDlg.Write_fmt_w_nl(Err_.Message_lang(exc));}
}
// all subs deleted; now delete dir
if (!args.MatchCrt().Matches(dir)) return;
try {engine.DeleteDir(dir.Url());}
catch (Exception exc) {usrDlg.Write_fmt_w_nl(Err_.Message_lang(exc));}
}
public void XferDir(IoEngine srcEngine, Io_url src, IoEngine trgEngine, Io_url trg, IoEngine_xrg_xferDir args) {
trgEngine.CreateDir(trg);
IoItmDir srcDir = QueryDirDeep(srcEngine, IoEngine_xrg_queryDir.new_(src).Recur_(false));
for (Object subSrcObj : srcDir.SubDirs()) {
IoItmDir subSrc = (IoItmDir)subSrcObj;
if (!args.SubDirScanCrt().Matches(subSrc)) continue;
if (!args.MatchCrt().Matches(subSrc)) continue;
Io_url subTrg = trg.GenSubDir_nest(subSrc.Url().NameOnly()); //EX: C:\abc\def\ -> C:\123\ + def\
if (args.Recur()) XferDir(srcEngine, subSrc.Url(), trgEngine, subTrg, args);
}
IoItmList srcFils = IoItmList.list_(src.Info().CaseSensitive());
for (Object srcFilObj : srcDir.SubFils()) {
IoItmFil srcFil = (IoItmFil)srcFilObj;
if (args.MatchCrt().Matches(srcFil)) srcFils.Add(srcFil);
}
for (Object srcFilObj : srcFils) {
IoItmFil srcFil = (IoItmFil)srcFilObj;
Io_url srcFilPath = srcFil.Url();
Io_url trgFilPath = trg.GenSubFil(srcFilPath.NameAndExt()); //EX: C:\abc\fil.txt -> C:\123\ + fil.txt
IoEngine_xrg_xferFil xferArgs = args.Type_move() ? IoEngine_xrg_xferFil.move_(srcFilPath, trgFilPath).Overwrite_(args.Overwrite()) : IoEngine_xrg_xferFil.copy_(srcFilPath, trgFilPath).Overwrite_(args.Overwrite());
XferFil(srcEngine, xferArgs);
}
if (args.Type_move()) srcEngine.DeleteDirDeep(IoEngine_xrg_deleteDir.new_(src).Recur_(args.Recur()).ReadOnlyFails_(args.ReadOnlyFails()));// this.DeleteDirDeep(srcEngine, src, IoEngine_xrg_deleteItm.new_(src).Recur_(args.Recur()).ReadOnlyIgnored_(args.ReadOnlyIgnored()));
}
public void XferFil(IoEngine srcEngine, IoEngine_xrg_xferFil args) {
Io_url src = args.Src(), trg = args.Trg();
if (String_.Eq(srcEngine.Key(), trg.Info().EngineKey())) {
if (args.Type_move())
srcEngine.MoveFil(args);
else
srcEngine.CopyFil(args);
}
else {
TransferStream(src, trg);
if (args.Type_move()) srcEngine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(src));
}
}
public IoItmDir QueryDirDeep(IoEngine engine, IoEngine_xrg_queryDir args) {
IoItmDir rv = IoItmDir_.top_(args.Url());
rv.Exists_set(QueryDirDeepCore(rv, args.Url(), engine, args.Recur(), args.SubDirScanCrt(), args.DirCrt(), args.FilCrt(), args.UsrDlg(), args.DirInclude()));
return rv;
}
static boolean QueryDirDeepCore(IoItmDir ownerDir, Io_url url, IoEngine engine, boolean recur, Criteria subDirScanCrt, Criteria dirCrt, Criteria filCrt, Console_adp usrDlg, boolean dirInclude) {
if (usrDlg.Canceled_chk()) return false;
if (usrDlg.Enabled()) usrDlg.Write_tmp(String_.Concat("scan: ", url.Raw()));
IoItmDir scanDir = engine.QueryDir(url);
for (Object subDirObj : scanDir.SubDirs()) {
IoItmDir subDir = (IoItmDir)subDirObj;
if (!subDirScanCrt.Matches(subDir)) continue;
if (dirCrt.Matches(subDir)) {
ownerDir.SubDirs().Add(subDir); // NOTE: always add subDir; do not use dirCrt here, else its subFils will be added to non-existent subDir
}
if (recur)
QueryDirDeepCore(subDir, subDir.Url(), engine, recur, subDirScanCrt, dirCrt, filCrt, usrDlg, dirInclude);
}
for (Object subFilObj : scanDir.SubFils()) {
IoItmFil subFil = (IoItmFil)subFilObj;
if (filCrt.Matches(subFil)) ownerDir.SubFils().Add(subFil);
}
return scanDir.Exists();
}
void TransferStream(Io_url src, Io_url trg) {
IoStream srcStream = null;
IoStream trgStream = null;
try {
srcStream = IoEnginePool.Instance.Get_by(src.Info().EngineKey()).OpenStreamRead(src);
trgStream = IoEngine_xrg_openWrite.new_(trg).Exec();
srcStream.Transfer(trgStream, bufferLength);
}
finally {
if (srcStream != null) srcStream.Rls();
if (trgStream != null) trgStream.Rls();
}
}
public static IoEngineUtl new_() {return new IoEngineUtl();} IoEngineUtl() {}
}

View File

@@ -0,0 +1,175 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.ios; import gplx.*; import gplx.core.*;
import gplx.core.ios.streams.*; import gplx.core.ios.atrs.*;
import gplx.core.consoles.*; import gplx.core.criterias.*; import gplx.core.caches.*;
import gplx.core.envs.*;
public class IoEngineUtl {
public int BufferLength() {return bufferLength;} public void BufferLength_set(int v) {bufferLength = v;} int bufferLength = 4096; // 0x1000
public void DeleteRecycleGplx(IoEngine engine, IoEngine_xrg_recycleFil xrg) {
Io_url recycleUrl = xrg.RecycleUrl();
if (recycleUrl.Type_fil())
engine.MoveFil(IoEngine_xrg_xferFil.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true));
else
engine.MoveDirDeep(IoEngine_xrg_xferDir.move_(xrg.Url(), recycleUrl).Overwrite_(false).ReadOnlyFails_(true));
}
public void DeleteDirDeep(IoEngine engine, Io_url dirUrl, IoEngine_xrg_deleteDir args) {
Console_adp usrDlg = args.UsrDlg();
IoItmDir dir = engine.QueryDir(dirUrl); if (!dir.Exists()) return;
for (Object subDirObj : dir.SubDirs()) {
IoItmDir subDir = (IoItmDir)subDirObj;
if (!args.SubDirScanCrt().Matches(subDir)) continue;
if (args.Recur()) DeleteDirDeep(engine, subDir.Url(), args);
}
for (Object subFilObj : dir.SubFils()) {
IoItmFil subFil = (IoItmFil)subFilObj;
if (!args.MatchCrt().Matches(subFil)) continue;
Io_url subFilUrl = subFil.Url();
try {engine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(subFilUrl).ReadOnlyFails_(args.ReadOnlyFails()));}
catch (Exception exc) {usrDlg.Write_fmt_w_nl(Err_.Message_lang(exc));}
}
// all subs deleted; now delete dir
if (!args.MatchCrt().Matches(dir)) return;
try {engine.DeleteDir(dir.Url());}
catch (Exception exc) {usrDlg.Write_fmt_w_nl(Err_.Message_lang(exc));}
}
public void XferDir(IoEngine srcEngine, Io_url src, IoEngine trgEngine, Io_url trg, IoEngine_xrg_xferDir args) {
trgEngine.CreateDir(trg);
IoItmDir srcDir = QueryDirDeep(srcEngine, IoEngine_xrg_queryDir.new_(src).Recur_(false));
for (Object subSrcObj : srcDir.SubDirs()) {
IoItmDir subSrc = (IoItmDir)subSrcObj;
if (!args.SubDirScanCrt().Matches(subSrc)) continue;
if (!args.MatchCrt().Matches(subSrc)) continue;
Io_url subTrg = trg.GenSubDir_nest(subSrc.Url().NameOnly()); //EX: C:\abc\def\ -> C:\123\ + def\
if (args.Recur()) XferDir(srcEngine, subSrc.Url(), trgEngine, subTrg, args);
}
IoItmList srcFils = IoItmList.list_(src.Info().CaseSensitive());
for (Object srcFilObj : srcDir.SubFils()) {
IoItmFil srcFil = (IoItmFil)srcFilObj;
if (args.MatchCrt().Matches(srcFil)) srcFils.Add(srcFil);
}
for (Object srcFilObj : srcFils) {
IoItmFil srcFil = (IoItmFil)srcFilObj;
Io_url srcFilPath = srcFil.Url();
Io_url trgFilPath = trg.GenSubFil(srcFilPath.NameAndExt()); //EX: C:\abc\fil.txt -> C:\123\ + fil.txt
IoEngine_xrg_xferFil xferArgs = args.Type_move() ? IoEngine_xrg_xferFil.move_(srcFilPath, trgFilPath).Overwrite_(args.Overwrite()) : IoEngine_xrg_xferFil.copy_(srcFilPath, trgFilPath).Overwrite_(args.Overwrite());
XferFil(srcEngine, xferArgs);
}
if (args.Type_move()) srcEngine.DeleteDirDeep(IoEngine_xrg_deleteDir.new_(src).Recur_(args.Recur()).ReadOnlyFails_(args.ReadOnlyFails()));// this.DeleteDirDeep(srcEngine, src, IoEngine_xrg_deleteItm.new_(src).Recur_(args.Recur()).ReadOnlyIgnored_(args.ReadOnlyIgnored()));
}
public void XferFil(IoEngine srcEngine, IoEngine_xrg_xferFil args) {
Io_url src = args.Src(), trg = args.Trg();
if (String_.Eq(srcEngine.Key(), trg.Info().EngineKey())) {
if (args.Type_move())
srcEngine.MoveFil(args);
else
srcEngine.CopyFil(args);
}
else {
TransferStream(src, trg);
if (args.Type_move()) srcEngine.DeleteFil_api(IoEngine_xrg_deleteFil.new_(src));
}
}
public IoItmDir QueryDirDeep(IoEngine engine, IoEngine_xrg_queryDir args) {
IoItmDir rv = IoItmDir_.top_(args.Url());
rv.Exists_set(QueryDirDeepCore(rv, args.Url(), engine, args.Recur(), args.SubDirScanCrt(), args.DirCrt(), args.FilCrt(), args.UsrDlg(), args.DirInclude()));
return rv;
}
static boolean QueryDirDeepCore(IoItmDir ownerDir, Io_url url, IoEngine engine, boolean recur, Criteria subDirScanCrt, Criteria dirCrt, Criteria filCrt, Console_adp usrDlg, boolean dirInclude) {
if (usrDlg.Canceled_chk()) return false;
if (usrDlg.Enabled()) usrDlg.Write_tmp(String_.Concat("scan: ", url.Raw()));
IoItmDir scanDir = engine.QueryDir(url);
for (Object subDirObj : scanDir.SubDirs()) {
IoItmDir subDir = (IoItmDir)subDirObj;
if (!subDirScanCrt.Matches(subDir)) continue;
if (dirCrt.Matches(subDir)) {
ownerDir.SubDirs().Add(subDir); // NOTE: always add subDir; do not use dirCrt here, else its subFils will be added to non-existent subDir
}
if (recur)
QueryDirDeepCore(subDir, subDir.Url(), engine, recur, subDirScanCrt, dirCrt, filCrt, usrDlg, dirInclude);
}
for (Object subFilObj : scanDir.SubFils()) {
IoItmFil subFil = (IoItmFil)subFilObj;
if (filCrt.Matches(subFil)) ownerDir.SubFils().Add(subFil);
}
return scanDir.Exists();
}
void TransferStream(Io_url src, Io_url trg) {
IoStream srcStream = null;
IoStream trgStream = null;
try {
srcStream = IoEnginePool.Instance.Get_by(src.Info().EngineKey()).OpenStreamRead(src);
trgStream = IoEngine_xrg_openWrite.new_(trg).Exec();
srcStream.Transfer(trgStream, bufferLength);
}
finally {
if (srcStream != null) srcStream.Rls();
if (trgStream != null) trgStream.Rls();
}
}
private static final Lru_cache Dir_cache = new Lru_cache(Bool_.Y, "gplx.ios.dir_cache", 128, 256);
public static boolean Query_read_only(IoEngine engine, Io_url url, int read_only_type) {
switch (read_only_type) {
case Io_mgr.Read_only__basic__file:
return engine.QueryFil(url).Attrib().ReadOnly();
case Io_mgr.Read_only__basic__file_and_dirs:
if (Op_sys.Cur().Tid_is_wnt()) // only examine owner_dirs if wnt
return Query_read_only__file_and_dirs(engine, url);
else
return engine.QueryFil(url).Attrib().ReadOnly();
case Io_mgr.Read_only__perms__file:
return engine.Query_itm_atrs(url, Io_itm_atr_req.New__read_only()).Is_read_only();
default:
throw Err_.new_unhandled_default(read_only_type);
}
}
private static boolean Query_read_only__file_and_dirs(IoEngine engine, Io_url url) {
// if fil
if (url.Type_fil()) {
IoItmFil fil = engine.QueryFil(url);
// if read-only, return true
if (fil.ReadOnly())
return true;
// else, set to owner dir
else
url = url.OwnerDir();
}
// loop until top
while (url != Io_url_.Empty) {
String dir_key = url.Raw();
// check cache first
IoItmDir dir = (IoItmDir)Dir_cache.Get_or_null(dir_key);
if (dir == null) {
// not in cache; query file_system
dir = engine.QueryDir(url);
Dir_cache.Set(dir_key, dir, 1);
}
// if read-only, return true
if (dir.ReadOnly())
return true;
// else, set to owner dir
else
url = url.OwnerDir();
}
return false;
}
public static IoEngineUtl new_() {return new IoEngineUtl();} IoEngineUtl() {}
}

View File

@@ -14,7 +14,8 @@ GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.ios; import gplx.*; import gplx.core.*;
import gplx.core.ios.streams.*;
import gplx.core.ios.streams.*; import gplx.core.ios.atrs.*;
import gplx.core.caches.*;
public abstract class IoEngine_base implements IoEngine {
public abstract String Key();
public abstract boolean ExistsFil_api(Io_url url);
@@ -24,6 +25,7 @@ public abstract class IoEngine_base implements IoEngine {
public abstract void CopyFil(IoEngine_xrg_xferFil args);
public abstract void MoveFil(IoEngine_xrg_xferFil args);
public abstract IoItmFil QueryFil(Io_url url);
public abstract Io_itm_atr_req Query_itm_atrs(Io_url url, Io_itm_atr_req req);
public abstract void UpdateFilAttrib(Io_url url, IoItmAttrib atr); // will fail if file does not exists
public abstract void UpdateFilModifiedTime(Io_url url, DateAdp modified);
public abstract IoStream OpenStreamRead(Io_url url);

View File

@@ -14,7 +14,7 @@ GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.ios; import gplx.*; import gplx.core.*;
import gplx.core.ios.streams.*;
import gplx.core.ios.streams.*; import gplx.core.ios.atrs.*;
public class IoEngine_memory extends IoEngine_base {
@Override public String Key() {return key;} private String key = IoEngine_.MemKey;
@Override public boolean ExistsFil_api(Io_url url) {return FetchFil(url) != IoItmFil_mem.Null;}
@@ -190,6 +190,9 @@ public class IoEngine_memory extends IoEngine_base {
byte[] bry = Bry_.new_u8(FetchFil(Io_url_.mem_fil_(xrg.Src())).Text());
return Io_stream_rdr_.New__mem(bry);
}
@Override public Io_itm_atr_req Query_itm_atrs(Io_url url, Io_itm_atr_req req) {
return req;
}
IoItmHash dirs = IoItmHash.new_();
IoEngineUtl utl = IoEngineUtl.new_();

View File

@@ -21,12 +21,8 @@ import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.*;
import java.nio.channels.*;
import java.util.Date;
import javax.print.FlavorException;
import javax.tools.JavaCompiler;
import gplx.core.criterias.*; import gplx.core.bits.*; import gplx.core.envs.*;
import gplx.core.ios.streams.*;
import gplx.core.ios.streams.*; import gplx.core.ios.atrs.*;
import gplx.core.progs.*;
public class IoEngine_system extends IoEngine_base {
@Override public String Key() {return IoEngine_.SysKey;}
@@ -42,6 +38,9 @@ public class IoEngine_system extends IoEngine_base {
if (!Fil_Exists(fil)) return;
MarkFileWritable(fil, url, args.ReadOnlyFails(), "DeleteFile");
DeleteFil_lang(fil, url);
}
@Override public Io_itm_atr_req Query_itm_atrs(Io_url url, Io_itm_atr_req req) {
return Io_itm_atr_wkr.New(url).Process(req);
}
@Override public boolean ExistsFil_api(Io_url url) {
File f = new File(url.Xto_api());
@@ -158,7 +157,9 @@ public class IoEngine_system extends IoEngine_base {
&& String_.Eq(url.OwnerDir().Raw(), String_.Empty) // folder is drive; EX: "C:"
)
url_api = url_api + "\\"; // add "\\"; else listFiles will return working folder's files, not C:; DATE:2016-04-07
File dirInfo = new File(url_api);
rv.ReadOnly_(!dirInfo.canWrite()); // get read-only flag for directories; ISSUE#:509; DATE:2019-07-11
if (!dirInfo.exists()) {
rv.Exists_set(false);
return rv;

View File

@@ -17,7 +17,8 @@ package gplx.core.ios; import gplx.*; import gplx.core.*;
import gplx.core.criterias.*;
public class IoItmDir extends IoItm_base {
public boolean Exists() {return exists;} public void Exists_set(boolean v) {exists = v;} private boolean exists = true;
@Override public int TypeId() {return Type_Dir;} @Override public boolean Type_dir() {return true;} @Override public boolean Type_fil() {return false;} public static final int Type_Dir = 1;
@Override public int TypeId() {return Type_Dir;} @Override public boolean Type_dir() {return true;} @Override public boolean Type_fil() {return false;} public static final int Type_Dir = 1;
public boolean ReadOnly() {return readOnly;} public IoItmDir ReadOnly_(boolean val) {this.readOnly = val; return this;} private boolean readOnly;
@gplx.New public IoItmDir XtnProps_set(String key, Object val) {return (IoItmDir)super.XtnProps_set(key, val);}
public IoItmList SubDirs() {return subDirs;} IoItmList subDirs;
public IoItmList SubFils() {return subFils;} IoItmList subFils;

View File

@@ -0,0 +1,35 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.ios.atrs; import gplx.*; import gplx.core.*; import gplx.core.ios.*;
public class Io_itm_atr_req {
Io_itm_atr_req(boolean ignore_errors, boolean check_read_only) {
this.ignore_errors = ignore_errors;
this.check_read_only = check_read_only;
}
public boolean Check_read_only() {return check_read_only;} private final boolean check_read_only;
public boolean Is_read_only() {return is_read_only;} public void Is_read_only_(boolean v) {this.is_read_only = v;} private boolean is_read_only;
public boolean Ignore_errors() {return ignore_errors;} private final boolean ignore_errors;
public String To_str() {
Keyval[] ary = new Keyval[2];
ary[0] = Keyval_.new_("check_read_only", check_read_only);
ary[1] = Keyval_.new_("is_read_only", is_read_only);
return Keyval_.Ary_to_str(ary);
}
public static Io_itm_atr_req New__read_only() {
return new Io_itm_atr_req(true, true);
}
}

View File

@@ -0,0 +1,63 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.ios.atrs; import gplx.*; import gplx.core.*; import gplx.core.ios.*;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.attribute.AclFileAttributeView;
import java.nio.file.attribute.PosixFileAttributeView;
import java.util.Set;
public abstract class Io_itm_atr_wkr {
private final Path path;
public Io_itm_atr_wkr(Path path) {
this.path = path;
}
public Io_itm_atr_req Process(Io_itm_atr_req req) {
try {
if (req.Check_read_only())
req.Is_read_only_(this.Is_read_only());
}
catch (Exception e) {
Err err = Err_.new_wo_type("query_itm_atrs failed", "url", path.toString(), "atrs", req.To_str(), "e", Err_.Message_gplx_log(e));
if (req.Ignore_errors()) { // https://stackoverflow.com/questions/25163174/get-generic-folder-permissions-like-generic-all-using-javas-aclfileattributev
Gfo_usr_dlg_.Instance.Warn_many("", "", err.To_str__log());
}
else {
throw err;
}
}
return req;
}
public abstract boolean Is_read_only();
public static Io_itm_atr_wkr New(Io_url url) {
File fil = new File(url.Xto_api());
Path path = fil.toPath();
Set<String> supported_views = path.getFileSystem().supportedFileAttributeViews();
if (supported_views.contains("posix")) {
return new Io_itm_atr_wkr__psx(path);
}
// WNT
else if (supported_views.contains("acl")) {
return new Io_itm_atr_wkr__acl(path);
}
else {
String set_string = "";
for (String view : supported_views) {
set_string += view + ";";
}
throw Err_.new_unhandled(set_string);
}
}
}

View File

@@ -0,0 +1,93 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.ios.atrs; import gplx.*; import gplx.core.*; import gplx.core.ios.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.AclEntry;
import java.nio.file.attribute.AclEntryPermission;
import java.nio.file.attribute.AclEntryType;
import java.nio.file.attribute.AclFileAttributeView;
import java.util.List;
import java.util.Set;
import gplx.core.primitives.Bool_obj_val;
class Io_itm_atr_wkr__acl extends Io_itm_atr_wkr { private final AclFileAttributeView view;
public Io_itm_atr_wkr__acl(Path path) {
super(path);
this.view = Files.getFileAttributeView(path, AclFileAttributeView.class);
}
@Override public boolean Is_read_only() {
try {
// convert AclEntry to Acl_entry
List<AclEntry> list = view.getAcl();
int len = list.size();
Acl_entry[] ary = new Acl_entry[len];
for (int i = 0; i < len; i++) {
AclEntry under = list.get(i);
ary[i] = new Acl_entry(under.principal().toString(), under.type(), under.permissions());
}
return !Is_permitted(ary, AclEntryPermission.WRITE_DATA);
} catch (Exception e) {
throw Err_.new_exc(e, "", "Is_read_only failed", "e", Err_.Message_lang(e));
}
}
public static boolean Is_permitted(Acl_entry[] ary, AclEntryPermission permission) {
boolean rv = false;
Hash_adp principals = Hash_adp_.New();
for (Acl_entry itm : ary) {
Set<AclEntryPermission> permissions = itm.Permissions();
switch (itm.Type()) {
// If multiple ALLOW entries
// * for same principal, return false if any of them do not have permission
// * for diff principals, return true if any of them does have permissions
case ALLOW: {
// if current principal is forbidden, ignore entry; want to skip lists like Everyone:Forbidden:C:/folder;Everyone:Allowed;C:/
Bool_obj_val forbidden = (Bool_obj_val)principals.Get_by(itm.Principal());
if (forbidden != null) {
continue;
}
if (!permissions.contains(permission) && !rv) {
rv = false;
principals.Add(itm.Principal(), Bool_obj_val.False);
}
else {
rv = true;
}
break;
}
// If any DENY entries, return false on first entry
case DENY: {
if (permissions.contains(permission)) {
return false;
}
break;
}
}
}
return rv;
}
}
class Acl_entry {
public Acl_entry(String principal, AclEntryType type, Set<AclEntryPermission> permissions) {
this.principal = principal;
this.type = type;
this.permissions = permissions;
}
public String Principal() {return principal;} private final String principal;
public AclEntryType Type() {return type;} private final AclEntryType type;
public Set<AclEntryPermission> Permissions() {return permissions;} private final Set<AclEntryPermission> permissions;
}
//#}

View File

@@ -0,0 +1,80 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.ios.atrs; import gplx.*; import gplx.core.*; import gplx.core.ios.*;
import org.junit.*; import gplx.core.tests.*;
import java.nio.file.attribute.AclEntryPermission;
import java.nio.file.attribute.AclEntryType;
import java.util.HashSet;
import java.util.Set;
public class Io_itm_atr_wkr__acl__tst {
private final Io_itm_attrib_wkr__acl__fxt fxt = new Io_itm_attrib_wkr__acl__fxt();
@Test public void Perm_exists() {
fxt.Test__Is_permitted
( Bool_.Y, AclEntryPermission.WRITE_DATA
, fxt.Make__acl("Everyone", AclEntryType.ALLOW, AclEntryPermission.WRITE_DATA)
);
}
@Test public void Perm_missing() {
fxt.Test__Is_permitted
( Bool_.N, AclEntryPermission.WRITE_DATA
, fxt.Make__acl("Everyone", AclEntryType.ALLOW, AclEntryPermission.READ_DATA)
);
}
@Test public void Deny_over_allow() {
fxt.Test__Is_permitted
( Bool_.N, AclEntryPermission.WRITE_DATA
, fxt.Make__acl("Everyone", AclEntryType.ALLOW, AclEntryPermission.WRITE_DATA)
, fxt.Make__acl("Everyone", AclEntryType.DENY , AclEntryPermission.WRITE_DATA)
);
}
@Test public void Same_principal__perm_missing_over_perm_exists() {
/*
EX: SD card wherein acl_list has 2 entries
* Entry[0] | //MACHINE/SHARE | Everyone:READ_DATA/READ_NAMED_ATTRS/EXECUTE/READ_ATTRIBUTES/READ_ACL/SYNCHRONIZE:ALLOW
* Entry[1] | DRIVE_NAME:/ | Everyone:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:ALLOW
*/
fxt.Test__Is_permitted
( Bool_.N, AclEntryPermission.WRITE_DATA
, fxt.Make__acl("Everyone", AclEntryType.ALLOW, AclEntryPermission.READ_DATA)
, fxt.Make__acl("Everyone", AclEntryType.ALLOW, AclEntryPermission.READ_DATA, AclEntryPermission.WRITE_DATA)
);
}
@Test public void Diff_principals__perm_exists_over_perm_missing() {
/*
EX: C drive wherein acl_list has 2 entries
* Entry[0] | C:/ | Administrators:READ_DATA/WRITE_DATA
* Entry[1] | C:/ | Everyone:READ_DATA
*/
fxt.Test__Is_permitted
( Bool_.Y, AclEntryPermission.WRITE_DATA
, fxt.Make__acl("Administrators", AclEntryType.ALLOW, AclEntryPermission.WRITE_DATA)
, fxt.Make__acl("Users" , AclEntryType.ALLOW, AclEntryPermission.READ_DATA)
);
}
}
class Io_itm_attrib_wkr__acl__fxt {
public void Test__Is_permitted(boolean expd, AclEntryPermission permission, Acl_entry... entries) {
boolean actl = Io_itm_atr_wkr__acl.Is_permitted(entries, permission);
Gftest.Eq__bool(expd, actl);
}
public Acl_entry Make__acl(String principal, AclEntryType type, AclEntryPermission... perms) {
Set<AclEntryPermission> perm_set = new HashSet<AclEntryPermission>();
for (AclEntryPermission perm : perms)
perm_set.add(perm);
return new Acl_entry(principal, type, perm_set);
}
}

View File

@@ -0,0 +1,52 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012-2017 gnosygnu@gmail.com
XOWA is licensed under the terms of the General Public License (GPL) Version 3,
or alternatively under the terms of the Apache License Version 2.0.
You may use XOWA according to either of these licenses as is most appropriate
for your project on a case-by-case basis.
The terms of each license can be found in the source code repository:
GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt
Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt
*/
package gplx.core.ios.atrs; import gplx.*; import gplx.core.*; import gplx.core.ios.*;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFileAttributes;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Set;
class Io_itm_atr_wkr__psx extends Io_itm_atr_wkr { private final PosixFileAttributeView view;
public Io_itm_atr_wkr__psx(Path path) {
super(path);
this.view = Files.getFileAttributeView(path, PosixFileAttributeView.class);
}
@Override public boolean Is_read_only() {
try {
// ASSUME:a file is read-only if it is read-only; Note that the directory may need write-access, but not handling it now; REF:https://superuser.com/a/114611
Set<PosixFilePermission> perms = view.readAttributes().permissions();
int perm_flag = Psx__permissions_to_int(perms);
return perm_flag == 0444;
} catch (Exception e) {
throw Err_.new_exc(e, "", "Is_read_only failed", "e", Err_.Message_lang(e));
}
}
public static int Psx__permissions_to_int(Set<PosixFilePermission> psx_perms) {
int rv = 0;
rv |= ((psx_perms.contains(PosixFilePermission.OWNER_READ)) ? 1 << 8 : 0);
rv |= ((psx_perms.contains(PosixFilePermission.OWNER_WRITE)) ? 1 << 7 : 0);
rv |= ((psx_perms.contains(PosixFilePermission.OWNER_EXECUTE)) ? 1 << 6 : 0);
rv |= ((psx_perms.contains(PosixFilePermission.GROUP_READ)) ? 1 << 5 : 0);
rv |= ((psx_perms.contains(PosixFilePermission.GROUP_WRITE)) ? 1 << 4 : 0);
rv |= ((psx_perms.contains(PosixFilePermission.GROUP_EXECUTE)) ? 1 << 3 : 0);
rv |= ((psx_perms.contains(PosixFilePermission.OTHERS_READ)) ? 1 << 2 : 0);
rv |= ((psx_perms.contains(PosixFilePermission.OTHERS_WRITE)) ? 1 << 1 : 0);
rv |= ((psx_perms.contains(PosixFilePermission.OTHERS_EXECUTE)) ? 1 : 0);
return rv;
}
}

View File

@@ -24,7 +24,7 @@ public class IoStream_mock implements IoStream {
if (bytes_read > read_limit) bytes_read = read_limit; // stream may limit maximum read; EX: bfr_len of 16k but only 2k will be filled
int bytes_left = data_bry_len - data_bry_pos;
if (bytes_read > bytes_left) bytes_read = bytes_left; // not enough bytes left in data_bry; bytes_read = whatever is left
Bry_.Copy_by_pos(data_bry, data_bry_pos, data_bry_pos + bytes_read, bfr, bfr_bgn);
Bry_.Copy_to(data_bry, data_bry_pos, data_bry_pos + bytes_read, bfr, bfr_bgn);
data_bry_pos += bytes_read;
return bytes_read;
}