Merge pull request #2079 from bergware/master

File manager: style fixes
This commit is contained in:
tom mortensen
2025-03-22 15:44:30 -07:00
committed by GitHub
9 changed files with 239 additions and 153 deletions

View File

@@ -3,8 +3,8 @@ Tag="home"
Nchan="file_manager"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2025, Lime Technology
* Copyright 2012-2025, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -18,21 +18,24 @@ Nchan="file_manager"
function dfm_quote($text) {
return "\"$text\"";
}
function dfm_array($array) {
return implode(',',array_map('dfm_quote',$array));
return implode(',', array_map('dfm_quote', $array));
}
function validdir($dir) {
$path = realpath($dir);
return in_array(explode('/',$path)[1]??'',['mnt','boot']) ? $path : '';
return in_array(explode('/', $path)[1] ?? '', ['mnt','boot']) ? $path : '';
}
$dir = validdir(htmlspecialchars_decode($dir));
[$none,$root,$main,$next,$rest] = my_explode('/',$dir,5);
$dir = htmlspecialchars(str_replace('\\','\\\\',$dir));
$lock = $root=='mnt' ? ($main ?: '---') : ($root=='boot' ? _('flash') : '---');
$isshare = $root=='mnt' && (!$main || !$next || ($main=='rootshare' && !$rest));
[$none,$root,$main,$next,$rest] = my_explode('/', $dir,5);
$dir = htmlspecialchars(str_replace('\\','\\\\', $dir));
$lock = $root == 'mnt' ? ($main ?: '---') : ($root == 'boot' ? _('flash') : '---');
$isshare = $root == 'mnt' && (!$main || !$next || ($main == 'rootshare' && !$rest));
$editor = '/boot/config/editor.cfg';
if (!file_exists($editor)) file_put_contents($editor,implode("\n",['','txt','js','php','page','plg','xml','old','bak','log','css']));
if (!file_exists($editor)) file_put_contents($editor, implode("\n",['','txt','js','php','page','plg','xml','old','bak','log','css']));
?>
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.filetree.css")?>">
<link type="text/css" rel="stylesheet" href="<?autov("/webGui/styles/jquery.switchbutton.css")?>">
@@ -41,19 +44,20 @@ if (!file_exists($editor)) file_put_contents($editor,implode("\n",['','txt','js'
<script src="<?autov("/webGui/javascript/jquery.switchbutton.js")?>"></script>
<script>
// General variables
var dir = "<?=$dir?>";
var dir = "<?=$dir?>";
var table = null;
var thead = null;
function autoscale(value) {
var unit = ['B','kB','MB','GB','TB','PB','EB'];
var base = value>1?Math.floor(Math.log(value)/Math.log(1000)):0;
var data = base<unit.length ? value/Math.pow(1000, base) : 0;
var unit = ['B','kB','MB','GB','TB','PB','EB'];
var base = value>1?Math.floor(Math.log(value)/Math.log(1000)):0;
var data = base<unit.length ? value/Math.pow(1000, base) : 0;
var scale = data<100?100:10;
if (data==0) base=0;
if (data == 0) base = 0;
return ((Math.round(scale*data)/scale)+' '+unit[base]).replace('.','<?=$display['number'][0]?>')+'/s';
}
function folderContextMenu(id,button) {
function folderContextMenu(id, button) {
var opts = [];
context.settings({button:button});
if (dfm.running) {
@@ -81,7 +85,8 @@ function folderContextMenu(id,button) {
}
context.attach('#'+id, opts);
}
function fileContextMenu(id,button) {
function fileContextMenu(id, button) {
var opts = [];
context.settings({button:button});
if (dfm.running) {
@@ -106,7 +111,8 @@ function fileContextMenu(id,button) {
}
context.attach('#'+id, opts);
}
function deviceFolderContextMenu(dev,id) {
function deviceFolderContextMenu(dev, id) {
var opts = [];
context.settings({button:'both'});
if (dfm.running) {
@@ -121,7 +127,8 @@ function deviceFolderContextMenu(dev,id) {
}
context.attach('#device_'+id, opts);
}
function deviceFileContextMenu(dev,id) {
function deviceFileContextMenu(dev, id) {
var opts = [];
context.settings({button:'both'});
if (dfm.running) {
@@ -134,7 +141,8 @@ function deviceFileContextMenu(dev,id) {
}
context.attach('#device_'+id, opts);
}
function home(source,target) {
function home(source, target) {
var equal = '?';
$.ajax({
async: false,
@@ -146,9 +154,11 @@ function home(source,target) {
});
return equal;
}
function resize() {
$('div.autoheight').height(Math.max(window.innerHeight-320,330));
}
function selectAll() {
if (dfm.running) {
context.attach('#check_0', [{text:"_(Job running)_", icon:"fa fa-ban"}]);
@@ -169,7 +179,8 @@ function selectAll() {
<?endif;?>
}
}
function selectOne(id,check=true) {
function selectOne(id, check=true) {
if (dfm.running && check) {
context.attach('#'+id, [{text:"_(Job running)_", icon:"fa fa-ban"}]);
return;
@@ -183,36 +194,42 @@ function selectOne(id,check=true) {
var checked = 0;
if (check) {
$('i[id^="check_"]').each(function(){if ($(this).prop('id')!='check_0' && $(this).hasClass('fa-check-square-o')) checked++;});
$('input.extra').prop('disabled',checked==0);
$('input.extra').prop('disabled',checked == 0);
<?if (!$isshare):?>
$('input.rename').prop('disabled',checked!=1);
$('input.rename').prop('disabled',checked != 1);
<?endif;?>
} else {
$('i[id^="queue_"]').each(function(){if ($(this).hasClass('fa-check-square-o')) checked++;});
$('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',checked==0);
$('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',checked == 0);
}
}
function errorSource() {
swal({title:"_(Invalid source)_",text:"_(Not allowed to mix disk and user shares)_",html:true,type:'error',confirmButtonText:"_(Ok)_"});
}
function errorTarget() {
swal({title:"_(Invalid target)_",text:"_(Enter a valid target)_",html:true,type:'error',confirmButtonText:"_(Ok)_"},function(x){dfm.window.find('#dfm_target').prop('disabled',false);});
}
function data(id) {
var data = id.attr('data').dfm_quote();
<?if ($isshare):?>
return id.attr('type')=='d' ? data+'/' : data;
return id.attr('type') == 'd' ? data+'/' : data;
<?else:?>
return data;
<?endif;?>
}
function fileName(file) {
return file.indexOf('/')>=0 ? file.split('/').pop() : file;
}
function fileExtension(file) {
file = fileName(file);
return file.indexOf('.')>=0 ? file.split('.').pop() : '';
}
function fileEdit(id) {
const known = ["","cfg","conf",<?=dfm_array(file($editor,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES))?>];
var source = $('#'+id.dfm_proxy()).attr('data').dfm_quote();
@@ -231,16 +248,16 @@ function fileEdit(id) {
// file editor dialog
dfm.window.html($("#dfm_templateEditFile").html().replace('{$0}',source).dfm_build());
dfm.window.dialog({
dialogClass: 'ui-dfm',
classes: {'ui-dialog': 'ui-dfm'},
autoOpen: true,
title: fileName(source),
height: Math.min(window.innerHeight-80,800),
width: Math.min(window.innerWidth,1200),
height: Math.min(window.innerHeight-80, 800),
width: Math.min(window.innerWidth, 1200),
resizable: false,
modal: true,
buttons: {
"_(Save)_": function(){
$.post('/webGui/include/Control.php',{mode:'save',file:encodeURIComponent(source), data:encodeURIComponent(editor.session.getValue())});
$.post('/webGui/include/Control.php',{mode:'save', file:encodeURIComponent(source), data:encodeURIComponent(editor.session.getValue())});
dfm.window.dialog('destroy');
setTimeout(loadList,100);
},
@@ -251,6 +268,7 @@ function fileEdit(id) {
});
$('.ui-dfm .ui-dialog-titlebar-close').html('<i class="fa fa-expand"></i>').prop('title',"_(Expand)_").prop('onclick',null).off('click').click(function(){fullWindow();}).show();
}
function fullWindow() {
if ($('.ui-dfm .ui-dialog-titlebar-close').html().indexOf('expand')>=0) {
dfm.window.dialog('option','height',window.innerHeight-40);
@@ -265,11 +283,12 @@ function fullWindow() {
}
editor.resize();
}
function doJobs(title) {
dfm.window = $("#dfm_dialogWindow");
dfm.window.html($('#dfm_templateJobs').html().dfm_build());
dfm.window.dialog({
dialogClass: 'ui-dfm',
classes: {'ui-dialog': 'ui-dfm'},
autoOpen: true,
title: title,
height: 630,
@@ -278,7 +297,7 @@ function doJobs(title) {
modal: true,
buttons: {
"_(Start)_": function(){
$.post('/webGui/include/Control.php',{mode:'start'},function(queue){
$.post('/webGui/include/Control.php', {mode:'start'}, function(queue){
if (parseInt(queue) > 0) {
if (dfm.window.find('i[id^="queue_"]').length < 2) $.removeCookie('dfm_control.jobs');
dfm.window.dialog('close');
@@ -295,7 +314,7 @@ function doJobs(title) {
$('#dfm_jobs').html(jobs);
if (dfm.window.find('i[id^="queue_"]').length==0) $.removeCookie('dfm_control.jobs');
});
if (parseInt(queue)==1) {
if (parseInt(queue) == 1) {
setTimeout(function(){$('#dfm_jobs').html("<div id='dfm_joblist'><i class='fa fa-fw fa-minus-square-o grey-text job'></i>_(No jobs scheduled)_ ...</div>");},100);
$('.ui-dfm .ui-dialog-buttonset button:eq(0)').prop('disabled',true);
$('.dfm_control.jobs').prop('disabled',true);
@@ -313,25 +332,26 @@ function doJobs(title) {
if (dfm.running) $('.ui-dfm .ui-dialog-buttonset button:eq(0)').prop('disabled',true);
$('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',true);
}
var filemonitor = new NchanSubscriber('/sub/filemonitor',{subscriber:'websocket'});
filemonitor.on('message', function(state) {
if (state==1 && !dfm.running && !timers.filemonitor) timers.filemonitor = setTimeout(function(){if (dfm.running) clearTimeout(timers.filemonitor); else refresh();},1500);
if (state == 1 && !dfm.running && !timers.filemonitor) timers.filemonitor = setTimeout(function(){if (dfm.running) clearTimeout(timers.filemonitor); else refresh();},1500);
});
setTimeout(function(){filemonitor.start();},3000);
function doAction(action,title,id) {
var link = id.substr(0,1)=='/';
function doAction(action, title, id) {
var link = id.substr(0,1) == '/';
var source = link ? id : data($('#'+id));
var path = source.substr(1).split('/');
var zfs = '';
<?if ($dfm['zfs']):?>
if ([1,4].includes(action) && path[0]=='mnt') {
if ([1,4].includes(action) && path[0] == 'mnt') {
switch (path.length) {
case 3:
if (path[2]=='') zfs = path[1]+'/';
if (path[2] == '') zfs = path[1]+'/';
break;
case 4:
if (path[3]=='') zfs = path[1]+'/'+path[2];
if (path[3] == '') zfs = path[1]+'/'+path[2];
break;
}
}
@@ -344,7 +364,7 @@ function doAction(action,title,id) {
var ud = ['disks','remotes'].includes(path[1]); // unassigned devices
var match = ud||user ? '' : '^(?!\\/mnt\\/user0?\\/).*$';
var name = path.pop()||path.pop();
var hdlink = "<?=$var['fuse_directio']==1?'1':''?>";
var hdlink = "<?=$var['fuse_directio'] == 1 ? '1' : ''?>";
dfm.window = $("#dfm_dialogWindow");
switch (action) {
case 0: // create folder
@@ -446,7 +466,7 @@ function doAction(action,title,id) {
break;
}
dfm.window.dialog({
dialogClass: 'ui-dfm',
classes: {'ui-dialog': 'ui-dfm'},
autoOpen: true,
title: title,
height: dfm.height,
@@ -472,7 +492,7 @@ function doAction(action,title,id) {
// check if 'mv' can be used
if (path.length > 2) {
if (user) {
if (home(source,target)==1) action++;
if (home(source,target) == 1) action++;
} else {
var mv = '/'+path[0]+'/'+path[1]+'/';
if (target.substr(0,mv.length) == mv) action++;
@@ -481,7 +501,7 @@ function doAction(action,title,id) {
break;
case 11: // change owner
var valid = /.+/;
target += (target=='root' ? ':root' : ':users');
target += (target == 'root' ? ':root' : ':users');
break;
case 12: // change permission
var valid = /.+/;
@@ -511,7 +531,7 @@ function doAction(action,title,id) {
dfm.window.find('#dfm_exist').prop('disabled',true);
dfm.window.find('.dfm_sparse').css({'opacity':'0.5'});
dfm.window.find('.dfm_exist').css({'opacity':'0.5'});
if (action==11) {
if (action == 11) {
dfm.window.find('#dfm_owner').prop('disabled',true);
dfm.window.find('#dfm_group').prop('disabled',true);
dfm.window.find('#dfm_other').prop('disabled',true);
@@ -542,7 +562,7 @@ function doAction(action,title,id) {
// check if 'mv' can be used
if (path.length > 2) {
if (user) {
if (home(source,target)==1) action++;
if (home(source,target) == 1) action++;
} else {
var mv = '/'+path[0]+'/'+path[1]+'/';
if (target.substr(0,mv.length) == mv) action++;
@@ -551,7 +571,7 @@ function doAction(action,title,id) {
break;
case 11: // change owner
var valid = /.+/;
target += (target=='root' ? ':root' : ':users');
target += (target == 'root' ? ':root' : ':users');
break;
case 12: // change permission
var valid = /.+/;
@@ -581,10 +601,11 @@ function doAction(action,title,id) {
}
});
dfm_close_button();
if (action==15) $('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',true);
if (action == 15) $('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',true);
setTimeout(function(){if (dfm.window.find('#dfm_target').length) dfm.window.find('#dfm_target').focus().click(); else $('.ui-dfm .ui-dialog-buttonset button:eq(0)').focus();});
}
function doActions(action,title) {
function doActions(action, title) {
var source = [], type = [], owner = [], perm = [], zfs = [];
if (action > 0) {
$('i[id^="check_"]').each(function(){
@@ -608,7 +629,7 @@ function doActions(action,title) {
var ud = ['disks','remotes'].includes(path[1]); // unassigned devices
var match = ud||user ? '' : '^(?!.*(user0?|rootshare)).*$';
var name = path.pop()||path.pop();
var hdlink = "<?=$var['fuse_directio']==1?'1':''?>";
var hdlink = "<?=$var['fuse_directio'] == 1 ? '1' : ''?>";
var u = false;
var d = false;
if (bulk) {
@@ -618,7 +639,7 @@ function doActions(action,title) {
var p = s.substr(1).split('/');
if (/^user0?$/.test(p[1])) u = true; else d = true;
<?if ($dfm['zfs']):?>
if ([1,4].includes(action) && p[0]=='mnt' && type[i]=='d') {
if ([1,4].includes(action) && p[0] == 'mnt' && type[i] == 'd') {
switch (p.length) {
case 2:
zfs.push(p[1]+'/');
@@ -631,7 +652,7 @@ function doActions(action,title) {
}
} else {
var p = source[0].substr(1).dfm_strip().split('/');
if ([1,4].includes(action) && p[0]=='mnt' && type[0]=='d') {
if ([1,4].includes(action) && p[0] == 'mnt' && type[0] == 'd') {
switch (p.length) {
case 2:
zfs.push(p[1]+'/');
@@ -667,10 +688,10 @@ function doActions(action,title) {
dfm.window.html($('#dfm_templateCopyObject').html());
dfm_createSource(source);
dfm.window.find('#dfm_target').attr('data-pickroot',root).attr('data-picktop',root).attr('data-pickmatch',match);
if (bulk || type[0]=='d') dfm.window.find('#dfm_target').attr('data-pickfilter','HIDE_FILES_FILTER');
if (bulk || type[0] == 'd') dfm.window.find('#dfm_target').attr('data-pickfilter','HIDE_FILES_FILTER');
dfm.window.find('#dfm_target').fileTreeAttach(null,null,function(path){
var bits = path.substr(1).split('/');
var auto = bulk || bits.length>3 ? '' : (type[0]=='d' ? share : '');
var auto = bulk || bits.length>3 ? '' : (type[0] == 'd' ? share : '');
dfm.window.find('#dfm_target').val(path+auto).change();
});
dfm.height = 630;
@@ -679,10 +700,10 @@ function doActions(action,title) {
dfm.window.html($('#dfm_templateMoveObject').html());
dfm_createSource(source);
dfm.window.find('#dfm_target').attr('data-pickroot',root).attr('data-picktop',root).attr('data-pickmatch',match);
if (bulk || type[0]=='d') dfm.window.find('#dfm_target').attr('data-pickfilter','HIDE_FILES_FILTER');
if (bulk || type[0] == 'd') dfm.window.find('#dfm_target').attr('data-pickfilter','HIDE_FILES_FILTER');
dfm.window.find('#dfm_target').fileTreeAttach(null,null,function(path){
var bits = path.substr(1).split('/');
var auto = bulk || bits.length>3 ? '' : (type[0]=='d' ? share : '');
var auto = bulk || bits.length > 3 ? '' : (type[0] == 'd' ? share : '');
dfm.window.find('#dfm_target').val(path+auto).change();
});
dfm.height = 630;
@@ -716,7 +737,7 @@ function doActions(action,title) {
// folders only
for (var i=0,t; t=type[i]; i++) if (t != 'd') source[i] = '';
source = source.filter(n=>n);
if (source.length==0) source[0] = dir;
if (source.length == 0) source[0] = dir;
dfm_createSource(source);
dfm.window.find('.dfm_loc').html('&nbsp;').css({'line-height':'normal'});
dfm.window.find('.dfm_text').html('').css({'line-height':'normal'});
@@ -725,7 +746,7 @@ function doActions(action,title) {
}
dfm.window.find('#dfm_source').attr('size',Math.min(dfm.tsize[action],source.length));
dfm.window.dialog({
dialogClass: 'ui-dfm',
classes: {'ui-dialog': 'ui-dfm'},
autoOpen: true,
title: title,
height: dfm.height,
@@ -750,7 +771,7 @@ function doActions(action,title) {
// check if 'mv' can be used
if (path.length > 2) {
if (user) {
if (home(source.join('\n'),target)==1) action++;
if (home(source.join('\n'),target) == 1) action++;
} else {
var mv = '/'+path[0]+'/'+path[1]+'/';
if (target.substr(0,mv.length) == mv) action++;
@@ -759,7 +780,7 @@ function doActions(action,title) {
break;
case 11: // change owner
var valid = /.+/;
target += (target=='root' ? ':root' : ':users');
target += (target == 'root' ? ':root' : ':users');
bulk = false;
break;
case 12: // change permission
@@ -791,7 +812,7 @@ function doActions(action,title) {
dfm.window.find('#dfm_exist').prop('disabled',true);
dfm.window.find('.dfm_sparse').css({'opacity':'0.5'});
dfm.window.find('.dfm_exist').css({'opacity':'0.5'});
if (action==12) {
if (action == 12) {
dfm.window.find('#dfm_owner').prop('disabled',true);
dfm.window.find('#dfm_group').prop('disabled',true);
dfm.window.find('#dfm_other').prop('disabled',true);
@@ -822,7 +843,7 @@ function doActions(action,title) {
// check if 'mv' can be used
if (path.length > 2) {
if (user) {
if (home(source.join('\n'),target)==1) action++;
if (home(source.join('\n'),target) == 1) action++;
} else {
var mv = '/'+path[0]+'/'+path[1]+'/';
if (target.substr(0,mv.length) == mv) action++;
@@ -831,7 +852,7 @@ function doActions(action,title) {
break;
case 11: // change owner
var valid = /.+/;
target += (target=='root' ? ':root' : ':users');
target += (target == 'root' ? ':root' : ':users');
bulk = false;
break;
case 12: // change permission
@@ -863,9 +884,10 @@ function doActions(action,title) {
}
});
dfm_close_button();
if (action==15) $('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',true);
if (action == 15) $('.ui-dfm .ui-dialog-buttonset button:eq(1)').prop('disabled',true);
setTimeout(function(){if (dfm.window.find('#dfm_target').length) dfm.window.find('#dfm_target').focus().click(); else $('.ui-dfm .ui-dialog-buttonset button:eq(0)').focus();});
}
function stopUpload(file,error) {
window.onbeforeunload = null;
$.post('/webGui/include/Control.php',{mode:'stop',file:encodeURIComponent(dfm_htmlspecialchars(file))});
@@ -876,6 +898,7 @@ function stopUpload(file,error) {
loadList();
if (error) setTimeout(function(){swal({title:"_(Upload Error)_",text:"_(File is removed)_",html:true,confirmButtonText:"_(Ok)_"});},200);
}
function downloadFile(source) {
var a = document.createElement('a');
a.setAttribute('href',source);
@@ -885,6 +908,7 @@ function downloadFile(source) {
a.click();
document.body.removeChild(a);
}
function uploadFile(files,index,start,time) {
var file = files[index];
var slice = 2097152; // 2M
@@ -893,8 +917,8 @@ function uploadFile(files,index,start,time) {
reader.onloadend = function(e){
if (e.target.readyState !== FileReader.DONE) return;
$.post('/webGui/include/Control.php',{mode:'upload',file:encodeURIComponent(dir+'/'+dfm_htmlspecialchars(file.name)),start:start,data:window.btoa(e.target.result),cancel:cancel},function(reply){
if (reply=='stop') {stopUpload(file.name); return;}
if (reply=='error') {stopUpload(file.name,true); return;}
if (reply == 'stop') {stopUpload(file.name); return;}
if (reply == 'error') {stopUpload(file.name,true); return;}
if (next < file.size) {
var total = 0;
for (var i=0,f; f=files[i]; i++) {
@@ -913,11 +937,12 @@ function uploadFile(files,index,start,time) {
};
reader.readAsBinaryString(blob);
}
var reader = {};
var cancel = 0;
function startUpload(files) {
if (files.length==0) return;
if (files.length == 0) return;
reader = new FileReader();
window.onbeforeunload = function(e){return '';};
$('#dfm_uploadButton').val("_(Cancel)_").prop('onclick',null).off('click').click(function(){cancel=1;});
@@ -925,17 +950,20 @@ function startUpload(files) {
const d = new Date();
uploadFile(files,0,0,d.getTime());
}
function filter(ext) {
$('td.ext').each(function(){
if ($(this).attr('data').search(ext)==-1) $(this).parent().hide(); else $(this).parent().show();
if ($(this).attr('data').search(ext) == -1) $(this).parent().hide(); else $(this).parent().show();
});
}
function toggleTime(init) {
$('.my_time').toggle();
$('.my_age').toggle();
if (init) return;
$.cookie('my_time')==null ? $.cookie('my_time','age') : $.removeCookie('my_time');
$.cookie('my_time') == null ? $.cookie('my_time','age') : $.removeCookie('my_time');
}
function loadList() {
var col = $.cookie('col')||2;
var ord = $.cookie('dir')||0;
@@ -952,15 +980,17 @@ function loadList() {
$('div#buttons').show();
});
}
function xlink(link) {
swal({title:'',text:decodeURIComponent(link),html:true,confirmButtonText:"_(Ok)_"});
}
$(function(){
var dirs = dir.split('/'), url = [];
if (dirs.length > 1) {
for (var n=1; n < dirs.length; n++) {
var subdir = dirs.slice(1,n+1);
url.push('<a class="none" href="/<?=$path?>?dir=/'+encodeURIComponent(subdir.join('/'))+'" oncontextmenu="xlink(\'/'+encodeURIComponent(subdir.join('/'))+'\');return false">'+(n==1 ? '<i class="fa fa-home"></i>' : dirs[n])+'</a>');
url.push('<a class="none" href="/<?=$path?>?dir=/'+encodeURIComponent(subdir.join('/'))+'" oncontextmenu="xlink(\'/'+encodeURIComponent(subdir.join('/'))+'\');return false">'+(n == 1 ? '<i class="fa fa-home"></i>' : dirs[n])+'</a>');
}
} else {
url.push('<i class="fa fa-home red-text"></i>');
@@ -985,6 +1015,7 @@ $(function(){
<?endif;?>
});
</script>
<div class="autoheight">
<table class="indexer tablesorter shift"><thead><tr><th><?if($dir){?><i id="check_0" class="fa fa-fw fa-square-o" onclick="selectAll()"></i><?}?></th><th>_(Type)_</th><th class='sorter-text'>_(Name)_</th><th>_(Owner)_</th><th>_(Permission)_</th><th>_(Size)_</th><th>_(Last Modified)_</th><th style="width:200px">_(Location)_</th><th>_(Action)_</th></tr></thead></table>
</div>

View File

@@ -4,8 +4,8 @@ Icon="icon-u-duplicate"
Code="e963"
---
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2025, Lime Technology
* Copyright 2012-2025, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -17,7 +17,7 @@ Code="e963"
?>
<?
$dfm = [
'browser' => $myPage['name']=='Browse',
'browser' => $myPage['name'] == 'Browse',
'running' => file_exists('/var/tmp/file.manager.active'),
'jobs' => file_exists('/var/tmp/file.manager.jobs'),
'zfs' => is_executable('/usr/sbin/zfs')
@@ -28,6 +28,7 @@ if ($dfm['running'] || $dfm['browser']) eval('?>'.parse_file("$docroot/webGui/in
function BrowseButton() {
location.replace('/<?=$task?>/Browse?dir=/mnt');
}
// Prototypes
String.prototype.dfm_patch = function(){return this.replace('rw','x+rw').replace('r-','wx+r').replace('--','rwx');}
String.prototype.dfm_proxy = function(){return this.replace('name','row');}
@@ -43,7 +44,7 @@ String.prototype.dfm_wedge = function(len){len=len||70;return this.length<=len ?
const dfm = {window:null, dialog:false, running:false, previous:'', height:0, tsize:{0:0,1:6,2:3,3:3,4:3,11:2,12:2,14:0,15:3}};
var dfm_read = {};
function dfm_footer(action,text) {
function dfm_footer(action, text) {
switch (action) {
case 'show':
$('#countdown').show();
@@ -54,7 +55,7 @@ function dfm_footer(action,text) {
$('#user-notice').hide();
break;
case 'write':
if ($('#countdown').html()=='') $('#countdown').html('<a class="hand" onclick="dfm_openDialog(true)" title="_(File Manager)_"><i class="icon-u-duplicate dfm"></i></a>');
if ($('#countdown').html() == '') $('#countdown').html('<a class="hand" onclick="dfm_openDialog(true)" title="_(File Manager)_"><i class="icon-u-duplicate dfm"></i></a>');
$('#user-notice').html(text);
break;
case 'clear':
@@ -63,26 +64,32 @@ function dfm_footer(action,text) {
break;
}
}
function dfm_done() {
dfm_footer('write',"<i class='fa fa-circle-thin dfm'></i>_(Searching)_... _(Done)_");
dfm_footer('write', "<i class='fa fa-circle-thin dfm'></i>_(Searching)_... _(Done)_");
}
function dfm_minimize() {
dfm.window.dialog('close');
dfm_footer('show');
}
function dfm_close_button() {
$('.ui-dfm .ui-dialog-titlebar-close').html('<i class="fa fa-window-minimize"></i>').prop({'title':"_(Minimize)_"}).prop('onclick',null).off('click').click(function(){dfm_minimize();}).show();
}
function dfm_htmlspecialchars(text) {
var map = {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'};
return text.replace(/[&<>"']/g,function(m){return map[m];});
return text.replace(/[&<>"']/g, function(m){return map[m];});
}
function dfm_escapeHTML(name) {
const data = document.createElement('div');
const text = document.createTextNode(name);
data.appendChild(text);
return data.innerHTML;
}
function dfm_createSource(source) {
var select = dfm.window.find('#dfm_source');
if (Array.isArray(source)) {
@@ -98,6 +105,7 @@ function dfm_createSource(source) {
select.html('<option selected>'+source+'</option>');
}
}
function dfm_showProgress(data) {
if (!data) return 0;
let file = null;
@@ -105,7 +113,7 @@ function dfm_showProgress(data) {
let line = text[0].split('... ');
let strict = /^mnt|^boot/;
let footer = false;
if (text[0]=='#cat#') {
if (text[0] == '#cat#') {
let loc = [], cat = [];
for (let i=1,row; row=text[i]; i++) {
if (!row) continue;
@@ -119,7 +127,7 @@ function dfm_showProgress(data) {
dfm.window.find('#dfm_files').html(loc.length+" "+"_(files)_");
}
return cat.length;
} else if (text.length==1) {
} else if (text.length == 1) {
text = text[0].dfm_wedge(80);
footer = text.indexOf("_(Searching)_") != -1;
} else {
@@ -134,10 +142,11 @@ function dfm_showProgress(data) {
footer = true;
}
}
if (file==null || strict.test(file)) dfm.window.find('.dfm_text').html((file?line[0]+'... /'+dfm_escapeHTML(file.dfm_wedge())+'<br>':'')+text);
if (file == null || strict.test(file)) dfm.window.find('.dfm_text').html((file?line[0]+'... /'+dfm_escapeHTML(file.dfm_wedge())+'<br>':'')+text);
if (footer) dfm_footer('write',text);
return 0;
}
function dfm_fileManager(action) {
switch (action) {
case 'start':
@@ -161,14 +170,15 @@ function dfm_fileManager(action) {
break;
}
}
function dfm_makeDialog(open) {
if (open && dfm_read.action==15) {
if (open && dfm_read.action == 15) {
dfm.window.dialog('open');
dfm_footer('hide');
return;
}
dfm.window = $('#dfm_dialogWindow');
if (dfm.window.dialog('instance') !== undefined) dfm.dialog = dfm.window.dialog('isOpen');
if (dfm.window.dialog('instance') !== undefined) dfm.dialog = dfm.window.dialog('isOpen');
var dfm_source = dfm_read.source.split('\r').slice(0,9);
switch (dfm_read.action) {
case 0: // create folder/object
@@ -245,8 +255,8 @@ function dfm_makeDialog(open) {
dfm.window.find('.dfm_sparse').css({'opacity':'0.5'});
dfm.window.find('.dfm_exist').css({'opacity':'0.5'});
dfm.window.dialog({
dialogClass: 'ui-dfm',
autoOpen: open||dfm.dialog,
classes: {'ui-dialog': 'ui-dfm'},
autoOpen: open || dfm.dialog,
title: dfm_read.title,
height: dfm.height,
width: 900,
@@ -254,7 +264,7 @@ function dfm_makeDialog(open) {
modal: true,
buttons: {
"_(Start)_": function(){
if (dfm_read.action==15) {
if (dfm_read.action == 15) {
var dfm_target = dfm.window.find('#dfm_target').val();
dfm.window.find('.dfm_loc').html('&nbsp;');
dfm.window.find('.dfm_text').html("_(Running)_...");
@@ -280,6 +290,7 @@ function dfm_makeDialog(open) {
setTimeout(function(){$('.ui-dfm .ui-dialog-buttonset button:eq(2)').focus();});
if (open||dfm.dialog) dfm_footer('hide'); else dfm_footer('show');
}
function dfm_openDialog(open) {
$.post('/webGui/include/Control.php',{mode:'read'},function(data){
if (data) {
@@ -289,6 +300,7 @@ function dfm_openDialog(open) {
dfm_makeDialog(open);
});
}
var nchan_filemanager = new NchanSubscriber('/sub/filemanager',{subscriber:'websocket'});
nchan_filemanager.on('message', function(msg) {
let data = $.parseJSON(msg);
@@ -304,7 +316,7 @@ nchan_filemanager.on('message', function(msg) {
$('.ui-dfm .ui-dialog-buttonset button:lt(2)').prop('disabled',false);
} else {
let cat = dfm_showProgress(data.status);
if (data.done==1) {
if (data.done == 1) {
setTimeout(function(){$.post('/webGui/include/Control.php',{mode:'start'},function(queue){
switch (parseInt(queue)) {
case 0:
@@ -324,16 +336,17 @@ nchan_filemanager.on('message', function(msg) {
break;
}
})});
} else if (data.done==2) {
} else if (data.done == 2) {
nchan_filemanager.stop();
dfm.running = false;
dfm.window.find('#dfm_target').prop('disabled',false).focus();
$('.ui-dfm .ui-dialog-buttonset button:eq(0)').prop('disabled',false);
if (cat==0) dfm.window.find('.dfm_text').html("_(No results found)_");
if (cat == 0) dfm.window.find('.dfm_text').html("_(No results found)_");
if ($('#user-notice:visible')) dfm_done();
}
}
});
<?if ($dfm['running']):?>
$(function(){
dfm_openDialog();

View File

@@ -1,6 +1,6 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2025, Lime Technology
* Copyright 2012-2025, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -22,19 +22,24 @@ function write(&$rows) {
if ($size = count($rows)) echo '<tbody>',implode(array_map(function($row){echo gzinflate($row);},$rows)),'</tbody>';
$rows = $size;
}
function validdir($dir) {
$path = realpath($dir);
return in_array(explode('/',$path)[1]??'',['mnt','boot']) ? $path : '';
}
function escapeQuote($data) {
return str_replace('"','&#34;',$data);
}
function add($number, $name, $single='', $plural='s') {
return $number.' '._($name.($number==1 ? $single : $plural));
}
function age($number,$time) {
return sprintf(_('%s '.($number==1 ? $time : $time.'s').' ago'),$number);
}
function my_age($time) {
if (!is_numeric($time)) $time = time();
$age = new DateTime('@'.$time);
@@ -46,11 +51,13 @@ function my_age($time) {
if ($age->i > 0) return age($age->i,'minute');
return age($age->s,'second');
}
function parent_link() {
global $dir,$path;
$parent = dirname($dir);
return $parent=='/' ? false : '<a href="/'.$path.'?dir='.rawurlencode(htmlspecialchars($parent)).'">'._('Parent Directory').'</a>';
}
function my_devs(&$devs,$name,$menu) {
global $disks,$lock;
$text = []; $i = 0;
@@ -72,6 +79,7 @@ function my_devs(&$devs,$name,$menu) {
}
return implode($text);
}
function icon_class($ext) {
switch ($ext) {
case '3gp': case 'asf': case 'avi': case 'f4v': case 'flv': case 'm4v': case 'mkv': case 'mov': case 'mp4': case 'mpeg': case 'mpg': case 'm2ts': case 'ogm': case 'ogv': case 'vob': case 'webm': case 'wmv':
@@ -144,6 +152,7 @@ if ($user ) {
for ($i = 0; $i < count($tmp); $i+=3) $set[basename($tmp[$i])] = explode('"',$tmp[$i+1])[1];
unset($tmp);
}
$stat = popen("shopt -s dotglob;stat -L -c'%F|%U|%A|%s|%Y|%n' ".escapeshellarg($dir)."/* 2>/dev/null",'r');
while (($row = fgets($stat))!==false) {
[$type,$owner,$perm,$size,$time,$name] = explode('|',rtrim($row,"\n"),6);
@@ -178,6 +187,7 @@ while (($row = fgets($stat))!==false) {
$total += $size;
}
}
pclose($stat);
if ($link = parent_link()) echo '<tbody class="tablesorter-infoOnly"><tr><td></td><td><i class="fa fa-folder-open-o"></i></td><td>',$link,'</td><td colspan="6"></td></tr></tbody>';
echo write($dirs),write($files),'<tfoot><tr><td></td><td></td><td colspan="7">',add($objs,'object'),': ',add($dirs,'director','y','ies'),', ',add($files,'file'),' (',my_scale($total,$unit),' ',$unit,' ',_('total'),')</td></tr></tfoot>';

View File

@@ -1,6 +1,6 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2025, Lime Technology
* Copyright 2012-2025, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -21,6 +21,7 @@ require_once "$docroot/webGui/include/Translations.php";
function age($number,$time) {
return sprintf(_('%s '.($number==1 ? $time : $time.'s').' ago'),$number);
}
function my_age($time) {
if (!is_numeric($time)) $time = time();
$age = new DateTime('@'.$time);
@@ -32,10 +33,12 @@ function my_age($time) {
if ($age->i > 0) return age($age->i,'minute');
return age($age->s,'second');
}
function validname($name) {
$path = realpath(dirname($name));
return in_array(explode('/',$path)[1]??'',['mnt','boot']) ? $path.'/'.basename($name) : '';
}
function escape($name) {return escapeshellarg(validname($name));}
function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',$name)) : escape($name);}

View File

@@ -1,6 +1,6 @@
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2025, Lime Technology
* Copyright 2012-2025, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,

View File

@@ -181,7 +181,7 @@ function get_nvme_info($device, $info) {
switch ($info) {
case 'temp':
exec("nvme id-ctrl /dev/$device 2>/dev/null | grep -Pom2 '^[wc]ctemp +: \K\d+'",$temp);
return [$temp[0]-273, $temp[1]-273];
return count($temp) >= 2 ? [$temp[0]-273, $temp[1]-273] : [0, 0];
case 'cctemp':
return exec("nvme id-ctrl /dev/$device 2>/dev/null | grep -Pom1 '^cctemp +: \K\d+'")-273;
case 'wctemp':

View File

@@ -1,7 +1,7 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2025, Lime Technology
* Copyright 2012-2025, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -21,46 +21,53 @@ $timer = time();
require_once "$docroot/webGui/include/Wrappers.php";
require_once "$docroot/webGui/include/publish.php";
extract(parse_plugin_cfg('dynamix',true));
extract(parse_plugin_cfg('dynamix', true));
// add translations
$_SERVER['REQUEST_URI'] = '';
$login_locale = $display['locale']??'';
$login_locale = $display['locale'] ?? '';
require_once "$docroot/webGui/include/Translations.php";
// remember current language
$locale_init = $locale;
function pool_only(&$disks) {
return array_filter($disks,function($disk){return $disk['type']=='Cache' && !empty($disk['uuid']);});
return array_filter($disks, function($disk){return $disk['type'] == 'Cache' && !empty($disk['uuid']);});
}
function pools_filter(&$disks) {
return array_keys(pool_only($disks));
}
function delete_file(...$file) {
array_map('unlink',array_filter($file,'file_exists'));
array_map('unlink', array_filter($file, 'file_exists'));
}
function pgrep($pid) {
$pid = is_array($pid) ? $pid[0] : $pid;
return $pid && file_exists("/proc/$pid") ? $pid : false;
}
function isdir($name) {
return mb_substr($name,-1)=='/';
return mb_substr($name, -1) == '/';
}
function truepath($name) {
$bits = array_filter(explode('/',$name),'mb_strlen');
$bits = array_filter(explode('/', $name), 'mb_strlen');
$path = [];
foreach ($bits as $bit) {
if ($bit == '.') continue;
if ($bit == '..') array_pop($path); else $path[] = $bit;
}
return '/'.implode('/',$path);
return '/'.implode('/', $path);
}
function validname($name, $real=true) {
$path = $real ? realpath(dirname($name)) : truepath(dirname($name));
$root = explode('/',$path)[1] ?? '';
return in_array($root,['mnt','boot']) ? $path.'/'.basename($name).(mb_substr($name,-1)=='/'?'/':'') : '';
$root = explode('/', $path)[1] ?? '';
return in_array($root, ['mnt','boot']) ? $path.'/'.basename($name).(mb_substr($name,-1) == '/' ? '/' : '') : '';
}
function update_translation($locale) {
global $docroot,$language;
$language = [];
@@ -68,59 +75,61 @@ function update_translation($locale) {
$text = "$docroot/languages/$locale/translations.txt";
if (file_exists($text)) {
$store = "$docroot/languages/$locale/translations.dot";
if (!file_exists($store)) file_put_contents($store,serialize(parse_lang_file($text)));
if (!file_exists($store)) file_put_contents($store, serialize(parse_lang_file($text)));
$language = unserialize(file_get_contents($store));
}
}
}
function cat($file) {
global $null;
$cat = $set = [];
$rows = file($file,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
if (count($rows)>0) {
$rows = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (count($rows) > 0) {
natcasesort($rows);
$user = array_filter($rows,function($path){return preg_match('/^\/mnt\/user0?\//',$path);});
if (count($user)>0) {
$user = array_filter($rows, function($path){return preg_match('/^\/mnt\/user0?\//', $path);});
if (count($user) > 0) {
for ($n=0; $n < count($user); $n+=100) {
$name = array_slice($user,$n,100);
$name = array_slice($user, $n, 100);
$set[] = exec("getfattr --no-dereference --absolute-names --only-values -n system.LOCATIONS ".quoted($name)." 2>$null");
}
$disks = parse_ini_file('state/disks.ini',true);
$disks = parse_ini_file('state/disks.ini', true);
$tag = implode('|',array_merge(['disk'],pools_filter($disks)));
$set = explode(';',str_replace(',;',',',preg_replace("/($tag)/",';$1',implode($set))));
$set = explode(';',str_replace(',;',',',preg_replace("/($tag)/", ';$1', implode($set))));
}
foreach (array_diff($rows,$user) as $row) {
[$none,$root,$main] = explode('/',$row,4);
$cat[] = ($root=='mnt' ? $main : ($root=='boot' ? 'flash' : '---'))."\0".$row;
foreach (array_diff($rows, $user) as $row) {
[$none, $root, $main] = explode('/',$row,4);
$cat[] = ($root == 'mnt' ? $main : ($root == 'boot' ? 'flash' : '---'))."\0".$row;
}
$i = 0;
foreach ($user as $row) $cat[] = $set[++$i]."\0".$row;
}
return "#cat#\n".implode("\n",$cat)."\n";
}
function escape($name) {return escapeshellarg(validname($name));}
function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',$name)) : escape($name);}
function source($name) {return is_array($name) ? implode(' ',array_map('escapeshellarg',$name)) : escapeshellarg($name);}
function quoted($name) {return is_array($name) ? implode(' ',array_map('escape', $name)) : escape($name);}
function source($name) {return is_array($name) ? implode(' ',array_map('escapeshellarg', $name)) : escapeshellarg($name);}
while (true) {
unset($action,$source,$target,$H,$sparse,$exist,$zfs);
unset($action, $source, $target, $H, $sparse, $exist, $zfs);
if (file_exists($active)) extract(parse_ini_file($active));
$reply = [];
if (isset($action)) {
// check for language changes
extract(parse_plugin_cfg('dynamix',true));
extract(parse_plugin_cfg('dynamix', true));
if ($display['locale'] != $locale_init) {
$locale_init = $display['locale'];
update_translation($locale_init);
}
$source = explode("\r",$source);
$source = explode("\r", $source);
switch ($action) {
case 0: // create folder
if (!empty($pid)) {
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Creating').'...';
} else {
$dir = $source[0].'/'.$target;
exec("mkdir -pm0777 ".quoted($dir)." 1>$null 2>$error & echo $!",$pid);
exec("mkdir -pm0777 ".quoted($dir)." 1>$null 2>$error & echo $!", $pid);
exec("chown -Rfv nobody:users ".quoted($dir));
}
break;
@@ -129,7 +138,7 @@ while (true) {
if (!empty($pid)) {
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Removing').'... '.exec("tail -1 $status");
} else {
exec("find ".quoted($source)." -name \"*\" -print -delete 1>$status 2>$null & echo \$!",$pid);
exec("find ".quoted($source)." -name \"*\" -print -delete 1>$status 2>$null & echo \$!", $pid);
}
break;
case 2: // rename folder
@@ -138,18 +147,18 @@ while (true) {
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Renaming').'...';
} else {
$path = dirname($source[0]);
exec("mv -f ".quoted($source)." ".quoted("$path/$target")." 1>$null 2>$error & echo \$!",$pid);
exec("mv -f ".quoted($source)." ".quoted("$path/$target")." 1>$null 2>$error & echo \$!", $pid);
}
break;
case 3: // copy folder
case 8: // copy file
if (!empty($pid)) {
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Copying').'... '.shell_exec("tail -2 $status|awk -F\"\\r\" '{gsub(/^ +/,\"\",\$NF);print \$NF}'");
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Copying').'... '.shell_exec("tail -2 $status | awk -F\"\\r\" '{gsub(/^ +/,\"\",\$NF);print \$NF}'");
} else {
$target = validname($target,false);
$target = validname($target, false);
if ($target) {
$mkpath = isdir($target) ? '--mkpath' : '';
exec("rsync -ahPIX$H $sparse $exist $mkpath --out-format=%f --info=flist0,misc0,stats0,name1,progress2 ".quoted($source)." ".escapeshellarg($target)." 1>$status 2>$error & echo \$!",$pid);
exec("rsync -ahPIX$H $sparse $exist $mkpath --out-format=%f --info=flist0,misc0,stats0,name1,progress2 ".quoted($source)." ".escapeshellarg($target)." 1>$status 2>$error & echo \$!", $pid);
} else {
$reply['error'] = 'Invalid target name';
}
@@ -158,13 +167,13 @@ while (true) {
case 4: // move folder (rsync)
case 9: // move file (rsync)
if (!empty($pid)) {
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Moving').'... '.($move===false ? exec("tail -1 $status") : shell_exec("tail -2 $status|awk -F\"\\r\" '{gsub(/^ +/,\"\",\$NF);print \$NF}'"));
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Moving').'... '.($move===false ? exec("tail -1 $status") : shell_exec("tail -2 $status | awk -F\"\\r\" '{gsub(/^ +/,\"\",\$NF);print \$NF}'"));
} else {
$target = validname($target,false);
$target = validname($target, false);
if ($target) {
$move = true;
$mkpath = isdir($target) ? '--mkpath' : '';
exec("rsync -ahPIX$H $sparse $exist $mkpath --out-format=%f --info=flist0,misc0,stats0,name1,progress2 --remove-source-files ".quoted($source)." ".escapeshellarg($target)." 1>$status 2>$error & echo \$!",$pid);
exec("rsync -ahPIX$H $sparse $exist $mkpath --out-format=%f --info=flist0,misc0,stats0,name1,progress2 --remove-source-files ".quoted($source)." ".escapeshellarg($target)." 1>$status 2>$error & echo \$!", $pid);
} else {
$reply['error'] = 'Invalid target name';
}
@@ -175,10 +184,10 @@ while (true) {
if (!empty($pid)) {
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Moving').'...';
} else {
$target = validname($target,false);
$target = validname($target, false);
if ($target) {
$f = $exist ? 'f' : 'n';
exec("mv -{$f}t ".escapeshellarg($target)." ".quoted($source)." 1>$status 2>$error & echo \$!",$pid);
exec("mv -{$f}t ".escapeshellarg($target)." ".quoted($source)." 1>$status 2>$error & echo \$!", $pid);
} else {
$reply['error'] = 'Invalid target name';
}
@@ -186,37 +195,37 @@ while (true) {
break;
case 11: // change owner
if (!empty($pid)) {
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Updating').'... '.exec("tail -2 $status|grep -Pom1 \"^.+ of '\\K[^']+\"");
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Updating').'... '.exec("tail -2 $status | grep -Pom1 \"^.+ of '\\K[^']+\"");
} else {
exec("chown -Rfv $target ".quoted($source)." 1>$status 2>$error & echo \$!",$pid);
exec("chown -Rfv $target ".quoted($source)." 1>$status 2>$error & echo \$!", $pid);
}
break;
case 12: // change permission
if (!empty($pid)) {
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Updating').'... '.exec("tail -2 $status|grep -Pom1 \"^.+ of '\\K[^']+\"");
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Updating').'... '.exec("tail -2 $status | grep -Pom1 \"^.+ of '\\K[^']+\"");
} else {
exec("chmod -Rfv $target ".quoted($source)." 1>$status 2>$error & echo \$!",$pid);
exec("chmod -Rfv $target ".quoted($source)." 1>$status 2>$error & echo \$!", $pid);
}
break;
case 15: // search
if (!empty($pid)) {
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Searching').'... '.exec("wc -l $status|grep -Pom1 '^[0-9]+'");
$reply['status'] = '<i class="fa fa-circle-o-notch fa-spin dfm"></i>'._('Searching').'... '.exec("wc -l $status | grep -Pom1 '^[0-9]+'");
} else {
exec("find ".source($source)." -iname ".escapeshellarg($target)." 1>$status 2>$null & echo \$!",$pid);
exec("find ".source($source)." -iname ".escapeshellarg($target)." 1>$status 2>$null & echo \$!", $pid);
}
break;
case 99: // kill running background process
if (!empty($pid)) exec("kill $pid");
delete_file($active,$status,$error);
unset($pid,$move);
delete_file($active, $status, $error);
unset($pid, $move);
break;
default:
continue 2;
}
$pid = pgrep($pid??0);
if ($pid===false) {
if ($pid === false) {
if (!empty($move)) {
exec("find ".quoted($source)." -type d -empty -print -delete 1>$status 2>$null & echo \$!",$pid);
exec("find ".quoted($source)." -type d -empty -print -delete 1>$status 2>$null & echo \$!", $pid);
$move = false;
$pid = pgrep($pid);
} else {
@@ -235,18 +244,18 @@ while (true) {
foreach ($datasets as $dataset) if (exec("ls --indicator-style=none /mnt/$dataset|wc -l")==0) exec("zfs destroy $dataset 2>/dev/null");
}
}
if (file_exists($error)) $reply['error'] = str_replace("\n","<br>",trim(file_get_contents($error)));
delete_file($active,$status,$error);
unset($pid,$move);
if (file_exists($error)) $reply['error'] = str_replace("\n","<br>", trim(file_get_contents($error)));
delete_file($active, $status, $error);
unset($pid, $move);
}
}
}
if (time()-$timer) {
if (time() - $timer) {
// update every second
publish('filemonitor',file_exists($active) ? 1 : 0);
publish('filemonitor', file_exists($active) ? 1 : 0);
$timer = time();
}
publish('filemanager',json_encode($reply));
publish('filemanager', json_encode($reply));
usleep(250000);
}
?>

View File

@@ -1,7 +1,7 @@
#!/usr/bin/php -q
<?PHP
/* Copyright 2005-2023, Lime Technology
* Copyright 2012-2023, Bergware International.
/* Copyright 2005-2025, Lime Technology
* Copyright 2012-2025, Bergware International.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2,
@@ -34,10 +34,12 @@ function my_power($device) {
global $display;
if (!_var($display,'power')) return '';
$number = _var($display,'number','.,');
[$power,$state] = explode('W ',get_nvme_info($device,'state'));
$state = strtr($state, ['non-operational' => 'green', 'operational' => 'orange']);
return " / <span class='$state'>".number_format($power,$power<10?2:1,$number[0]).' '._('W')."</span>";
[$power,$state] = my_explode('W ', get_nvme_info($device,'state'));
$power = $power ?: 0;
$state = $state ? strtr($state, ['non-operational' => 'green', 'operational' => 'orange']) : '';
return " / <span class='$state'>".number_format($power, $power < 10 ? 2 : 1, $number[0]).' '._('W')."</span>";
}
function my_clock($time) {
if (!$time) return _('less than a minute');
$days = floor($time/1440);
@@ -45,12 +47,14 @@ function my_clock($time) {
$mins = $time%60;
return plus($days,'day',($hour|$mins)==0).plus($hour,'hour',$mins==0).plus($mins,'minute',true);
}
function find_day($D) {
global $days;
if ($days[0] == '*') return $D;
foreach ($days as $d) if ($d >= $D) return $d;
return $days[0];
}
function find_month($M) {
global $months, $Y;
if ($M > 12) {$M = 1; $Y++;}
@@ -58,6 +62,7 @@ function find_month($M) {
foreach ($months as $m) if ($m >= $M) return $m;
return $months[0];
}
function today($D) {
global $days, $M, $Y;
if ($days[0]=='*') return date('w',mktime(0,0,0,$M,$D,$Y));
@@ -66,18 +71,22 @@ function today($D) {
if (in_array($day,$days)) return $day;
}
}
function next_day($D) {
return find_day(($D+1)%7);
}
function last_day() {
global $M, $Y;
return date('t',mktime(0,0,0,$M,1,$Y));
}
function mkdate($D, $s) {
global $M, $Y;
if ($s > last_day()) {$s = 1; $M = find_month($M+1);}
for ($d = $s; $d < $s+7; $d++) if ($D == date('w',mktime(0,0,0,$M,$d,$Y))) return $d;
}
function stage($i) {
global $h, $m, $D, $M, $Y, $time, $now;
if ($i < 0) {
@@ -123,14 +132,17 @@ function stage($i) {
}
return $t;
}
function normalize($type,$count) {
$words = explode('_',$type);
foreach ($words as &$word) $word = $word==strtoupper($word) ? $word : preg_replace(['/^(ct|cnt)$/','/^blk$/'],['count','block'],strtolower($word));
return ucfirst(implode(' ',$words)).": ".str_replace('_',' ',strtolower($count))."\n";
}
function active_disks($disk) {
return substr(_var($disk,'status'),0,7)!='DISK_NP' && in_array(_var($disk,'type'),['Parity','Data']);
}
function device_name(&$disk) {
switch (_var($disk,'type')) {
case 'Extra' :
@@ -142,6 +154,7 @@ function device_name(&$disk) {
$fancy = _(my_disk(native($name,1)),3);
return "<i class='icon-$type f14'></i> <a href=\"".htmlspecialchars("/Dashboard/Main/Settings/Device?name=$name")."\" title=\"$fancy settings\">$fancy</a>";
}
function yellow_text($disk) {
global $var;
if (_var($disk, 'type')=='Parity') {
@@ -153,6 +166,7 @@ function yellow_text($disk) {
}
return $text;
}
function device_status(&$disk, &$error, &$warning) {
global $var;
if (_var($disk,'type')!='Extra' && _var($var,'fsState')=='Stopped') {
@@ -171,6 +185,7 @@ function device_status(&$disk, &$error, &$warning) {
}
return "<i class='fa fa-circle orb $color-orb middle'></i>"._($text);
}
function device_temp(&$disk, &$red, &$orange) {
global $display;
$spin = strpos(_var($disk,'color'),'blink')===false;
@@ -189,6 +204,7 @@ function device_temp(&$disk, &$red, &$orange) {
}
return ($spin ? "<span class='$color-text'>".my_temp($temp)."</span>" : "*").($nvme ? my_power($dev) : "");
}
function device_smart(&$disk, &$fail, &$smart) {
global $numbers,$saved;
if (!_var($disk,'device') || strpos(_var($disk,'color'),'blink')!==false) return "-";
@@ -222,6 +238,7 @@ function device_smart(&$disk, &$fail, &$smart) {
$title .= _('Click for context menu');
return "<span id='smart-$named' name=Device class='fa fa-$thumb $color-text' style='margin-right:8px' onmouseover='this.style.cursor=\"pointer\"' title='$title'></span><span id='text-$named'>$text</span>";
}
function device_usage(&$disk, &$full, &$high) {
global $display;
$text = $display['text'];
@@ -242,6 +259,7 @@ function device_usage(&$disk, &$full, &$high) {
return $text%10==0 ? "-" : "<span class='load'>-</span><div class='usage-disk sys none'><span></span></div>";
}
}
function array_group($type, $pool=false) {
global $disks,$error,$warning,$red,$orange,$fail,$smart,$full,$high;
if ($type != 'Data') {$error = $warning = $red = $orange = $fail = $smart = $full = $high = 0;}
@@ -257,6 +275,7 @@ function array_group($type, $pool=false) {
}
return implode($echo);
}
function extra_group() {
global $devs,$error,$warning,$red,$orange,$fail,$smart,$full,$high;
$error = $warning = $red = $orange = $fail = $smart = $full = $high = 0;
@@ -275,6 +294,7 @@ function extra_group() {
}
return implode($echo);
}
function update_translation($locale) {
global $docroot,$language;
$language = [];
@@ -293,9 +313,11 @@ function update_translation($locale) {
}
}
}
function create_sync($file) {
return file_exists($file) ? explode(',',file_get_contents($file)) : [];
}
function print_error($error) {
return sprintf(_('Finding **%s** error'.($error==1?'':'s')),$error?:'0');
}

View File

@@ -12,7 +12,6 @@ table.tablesorter.indexer thead th:nth-child(2){width:3%!important}
table.tablesorter.indexer thead th:nth-child(3){width:auto!important}
table.tablesorter.indexer thead th:nth-child(n+4){width:10%!important}
table.tablesorter.indexer thead th:nth-child(9){width:3%!important}
table.tablesorter.indexer tbody tr:hover td{background-color:<?=$dfm['hover']?>}
table.tablesorter.indexer thead th{text-align:left}
table.tablesorter.indexer tbody td{text-align:left}
table.tablesorter.indexer thead th:last-child{text-align:right}
@@ -21,6 +20,5 @@ i[id^="row_"],i[id^="check_"]{cursor:pointer;font-size:1.8rem;color:gray}
td[id^="name_"]{cursor:pointer}
i.fa-home{font-size:2rem}
i.fa-chevron-right{font-size:1.2rem;margin:0 8px}
div.autoheight{width:100%;overflow-y:auto;margin-top:<?=$themes1?'-30px':'0'?>}
div#buttons{display:none}
.dropdown-menu{z-index:10001}