How can I see if I have reached beginning of file? - c

I have a task to rewrite the Unix system function tail. My algorithm works in the following way:
I lseek to the end of the file, enter a loop, move the file descriptor a bit back, read a couple of bytes, and if I find any new lines, I increase the counter. Once, I get 10 new lines ( I think it should be 11, but the thing is not finished yet and this works for me for now ), I leave the loop.
If the file has less than 10 new lines, I get into an infinite loop, because of the way I wrote it.
Is there a way to see if I have reached the beginning of the file, so I can leave the loop then?
Code :
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main (int argc, char *argv[])
{
int fd;
off_t offset = 10;
size_t size = 10;
unsigned char buff[10];
int new_line_counter = 0;
off_t total_offset = 0;//dont mind this
fd = open("a.txt", O_RDONLY);
if (fd == -1)
{
perror("open");
return 1;
}
lseek(fd,0,SEEK_END);
while (new_line_counter < 10)
{
lseek(fd,-offset,SEEK_CUR);
total_offset+=10;//dont mind this
for(int i = 0; i<10;i++)
{
if(buff[i]=='\n')
{
if(new_line_counter==10)break;
new_line_counter++;
//printf("%d",new_line_counter);
}
}
read(fd,buff,size);
lseek(fd,-offset,SEEK_CUR);
}
}

Use the return value of lseek. It will return the current file position, or, -1 on error.
You first lseek(fd,0,SEEK_END) will give you the file size.
Use that to keep track the current file position (and make sure that to adjust 'offset' so that lseek(fd,-offset,SEEK_CUR); will never seek before file begin.
This is necessary, otherwise you might miss the first line.

lseek() returns a value, it's either the new offset or -1. Check for that value like this:
while (new_line_counter < 10)
{
if (-1==lseek(fd,-offset,SEEK_CUR)) break;

Related

Using feof to read whole file and print result give me double end

I have, I'm trying to read a binary file until end and print the result, I'm using and while with "feof" to read until end of file and printing each result, but I have a problem it is giving me double end result.
I'm still learning C, so I don't know why its giving me double end result, I have tried so many ways, but this was for me the best way and easiest that at least works, but now I'm stuck after 2 hours trying to fix it.
Result:
0
1
2
3
4
5
6
7
8
9
9
Expected:
0
1
2
3
4
5
6
7
8
9
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
// https://www.aprendeaprogramar.com/cursos/verApartado.php?id=16007
struct Datos
{
int cero;
int uno;
int dos;
int tres;
int cuatro;
int cinco;
int seis;
int siete;
int ocho;
int nueve;
};
struct Datos datosEscrito = {0,1,2,3,4,5,6,7,8,9};
FILE *fichero;
fichero = fopen("tabla2.dat", "wb");
fwrite(&datosEscrito, sizeof(datosEscrito), 1, fichero);
fclose(fichero);
int datoLeido;
FILE *fichero2;
fichero2 = fopen("tabla2.dat", "rb");
while (!feof(fichero2))
{
fread(&datoLeido, sizeof(datoLeido), 1, fichero2);
printf("%u", datoLeido);
printf("\n");
}
fclose(fichero2);
}
PD: I don't want the code fix, I want to understand why is giving me double end and an approach to fix the error myself, or another way to do the same. Thanks for the help.
Code edit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fichero;
fichero = fopen("tabla2.dat", "wb");
int count=0;
while (count != 10)
{
fwrite(&count, sizeof(count), 1, fichero);
count++;
}
fclose(fichero);
// PARTE LEER
int datoLeido;
FILE *fichero2;
fichero2 = fopen("tabla2.dat", "rb");
while (!feof(fichero2))
{
fread(&datoLeido, sizeof(datoLeido), 1, fichero2);
printf("%u", datoLeido);
printf("\n");
}
fclose(fichero2);
return 0;
}
The main problems in your program are that feof will only return a nonzero value when the previous fread (or other read operation) has detected an end-of-file condition and that you use the value even when fread would have told you by its return value that it has not read any data.
The functions feof and ferror are intended to distinguish between EOF and error after a failed file operation.
To fix the read loop you can use e.g.
do
{
/* we expect to read 1 member */
if(fread(&datoLeido, sizeof(datoLeido), 1, fichero2) == 1)
{
printf("%u", datoLeido);
printf("\n");
}
} while ((!feof(fichero2)) && !ferror(fichero2));
There are more problems in your code.
The format %u corresponds to a type unsigned int. For int you should use %d.
You write the binary representation of a structure struct Datos to a file, then you read back individual values of type int.
Although this seems to produce the expected result in your case it may not work in other cases. A structure can contain padding bytes that are not part of any structure field. These would have undefined values. In any case writing/reading the binary representation of variables is implementation-dependent. The data format may change when you use a different compiler (new version, different OS, different CPU...) or even with different compiler settings.
I was able to "fix" the problem, but i think it is a dirty fix, but at least works:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fichero;
fichero = fopen("tabla2.dat", "wb");
int count=0;
while (count != 10)
{
fwrite(&count, sizeof(count), 1, fichero);
count++;
}
fclose(fichero);
// PARTE LEER
int datoLeido;
FILE *fichero2;
fichero2 = fopen("tabla2.dat", "rb");
while (!feof(fichero2))
{
fread(&datoLeido, sizeof(datoLeido), 1, fichero2);
if(!feof(fichero2))
{
printf("%d", datoLeido);
printf("\n");
}
}
fclose(fichero2);
return 0;
}
Thanks to all for the help and #David Schwartz gave me the hint after reading that i am not checking if the file end it before print the data

