C Low Level File I/O O_APPEND flag not working - c

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
void cp(char* src, char* dest)
{
int infile, outfile;
const int BUFF_SIZE = 65536;
struct stat instats, outstats;
long bytes;
char *buff;
/* Open source and destination files */
if ((infile = open(src, O_RDONLY)) == -1) exit(1);
if ((outfile = open(dest, O_WRONLY | O_APPEND | O_CREAT)) == -1) exit(1);
/* Calculate optimal buffer size */
//fstat(infile, &instats);
//fstat(outfile, &outstats);
//optimal = LCM(instats.st_blksize, outfile.st_blksize);
//buff_size = MIN(optimal, 65536);
buff = (char*)malloc(sizeof(char) * BUFF_SIZE);
/* Copy file */
while((bytes = read(infile, buff, BUFF_SIZE)) > 0)
write(outfile, buff, bytes);
close(infile);
close(outfile);
free(buff);
}
int main()
{
DIR* dirp;
dirp = opendir(".");
if(dirp == NULL) exit(1);
else
{
struct dirent* dentry;
dentry = readdir(dirp);
while(dentry != NULL)
{
struct stat fst;
int statr = stat(dentry->d_name, &fst);
char* src = (char*)malloc(sizeof(char) * (2 + 1024));
src = strcpy(src, "./");
src = strcat(src, dentry->d_name);
//printf("%s", src);
if(!statr)
{
if(S_ISREG(fst.st_mode))
{
printf("NAME: %s\n", src);
cp(src, "archive");
}
}
dentry = readdir(dirp);
free(src);
}
}
return 0;
}
This is my current code. I want to take all regular files in the working directory and append their contents to a file called "archive" so that they may be recreated from the archive file. I don't quite know what is going wrong as I am opening the archive file with O_APPEND flag and the data I'm attempting to write is not appending to the file.

Related

how to open file within while loop that is dependant on information not yet declared?

I am attempting to open a file that will only be known once it has been created within a directory, however the FILE *infile (etc, etc..) function does not work in this scenario as "infile" has not previously been delcared. I can't work out how to declare this before the loop so that it gets the current file that is being iterated at that time.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/inotify.h>
#include <openssl/sha.h>
int main (int argc, char *argv[])
{
int result;
int fd;
int wd;
unsigned char c[SHA512_DIGEST_LENGTH];
int i;
//FILE *inFile = fopen (filename, "rb"); //I'm aware this would usually
//be declared here
SHA512_CTX mdContext;
int bytes;
unsigned char data[1024];
const int event_size = sizeof(struct inotify_event);
const int buf_len = 1024 * (event_size + FILENAME_MAX);
fd = inotify_init();
if (fd < 0) {
perror("inotify_init");
}
wd = inotify_add_watch(fd, "/home/joe/Documents", IN_CREATE);
while (1) {
char buff[buf_len];
char target[FILENAME_MAX];
int no_of_events, count = 0;
no_of_events = read (fd, buff, buf_len);
while (count < no_of_events) {
struct inotify_event *event = (struct inotify_event *)&buff[count];
if (event->len) {
if (event->mask & IN_CREATE)
if(!(event->mask & IN_ISDIR)) {
printf("The file %s has been created\n", event->name);
//FILE *infile = fopen (filename, "rb"); //issue arises here
//when not commented
SHA512_Init (&mdContext);
while ((bytes = fread (data, 1, 1024, filename)) != 0)
SHA512_Update (&mdContext, data, bytes);
SHA512_Final (c,&mdContext);
for(i = 0; i < SHA512_DIGEST_LENGTH; i++) printf("%02x", c[i]);
printf (" %s\n", event->name);
fclose (filename);
return 0;
fflush(stdout);
}
}
count += event_size + event->len;
}
}
return 0;
}
I'm trying to work out the issue hence the comments and also undeclared "filename".
The name of the file that you want to open is stored in event->name. That's what you want to pass to fopen. Also, you want to pass infile to both fread and fclose.
FILE *infile = fopen (event->name, "rb"); // event->name is the filename
SHA512_Init (&mdContext);
while ((bytes = fread (data, 1, 1024, infile )) != 0) // read from infile
SHA512_Update (&mdContext, data, bytes);
SHA512_Final (c,&mdContext);
for(i = 0; i < SHA512_DIGEST_LENGTH; i++) printf("%02x", c[i]);
printf (" %s\n", event->name);
fclose (infile); // close infile

Reading and writing pdf or binary data in C

