POSIX seekdir() and telldir() behaviour after target folder modification - c

consider the following task :
1) read a target directory contents, pass each found dirent structure to some filter function and remember filtered elements somehow for the later processing
2) some time later, iterate through the filtered elements and process them (do some I/O)
The most obvious way is to save names of sub-directories.
However, I want to keep memory usage to the minimum and to avoid additional I/O.
According to POSIX manuals, I can save position of each directory entry using telldir() and restore them later using seekdir(). To keep these positions valid, I have to keep target directory opened and to not use rewinddir() call.
Keeping a directory stream open and storing a list of dir positions(long int`s) seems to be an appropriate solution.
However, it is unclear whether stored positions remain valid after folder modification. I didn`t found any comments on these conditions in the POSIX standard.
1) Whether stored positions remain valid when only new directory entries are added/removed ?
2) Whether stored positions of unmodified directory entries remain valid in case of some of the filtered directory entries were removed ?
3) Is it possible for the stored position to point to another directory entry after folder modification ?
It is easy to test and find out the answer on these questions for the particular system, but I would like to know what standards say on this topic
Thank you

Until you call rewinddir or close and reopen the directory, your view of the directory contents should not change. Sorry I don't have the reference handy. I'll find it later if you need it.

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++?

Is there a way to check the last time a program was run? (C in Unix)

I'm writing a program/utility in C to find (and then move to a new directory) the files in the current directory that have been modified after the last time the utility was run.
What I'm trying to find out is if there is a way to find the last time this utility ran. Or alternatively, a way to store the time in the program (so as to compare the last stored time against the current time, and then update the "last time" variable to current time).
As I type this it occurs to me that I could write the time to a file (overwriting the single entry as the utility is run) and retrieve the value from the file in the program, although I don't know if this would be the best approach.
you can make a class contains info and serialize it to a text file , it's more easy to access and can store multiple values,
then to store new values first delete file and then create file again.
another approach could be a register key containing information.
hope it would be useful ;)
You can use the last access time from the filesystem (In GNU/linux you can use ls -lu to see last access time).
This is not a portable solution because it depends on filesystem and filesystem settings (see JoachimPileborg edit below)
Moreover look at this question to get last acces time in C (use atime instead of mtime).

How can I search for a file within a directory and its sub-directories in c?

