LinuxQuestions.org
Support LQ: Use code LQ3 and save $3 on Domain Registration
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Software
User Name
Password
Linux - Software This forum is for Software issues.
Having a problem installing a new program? Want to know which application is best for the job? Post your question in this forum.

Notices

Reply
 
Search this Thread
Old 08-23-2007, 11:25 AM   #1
jhwilliams
Senior Member
 
Registered: Apr 2007
Location: Portland, OR
Distribution: Debian, Android, LFS
Posts: 1,168

Rep: Reputation: 207Reputation: 207Reputation: 207
list most recent file without ls -t


I have directory that is absolutely too huge. I need to know the most recently updated file in the directory, but it is too costly to do something like
Code:
ls -rt | tail -1
being it the case that i am stuck in this situation, is there a faster way to get the most recently updated file in the dir?

thanks,
jameson
 
Old 08-23-2007, 12:59 PM   #2
crabboy
Moderator
 
Registered: Feb 2001
Location: Atlanta, GA
Distribution: Slackware
Posts: 1,823

Rep: Reputation: 120Reputation: 120
I can't think of a way off the top of my head without sorting the list, which is why ls is taking so long. This C program will keep track of the most recent file it encountered during a recursive search and spit it out when its done. No frills, run the program from where you want to start the search. You can modify it to suite your needs.

Code:
#include <stdio.h>
#include <pwd.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h>

struct stat MostRecent;
char MostRecentName[MAXPATHLEN];

void listdir(char * directory)
{
    struct stat FileInfo;
    char name[MAXPATHLEN];
    struct stat dirinfo;
    struct dirent * files;
    DIR * dirin;
    int len, a, log;

    if (lstat(directory, &dirinfo) < 0)
    {
        perror (directory);
        return;
    }
    if (!S_ISDIR(dirinfo.st_mode))
        return;
    if ((dirin = opendir(directory)) == NULL)
    {
        perror(directory);
        return;
    }
    while ((files = readdir(dirin)) != NULL)
    {
        sprintf(name, "%s/%s", directory, files -> d_name);
        if (lstat(name, &FileInfo) < 0)
            perror(name);

        //printf("%s\n", name);

        if ( S_ISDIR( FileInfo.st_mode ) &&
             strcmp(files -> d_name, ".") != 0 &&
             strcmp(files -> d_name, "..") != 0 )
        {
            listdir(name);
        }
        else if ( ! S_ISDIR( FileInfo.st_mode ))
        {

           if ( MostRecent.st_ino = 0 )
           {
              MostRecent = FileInfo;
              strcpy( MostRecentName, name );
           }
           else
           {
              if ( MostRecent.st_mtime < FileInfo.st_mtime )
              {
                 MostRecent = FileInfo;
                 strcpy( MostRecentName, name );
              }
           }
        }
     }
    closedir(dirin);
}


main(int argc, char * argv[])
{

   char szInitialDirectory[MAXPATHLEN];
   MostRecent.st_ino = 0;

   getcwd( szInitialDirectory, MAXPATHLEN - 1 );
   listdir( szInitialDirectory );
   printf("MostRecent: %s\n ", MostRecentName );

}
 
Old 08-24-2007, 08:26 AM   #3
wjevans_7d1@yahoo.co
Member
 
Registered: Jun 2006
Location: Mariposa
Distribution: Slackware 9.1
Posts: 938

Rep: Reputation: 30
You know that if you post a completely runnable program as a solution to someone's problem, some jerk is going to come out of the woodwork and criticize the program. No good deed goes unpunished.

For the sake of better C, I would like to be that jerk for a moment.

crabboy, your program is an excellent idea. It does have a few problems in its current form.