I'm implementing ftp and I want to upload and download files, when I download or upload pdf files they are corrupted. How can handle reading any file, using read() and write() or mmap? below is my simplified code of what I have tried.
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int is_regular_file(const char *path)
{
struct stat path_stat;
stat(path, &path_stat);
return (S_ISREG(path_stat.st_mode));
}
int ft_get_file_size(const char *filename)
{
struct stat file;
int fd;
if (!is_regular_file(filename))
return (-1);
fd = open(filename, O_RDONLY);
memset(&file, 0, sizeof(struct stat));
fstat(fd, &file);
close(fd);
return (file.st_size);
}
char *read_file(const char *filename)
{
char *content;
int file_size;
int fd;
ssize_t retval;
if ((file_size = ft_get_file_size(filename)) <= 0)
return (NULL);
content = (char *)malloc(sizeof(char) * file_size + 1);
fd = open(filename, O_RDONLY);
retval = read(fd, content, file_size);
content[retval + 1] = '\0';
close(fd);
return (content);
}
void write_file(char *file, char *content)
{
int fd;
fd = open(file, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
if (fd)
write(fd, content, strlen(content));
close(fd);
}
int main() {
char *test = read_file("ftp.en.pdf");
write_file("copy.pdf", test);
return EXIT_SUCCESS;
}
The process of downloading and uploading the file, is reading all the data from the file and then send that data to the socket. I have tried using mmap and I still get corrupted file.
Document is damaged error message
As binary data can have \0 characters, you cannot treat your content as a string, so strlen(content) is wrong. You must return the size of the content from your read_file function.
For example, define your function as char *read_file(const char *filename, int *size) and return the size in *size. Likewise define your write function as void write_file(char *file, char *content, int size)
(and forget the +1 in malloc)

NULL memories entry

I wrote this little program that reads a file in binary form (Databases.db in this example) and copies its content in the cpydatabases.db...
When I run the debugger in the fopen_s(&source, "Databases.db", "r");, the source is always NULL (while debugging it shows that the memory entry is always Null, 0x000000000000 <NULL>).
This program runs in visual studio 2015.
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include "dirent.h"
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#define BUFFSIZE 2048
char ch, *readbuf;
int nread, nwrit;
FILE *source, *target;
int main()
{
int returnv;
fopen_s(&source, "Databases.db", "r");
if ( source !== NULL)
{
fclose(source);
return (EXIT_FAILURE);
}
fopen_s(&target,"cpydatabases.db", "w");
//check again
if (target == NULL)
{
fclose(target);
return(EXIT_FAILURE);
}
//setting the char that reads the binary
readbuf = (char *)malloc(BUFFSIZE* sizeof(char));
if (readbuf == NULL)
{
fclose(source);
fclose(target);
return(EXIT_FAILURE);
}
while (1)
{
nread = fread((void *)readbuf, sizeof(char), BUFFSIZE, source) ;
// fwrite((void *)readbuf, sizeof(char), nread, target);
nwrit = fwrite((void *)readbuf, sizeof(char), nread, target);
if (nwrit < nread)
{
returnv = (EXIT_FAILURE);
}
if (nread <= BUFFSIZE)
{
returnv = (EXIT_SUCCESS);
break;
}
}
fclose(source);
fclose(target);
return 0;
}
This worked for me. You should have your Databases.db file in the same folder as your source.cpp file, or use an absolute path like "C:/Databases". Anyway this code worked for me:
#define BUFFSIZE 2048
char ch, source_file[50], target_file[50], *readbuf;
int nread, nwrit;
FILE *source, *target;
int main()
{
int returnv;
fopen_s(&source, "Databases.db", "r");
if (source == NULL)
{
//fclose(source);
return (EXIT_FAILURE);
}
fopen_s(&target, "cpydatabases.db", "w");
//check again
if (target == NULL)
{
fclose(target);
return(EXIT_FAILURE);
}
I think "Databases.db" is in not in same directory where executable is.
You can give complete path of "Databases.db" or copy this file where your .sln file is.

Recursive listing of directories and files C

My C code for recursively listing directories and files get executed multiple times. I am not sure how to fix it and why it keeps happening... It is not infinite its just like 10 times shows the current directory.
void printdir(char *dir, int depth)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
int spaces = depth;
dp = opendir(dir);
while((entry = readdir(dp))) {
lstat(entry->d_name,&statbuf);
if(S_ISDIR(statbuf.st_mode)) {
/* Found a directory, but ignore . and .. */
if(strcmp(".",entry->d_name) == 0 ||
strcmp("..",entry->d_name) == 0)
continue;
printf("%*s%s/\n",spaces,"",entry->d_name);
/* Recurse at a new indent level */
printdir(entry->d_name,depth+1);
}
else printf("%*s%s\n",spaces,"",entry->d_name);
}
closedir(dp);
}
int print_file(char *file, char *dir, struct stat buf, int showinode, int showlong, int showRec)
{
if (showinode)
printf("%lld ", buf.st_ino);
if (showlong)
print_long(file, dir, buf);
if (showRec)
printdir(dir, 0);
else
printf("%s\n", file);
return 0;
}
Here's a recursive function that lists the directories it comes across, using openat(), fdopendir(), fstatat() to avoid string-operations on paths (and, possibly, race-conditions on the directory-tree):
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int sanerecursivedirsearch(int dirfd)
{
DIR *curdir = fdopendir(dirfd);
if (!curdir)
{
perror("fdopendir()");
close(dirfd);
return -1;
}
struct dirent *direp;
while (!!(direp = readdir(curdir)))
{
if (!strcmp(direp->d_name, "..") || !strcmp(direp->d_name, "."))
continue;
struct stat statbuf;
fstatat(dirfd, direp->d_name, &statbuf, 0);
if (S_ISDIR(statbuf.st_mode))
{
int newfd = openat(dirfd, direp->d_name,
O_RDONLY | O_DIRECTORY);
if (newfd == -1)
{
perror("openat()");
continue;
}
printf("directory found:\t%s\n", direp->d_name);
sanerecursivedirsearch(newfd);
}
}
closedir(curdir);
return 0;
}
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf(stderr, "insufficient command-line arguments");
exit(EXIT_FAILURE);
}
int fd = openat(AT_FDCWD, argv[1],
O_RDONLY | O_DIRECTORY);
if (fd == -1)
{
perror("openat()");
exit(EXIT_FAILURE);
}
sanerecursivedirsearch(fd);
return 0;
}

