In Linux, you can use the following solution:
filename=d.img logname=d.log clsz=$(sudo ntfsinfo -m -f $filename 2>/dev/null | grep 'Cluster Size' | \ sed -r "s/.*:/obase=16;/" | bc) for r in $(cat $logname | grep '-' | grep -v 'ddrescue' | \ sed -r "s/0x(\w+)\s+0x(\w+)\s+.*/\1\/$clsz; (\1+\2)\/$clsz/;1s/^/ibase=16\n" | \ bc | tr '\n' '-' | sed -r 's/(\w+-\w+)-/\1\n/g' | uniq | tr '\n' ' ' | \ sed -r 's/-(\w+) \1\b//g' | sed -r 's/ /\n/g' | \ sed -r 's/(\w+)-(\w+)/\1;\2;\2+1;/' | bc | tr '\n' '-' | \ sed -r 's/(\w+-\w+-\w+)-/\1 /g' | sed -r 's/-\w+-(\w+) \1//g' | \ sed -r 's/(-\w+)-\w+/\1/g'); \ do sudo ntfscluster -f -c $r $filename 2>/dev/null; done
I note that you must first run any sudo
command so that the last command is not eaten as a password. Then the rest of the team will not be asked for a password and everything will work.
A significant disadvantage of this solution is that for each cluster range the file system is scanned again, i.e. it works very slowly.
Now I will explain what is happening here.
First, determine the cluster size.
Information about the disk can be obtained using ntfsinfo
.
The -f
option is needed so that the image is not put to check with a request to reboot twice.
Redirecting errors to /dev/null
to get rid of the WARNING: Dirty volume mount was forced by the 'force' mount option.
sudo ntfsinfo -m -f d.img 2>/dev/null
From here select a row with information about the cluster size:
... | grep 'Cluster Size'
We will get a number from it and translate it into a hexadecimal number system:
... | sed -r "s/.*:/obase=16;/" | bc
Save to variable:
clsz=$(...)
The whole team:
clsz=$(sudo ntfsinfo -m -f d.img 2>/dev/null | grep 'Cluster Size' | \ sed -r "s/.*:/obase=16;/" | bc)
Probably get the value 1000.
Now we define the ranges of clusters.
Select from the map all the bad pieces (contain -
and are not a line with the command itself):
cat d.log | grep '-' | grep -v 'ddrescue'
Something will turn out such:
0x52C15CAC00 0x00000400 - 0x52C15DC600 0x00000200 - 0xA74593D600 0x00000200 - 0xA74593DA00 0x00000600 - 0xA74593E600 0x00000200 - 0xA745945000 0x00000400 - 0xA745945600 0x00000200 - 0xA745945C00 0x00000400 - 0xA745947600 0x00000200 - 0xA7459C3200 0x00000C00 - 0xA7459CB000 0x00000200 - 0xA7459CB400 0x00000200 - 0xA7459CB800 0x00000400 -
Let us transform into formulas for calculating cluster numbers in the 16-notation number system:
... | sed -r "s/0x(\w+)\s+0x(\w+)\s+.*/\1\/$clsz; (\1+\2)\/$clsz/;1s/^/ibase=16\n/"
ibase=16; 52C15CAC00/1000; (52C15CAC00+00000400)/1000; ibase=A; ibase=16; 52C15DC600/1000; (52C15DC600+00000200)/1000; ibase=A; ibase=16; A74593D600/1000; (A74593D600+00000200)/1000; ibase=A; ibase=16; A74593DA00/1000; (A74593DA00+00000600)/1000; ibase=A; ibase=16; A74593E600/1000; (A74593E600+00000200)/1000; ibase=A; ibase=16; A745945000/1000; (A745945000+00000400)/1000; ibase=A; ibase=16; A745945600/1000; (A745945600+00000200)/1000; ibase=A; ibase=16; A745945C00/1000; (A745945C00+00000400)/1000; ibase=A; ibase=16; A745947600/1000; (A745947600+00000200)/1000; ibase=A; ibase=16; A7459C3200/1000; (A7459C3200+00000C00)/1000; ibase=A; ibase=16; A7459CB000/1000; (A7459CB000+00000200)/1000; ibase=A; ibase=16; A7459CB400/1000; (A7459CB400+00000200)/1000; ibase=A; ibase=16; A7459CB800/1000; (A7459CB800+00000400)/1000; ibase=A;
And we calculate
... | bc
86775242 86775243 86775260 86775260 175397181 175397181 175397181 175397182 175397182 175397182 175397189 175397189 175397189 175397189 175397189 175397190 175397191 175397191 175397315 175397315 175397323 175397323 175397323 175397323 175397323 175397323
Unfortunately, the numbers turned out on different lines - we combine them with a hyphen, then we replace every other hyphen with a newline, then remove duplicate lines:
... | tr '\n' '-' | sed -r 's/(\w+-\w+)-/\1\n/g' | uniq
86775242-86775243 86775260-86775260 175397181-175397181 175397181-175397182 175397182-175397182 175397189-175397189 175397189-175397190 175397191-175397191 175397315-175397315 175397323-175397323
We unite consecutive chains if the final cluster of the first coincides with the initial one following. To do this, combine the lines separated by a space and remove -число такое-же-число\b
. My sed
didn't eat \d
, so I used \w
. After replacing, we will replace the line breaks.
... | tr '\n' ' ' | sed -r 's/-(\w+) \1\b//g' | sed -r 's/ /\n/g'
86775242-86775243 86775260-86775260 175397181-175397182 175397189-175397190 175397191-175397191 175397315-175397315 175397323-175397323
Prepare to count the number following the end of the cluster:
... | sed -r 's/(\w+)-(\w+)/\1;\2;\2+1;/'
86775242;86775243;86775243+1; 86775260;86775260;86775260+1; 175397181;175397182;175397182+1; 175397189;175397190;175397190+1; 175397191;175397191;175397191+1; 175397315;175397315;175397315+1; 175397323;175397323;175397323+1;
And calculate this:
... | bc
86775242 86775243 86775244 86775260 86775260 86775261 175397181 175397182 175397183 175397189 175397190 175397191 175397191 175397191 175397192 175397315 175397315 175397316 175397323 175397323 175397324
By analogy with the last time, we combine lines with a hyphen, and every third defois is replaced with a space:
... | tr '\n' '-' | sed -r 's/(\w+-\w+-\w+)-/\1 /g'
We unite the chains, where the initial cluster next coincides with the next one after the final cluster of the previous one:
... | sed -r 's/-\w+-(\w+) \1//g'
86775242-86775243-86775244 86775260-86775260-86775261 175397181-175397182-175397183 175397189-175397191-175397192 175397315-175397315-175397316 175397323-175397323-175397324
We remove the extra information about the following cluster:
... | sed -r 's/(-\w+)-\w+/\1/g'
86775242-86775243 86775260-86775260 175397181-175397182 175397189-175397191 175397315-175397315 175397323-175397323
The whole team:
cat d.log | grep '-' | grep -v 'ddrescue' | \ sed -r "s/0x(\w+)\s+0x(\w+)\s+.*/\1\/$clsz; (\1+\2)\/$clsz/;1s/^ibase=16\n/" | \ bc | tr '\n' '-' | sed -r 's/(\w+-\w+)-/\1\n/g' | uniq | tr '\n' ' ' | \ sed -r 's/-(\w+) \1\b//g' | sed -r 's/ /\n/g' | \ sed -r 's/(\w+)-(\w+)/\1;\2;\2+1;/' | bc | tr '\n' '-' | \ sed -r 's/(\w+-\w+-\w+)-/\1 /g' | sed -r 's/-\w+-(\w+) \1//g' | \ sed -r 's/(-\w+)-\w+/\1/g'
Use the list to search for files:
Wrap the resulting construction as a set for a for loop:
for r in $(...); do echo $r; done
Finally, change echo $r
to something useful:
sudo ntfscluster -f -c $r d.img 2>/dev/null
The result is a list of files that interest us, along with the indication of clusters.
ntfscluster
only understands a continuous chain of clusters, it seems like a set cannot be listed? But I have a few of them, so it will fit. - Qwertiy ♦for i in 0-100 101-200 201-300; do sudo ntfscluster -s $i раздел; done
for i in 0-100 101-200 201-300; do sudo ntfscluster -s $i раздел; done
for i in 0-100 101-200 201-300; do sudo ntfscluster -s $i раздел; done
. can I explain the stderr redirect? - Yes, ask. - aleksandr barakinn
ranges, the calculation will taken
times longer than necessary — somehow irrational? 2. About stderr - what does it bring there, why is this redirection needed? - Qwertiy ♦