Print the name of the most recently modified file/directory whose name starts with 0-9 in the current directory

I need to write a simple program that prints the name of the most recently modified file whose name starts with 0-9 in the current directory. So far I can get it to print the name of a file that starts with 0-9, but it fails to consistently print the one that was modified most recently. I have been stuck at this part and I am in very desperate need to figure this out. Any help or hints would be of much help! Thank you!
Below is my code:
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
int main(void){
// Open the current directory
DIR* currDir = opendir("./");
struct dirent *aDir;
time_t lastModifTime;
struct stat dirStat;
int first_file_checked = 0;
char directoryName[256];
// Go through all the entries
while((aDir = readdir(currDir)) != NULL){
// only check on directories with a name that starts with 0-9
if (48 <= (int)aDir->d_name[0] && (int)aDir->d_name[0] <= 57) {
// Get meta-data for the current entry
stat(aDir->d_name, &dirStat);
// Use the difftime function to get the time difference between the current value of lastModifTime and the st_mtime value of the directory entry
if(first_file_checked == 0 || difftime(dirStat.st_mtime, lastModifTime) > 0){
lastModifTime = dirStat.st_mtime;
memset(directoryName, '\0', sizeof(directoryName));
strcpy(directoryName, aDir->d_name);
}
first_file_checked = 1;
}
}
// Close the directory
closedir(currDir);
printf("The last file/directory modified in the current directory is %s\n", directoryName);
return 0;
}
Works here:
BTW: you dont check for directories, you need to add a check for d_type to accomplish that.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
int main(void){
// Open the current directory
DIR* currDir ;
struct dirent *aDir;
time_t lastModifTime;
struct stat dirStat;
int count ;
char thename[256] = "";
// Go through all the entries
currDir = opendir("./");
for(count=0; (aDir = readdir(currDir)) ; ){
int rc;
// only check on directories with a name that starts with 0-9
if (aDir->d_name[0] < '0' || aDir->d_name[0] > '9' ) continue;
// Get meta-data for the current entry
rc = stat(aDir->d_name, &dirStat);
if (rc < 0) continue; // check the return value!
if(!count++ || dirStat.st_mtime < lastModifTime ){
lastModifTime = dirStat.st_mtime;
strcpy(thename, aDir->d_name);
}
}
// Close the directory
closedir(currDir);
if (count) {
printf("%d files checked. The last file/directory modified in the current directory is %s(time=%u)\n"
, count, thename, (unsigned) lastModifTime);
}
else {
printf("No files/directories were found\n");
}
return 0;
}