Print the names of all files in the current directory - c

I need to print the names of all files in the current directory.
but I must do it only with system calls, so I have the SYS_OPEN, SYS_GETDENTS, SYS_READ etc. I'm working on Ubuntu.
How can I do it?
I tried to use this:
system_call(SYS_OPEN, ".", 0, 0777);
and then to READ from and write to STDOUT.. but it's not working.
** I cannot use the standard library.
Thank you!
EDIT:
an example code:
** there is a file in assembly, with the function "system call" that do the call.
#include "util.h"
#define SYS_WRITE 4
#define SYS_OPEN 5
#define SYS_CLOSE 6
#define SYS_READ 3
#define SYS_LSEEK 19
#define SYS_GETDENTS 141
#define BUF_SIZE 1024
#define STDOUT 1
struct linux_dirent {
long d_ino;
int d_off;
unsigned short d_reclen;
char d_name[];
};
int main (int argc , char* argv[], char* envp[])
{
int fd=0;
int nread;
char * nread_str;
char buf[BUF_SIZE];
struct linux_dirent *d;
int bpos;
char d_type;
fd=system_call(SYS_OPEN,".", 0 , 0);
for ( ; ; ) {
nread = system_call(SYS_GETDENTS, fd, buf, BUF_SIZE);
if (nread == -1)
system_call(SYS_WRITE,STDOUT, "error-getdents",BUF_SIZE);
if (nread == 0)
break;
system_call(SYS_WRITE,STDOUT, "--------------- nread=%d ---------------\n",100);
nread_str=itoa(nread);
system_call(SYS_WRITE,STDOUT, nread_str,100);
system_call(SYS_WRITE,STDOUT, "i-node# file type d_reclen d_off d_name\n",100);
for (bpos = 0; bpos < nread;) {
d = (struct linux_dirent *) (buf + bpos);
/* printf("%8ld ", d->d_ino);**/
d_type = *(buf + bpos + d->d_reclen - 1);
/* printf("%4d %10lld %s\n", d->d_reclen,
(long long) d->d_off, (char *) d->d_name);**/
bpos += d->d_reclen;
}
}
}
return 0;
}
#include <fstream>
#include <iostream>
#include <string>
#include <dirent.h>
using namespace std;
int main()
{
DIR *dir;
struct dirent *ent;
if ((dir = opendir ("c:\\")) != 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 ("");
return EXIT_FAILURE;}
}
Read the manual pages for opendir etc.
See http://linux.die.net/man/3/opendir

Resources