TestDisk NTFS undelete - filter by year

Using TestDisk to undelete files
Forum rules
When asking for technical support:
- Search for posts on the same topic before posting a new question.
- Give clear, specific information in the title of your post.
- Include as many details as you can, MOST POSTS WILL GET ONLY ONE OR TWO ANSWERS.
- Post a follow up with a "Thank you" or "This worked!"
- When you learn something, use that knowledge to HELP ANOTHER USER LATER.
Before posting, please read https://www.cgsecurity.org/testdisk.pdf
Locked
Message
Author
leonardorame
Posts: 5
Joined: 02 May 2020, 18:51

TestDisk NTFS undelete - filter by year

#1 Post by leonardorame »

Hi Christophe, last night I've sent you an email with the following content, maybe it's in your spam folder, please take a look.

I'm using your wonderful TestDisk to recover a lot of files deleted from an USB external NTFS disk.

I can recover the files by searching by name (using the 'f' shortcut), but as there are a lot of files and I don't need all of then I would like to be able to filter by date, or better yet by YEAR.

In TestDisk 7.0 I can check the file date by looking a the Date column (marked with red in the next image):

Image

Now, to be able to filter by date I implemented a quick and dirty "Date filter" shortcut in ntfs_udl.c cloned from git:

Code: Select all

        case 'd':
          {
            const char *needle=ask_string_ncurses("Date filter ");
            if(needle!=NULL && needle[0]!='\0')
            {
              td_list_for_each(file_walker,&dir_list->list)
              {
                file_info_t *file_info;
                file_info=td_list_entry(file_walker, file_info_t, list);
                struct tm *local = localtime(&file_info->td_mtime);
                if((file_info->status&FILE_STATUS_DELETED)==0 &&
                    local->tm_year + 1900!=2020)  // only filter files modified in year 2020.
                  file_info->status|=FILE_STATUS_DELETED;
              }
              pos_num=0;
              current_file=ntfs_next_non_deleted(&dir_list->list, &dir_list->list);
            }
          }
          break;

I just need to recover files created on year 2020, so, if my fix is ok this should work.

The problem I have now is I can't check the file date, because the version I can compile is 7.2-WIP, and this version doesn't show the file date, please check the next screenshot:

Image

The questions are:

1. With my fix, can I be sure all the files created in year 2020 will be filtered to be undeleted?
2. If not, could you help me show the file date column?, this way I could debug my fix.

Regards,
Leonardo M. Ramé

User avatar
cgrenier
Site Admin
Posts: 5432
Joined: 18 Feb 2012, 15:08
Location: Le Perreux Sur Marne, France
Contact:

Re: TestDisk NTFS undelete - filter by year

#2 Post by cgrenier »

I have uploaded a new 7.2-WIP with a fix for this problem
https://git.cgsecurity.org/cgit/testdis ... dc3acfcdf9

Can you try it ?

leonardorame
Posts: 5
Joined: 02 May 2020, 18:51

Re: TestDisk NTFS undelete - filter by year

#3 Post by leonardorame »

Thanks for the fix, I wasn't able to test because the problematic PC was powered off on the remote side. Now I compiled the new version and tested, it works.

screenshot_5.png
screenshot_5.png (153.89 KiB) Viewed 8983 times
Now, could you help me implement the Date filter?. It would be great to have the possibility to filter between two days and list the deleted files in that range.

leonardorame
Posts: 5
Joined: 02 May 2020, 18:51

Re: TestDisk NTFS undelete - filter by year

#4 Post by leonardorame »

As a starting point I made this:

Code: Select all

        case 'd':
          {
            const char *needle=ask_string_ncurses("Date filter ");
            if(needle!=NULL && needle[0]!='\0')
            {
              td_list_for_each(file_walker,&dir_list->list)
              {
                file_info_t *file_info;
                file_info=td_list_entry(file_walker, file_info_t, list);
                if((file_info->status&FILE_STATUS_DELETED)==0 &&
                    ((file_info->td_ctime < 1580515200) || (file_info->td_ctime > 1583020799))
                )
                  file_info->status|=FILE_STATUS_DELETED;
              }
              pos_num=0;
              current_file=ntfs_next_non_deleted(&dir_list->list, &dir_list->list);
            }
          }
          break;

The

Code: Select all

((file_info->td_ctime < 1580515200) || (file_info->td_ctime > 1583020799))
part indicates exclude all files created before 2020-02-01 and after 2020-02-29.

leonardorame
Posts: 5
Joined: 02 May 2020, 18:51

Re: TestDisk NTFS undelete - filter by year

#5 Post by leonardorame »

This little program converts two dates YYYYMMDD-YYYYMMDD to epoch. I'll add this to the Date Filter later.

Code: Select all

#include <stdio.h>
#include <string.h>

#define __USE_XOPEN
#include <time.h>