How can I search for a file within a directory and its sub-directories in C?
I'm not allowed to use find and I must use opendir , readdir and stat.
I want to perform something like the command ls -ln if the file indeed exists.
For traversing the directories, you will need: opendir(3), readdir(3), and closedir(3).
For checking the type of file (to see if it's a directory and if you should recursively search within it) you will need stat(2).
You will want to check
(struct stat).st_mode & S_IFDIR
to see if the file is a directory. See <sys/stat.h> for more information.
If we try to write a small piece of code in C then we can do this search activity easily.
Suppose you need to search abc.txt in a /home/Jack/ then just open a file stream and pass the file path as a parameter.
Now when this statement will be executed, it will try to open the existing file. This API will return non zero if the file exists otherwise it is returned -1 or zero.
You've already provided the basic answer: opendir/readdir/closedir. As you walk the directory entries, you check whether each refers to a file or a directory. Those that refer to directories, you traverse as well (typically recursively). For those that refer to files, you compare their names to the file(s) you're looking for, and see if you've found it.
One other minor detail: you probably also want to check for symbolic links. A symbolic link can (for example) refer to a parent directory, which could/can lead to infinite recursion. You may want to ignore symbolic links completely, or you may want to keep a list of directories you've already at least started to traverse, and resolve/traverse what's in the symbolic link only if it's not already in the list.

Open every file but not links to other directories when using scandir()

I want to recursively copy one directory into another (like cp -R) using POSIX scandir().
The problem is that when I copy a directory like /sys/bus/, which contains links to higher levels (for example: foo/foo1/foo2/foo/foo1/foo2/foo/... ) the system enters a loop status and copies the directories "in the middle" forever...
How can I check if the file I'm opening with dirent is a link or not?
Look at this: How to check whether two file names point to the same physical file
You need to store a list of inodes that you have visited to make sure that you don't get any duplicates. If you have two hard links to the same file, there is no "one" canonical name. One possibility is to first store all the files and then recurse through all the filenames. You can store the path structure separately from the inodes and file contents.

stdio's remove() not always deleting on time

For a particular piece of homework, I'm implementing a basic data storage system using sequential files under standard C, which cannot load more than 1 record at a time. So, the basic part is creating a new file where the results of whatever we do with the original records are stored. The previous file's renamed, and a new one under the working name is created. The code's compiled with MinGW 5.1.6 on Windows 7.
Problem is, this particular version of the code (I've got nearly-identical versions of this floating around my functions) doesn't always remove the old file, so the rename fails and hence the stored data gets wiped by the fopen().
FILE *archivo, *antiguo;
remove("IndiceNecesidades.old"); // This randomly fails to work in time.
rename("IndiceNecesidades.dat", "IndiceNecesidades.old"); // So rename() fails.
antiguo = fopen("IndiceNecesidades.old", "rb");
// But apparently it still gets deleted, since this turns out null (and I never find the .old in my working folder after the program's done).
archivo = fopen("IndiceNecesidades.dat", "wb"); // And here the data gets wiped.
Basically, anytime the .old previously exists, there's a chance it's not removed in time for the rename() to take effect successfully. No possible name conflicts both internally and externally.
The weird thing's that it's only with this particular file. Identical snippets except with the name changed to Necesidades.dat (which happen in 3 different functions) work perfectly fine.
// I'm yet to see this snippet fail.
FILE *antiguo, *archivo;
remove("Necesidades.old");
rename("Necesidades.dat", "Necesidades.old");
antiguo = fopen("Necesidades.old", "rb");
archivo = fopen("Necesidades.dat", "wb");
Any ideas on why would this happen, and/or how can I ensure the remove() command has taken effect by the time rename() is executed? (I thought of just using a while loop to force call remove() again so long as fopen() returns a non-null pointer, but that sounds like begging for a crash due to overflowing the OS with delete requests or something.)
So suddenly, after reading Scott's mention of permissions, I thought about "Permission Denied" and applied some Google. Turned out it's a pretty common, if obscure, error.
caf was right, it was in another piece of code. Namely, I had forgotten to fclose that same file in the function meant to show the contents. Since I wasn't tracking that particular detail, it appeared to be random.
Disclaimer: Weekly math assigments make for very little sleeptime. ¬¬
That sounds quite strange, and even more so when you say that the same code works OK with a different filename - I would strongly suspect a bug elsewhere in your code. However, you should be able to work around it by renaming the file you want to remove:
rename("IndiceNecesidades.old", "IndiceNecesidades.older");
remove("IndiceNecesidades.older");
rename("IndiceNecesidades.dat", "IndiceNecesidades.old");
It would probably be a good idea to check the remove() function for errors. man remove says that the function returns 0 on success and -1 on failure, setting errno to record the error. Try replacing the call with
if (remove("IndiceNecesidades.old") != 0){
perror("remove(\"IndiceNecesidades.old\") failed");
}
which should give an error message saying what failed.
Further, it doesn't appear that the remove is neccessary
man rename()
The rename() system call causes the
link named old to be renamed as new.
If new exists, it is first removed.
Both old and new must be of the same
type (that is, both must be either
directories or non-directories) and
must reside on the same file system.
The rename() system call guarantees
that an instance of new will always
exist, even if the system should crash
in the middle of the operation.
If the final component of old is a
symbolic link, the symbolic link is
renamed, not the file or directory to
which it points.
EPERM will be returned if:
[EPERM] The directory
containing old is marked sticky, and
neither the containing directory nor
old are owned by the effective user
ID.
[EPERM] The new file
exists, the directory containing new
is marked sticky, and neither the
containing directory nor new are owned
by the effec-
tive user ID.
so the next step would be to check you have permissions on the containing directory

Resources