How to know the file is modifed in linux - c

I want to know what system call is used in linux C programming is used to know whether a file is modified.
I know that make utility compiles the file using the modification dates only.
I want know how to find whether the file is modified or not.
Thanks in advance

Using md5sum or sha1sum will hash the contents of the file, which should give you a better indication of actual changes than modification dates.

stat(2) gives you file times and more.
Edit 0:
You can look into fcntl(2) and F_NOTIFY flag - you'd have to open the directory, not the file itself though. Or the newer Linux inotify(7) facility.

You can use ls and various flags on it, like -l or -t and pipe to grep or something. That will tell you when the last file was modified. But it doesn't really tell you if the file was modified. I think the only real way you can know that is if you are keeping track of when the last time it was modified in general (like checking from backups or something).

Related

How would I know that file is opened and it is saved after some writing operation using C code?

I have a set of configuration files (10 or more), and if user opens any of these file using any editor (e.g vim,vi,geany,qt,leafpad..). How would I come to know that which file is opened and if some writing process is done, then it is saved or not (using C code).
For the 1st part of your question, please refer e.g. to How to check if a file has been opened by another application in C++?
One way described there is to use a system tool like lsof and call this via a system() call.
For the 2nd part, about knowing whether a file has been modified, you will have to create a backup file to check against. Most editors already do that, but their naming scheme is different, so you might want to take care of that yourself. How to do that? Just automatically create a (hidden) file .mylogfile.txt if it does not exist by simply copying mylogfile.txt. If .mylogfile.txt exists, is having an older timestamp than mylogfile.txt, and differs in size and/or hash-value (using e.g. md5sum) your file was modified.
But before re-implementing this, take a look at How do I make my program watch for file modification in C++?

How do i use vfs_readdir in linux kernel?

I'm trying to use a system call to display the contents of a directory. I've been pointed in the direction of vfs_readdir, but I have no clue of how to use it or what to pass to it to get the contents of a directory. All I want to do is be able to list files in a directory similar to how ls works. (I eventually intend to store this in some sort of buffer, but for now just being able to print the contents of a dir would be enough).
I think you probably have to open the directory using filp_open.
For the "flags" argument, you proably need to put some combination of the LOOKUP_ flags listed in include/linux/namei.h
You can see what build_open_flags does here: http://lxr.linux.no/#linux+v3.1.5/fs/open.c#L876 to provide flags to filp_open.
As far as I know, filp_open IS the correct way of opening a file in kernel-space. However, doing so is discouraged.
Provided you do so from the context of a "normal" thread belonging to a user process, I think you will be ok.

C - Reading multiple files

just had a general question about how to approach a certain problem I'm facing. I'm fairly new to C so bear with me here. Say I have a folder with 1000+ text files, the files are not named in any kind of numbered order, but they are alphabetical. For my problem I have files of stock data, each file is named after the company's respective ticker. I want to write a program that will open each file, read the data find the historical low and compare it to the current price and calculate the percent change, and then print it. Searching and calculating are not a problem, the problem is getting the program to go through and open each file. The only way I can see to attack this is to create a text file containing all of the ticker symbols, having the program read that into an array and then run a loop that first opens the first filename in the array, perform the calculations, print the output, close the file, then loop back around moving to the second element (the next ticker symbol) in the array. This would be fairly simple to set up (I think) but I'd really like to avoid typing out over a thousand file names into a text file. Is there a better way to approach this? Not really asking for code ( unless there is some amazing function in c that will do this for me ;) ), just some advice from more experienced C programmers.
Thanks :)
Edit: This is on Linux, sorry I forgot to metion that!
Under Linux/Unix (BSD, OS X, POSIX, etc.) you can use opendir / readdir to go through the directory structure. No need to generate static files that need to be updated, when the file system has the information you want. If you only want a sub-set of stocks at a given time, then using glob would be quicker, there is also scandir.
I don't know what Win32 (Windows / Platform SDK) functions are called, if you are developing using Visual C++ as your C compiler. Searching MSDN Library should help you.
Assuming you're running on linux...
ls /path/to/text/files > names.txt
is exactly what you want.
opendir(); on linux.
http://linux.die.net/man/3/opendir
Exemple :
http://snippets.dzone.com/posts/show/5734
In pseudo code it would look like this, I cannot define the code as I'm not 100% sure if this is the correct approach...
for each directory entry
scan the filename
extract the ticker name from the filename
open the file
read the data
create a record consisting of the filename, data.....
close the file
add the record to a list/array...
> sort the list/array into alphabetical order based on
the ticker name in the filename...
You could vary it slightly if you wish, scan the filenames in the directory entries and sort them first by building a record with the filenames first, then go back to the start of the list/array and open each one individually reading the data and putting it into the record then....
Hope this helps,
best regards,
Tom.
There are no functions in standard C that have any notion of a "directory". You will need to use some kind of platform-specific function to do this. For some examples, take a look at this post from Cprogrammnig.com.
Personally, I prefer using the opendir()/readdir() approach as shown in the second example. It works natively under Linux and also on Windows if you are using Cygwin.
Approach 1) I would just have a specific directory in which I have ONLY these files containing the ticker data and nothing else. I would then use the C readdir API to list all files in the directory and iterate over each one performing the data processing that you require. Which ticker the file applies to is determined only by the filename.
Pros: Easy to code
Cons: It really depends where the files are stored and where they come from.
Approach 2) Change the file format so the ticker files start with a magic code identifying that this is a ticker file, and a string containing the name. As before use readdir to iterate through all files in the folder and open each file, ensure that the magic number is set and read the ticker name from the file, and process the data as before
Pros: More flexible than before. Filename needn't reflect name of ticker
Cons: Harder to code, file format may be fixed.
but I'd really like to avoid typing out over a thousand file names into a text file. Is there a better way to approach this?
I have solved the exact same problem a while back, albeit for personal uses :)
What I did was to use the OS shell commands to generate a list of those files and redirected the output to a text file and had my program run through them.
On UNIX, there's the handy glob function:
glob_t results;
memset(&results, 0, sizeof(results));
glob("*.txt", 0, NULL, &results);
for (i = 0; i < results.gl_pathc; i++)
printf("%s\n", results.gl_pathv[i]);
globfree(&results);
On Linux or a related system, you could use the fts library. It's designed for traversing file hierarchies: man fts,
or even something as simple as readdir
If on Windows, you can use their Directory Management API's. More specifically, the FindFirstFile function, used with wildcards, in conjunction with FindNextFile