First, it's usually a good idea to compile with the -Wall switch. That will reveal these aspects of the code:
Code:
g.c: In function `listdir':
g.c:52: warning: suggest parentheses around assignment used as truth value
g.c:21: warning: unused variable `len'
g.c:21: warning: unused variable `a'
g.c:21: warning: unused variable `log'
g.c: At top level:
g.c:72: warning: return type defaults to `int'
g.c: In function `main':
g.c:77: warning: implicit declaration of function `getcwd'
g.c:81: warning: control reaches end of non-void function
Translations into English:
Code:
g.c:52: warning: suggest parentheses around assignment used as truth value
Oops. You have this:
Code:
           if ( MostRecent.st_ino = 0 )
This is a common error. The effects of this line are to assign 0 to that field, and to always take the else path, because the value of an assignment is the value assigned. You meant:
Code:
           if ( MostRecent.st_ino == 0 )
Code:
g.c:21: warning: unused variable `len'
g.c:21: warning: unused variable `a'
g.c:21: warning: unused variable `log'
No real harm here. But if you're going to share code with a user who might not be too familiar with C, it's a good idea to lose unused variables so as to avoid confusion.
Code:
g.c:77: warning: implicit declaration of function `getcwd'
I'm getting on in years, so for many functions that I don't use every day I routinely do something like this at the command line to get the name of the #include file I should use:
Code:
man getcwd
In this case, the man page says to do this:
Code:
#include <unistd.h>
And as long as we're talking about #include, let's include only one copy of this:
Code:
#include <stdio.h>
so as not to confuse those who might be just now learning C.

Also, to minimize confusion for them, let's not include these, because your program as it stands doesn't use them:
Code:
#include <pwd.h>
#include <fcntl.h>
#include <sys/types.h>
For the remaining error messages, always declare function main() as of type int, and, instead of falling off the end of the function, return some integer value. (0 is the usual value.)

The next problem is more subtle, and probably more dangerous. Consider this program:

Code:
#include <stdio.h>
#include <sys/param.h>
#include <unistd.h>

int main(void)
{
  printf("%d\n",MAXPATHLEN);
  printf("%d\n",PATH_MAX);
  printf("%ld\n",pathconf(".",_PC_PATH_MAX));

  return 0;

} /* main() */
On my system the output is 4096 for each value. But the value isn't as, um, valuable as it seems. Donald Lewine's excellent book POSIX Programmer's Guide warns us about _PC_PATH_MAX:
Quote:
The value returned by _PC_PATH_MAX is not useful for allocating storage. Files with paths longer than _PC_PATH_MAX may exist.
That makes the following two lines of code dangerous:
Code:
    char name[MAXPATHLEN];
.
.
.
        sprintf(name, "%s/%s", directory, files -> d_name);
This sounds trivial, but buffer overflows are a huge problem with writing in C, and crackers have exploited such bugs more times than one would care to count.

Consider the following script:
Code:
#!/bin/sh

if [[ $1 < 1 ]]
then
  rm -rf xxxxxx*
  export program_name=`pwd`/$0
  echo $program_name
fi

new_level=$(($1+1))
echo $new_level

stupid_name=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
dumber_name=yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy

mkdir $stupid_name
cd $stupid_name
pwd
mkdir $dumber_name
mkdir $dumber_name/$dumber_name
mkdir $dumber_name/$dumber_name/$dumber_name

if [[ $new_level -lt 70 ]]
then
  $program_name $new_level
fi
I ran this script and found that it created paths under my current working directory with lengths greater than 4096. I measured those lengths by running this script:
Code:
#!/bin/sh

find xxx* | while read; do echo ${#REPLY}; done
True, when you run your program against the monstrosity that I've generated, you'll get appropriate messages about a file name being too long, but you will get the buffer overflow first.

To demonstrate that, I inserted the following code just after the sprintf() call:
Code:
        if(strlen(name)>sizeof(name)-1)
        {
          fprintf(stderr,"buffer overflow\n");
          exit(1);
        }
... and, to make the exit() call work, I added this:
Code:
#include <stdlib.h>
Sure enough, I got a buffer overflow before getting any other error message. You want to avoid buffer overflows at all cost.

The solution is to avoid declaring name as being an array of characters; instead, declare it as a pointer, and say something like
Code:
#include <stdlib.h>
.
.
.
name=malloc(strlen(directory)+MAXPATHLEN+2);
if(name==NULL)
{
  fprintf(stderr,"memory allocation failed\n");
  exit(1);
}
.
.
.

/* at the end of function listdir(): */

free(name);
Sorry. Couldn't help myself.
 
Old 08-24-2007, 08:50 AM   #4
theYinYeti
Senior Member
 
Registered: Jul 2004
Location: France
Distribution: Arch Linux
Posts: 1,897

Rep: Reputation: 61
What about using find with -mmin or -mtime?

Yves.
 
Old 08-24-2007, 09:00 AM   #5
chrism01
Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Centos 6.5, Centos 5.10
Posts: 16,269

Rep: Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028Reputation: 2028
ls -rt|tail -1
does a sort and reverse the list.
Do it this way
ls -t|head -1
 
Old 08-24-2007, 11:04 AM   #6
crabboy
Moderator
 
Registered: Feb 2001
Location: Atlanta, GA
Distribution: Slackware
Posts: 1,823

Rep: Reputation: 120Reputation: 120
Great to know that finally someone that knows C has joined the forums.

Last edited by crabboy; 08-24-2007 at 11:43 AM.
 
Old 08-26-2007, 09:00 PM   #7
wjevans_7d1@yahoo.co
Member
 
Registered: Jun 2006
Location: Mariposa
Distribution: Slackware 9.1
Posts: 938

Rep: Reputation: 30
When it comes to C, we're all students on this bus.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
OpenOffice Writer:how to delete Open Recent list? oser Linux - Software 4 03-25-2006 12:17 AM
how to list most recent files last: "ls -altr" is almost it learnfast Linux - Newbie 1 05-20-2005 10:53 AM
list most recent file script Henster Linux - Newbie 4 10-01-2004 01:16 PM
Clearing Recent Doc List b_suny Linux - Software 0 05-14-2004 01:41 AM
clear recent list, edit reopened text file obby Linux - General 0 09-17-2003 08:30 AM


All times are GMT -5. The time now is 09:22 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration