Skip to content

Commit 77c8694

Browse files
committed
feat: ntfs file system support
1 parent e2c589b commit 77c8694

File tree

4 files changed

+236
-4
lines changed

4 files changed

+236
-4
lines changed

emhttp/languages/en_US/helptext.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,20 @@ Not much info is printed in the window, but you can verify the operation is runn
350350
increasing for the device on the Main page.
351351
:end
352352

353+
:info_ntfs_check_help:
354+
**Check** will run the *ntfsfix* program to check file system integrity on the device. This utility fixes some common NTFS
355+
problems; however, it is NOT a Linux version of chkdsk. It only repairs some fundamental NTFS inconsistencies, resets
356+
the NTFS journal file and schedules an NTFS consistency check for the first boot into Windows. Note: *ntfsfix* will
357+
immediately exit if a hibernation file is detected (to prevent corruption).
358+
359+
The *Options* field is initialized with *-d* to clear the volume dirty flag if the volume can be fixed and mounted.
360+
361+
After starting a Check, you should monitor progress and status. Depending on how large the file system is, and what errors
362+
might be present, the operation can take a **long time** to finish (hours).
363+
Not much info is printed in the window, but you can verify the operation is running by observing the read/write counters
364+
increasing for the device on the Main page.
365+
:end
366+
353367
:info_ext_cancel_help:
354368
**Cancel** will cancel the Check operation in progress.
355369
:end