moving a perl script/dbm to a new server, and shifting out of dbm?

I've been tasked with mirroring a site onto a new server. The old site has a few Perl scripts that, as far as I can see internally (i know nothing about Perl, though I have a pretty good understanding of coding generally, and specifically PHP/js/etc) aren't reliant on the old server. That said, when I try to run this script, which looks through a database file to find the appropriate article file, it doesnt retrieve anything.
Basically, this is a rudimentary old CMS, as I explain it, where it searched the PAG file for the filename and displayed it. I am a little bit lost here. Is there a reason why the mirroring doesn't work on the new site? I've checked the permissions, I've checked that Perl is installed in the same /usr/etc directories. I think it uses dbm because, according to another article, if I see commands like these:
dbmopen( %ARTS, $art_dbm, 0644 );
$entry = $ARTS{$article_id};
dbmclose( %ARTS );
it must be dbm, right?
On a related note, is there any way to merge that PAG file's info with the original files without an incredibly sophisticated Perl script; i.e., recreate the 100 text files with that info in the file itself, rather than stored separately?
EDIT: thanks for the 1st answer below. can you explain what that HASH may be, and the mask? I've doublechecked that the .pag file (the database name) is indeed in the place where its defined earlier in the .pl file, and that it was transferred in binary. yet somehow I cant get it to open it correctly!
EDIT 3: Ok, sorry, final editing here: I used the die code below (Shwern) and found that it is not finding that DB file, despite it being there (two files articles.pag and articles.dir, but the variable only references "articles" without extensions) in the right directory and with the right permissions... So, the question here is now what the hell is going on? are these different versions of perl? or am i just doing something basic and stupid? for the record (yes, its terrible) i dont have shell access just yet, though i'm working on it... I was asked to do this because of my "new web" skills, and I'm certainly not the appropriate person for things like perl and dbm, though i can read the files and understand them. As a final suggestion, does anyone know how (a script or the like) I could ask the original server people (who are NOT the coders) to do an ASCII dump of this, or would that be out of line? I need to get this into CSV and back into the file so I can reuse it in another db... ugh what a nightmare!
If I read your question correctly, you're having difficulty opening the database on a new machine. Does the database exist there?
The documentation for the dbmopen method is available on the command line via perldoc -f dbmopen (and at this link for the latest stable perl release, 5.10.1).
As you can see from the docs, the second argument to dbmopen contains the filename being opened. In the code you pasted, that's contained in the scalar variable $art_dbm. So what you need to do is look for some earlier declaration of this variable (perhaps it is loaded in from a configuration file, or it could be hard-coded). Then once you've found that DB, all that should be necessary is transferring that file over to your new machine.
If you need more help deciphering the code, feel free to edit your question with a code snippet and we can go from there.
(Now, if you've found the database but you just can't open it, you've got some other problem.. It's been a long time since I dealt with PAG files however.)
Do you still have access to the original machines?
Although you are using a DBM files, that actual functionality can come from one of several implementations, some of which are not compatible. I'd dump the file with the same perl that created it, then recreate it with the new perl.
There's a few things which could be going wrong. The most obvious one is that the dbmopen() call isn't opening the file. If the DBM file doesn't exist, rather than failing dbmopen() just makes a new one which could be why it appears empty.
To eliminate that possibility, make sure the DBM file does exist and is readable. You also want to check if the dbmopen() succeeded, it will (usually) error out if its the wrong format.
die "$art_dbm does not exist" unless -e $art_dbm;
die "Cannot read $art_dbm" unless -r $art_dbm;
dbmopen( %ARTS, $art_dbm, 0644 ) or die "dbmopen of $art_dbm failed: $!";
Unfortunately dbmopen() is too clever for its own good. If you give it "foo" it might create "foo.db" instead. Depends on the implementation. See below.
The other possibility is that your two Perls are trying to open the file with two different DBM implementations. Perl can be compiled with different sets of DBM implementations on your different machines. dbmopen() will use the first one in a hard coded (and historically barnacled) list. Its actually a wrapper around AnyDBM_File. You can check which implementation is being used with...
use AnyDBM_File;
print "#AnyDBM_File::ISA\n";
Make sure they're the same. If not, load the DBM library in question before using dbmopen. perldoc -f dbmopen explains.
Here's a demonstration. First we see what dbmopen() will default to.
$ perl -wle 'use AnyDBM_File; print "#AnyDBM_File::ISA"'
NDBM_File
Then create and populate a dbm file.
$ perl -wle 'dbmopen(%foo, "tmpdbm", 0644) or die $!; $foo{23} = 42; print %foo'
2342
Now demonstrate we can read it.
$ perl -wle 'dbmopen(%foo, "tmpdbm", 0644) or die $!; print %foo'
2342
And try to read it using a different DBM implementation.
$ perl -wle 'use GDBM_File; dbmopen(%foo, "tmpdbm", 0644) or die $!; print %foo'
Nothing in the file, but no error either. Turns out it made a file called tmpdbm whereas ndbm was using tmpdbm.db. Let's try Berkeley DB.
$ perl -wle 'use DB_File; dbmopen(%foo, "tmpdbm", 0644) or die $!; print %foo'
Inappropriate file type or format at -e line 1.
At least that gives an error.
Your best bet is to figure out what DBM implementation the original machine is using and use that module before the dbmopen() call. That will make the situation static.
PS The Unix file utility will also give you a good idea what type of DBM it is.
$ file tmpdbm
tmpdbm: GNU dbm 1.x or ndbm database, little endian
$ file tmpdbm.db
tmpdbm.db: Berkeley DB 1.85 (Hash, version 2, native byte-order)
And hope to $diety its not a byte-order issue, less common now that almost everything is x86.
PPS As you can see, using DBM files is a bit of a mess. Strange considering its supposed to be just a hash-on-disk.