working with directories in POSIX with C

I will go ahead and say this is a homework assignment for an intro to Linux class. I would not be posting it without extensive attempts on my own, and seeing as I am a distance student this semester, I cannot make it to campus for tutoring. I need some help finding out what the issue is.
Essentially the assignment asks us to make a program that serves the same basic function as the pwd command in POSIX, to show the absolute path for the current directory. We are to use three functions along with main. We are not to use the getcwd command as well. I'll list them and their purpose
inum_to_filename: Accepts three arguments (inode number to translate, a pointer to a buffer where the name is written, and the size of the buffer). Returns nothing. It is to:
Open the current directory,
Read the first directory entry,
If the inode of the current directory matches the one passed in, copy name to buffer and return.
Otherwise read the next directory entry and repeat the previous step.
filename_to_inum: Accepts one argument (a char * representing the filename). It returns the corresponding inode number. It is to:
Read the information from the files inode into a structure in memory.
If there is any problem, display the appropriate error.
Return the inode number from the structure.
display_path: Accepts one argument (inode from the current working directory). It returns nothing. It is to:
Create an array of characters to use as a buffer for the name of the directory.
Get the inode for the parent directory using filename_to_inode.
If the parent inode is equal to the current inode, we have reached root and can return.
Otherwise, change to the parent directory and use inum_to_filename to find the name for the inode that was passed into the function. Use the buffer from step 1 to store it.
Recursively call display_path to display the absolute path.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) {
DIR *dir_ptr = opendir(".");
struct dirent *dirent_ptr = readdir(dir_ptr);
int counter = 0;
while (counter != 1) {
if (inode_arg == dirent_ptr->d_ino) {
strcat(pathBuffer, "/");
strcat(pathBuffer, dirent_ptr->d_name);
counter = counter + 1;
return;
} else {
dirent_ptr = readdir(dir_ptr);
}
}
closedir(dir_ptr);
}
int filename_to_inum (char *src) {
int res = 0;
struct stat info;
int result = stat(src, &info);
if (result != 0) {
fprintf(stderr, "Cannot stat ");
perror(src);
exit(EXIT_FAILURE);
} else {
res = info.st_ino;
}
return res;
}
void display_path (int ino_src) {
int bufSize = 4096;
char pathBuffer[bufSize];
int ino_prnt = filename_to_inum("..");
if (ino_src == ino_prnt) {
//print for test
inum_to_filename(ino_src, pathBuffer, bufSize);
printf("%s", pathBuffer);
return;
} else {
//print for test
chdir("..");
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("%s", pathBuffer);
}
}
int main (int argc, char *argv[]) {
int c_ino = filename_to_inum(".");
display_path(c_ino);
printf("\n");
}
As of right now it is displaying "/./MyName" with MyName being my personal named directory on the server. It is the directory I am running the program from. When using pwd I return "/home/MyName". I'm not really sure what my next step to getting the absolute path correct is.
The code is mostly set up to print one name at a time in the correct order, so the primary problem is the use of strcat() rather than strcpy(). Also, detecting when you're in the root directory at the start is important; if you don't, you can end up with /. or something similar (depending on exactly how you coordinate the printing) when the current directory is the root directory.
This version of your code has:
Squished the loop in inum_to_filename(), but also added error reporting. Remember, a process can be run in a directory which it does not have permission to get to (it requires a setuid program, usually — although permissions could be changed after the program is launched). In that case, it may fail to open .. (or .).
Lost variable count; it wasn't serving a useful purpose. Using the assign-and-test idiom allows the code to contain a single call to readdir().
Use strcpy() instead of strcat().
Use type ino_t to store inode numbers. Use size_t for sizes.
Reduce number of intermediate variables in filename_to_inum().
Note that the code in the if (ino_src == ino_prnt) statement body is for the root directory; in the absence of the testing print, it would do nothing.
Note that the printing in the else part is a major part of the operations, not just test printing.
Error check chdir("..");
Detect root in main().
Observe that this code is not directly suitable for rewriting into a function because it changes the process's current directory to / when it succeeds.
Revised code:
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
static void inum_to_filename(ino_t inode_arg, char *pathBuffer, size_t size_arg)
{
assert(size_arg > 0);
DIR *dir_ptr = opendir(".");
if (dir_ptr == 0)
{
fprintf(stderr, "Failed to open directory '.' (%d: %s)\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
struct dirent *dirent_ptr;
while ((dirent_ptr = readdir(dir_ptr)) != 0)
{
if (inode_arg == dirent_ptr->d_ino)
{
if (strlen(dirent_ptr->d_name) >= size_arg)
{
fprintf(stderr, "File name %s too long (%zu vs %zu max)\n",
dirent_ptr->d_name, strlen(dirent_ptr->d_name), size_arg);
exit(EXIT_FAILURE);
}
strcpy(pathBuffer, dirent_ptr->d_name);
break;
}
}
closedir(dir_ptr);
}
static ino_t filename_to_inum(char *src)
{
struct stat info;
if (stat(src, &info) != 0)
{
fprintf(stderr, "Cannot stat ");
perror(src);
exit(EXIT_FAILURE);
}
return info.st_ino;
}
static void display_path(ino_t ino_src)
{
size_t bufSize = 4096;
char pathBuffer[bufSize];
ino_t ino_prnt = filename_to_inum("..");
if (ino_src == ino_prnt)
{
// print for test
inum_to_filename(ino_src, pathBuffer, bufSize);
printf("%s", "(root): /\n");
}
else
{
// print for real
if (chdir("..") != 0)
{
fprintf(stderr, "Failed to chdir to .. (%d: %s)\n",
errno, strerror(errno));
}
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("/%s", pathBuffer);
}
}
int main(void)
{
ino_t c_ino = filename_to_inum(".");
ino_t r_ino = filename_to_inum("/");
if (r_ino == c_ino)
putchar('/');
else
display_path(c_ino);
printf("\n");
}
There are undoubtedly other ways to fix this.
Caveat: this is giving me some grief when working in /Volumes/CRUZER/Sub-Directory which is a memory stick. It fails to find the inode (1, which is surprising) when scanning /Volumes, and I've not worked out why. One of my programs — a getpwd implementation — is working fine; another is having a different problem. I expect I'll get to the bottom of it all. Testing on Mac OS X 10.10.5 with GCC 5.1.0.
this is really nice assignment :).
I read and tried your code, and it is almost correct. There were two small issues which were causing the incorrect behaviour.
First issue
When display_path reaches the root folder you don't need to call inum_to_filename and print the name of the folder because you have already printed the first folder of the path in the previous iteration. This prevents your code from showing a "./" in the beginning of the path.
That is, the if condition becomes:
if (ino_src == ino_prnt) {
return;
} else {
chdir("..");
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("%s", pathBuffer);
}
Second Issue:
You're not initializing propertly the buffer where you save the name of the directory. This causes random values to be displayed. To solve this issue you can just set the initial value of the buffer to zero by using memset.
void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) {
DIR *dir_ptr = opendir(".");
struct dirent *dirent_ptr = readdir(dir_ptr);
int counter = 0;
memset(pathBuffer, 0, size_arg);
while (counter != 1) {
...
}
closedir(dir_ptr);
}
Full code working :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
void inum_to_filename (int inode_arg, char *pathBuffer, int size_arg) {
DIR *dir_ptr = opendir(".");
struct dirent *dirent_ptr = readdir(dir_ptr);
int counter = 0;
memset(pathBuffer, 0, size_arg);
while (counter != 1) {
if (inode_arg == dirent_ptr->d_ino) {
strcat(pathBuffer, "/");
strcat(pathBuffer, dirent_ptr->d_name);
counter = counter + 1;
return;
} else {
dirent_ptr = readdir(dir_ptr);
}
}
closedir(dir_ptr);
}
int filename_to_inum (char *src) {
int res = 0;
struct stat info;
int result = stat(src, &info);
if (result != 0) {
fprintf(stderr, "Cannot stat ");
perror(src);
exit(EXIT_FAILURE);
} else {
res = info.st_ino;
}
return res;
}
/*
- Create an array of characters to use as a buffer for the name of the directory.
- Get the inode for the parent directory using filename_to_inode.
- If the parent inode is equal to the current inode, we have reached root and can return.
- Otherwise, change to the parent directory and use inum_to_filename to find the name for
the inode that was passed into the function. Use the buffer from step 1 to store it.
- Recursively call display_path to display the absolute path.
*/
void display_path (int ino_src) {
int bufSize = 4096;
char pathBuffer[bufSize];
int ino_prnt = filename_to_inum("..");
if (ino_src == ino_prnt) {
return;
} else {
chdir("..");
inum_to_filename(ino_src, pathBuffer, bufSize);
display_path(ino_prnt);
printf("%s", pathBuffer);
}
}
int main (int argc, char *argv[]) {
int c_ino = filename_to_inum(".");
display_path(c_ino);
printf("\n");
}
Output :
ubuntu#ubuntu-VirtualBox:~/dev$ vi pwd.c
ubuntu#ubuntu-VirtualBox:~/dev$ gcc pwd.c
ubuntu#ubuntu-VirtualBox:~/dev$ ./a.out
/home/ubuntu/dev
ubuntu#ubuntu-VirtualBox:~/dev$ pwd
/home/ubuntu/dev
ubuntu#ubuntu-VirtualBox:~/dev$

