I was going through an example from Maurice Bach's Unix Book. He writes a simple copy program like mentioned below. However it fails when the inputfile is a directory file. I did stumble upon opendir and few other such API's - should I use that?
If a binary file can work with this, why is directory file considered different? In Unix, isn't everything abstracted as a file regardless of the way it is interpreted by the program.
Also how can I extend this program to support directory file and then create a mknod of that? I want to test this, suppose I am in /home/user1 and do a $./copy /home/user user-home-clone and mknod it to see how that directory will be different from home. I guess that the user-home-clone might not have a reference to itself, but all the other files in /home/user [ even though it would a file called user-home-clone would be there in /home/user ] since it was not there when we did the copy command?
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
char buffer[2048];
int copy(FILE *source, FILE *destination)
{
int count;
while ((count = fread(buffer, 1, sizeof buffer , source)) > 0)
{
fwrite(buffer, 1, count, destination);
}
return 0;
}
int main(int argc, char* argv[])
{
int status;
FILE *source;
FILE *destination;
if (argc != 3)
{
printf("%s takes exactly 3 arguments\n", argv[0]);
exit(1);
}
source = fopen(argv[1], "r");
if (source == NULL)
{
printf("%s can't be opened for reading\n", argv[1]);
exit(1);
}
destination = fopen(argv[2], "wb");
if (destination == NULL)
{
printf("%s can't be opened for writing\n", argv[2]);
exit(1);
}
if (copy(source, destination) == 0)
{
status = 0;
}
else
{
status = 1;
}
fclose(source);
fclose(destination);
exit(status);
}
I use Centos 6.5 Linux Ext4 Filesystem
In early versions of Unix, directory files could be read as binary files. However, when network and other types of virtual filesystems were added, this ability was removed, because different filesystems implement directories differently. While it would be technically possible for the driver to emulate a byte stream structure for these directories, it wasn't seen as a useful feature. Directories should be treated as opaque, abstract collections, and accessed using the directory-specific functions.
Related
I don't understand why my script below seems to work without creating any files.
script.c:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]){
printf("P_tmpdir is '%s'\n", P_tmpdir);
FILE *tmp = tmpfile();
if(tmp == NULL){
printf("Unable to create temp file");
exit(1);
}
else{
printf("Temporary file is created\n");
}
for(int i = 0; string[i] != '\0'){
fputc(string[i], tmp);
}
rewind(tmp);
while(!feof(tmp)){
putchar(fgetc(tmp));
}
sleep(3);
return(0);
}
The P_tmpdir variable returns me the "/tmp" directory although in the sleeping time no new file is created in it... can you help me or explain me plz ?
Quoting cppreference.com (emphasis mine):
On some implementations (e.g. Linux), this function actually creates, opens, and immediately deletes the file from the file system: as long as an open file descriptor to a deleted file is held by a program, the file exists, but since it was deleted, its name does not appear in any directory, so that no other process can open it.
The file does not have to be "visible" in the file system tree, as long as a process has a handle on it, the file continues to exist.
If you want a file that's visible in the file system tree you should use mkstemp.
char * read_file(char * filename) {
char * file_contents = malloc(4096 * sizeof(char));
FILE * file;
file = fopen(filename, "r");
fread(file_contents, 4096, sizeof(char), file);
fclose(file);
return file_contents;
}
char * read_flag() {
return read_file("/flag.txt"); // outside of current working directory ;)
}
int main(int argc, char* argv[]) {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
char * flag = read_flag();
char input_filename[40];
//Current directory is /home/problem
printf("Current working directory is: ");
system("pwd");
printf("Enter a filename to print the contents of the file => ");
scanf("%39s", input_filename);
while ((directory_entry = readdir(directory)) != NULL) {
if (strcmp(input_filename, directory_entry->d_name) == 0) {
printf("File contents:\n");
printf("%s\n", read_file(input_filename));
return 0;
}
}
}
I need to open a file that is outside of this directory ("/flag.txt"). I have tried something like "../" in the input to get out from this directory but it is not working. I am not sure how do i enter the filename such that it can retrieve the file that is outside of the /home/problem directory. I am currently using Ubuntu to do this. I think the idea should be using something like %s%d when i enter my input. Is this possible to use any specifier or exploit this program in order to read the entire contents?
You need to pass the full path to your file if it is outside the solution directory either with \\ or one /. On a windows based system this would be for example C:\\folder\\file.txt. I do not use linux currently, but it should be /home/folder/file.txt.
The fopen function can fail, and you should handle that. Read fopen(3), open(2), path_resolution(7), errno(3) to understand the possible failure reasons. Details could be file system and computer specific (and could include hardware failures).
I recommend using perror(3) and exit(3) on failure (don't forget to include both <stdio.h> for perror and <stdlib.h> for exit):
FILE* file = fopen(filename, "r");
if (!file) {
perror(filename);
exit(EXIT_FAILURE);
}
then you'll get a meaningful error message (into stderr) on failure
My guess: your root file system (and root directory / ...) don't have a flag.txt file and you might want to retrieve what your shell understands from ~/flag.txt. Perhaps you want to retrieve it in your home directory (then build its file path, using getenv("HOME") on Linux or Unix; see this).
Read also about globbing, and glob(7).
Read also some Linux programming book, perhaps the old ALP.
Well, I try to play a bit with stack overflow and security cookies,
But its seem that most of the tutorial programs that people with POC tutorial with them are not compile with security cookies.
So i decide to create a program that take input from file and create a buffer overflow.
This is what I come out with:
#include <stdio.h>
#include <string.h>
void manipulate(char *buffer)
{
char newbuffer[80];
strcpy(newbuffer, buffer);
}
int main()
{
char ch, buffer[4096];
char filename[] = "exploit.txt";
int i = 0;
FILE *inFile;
inFile = fopen(filename, "rb");
if (inFile == NULL)
{
fprintf(stderr, "Can't open input file !\n");
getchar();
return 1 ;
}
while (buffer[i] != EOF)
{
buffer[i++] = fgetc(inFile);
manipulate(buffer);
printf("The value of i is : %d\n", i);
getchar();
return 0;
}
}
My problem is that I am always get Can't open input file !\n. even when i created "exploit.txt" in the same location and put some "aaaa" in it.
The basics of opening a file are correct. You can improve your program by using errno and strerror to inform the user of why the attempt to open the file failed.
#include <errno.h>
fprintf(stderr, "Error opening \"%s\": %s\n", filename, strerror(errno));
I was able to successfully run your example program (ignoring the stack overflow portion) with no changes.
The issue is with the value of the current or present working directory which is used as the basis for the completing file path used to open any file.
You can check the program's working directory using either getcwd() from <unixstd.h> for Linux, BSD, and POSIX systems or _getcwd() from <direct.h> for some other type.
Nitpicking: The "txt" file extension is misleading when compared with the fopen opening in binary mode, as specificed by rb.
I've been reading Brian Kernighan and Dennis Ritchie - The C Programming Language and chapter 8.6 is about directory listing under UNIX OS. They say that everything and even directory is a file. This means that I should be able to open directory as a file? I've tried it using stdio functions and it didn't work. Now, I'm trying it with UNIX system functions. Of course, I'm not using UNIX, I'm using Ubuntu linux. Here is my code:
#include <syscall.h>
#include <fcntl.h>
int main(int argn, char* argv[]) {
int fd;
if (argn!=1) fd=open(argv[1],O_RDONLY,0);
else fd=open(".",O_RDONLY,0);
if (fd==-1) return -1;
char buf[1024];
int n;
while ((n=read(fd,buf,1024))>0)
write(1,buf,n);
close (fd);
return 0;
}
This writes nothing even when argn is 1 (no parameters) and I'm trying to read current directory.
Any ideas/explanations? :)
Files are also called regular files to distinguish them from special files.
Directory or not a regular file. The most common special file is the directory. The layout of a directory file is defined by the filesystem used.
So use opendir to open diretory.
Nachiket's answer is correct (as indeed is sujin) but they don't clear up the mystery as to why open works and not read. Out of curiosity I made some changes to the given code to find out exactly what was going on.
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char* argv[]) {
int fd = -1;
if (argc!=1) fd=open(argv[1],O_RDONLY,0);
else fd=open(".",O_RDONLY,0);
if (fd < 0){
perror("file open");
printf("error on open = %d", errno);
return -1;
}
printf("file descriptor is %d\n", fd);
char buf[1024];
int n;
if ((n=read(fd,buf,1024))>0){
write(1,buf,n);
}
else {
printf("n = %d\n", n);
if (n < 0) {
printf("read failure %d\n", errno);
perror("cannot read");
}
}
close (fd);
return 0;
}
The result of compiling and running this:
file descriptor is 3
n = -1
read failure 21
cannot read: Is a directory
That settles it, though I'd have expected open to fail, since the correct system function for opening directories is opendir().
Though everything in unix is a file (directory also) but still filetype is concept is present in unix and applicable to all files.
there are file types like regular file,directory etc and certain operations and functions are allowed/present for every file type.
In your case readdir is applicable for reading contents of directory.
If you want to see the files in a directory you have to use the opendir and readdir functions.
K&R were correct for the original UNIX. I remember doing it back when UNIX file systems had a 14 character length limit for filenames. The opendir(), readdir(), ... stuff happened about the time that longer file names became common (around 1990?)
I'm not sure if C can do this, but I'm hoping that I can make a program that will look into a directory, and print out all of the contents of the directory along with the file size of each file. As in I wanted it to look like this (possibly):
filename.txt -- 300 bytes
filename2.txt -- 400 bytes
filename3.txt -- 500 bytes
And so on.
So far, I created a program that can open a file, and it will print the bytes, but it does not read the entire directory, and I have to be specific with which file I want to read.. (which is not what I want).
Here is what I have so far:
#include <stdio.h>
int main(){
FILE *fp; // file pointer
long fileSize;
int size;
// opens specified file and reads
fp = fopen( "importantcommands.txt", "rw" );
if( fp == NULL ){
printf( "Opening file error\n" );
return 0;
}
// uses fileLength function and prints here
size = fileLength(fp);
printf( "\n Size of file: %d bytes", size );
fclose(fp);
return 0;
}
int fileLength( FILE *f ){
int pos;
int end;
// seeks the beginning of the file to the end and counts
// it and returns into variable end
pos = ftell(f);
fseek (f, 0, SEEK_END);
end = ftell(f);
fseek (f, pos, SEEK_SET);
return end;
}
Please help.
C can certainly do it - the ls(1) command can, for example, and it's written in C.
To iterate over a directory, you can use the opendir(3) and readdir(3) functions. It's probably easier to just let the shell do it for you, though.
As far as getting the filename, you can just take it as a command line parameter by defining main as:
int main(int argc, char **argv)
Command line parameters will begin at argv[1].
See opendir() / fdopendir() and readdir() if you are using linux in dirent.h
man page
Simple example from a : SO Post
DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\\src\\")) != NULL) {
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL) {
printf ("%s\n", ent->d_name);
}
closedir (dir);
}
else {
/* could not open directory */
perror ("Could not open directory");
return EXIT_FAILURE;
}
Also You can use the fstat() system call which can fill in the struct stat for any file you want. From that stat you can access that file's size.
Please use the man pages to help you out. (Almost) Everything related to Linux is insanely well documented.
To read a list of files in a directory look at opendir, readdir, closedir for Linux
use stat to get the length of the file.
These are of Linux
For winodws see http://msdn.microsoft.com/en-gb/library/windows/desktop/aa365200%28v=vs.85%29.asp and the link http://blog.kowalczyk.info/article/8f/Get-file-size-under-windows.html will show you how to do this.
To get the list of files in a directory look for "libc opendir". To get the size of a file without opening it you can use fstat.
This seems strangely similar to another question I saw recently. Anyway, here's my strangely similar answer (for Linux, not sure how it'll fare on Windows 7):
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
int main(int argc, char *argv[]) {
struct stat file_stats;
DIR *dirp;
struct dirent* dent;
dirp=opendir("."); // specify directory here: "." is the "current directory"
do {
dent = readdir(dirp);
if (dent)
{
printf("%s -- ", dent->d_name);
if (!stat(dent->d_name, &file_stats))
{
printf("%u bytes\n", (unsigned int)file_stats.st_size);
}
else
{
printf("(stat() failed for this file)\n");
}
}
} while (dent);
closedir(dirp);
}
There are little things need to be taken care for the given examples (under Linux or other UNIX).
You properly only want to print out the file name and size of a regular file only. Use S_ISREG() to test the st_mode field
If you want to recursively print out all files under sub directories also, you then need to use S_ISDIR() to test for direcotry and be carefull of special directory '.' and '..'.