How to generate random file name for socket under Linux?

I want to make a small program which use local namespace socket and I will need to use temporary file name as address of the socket.
So how to generate random file name under Linux?
+ I'm using the C programming language under Debian Linux.
+ Acoording to the GNU C Library Reference,tmpname is not safe.But the safe ones tmpfile and mkstemp create and open the generated file.Is there any safe and non-create-open to this.In other words, the function should forbidden any other request to create the generated file name under specific directory.
thanks.
If you're doing this in C, use mkdtemp to create a directory, and put your socket inside this directory.
Other functions such as tmpnam or mktemp are insecure; since they don't create and open the temp file for you, it's easy to be vulnerable to following a pre-existing symlink (placed by an attacker who guessed your temp filename) to some important file (like /etc/passwd), overwriting it.
Note that there's no way to 'lock' a path - all you can do is create something there. If you need to put a socket there eventually, using a directory as a placeholder is your best bet.
There is mktemp program which is available as part of GNU coreutils. See it's manpage for details.
Typical usage is as simple as this:
TEMPDIR=$(mktemp -d)
echo $TEMPDIR
touch $TEMPDIR/yourfile.txt
(As noted in other answer it is only safe to create a directory.)
You didn't specify the language you are using, but assuming it is a C/C++ dialect (or some other language with access to the C runtime library), you could use the tmpnam function.
There are some issues with tmpnam, the most serious of which is probably that the temporary file name you get back isn't actually "locked" until you use it to create a file, so theoretically some other process could create the file out from under you. You also have to make absolutely sure the buffer you pass tmpnam has enough space to hold the longest path your OS can support.
These days it is recommended that you call tmpfile instead. This will create the file for you in one (hopefully atomic) operation, and give you back a file handle. Another nice benefit is that the file is deleted for you automatically when you close it. No muss, no fuss.
Play with /dev/random.
A quick search on google gave me this hit:
< /dev/urandom tr -dc A-Za-z0-9 | head -c8
If you would like to do the same in C,
just open /dev/random and convert it into a string (ignore non valid chars).

Resources