emhttp/plugins/dynamix/DeviceInfo.page

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,12 @@ function selectDiskFsProfileEXT() {
278278
$('#diskFsProfile').val('');
279279
setDiskFsWidth(1);
280280
}
281+
function selectDiskFsProfileNTFS() {
282+
$('#diskFsProfile').empty();
283+
$('#diskFsProfile').append($('<option>', {value: '', text:''}));
284+
$('#diskFsProfile').val('');
285+
setDiskFsWidth(1);
286+
}
281287
function selectDiskFsProfileBTRFS(slots,init) {
282288
$('#diskFsProfile').empty();
283289
$('#diskFsProfile').append($('<option>', {value: 'single', text:_('single')}));
@@ -407,9 +413,11 @@ function selectDiskFsProfile(init) {
407413
selectDiskFsProfileXFS();
408414
} else if (fsType.indexOf('ext') != -1) {
409415
selectDiskFsProfileEXT();
416+
} else if (fsType.indexOf('ntfs') != -1) {
417+
selectDiskFsProfileNTFS();
410418
}
411419

412-
if (subpool != '' || fsType == 'auto' || fsType.indexOf('xfs') != -1 || fsType.indexOf('ext') != -1) {
420+
if (subpool != '' || fsType == 'auto' || fsType.indexOf('xfs') != -1 || fsType.indexOf('ext') != -1 || fsType.indexOf('ntfs') != -1) {
413421
$('#compression').hide(t);
414422
$('#diskCompression').prop('disabled',true);
415423
} else {
@@ -586,7 +594,7 @@ function zfsResilver(path) {
586594
}
587595
function zfsExpansion(path) {
588596
$.post('/webGui/include/FileSystemStatus.php',{cmd:'zfs-expansion',path:path},function(data) {
589-
if (data.indexOf('expansion')>0 && data.indexOf('in progress')>0) {
597+
if (/expansion of \S+ in progress/.test(data)) {
590598
$('#zfs-button').prop('disabled',true);
591599
$('#zfs-pool').text(data);
592600
setTimeout(function(){zfsExpansion(path);},1000);
@@ -633,6 +641,18 @@ function extCheck(path) {
633641
});
634642
return false;
635643
}
644+
function ntfsCheck(path) {
645+
$.post('/webGui/include/FileSystemStatus.php',{cmd:'ntfs-check',path:path},function(data) {
646+
$('#ntfs-check').text(data);
647+
if (data.slice(-1)!='\0') {
648+
setTimeout(function(){ntfsCheck(path);},1000);
649+
} else {
650+
$.removeCookie('ntfs-check-<?=$tag?>');
651+
refresh();
652+
}
653+
});
654+
return false;
655+
}
636656
function updateMode(form,mode) {
637657
$(form).find('input[name="#arg[3]"]').val(mode);
638658
}
@@ -850,6 +870,7 @@ _(File system type)_:
850870
<?if (_var($disk,'slots',1) == 1) echo mk_option(_var($disk,'fsType'), "ext4", _('ext4'))?>
851871
<?if (_var($disk,'slots',1) == 1) echo mk_option(_var($disk,'fsType'), "ext3", _('ext3'), "disabled")?>
852872
<?if (_var($disk,'slots',1) == 1) echo mk_option(_var($disk,'fsType'), "ext2", _('ext2'), "disabled")?>
873+
<?if (_var($disk,'slots',1) == 1) echo mk_option(_var($disk,'fsType'), "ntfs", _('ntfs'))?>
853874
<?if (_var($disk,'slots',1) == 1) echo mk_option(_var($disk,'fsType'), "reiserfs", _('reiserfs'), "disabled")?>
854875
<?if (_var($disk,'slots',1) == 1) echo mk_option(_var($disk,'fsType'), "luks:xfs", _('xfs')." - "._('encrypted'))?>
855876
<?=mk_option(_var($disk, 'fsType'), "luks:zfs", _('zfs')." - "._('encrypted'))?>
@@ -1543,6 +1564,106 @@ _(xfs_repair status)_:
15431564
<?endif;?>
15441565
<?else:?>
15451566

1567+
&nbsp;
1568+
: <span class="inline-block">
1569+
<input type="submit" value="_(Check)_" disabled>
1570+
<span>**_(Check)_** _(is only available when array is Started in **Maintenance** mode)_.
1571+
</span>
1572+
1573+
<?endif;?>
1574+
</form>
1575+
<?endif;?>
1576+
<?if (fsType('ntfs')):?>
1577+
<div class="title nocontrol">
1578+
<span class="left">
1579+
<i class="title fa fa-shield"></i>_(Check Filesystem Status)_
1580+
</span>
1581+
</div>
1582+
<form markdown="1" method="POST" action="/update.php" target="progressFrame" onsubmit="prepareFS(this,'ntfs-check-<?=$tag?>','/dev/<?=_var($disk, 'deviceSb')?> <?=_var($disk, 'id')?>')">
1583+
<?if (maintenance_mode()):?>
1584+
<?exec("$docroot/webGui/scripts/ntfs_check status /dev/"._var($disk,'deviceSb')." "._var($disk,'id'), $check_status, $retval)?>
1585+
1586+
_(ntfsfix_ status)_:
1587+
: <pre id='ntfs-check'><?=implode("\n", $check_status)?></pre>
1588+
1589+
<?if ($retval == 0 || $retval == 8):?>
1590+
<input type="hidden" name="#command" value="/webGui/scripts/ntfs_check">
1591+
<input type="hidden" name="#arg[1]" value="start">
1592+
<input type="hidden" name="#arg[2]" value="/dev/<?=_var($disk, 'deviceSb')?>">
1593+
<input type="hidden" name="#arg[3]" value="<?=_var($disk, 'id')?>">
1594+
<input type="hidden" name="#arg[4]" value="-d">
1595+
1596+
&nbsp;
1597+
: <span class="buttons-spaced">
1598+
<input type="submit" value="_(Check)_">
1599+
<?if ($retval == 0): ?> _(No file system corruption detected)_.<?endif; ?>
1600+
</span>
1601+
1602+
:info_ntfs_check_help:
1603+
1604+
<?elseif ($retval == 1):?>
1605+
<input type="hidden" name="#command" value="/webGui/scripts/ntfs_check">
1606+
<input type="hidden" name="#arg[1]" value="start">
1607+
<input type="hidden" name="#arg[2]" value="/dev/<?=_var($disk, 'deviceSb')?>">
1608+
<input type="hidden" name="#arg[3]" value="<?=_var($disk, 'id')?>">
1609+
<input type="hidden" name="#arg[4]" value="-e">
1610+
1611+
&nbsp;
1612+
: <span class="buttons-spaced">
1613+
<input type="submit" value="_(Fix)_">
1614+
<span style="color: red;">_(File system corruption detected)_.</span>
1615+
</span>
1616+
1617+
:info_ntfs_check_help:
1618+
1619+
<?elseif ($retval == 2):?>
1620+
<input type="hidden" name="#command" value="/webGui/scripts/ntfs_check">
1621+
<input type="hidden" name="#arg[1]" value="start">
1622+
<input type="hidden" name="#arg[2]" value="/dev/<?=_var($disk, 'deviceSb')?>">
1623+
<input type="hidden" name="#arg[3]" value="<?=_var($disk, 'id')?>">
1624+
<input type="hidden" name="#arg[4]" value="-eL">
1625+
1626+
&nbsp;
1627+
: <span class="buttons-spaced">
1628+
<input type="submit" value="_(Zero Log)_">
1629+
<span style="color: red;">_(Dirty log detected)_.</span>
1630+
</span>
1631+
1632+
<p>_(Note)_: _(While there is some risk, if it is not possible to first mount the filesystem to clear the log, zeroing it is the only option to try and repair the filesystem, and in most cases it results in little or no data loss)_.</p>
1633+
1634+
:info_ntfs_check_help:
1635+
1636+
<?elseif ($retval == 4):?>
1637+
<input type="hidden" name="#command" value="/webGui/scripts/ntfs_check">
1638+
<input type="hidden" name="#arg[1]" value="start">
1639+
<input type="hidden" name="#arg[2]" value="/dev/<?=_var($disk, 'deviceSb')?>">
1640+
<input type="hidden" name="#arg[3]" value="<?=_var($disk, 'id')?>">
1641+
<input type="hidden" name="#arg[4]" value="-n">
1642+
1643+
&nbsp;
1644+
: <span class="buttons-spaced">
1645+
<input type="submit" value="_(Check)_">
1646+
_(File system corruption fixed)_
1647+
</span>
1648+
1649+
:info_ntfs_check_help:
1650+
1651+
<?elseif ($retval == 9):?>
1652+
<input type="hidden" name="#command" value="/webGui/scripts/ntfs_check">
1653+
<input type="hidden" name="#arg[1]" value="cancel">
1654+
<input type="hidden" name="#arg[2]" value="/dev/<?=_var($disk, 'deviceSb')?>">
1655+
1656+
&nbsp;
1657+
: <span class="buttons-spaced">
1658+
<input type="submit" value="_(Cancel)_">
1659+
*_(Running)_*
1660+
</span>
1661+
1662+
:info_ntfs_cancel_help:
1663+
1664+
<?endif;?>
1665+
<?else:?>
1666+
15461667
&nbsp;
15471668
: <span class="inline-block">
15481669
<input type="submit" value="_(Check)_" disabled>
@@ -1797,6 +1918,7 @@ $(function() {
17971918
if ($.cookie('zfs-expansion-<?=$tag?>')) status = zfsExpansion($.cookie('zfs-expansion-<?=$tag?>'));
17981919
if ($.cookie('rfs-check-<?=$tag?>')) status = rfsCheck($.cookie('rfs-check-<?=$tag?>'));
17991920
if ($.cookie('xfs-check-<?=$tag?>')) status = xfsCheck($.cookie('xfs-check-<?=$tag?>'));
1921+
if ($.cookie('ntfs-check-<?=$tag?>')) status = ntfsCheck($.cookie('ntfs-check-<?=$tag?>'));
18001922
if ($.cookie('ext-check-<?=$tag?>')) status = extCheck($.cookie('ext-check-<?=$tag?>'));
18011923
if (status) {
18021924
$.post('/webGui/include/FileSystemStatus.php',{cmd:'status',path:'<?=$tag?>'},function(a){

emhttp/plugins/dynamix/include/FileSystemStatus.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@
1414
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
1515

1616
$cmd = $_POST['cmd'];
17-
$path = $_POST['path'];
17+
$path = escapeshellarg($_POST['path']);
1818

1919
function btrfs($data) {return "btrfs-$data";}
2020
function zfs($data) {return "zfs-".strtok($data,' ');}
2121

2222
switch ($cmd) {
2323
case 'status':
2424
exec("ps -C btrfs -o cmd=|awk '/$path\$/{print $2}'",$btrfs);
25-
exec("/usr/sbin/zpool status $path|grep -Po '(scrub|resilver|expansion) in progress'",$zfs);
25+
exec("/usr/sbin/zpool status $path|grep -Po '(scrub|resilver|expansion of \S+) in progress'",$zfs);
2626
echo implode(',',array_merge(array_map('btrfs',$btrfs),array_map('zfs',$zfs)));
2727
break;
2828
case 'btrfs-balance':
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/bin/bash
2+
# ntfs_check start <dev> <id> <options>
3+
# ntfs_check status <dev> <id>
4+
# ntfs_check cancel <dev> <id>
5+
6+
# Exit codes:
7+
# 0 - No corruption detected or process not found.
8+
# 1 - Corruption detected.
9+
# 4 - File system corruption fixed.
10+
# 8 - No check has been run yet.
11+
# 9 - Process is still running.
12+
13+
# Using /var/lib because that's where btrfs puts status
14+
mkdir -p /var/lib/ntfs
15+
16+
case "$1" in
17+
'start')
18+
# Start the ntfsfix process in the background and log output
19+
rm -f /var/lib/ntfs/check.status.$3
20+
{
21+
/bin/ntfsfix $4 $2 &> /var/lib/ntfs/check.status.$3
22+
echo $? > /var/lib/ntfs/check.status.$3.exit
23+
} > /dev/null 2>&1 &
24+
echo $! > /var/lib/ntfs/check.pid.$3
25+
exit 0
26+
;;
27+
28+
'status')
29+
# Check if the process is still running
30+
if [ -f /var/lib/ntfs/check.pid.$3 ]; then
31+
pid=$(cat /var/lib/ntfs/check.pid.$3)
32+
if kill -0 $pid 2>/dev/null; then
33+
# Process is running, return status and exit code 9
34+
cat /var/lib/ntfs/check.status.$3
35+
exit 9
36+
else
37+
# Process is not running, read the exit status if available
38+
if [ -f /var/lib/ntfs/check.status.$3.exit ]; then
39+
exit_status=$(cat /var/lib/ntfs/check.status.$3.exit)
40+
cat /var/lib/ntfs/check.status.$3
41+
rm -f /var/lib/ntfs/check.pid.$3
42+
(( exit_status & 1 )) && exit 4
43+
(( exit_status & 6 )) && exit 1
44+
exit 0
45+
else
46+
# Exit status file does not exist, but return status file if available
47+
if [ -f /var/lib/ntfs/check.status.$3 ]; then
48+
cat /var/lib/ntfs/check.status.$3
49+
fi
50+
exit 8
51+
fi
52+
fi
53+
else
54+
# No PID file found, check for existing status
55+
if [ -f /var/lib/ntfs/check.status.$3 ]; then
56+
cat /var/lib/ntfs/check.status.$3
57+
# If no exit status file, assume process completed successfully
58+
if [ -f /var/lib/ntfs/check.status.$3.exit ]; then
59+
exit_status=$(cat /var/lib/ntfs/check.status.$3.exit)
60+
(( exit_status & 1 )) && exit 4
61+
(( exit_status & 4 )) && exit 1
62+
exit 0
63+
else
64+
exit 8
65+
fi
66+
else
67+
# No status file found
68+
echo "Not available"
69+
exit 8
70+
fi
71+
fi
72+
;;
73+
74+
'cancel')
75+
# Cancel the ntfsfix process
76+
if [ -f /var/lib/ntfs/check.pid.$3 ]; then
77+
pid=$(cat /var/lib/ntfs/check.pid.$3)
78+
kill $pid
79+
while kill -0 $pid 2>/dev/null; do
80+
sleep 1
81+
done
82+
echo -e "\nCancelled" >> /var/lib/ntfs/check.status.$3
83+
rm -f /var/lib/ntfs/check.pid.$3
84+
else
85+
echo "No process to cancel"
86+
fi
87+
88+
exit 0
89+
;;
90+
91+
*)
92+
# Handle invalid commands
93+
echo "Invalid command"
94+
exit 0
95+
;;
96+
esac

0 commit comments

Comments
 (0)