int main()
{
        char src[] = "20200101-20200131"; 
        char from[9]; 
        char to[9]; 
        memset(from, '\0', sizeof(from));
        memset(to, '\0', sizeof(to));

        strncpy(from, src, 8); 

        char *src2 = src + 9;
        strncpy(to, src2, 8); 

        printf("%s\n%s\n", from, to); 

        struct tm ltm = {0};
        if (strptime(from, "%Y%m%d", &ltm) ) {
                printf("year: %02d; month: %d; day: %d;\n",
                                                ltm.tm_year + 1900, ltm.tm_mon + 1, ltm.tm_mday);
        };

        time_t epochFrom = timegm(&ltm);

        if (strptime(to, "%Y%m%d", &ltm) ) {
                ltm.tm_sec = 59;
                ltm.tm_min = 59;
                ltm.tm_hour = 23;
                printf("year: %02d; month: %d; day: %d;\n",
                                                ltm.tm_year + 1900, ltm.tm_mon + 1, ltm.tm_mday);
        };

        time_t epochTo = timegm(&ltm);
        printf("%ld\n%ld\n", epochFrom, epochTo);

        return 0;
}
The result is this:

Code: Select all

20200101
20200131
year: 2020; month: 1; day: 1;
year: 2020; month: 1; day: 31;
1577836800
1580515199

leonardorame
Posts: 5
Joined: 02 May 2020, 18:51

Re: TestDisk NTFS undelete - filter by year

#6 Post by leonardorame »

I finally implemented the "Date range filter", you'll have to add this block of code to ntfs_udl.c just before the *case 'f';*

Code: Select all

  case 'd':                                                                                                                                                                                     
    {                                                                                                                                                                                           
      const char *dateRange=ask_string_ncurses("Date range (YYYYMMDD-YYYMMDD)");                                                                                                                
      if(dateRange!=NULL && dateRange[0]!='\0')                                                                                                                                                 
      {                                                                                                                                                                                         
          char from[9];                                                                                                                                                                         
          char to[9];                                                                                                                                                                           
          const char *src2;                                                                                                                                                                     
          struct tm ltm = {0};                                                                                                                                                                  
          time_t epochFrom;                                                                                                                                                                     
          time_t epochTo;                                                                                                                                                                       
          memset(from, '\0', sizeof(from));                                                                                                                                                     
          memset(to, '\0', sizeof(to));                                                                                                                                                         
                                                                                                                                                                                                
          // extract from                                                                                                                                                                       
          strncpy(from, dateRange, 8);                                                                                                                                                          
                                                                                                                                                                                                
          // extract to                                                                                                                                                                         
          src2 = dateRange + 9;                                                                                                                                                                 
          strncpy(to, src2, 8);                                                                                                                                                                 
                                                                                                                                                                                                
          // convert from date to epoch                                                                                                                                                         
          strptime(from, "%Y%m%d", &ltm);                                                                                                                                                       
          epochFrom = timegm(&ltm);                                                                                                                                                             
                                                                                                                                                                                                
          // convert to date to epoch                                                                                                                                                           
          strptime(to, "%Y%m%d", &ltm);                                                                                                                                                         
          ltm.tm_sec = 59;                                                                                                                                                                      
          ltm.tm_min = 59;                                                                                                                                                                      
          ltm.tm_hour = 23;                                                                                                                                                                     
          epochTo = timegm(&ltm);                                                                                                                                                               
                                                                                                                                                                                                
          td_list_for_each(file_walker,&dir_list->list)                                                                                                                                         
          {                                                                                                                                                                                     
              file_info_t *file_info;                                                                                                                                                           
              file_info=td_list_entry(file_walker, file_info_t, list);                                                                                                                          
              if((file_info->status&FILE_STATUS_DELETED)==0 &&                                                                                                                                  
                  ((file_info->td_ctime < epochFrom) || (file_info->td_ctime > epochTo))                                                                                                        
              )                                                                                                                                                                                 
              file_info->status|=FILE_STATUS_DELETED;                                                                                                                                           
          }                                                                                                                                                                                     
          pos_num=0;                                                                                                                                                                            
          current_file=ntfs_next_non_deleted(&dir_list->list, &dir_list->list);                                                                                                                 
      }                                                                                                                                                                                         
    }                                                                                                                                                                                           
    break; 
How it works:

When you are in the Advanced -> Undelete screen just press 'd' key and a dialog asking for the date range will show up on screen, there you must enter an YYYYMMDD-YYYYMMDD range, for example 20200101-20200131 and press enter, then the filtered range of files will show and you can select, then undelete.

Here are two screenshots that explain themselves:

screenshot_7.png
screenshot_7.png (179.13 KiB) Viewed 8858 times
screenshot_6.png
screenshot_6.png (194.37 KiB) Viewed 8858 times
I hope you'll find useful.

Christophe, do you think this can be added to the official program?.

Regards,
Leonardo.

Locked