Using ddrescue created a disk image. To him there is a map that could not be copied. It starts like this:

 # Rescue Logfile. Created by GNU ddrescue version 1.17 # Command line: ddrescue -v -d --max-retries=1 --cluster-size=3 /dev/sdb2 d.img d.log # current_pos current_status 0xA7459CBA00 + # pos size status 0x00000000 0x52C15CAC00 + 0x52C15CAC00 0x00000400 - 0x52C15CB000 0x00011600 + 

As far as I understand, this means that 0x400 bytes since 0x52C15CAC00 could not be read. How to understand exactly which files are damaged? NTFS file system.

  • one
    radagast.ca/linux/… - aleksandr barakin
  • @alexanderbarakin, in principle, yes (why not with the answer, then?), but for different records it is not very suitable, 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
  • @alexanderbarakin, but also, can we explain the stderr redirection? - Qwertiy
  • set like can not list? same not ms / windows . it’s easy to do this here: 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 barakin
  • @alexanderbarakin, 1. But after all, for each iteration, the entire file system will be scanned again, i.e., with n ranges, the calculation will take n times longer than necessary — somehow irrational? 2. About stderr - what does it bring there, why is this redirection needed? - Qwertiy

2 answers 2

as they write here , you need to divide the block number by the size of the cluster used by this file system, and translate the result into a decimal number system.

cluster size:

 $ sudo ntfsinfo -m раздел | grep -i 'cluster size' Cluster Size: 4096 

in hex it will be:

 $ echo 'obase=16;4096' | bc 1000 

divide the number from the question (0x52C15CAC00) by 1000 and get the result in decimal notation:

 $ echo 'ibase=16;52C15CAC00/1000' | bc 86775242 

we learn that the file (s) are located in this cluster (an example of the output of the command is taken from the above instructions):

 $ sudo ntfscluster -c 86775242 раздел Searching for cluster 9369 Inode 89381 /Windows/System32/atidxx64.dll/$DATA 
  • I have built up something here on the basis of this scheme - can you look and say how to improve? - Qwertiy
  • My ntfscluster also wants -f , but I did not mount the disk. - Qwertiy

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.

  • one
    1. It is better to break long teams so that they fit on the screen. 2. What caught my eye: when forming a program for bc, there is no need to constantly override ibase. once at the beginning of the first line is enough: sed -r "s/0x(\w+)\s+0x(\w+)\s+.*/\1\/$clsz; (\1+\2)\/$clsz/;1s/^/ibase=16\n/" - aleksandr barakin
  • @alexanderbarakin, I didn’t know about the substitution only at the beginning, so I drove back and forth to work in every line. In general, this code gives me the feeling that it can be shortened several times if you use normal (or more normal) commands? - Qwertiy
  • @alexanderbarakin, because of the cycle, this code runs for 135 seconds instead of 28. The first scan is 28 seconds, the second is 24, the rest are around 21. If there are more dead areas, this will become a critical problem. We need something that will immediately eat a set of clusters ... - Qwertiy
  • is it time to patch ntfscluster? - aleksandr barakin
  • @alexanderbarakin, and less radical?))) - Qwertiy