cleaning the files in directory in linux - c

I want to clean all files in a directory on Linux (not deleteing them, only clear their content)
I need to do it in C.

Actually, you really don't need to do it in C. UNIX includes tools that can just about do any task that you want.
find . -type f -exec cp /dev/null {} ';'
That particular snippet above will find all files under the current directory and attempt to copy the null device to it, effectively truncating the file to 0 bytes.
You can change the starting (top level) directory, restrict names (with -name '*.jpg' for example) and even restrict it to the current directory (no subdirectories) with -maxdepth 0.
There are many other options with find that you can discover by entering man find into your command line shell. Just don't enter it into Google, you may get more than you bargained for :-)
If the need to use C is an absolutely non-negotiable one, I would still do it this way but with:
system ("find . -type f -exec cp /dev/null {} ';'");
I'm not keen on re-writing software that someone's already put a bucketload of effort into providing for free :-)
If, after my advice, you still want to do it the hard way, you need to look into opendir, readdir and closedir for processing directories, then just use fopen in write mode followed by fclose on each candidate file.
If you want to navigate whole directory structures rather than just the current directory, you'll have to detect directories from readdir and probably recurse through them.

scandir to list them, then for every file:
fopen(, w+)
fstat to get the size
fwrite the whole file with zeroes? (this is what you mean by clear?)
fclose
A nice shell variant would be: shred -z directory/*

In Bash:
for i in directory/*; do > $i; done
This will preserve ownership and permissions of the file.
Don't do shell work in C! Save a huge amount of time by using the best tool for the job. If this is homework, mark it as such.

You can open the file in write mode and then close it.

Related

How to force deletion of file in C?

How can I remove opened file in linux?
In shell I can do this:
rm -rf /path/to/file_or_directory
But how can I do it in C?
I don't want to using system() function.
I have seen unlink and remove method but it's haven't any flags to set force deletion.
The unlink and remove functions force deletion. The rm command is doing extra checks before it calls one of those functions. But once you answer y, it just uses that function to do the real work.
Well, I hope this answers your question.. This program searches the current directory for the filename, you have to add the feature of opening a different directory, which shouldn't be too hard... I don't understand the last line of your question, can you elaborate? But flags aren't necessary for remove and unlink (They force delete)...
#include<stdio.h>
int main()
{
int status;
char file_name[25];
printf("Enter the name of file you wish to delete\n");
fgets(file_name,25,stdin);
status = remove(file_name);
if( status == 0 )
printf("%s file deleted successfully.\n",file_name);
else
{
printf("Unable to delete the file\n");
perror("Error");
}
return 0;
}
To perform a recursive removal, you have to write a moderately complicated program which performs a file system walk. ISO C has no library features for this; it requires platform-specific functions for scanning the directory structure recursively.
On POSIX systems you can use opendir, readdir and closedir to walk individual directories, and use programming language recursion to handle subdirectories. The functions ftw and its newer variant nwft perform an encapsulated file system walk; you just supply a callback function to process the visited paths. nftw is better because it has a flags argument using which you can specify the FTW_DEPTH flag to do the search depth first: visit the contents of a directory before reporting the directory. That, of course, is what you want for recursive deletion.
On MS Windows, there is FindFirstFile and FindNextFile to cob together a recursive traversal.
About -f, that only suppresses certain checks done by the rm program above and beyond what the operating system requires. Without -f, you get prompted if you want to delete a read-only file, but actually, in a Unix-like system, only the directory write permission is relevant, not that of the file, for deletion. The remove library function doesn't have such a check.
By the way, remove is in ISO C, so it is platform-independent. On POSIX systems, it calls rmdir for directories and unlink for other objects. So remove is not only portable, but lets you not worry about what type of thing you're deleting. If a directory is being removed, it has to be empty though. (Not a requirement of the remove function itself, but of mainstream operating systems that support it).
remove or unlink is basically equivalent to rm -f already--that is, it removes the specified item without prompting for further input.
If you want something equivalent to rm -r, you'll need to code up walking through the directory structure and deleting items individually. Boost Filesystem (for one example) has code to let you do that fairly simply while keeping the code reasonably portable.

Get all the functions' names from c/cpp files

For example, there is a C file a.c, there are three functions in this file: funA(), funB() and funC().
I want to get all the function names from this file.
Additionally, I also want to get the start line number and end line number of each function.
Is there any solution?
Can I use clang to implement it?
You can compile the file and use nm http://en.wikipedia.org/wiki/Nm_(Unix) on the generated binary. You can then just parse the output of nm to get the function names.
If you want to get line numbers, you can use the function names to parse the source file for line numbers.
All the this can be accomplished with a short perl script that makes system calls to gcc and nm.
This is assuming you are using a *nix system of course...
One solution that works well for the job is cproto. It will scan source files (in K&R or ANSI-C format) and output the function prototypes. You can process entire directories of source files with a find command similar to:
find "$dirname" -type f -name "*.c" \
-exec /path/to/cproto -s \
-I/path/to/extra/includes '{}' >> "$outputfile" \;
While the cproto project is no longer actively developed, the cproto application continues to work very, very well. It provides function output in a reasonable form that can be fairly easily parsed/formatted as you desire.
Note: this is just one option based on my use. There are many others available.

How do I add an operator to Bash in Linux?

I'd like to add an operator ( e.g. ^> ) to handle prepend instead append (>>). Do I need to modify Bash source or is there an easier way (plugin, etc)?
First of all, you'd need to modify bash sources and quite heavily. Because, above all, your ^> would be really hard to implement.
Note that bash redirection operators usually do a very simple writes, and work on a single file (or program in case of pipes) only. Excluding very specific solutions, you usually can't write to a beginning of a file for the very simple reason you'd need to move all remaining contents forward after each write. You could try doing that but it will be hard, very ineffective (since every write will require re-writing the whole file) and very unsafe (since with any error you will end up with random mix of old and new version).
That said, you are indeed probably better off with a function or any other solution which would use a temporary file, like others suggested.
For completeness, my own implementation of that:
prepend() {
local tmp=$(tempfile)
if cat - "${1}" > "${tmp}"; then
mv "${tmp}" "${1}"
else
rm -f "${tmp}"
# some error reporting
fi
}
Note that you unlike #jpa suggested, you should be writing the concatenated data to a temporary file as that operation can fail and if it does, you don't want to lose your original file. Afterwards, you just replace the old file with new one, or delete the temporary file and handle the failure any way you like.
Synopsis the same as with the other solution:
echo test | prepend file.txt
And a bit modified version to retain permissions and play safe with symlinks (if that is necessary) like >> does:
prepend() {
local tmp=$(tempfile)
if cat - "${1}" > "${tmp}"; then
cat "${tmp}" > "${1}"
rm -f "${tmp}"
else
rm -f "${tmp}"
# some error reporting
fi
}
Just note that this version is actually less safe since if during second cat something else will write to disk and fill it up, you'll end up with incomplete file.
To be honest, I wouldn't personally use it but handle symlinks and resetting permissions externally, if necessary.
^ is a poor choice of character, as it is already used in history substitution.
To add a new redirection type to the shell grammar, start in parse.y. Declare it as a new %token so that it may be used, add it to STRING_INT_ALIST other_token_alist[] so that it may appear in output (such as error messages), update the redirection rule in the parser, and update the lexer to emit this token upon encountering the appropriate characters.
command.h contains enum r_instruction of redirection types, which will need to be extended. There's a giant switch statement in make_redirection in make_cmd.c processing redirection instructions, and the actual redirection is performed by functions throughout redir.c. Scattered throughout the rest of source code are various functions for printing, copying, and destroying pipelines, which may also need to be updated.
That's all! Bash isn't really that complex.
This doesn't discuss how to implement a prepending redirection, which will be difficult as the UNIX file API only provides for appending and overwriting. The only way to prepend to a file is to rewrite it entirely, which (as other answers mention) is significantly more complex than any existing shell redirections.
Might be quite difficult to add an operator, but perhaps a function could be enough?
function prepend { tmp=`tempfile`; cp $1 $tmp; cat - $tmp > $1; rm $tmp; }
Example use:
echo foobar | prepend file.txt
prepends the text "foobar" to file.txt.
I think bash's plugin architecture (loading shared objects via the 'enable' built-in command) is limited to providing additional built-in commands. The redirection operators are part of they syntax for running simple commands, so I think you would need to modify the parser to recognize and handle your new ^> operator.
Most Linux filesystems do not support prepending. In fact, I don't know of any one that has a stable userspace interface for it. So, as stated by others already, you can only rely on overwriting, either just the initial parts, or the entire file, depending on your needs.
You can easily (partially) overwrite initial file contents in Bash, without truncating the file:
exec {fd}<>"$filename"
printf 'New initial contents' >$fd
exec {fd}>&-
Above, $fd is the file descriptor automatically allocated by Bash, and $filename is the name of the target file. Bash opens a new read-write file descriptor to the target file on the first line; this does not truncate the file. The second line overwrites the initial part of the file. The position in the file advances, so you can use multiple commands to overwrite consecutive parts in the file. The third line closes the descriptor; since there is only a limited number available to each process, you want to close them after you no longer need them, or a long-running script might run out.
Please note that > does less than you expected:
Remove the > and the following word from the commandline, remembering the redirection.
When the commandline is processed and the command can be launched, calling fork(2) (or clone(2)), to create a new process.
Modify the new process according to the command. That includes things like modified environment variables (SOMEVAR=foo yourcommand), but also changed filedescriptors. At this point, a > yourfile from the cmdline will have the effect that the file is open(2)'ed at the stdout filedescriptor (that is #1) in write-only mode truncating the file to zero bytes. A >> yourfile would have the effect that the file is oppend at stdout in write-only mode and append mode.
(Only now launch the program, like execv(yourprogram, yourargs)
The redirections could, for a simple example, be implemented like
open(yourfile, O_WRONLY|O_TRUNC);
or
open(yourfile, O_WRONLY|O_APPEND);
respectively.
The program then launched will have the correct environment set up, and can happily write to fd1. From here, the shell is not involved. The real work is not done by the shell, but by the operating system. As Unix doesn't have a prepend mode (and it would be impossible to integrate that feature correctly), everything you could try would end up in a very lousy hack.
Try to re-think your requirements, there's always a simpler way around.

Efficient way to write multiple file content into a single file

There are n-number of files with vary in size. How we could efficently append the content of all the files into a single file?
Techniques or algorithm would help? Basically I am expecting efficent method to achieve this in c language.
Start simple. Multithreading will introduce significant complexity, and won't necessarily make things run any faster. Pseudocode time:
Create a new file "dest" in write-only mode.
For each file "source" you want to append:
Open "source" in read-only mode
For each line "L" in "source":
Write "L" to "dest"
Close "source"
Close "dest"
BTW, this is dead simple (and near-optimal) to implement using simple command-line Linux tools (cat, etc.), though of couse that isn't exactly portable to Windows. One-liner example:
for i in `find . -type f -name "*.txt"`; do cat $i >> result.out; done
(Find every .txt file in the current directory and append it to result.out.)
Go through and find the total size of all of the files.
Then allocate an output file of that size, go through them again and write the data to your output.
Since I don't what the contents of the files are or the purpose of appending them, this solution might not be the best if its just text or something. However, I'd probably find a zip library to use (either licensed or open source), then just zip all the files into a single archive.
zlib looks interesting: http://www.zlib.net/
get the size Sn of each file and calculate the total size T of all the files
create the dest file
use mmap to map the dest file with the size T, you will get a pointer P to the start address of the memmap region
mmap each file to mem, and copy each data to the region above in order.
after that, you would get the dest file with all the data from all the files

How to check whether two file names point to the same physical file

I have a program that accepts two file names as arguments: it reads the first file in order to create the second file. How can I ensure that the program won't overwrite the first file?
Restrictions:
The method must keep working when the file system supports (soft or hard) links
File permissions are fixed and it is only required that the first file is readable and the second file writeable
It should preferably be platform-neutral (although Linux is the primary target)
On linux, open both files, and use fstat to check if st_ino (edit:) and st_dev are the same. open will follow symbolic links. Don't use stat directly, to prevent race conditions.
The best bet is not to use filenames as identities. Instead, when you open the file for reading, lock it, using whatever mechanism your OS supports. When you then also open the file for writing, also lock it - if the lock fails, report an error.
If possible, open the first file read-only, (O_RDONLY) in LINUX. Then, if you try to open it again to write to it, you will get an error.
You can use stat to get the file status, and check if the inode numbers are the same.
Maybe you could use the system() function in order to invoke some shell commands?
In bash, you would simply call:
stat -c %i filename
This displays the inode number of a file. You can compare two files this way and if their inodes are identical, it means they are hard links. The following call:
stat -c %N filename
will display the file's name and if it's a symbolic link, it'll print the file name it links to as well. It prints out only one name, even if the file it points to has hard links, so checking the symbolic link would require comparing inode numbers for the 2nd file and the file the symbolic links links to in order to make sure.
You could redirect stat output to a text file and then parse the file in your program.
If you mean the same inode, in bash, you could do
[ FILE1 -ef FILE2 ] && echo equal || echo difference
Combined with realpath/readlink, that should handle the soft-links as well.

Resources