creating multiple recursive directories in c

I am completing cs50x (the edX (free) version of the Harvard cs50) course and am trying to be a bit tricky/lazy/test myself.
I am trying to use a C program to create all the directories I will need for my psets.
I have looked online and found that <sys/stat.h> includes the mkdir() function and therefore tried creating some nested loops to create all the necessary folders by doing something similar to mkdir {pset1,pset1/{standard,hacker},pset2,pset2{standard... to give me a directory structure like this:
pset1/Standard
pset1/Hacker
pset2/Standard
etc...
I came up with this:
#include <cs50.h>
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, string argv[])
{
for(int i = 1; i <=8; i++)
{
string dir = argv[1];
sprintf(dir,"%s%i", argv[1], i);
mkdir(dir, 0777);
for(int j = 0; j<2; j++)
{
string subDir[] = {"Standard","Hacker"};
sprintf(dir,"%s%i/%s", argv[1], i, subDir[j]);
mkdir(dir, 0777);
}
}
}
However, the program only creates pset1 and completes, there are no subfolders, no pset2 etc.
Yes, you're being lazy since you seem to have very little knowledge of C, yet try to program in it. :)
C is not Python, there is no string interpolation/formatting operator. You have to call a function, specificially snprintf(). Read that manual page.
Also, you can't create a bunch of nested directories with a single call to mkdir(). Read the manual page.
To create nested directories, you're either going to have to build each's absolute path (i.e. each successive time you call mkdir() the path will be longer than the previous time), or actually enter each directory as you create it, and go from there.
To create a full path you can call mkdir() recursivly like this:
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
int mkdirr(const char * path, const mode_t mode, const int fail_on_exist)
{
int result = 0;
char * dir = NULL;
do
{
if (NULL == path)
{
errno = EINVAL;
result = -1;
break;
}
if ((dir = strrchr(path, '/')))
{
*dir = '\0';
result = mkdirr(path, mode, fail_on_exist);
*dir = '/';
if (result)
{
break;
}
}
if (strlen(path))
{
if ((result = mkdir(path, mode)))
{
char s[PATH_MAX];
sprintf(s, "mkdir() failed for '%s'", path);
perror(s);
if ((EEXIST == result) && (0 == fail_on_exist))
{
result = 0;
}
else
{
break;
}
}
}
} while (0);
return result;
}
And then call mkdirr() like this;
int main(void)
{
char p[] = "test/1/2/3";
if (-1 == mkdirr(p, 0777, 0))
{
perror("mkdirr() failed()");
}
return 0;
}

Values of an array changing randomly during execution

I'm trying to make a little programme in C using SDL, displaying a robot moving on a grid. This grid is represented by a txt file of 0s and 1s.
Here is the fonction creating an array from the txt file, which works.
// create a map(array) from a text file
int (*newMap())[SIZE_HEIGHT][SIZE_WIDTH]
{
static const char filename[] = "input.txt"; /* the name of a file to open */
FILE *file = fopen(filename, "r"); /* try to open the file */
int map[SIZE_HEIGHT][SIZE_WIDTH];
char line[BUFSIZ]; /* space to read a line into */
int k = 0;
while ( fgets(line, sizeof line, file)!=NULL && k<SIZE_HEIGHT) /* read each line */
{
int i;
char *token = line; /* point to the beginning of the line */
for ( i = 0; i<SIZE_WIDTH; i++ )
{
map[k][i]=((int)*token)-48;
token+=sizeof(char);
printf("map[%d][%d]=%d\n", (int)k,(int)i,map[k][i]);
}
puts("----\n");
k++;
}
fclose(file);
int (*p)[SIZE_HEIGHT][SIZE_WIDTH];
p=&map;
return p;
}
Then I try to put the grid on the sreen (not the whole fonction):
#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include <time.h>
#include <string.h>
#include "Parameters.h"
#include "simulation.h"
#include "editor.h"
void simulate(SDL_Surface *ecran)
{
SDL_Surface *carreVert = SDL_LoadBMP("carreVert.bmp");
SDL_Surface *carreRouge = SDL_LoadBMP("carreRouge.bmp");
SDL_Surface *robot = SDL_LoadBMP("robotRouge.bmp");
SDL_SetColorKey(robot, SDL_SRCCOLORKEY, SDL_MapRGB(robot->format, 255, 255, 255));
int (*map)[SIZE_HEIGHT][SIZE_WIDTH];
map=newMap();
SDL_Rect positionFond;
int i;
int j;
for(j=0; j<SIZE_HEIGHT; j++)
{
for(i=0; i<SIZE_WIDTH; i++)
{
positionFond.x = 100*i;
positionFond.y = 100*j;
if((*map)[j][i]+1)
{
SDL_BlitSurface(carreVert, NULL, ecran, &positionFond);
}else
{
SDL_BlitSurface(carreRouge, NULL, ecran, &positionFond);
}
}
}
And then something strange happens: when I observe the array *map with the debugger, I see that the values are changing when I go through the test. So the grid does appear, but not with the right pattern. Why does that happen?
Edit:no error an compiler.
Edit: Any guess of what might do that would be gladly accepted.
The array map is local to the function. It ceases to exist when the function finishes. You pass its address to the caller, but when the caller tries to use it ... BANG!
Fast solution: make the array map a static one: make sure you never call newMap more than once per run.
Other solutions:
move the creation of the array outwards and pass the address around
use malloc and friends to manage the array
You are returning a pointer to an object with automatic storage duration (an array that gets "deallocated" on return from the function where it is declared), so you end up seeing random garbage.

Resources