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)
Related
#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.
So I'm using mmap to then write to another file. But the weird thing is, when my code hits mmap, what it does is clears the file. So I have a file that's populated with random characters (AB, HAA, JAK, etc...). What it's supposed to do is use mmap as read basically and then write that file to the new file. So that first if (argc == 3) is the normal read and write, the second if (argc ==4) is supposed to use mmap. Does anyone have any idea why on Earth this is happening?
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/io.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/resource.h>
int main(int argc, char const *argv[])
{
int nbyte = 512;
char buffer[nbyte];
unsigned char *f;
int bytesRead = 0;
int size;
int totalBuffer;
struct stat s;
const char * file_name = argv[1];
int fd = open (argv[1], O_RDONLY);
int i = 0;
char c;
int fileInput = open(argv[1], O_RDONLY);
int fileOutPut = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
fstat(fileInput, &s);
size = s.st_size;
printf("%d\n", size);
if (argc == 3)
{
printf("size: %d\n", size);
printf("nbyte: %d\n", nbyte);
while (size - bytesRead >= nbyte)
{
read(fileInput, buffer, nbyte);
bytesRead += nbyte;
write(fileOutPut, buffer, nbyte);
}
read(fileInput, buffer, size - bytesRead);
write(fileOutPut, buffer, size - bytesRead);
}
else if (argc == 4)
{
int i = 0;
printf("4 arg\n");
f = (char *) mmap (0, size, PROT_READ, MAP_PRIVATE, fileInput, 0);
/* This is where it is being wipped */
}
close(fileInput);
close(fileOutPut);
int who = RUSAGE_SELF;
struct rusage usage;
int ret;
/* Get the status of the file and print some. Easy to do what "ls" does with fstat system call... */
int status = fstat (fd, & s);
printf("File Size: %d bytes\n",s.st_size);
printf("Number of Links: %d\n",s.st_nlink);
return 0;
}
EDIT: I wanted to mention that the first read and write works perfectly, it is only when you try to do it through the mmap.
If you mean it's clearing your destination file, then yes, that's exactly what your code will do.
It opens the destination with truncation and then, in your argc==4 section, you map the input file but do absolutely nothing to transfer the data to the output file.
You'll need a while loop of some description, similar to the one in the argc==3 case, but which writes the bytes in mapped memory to the fileOutput descriptor.
I want to make the syscall using filp_open!!
purpose is file copy!!
but a problem is that i can't find end of file.
opersting system is redhat9 and kernel version is 2.6.32!!
i want to help to me plz!!!!
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#define BUF_SIZE 4096
asmlinkage int sys_forensiccopy(char *src, char *dst)
{
struct file *input_fd;
struct file *output_fd;
size_t ret_in, ret_out; /* Number of bytes returned by read() and write() */
char buffer[BUF_SIZE]={0,}; /* Character buffer */
int ret;
int i;
mm_segment_t old_fs;
/* Create input file descriptor */
input_fd = filp_open(src, O_RDONLY, 0);
if (input_fd == -1) {
printk ("[!] Can not open the src file");
return 2;
}
/* Create output file descriptor */
output_fd = filp_open(dst, O_WRONLY|O_CREAT, 0644);
if(output_fd == -1){
printk("[!] Can't crate the dstfile");
return 3;
}
old_fs=get_fs();
set_fs(get_ds());
printk("%d\n", input_fd->f_op->read(input_fd,buffer,BUF_SIZE,&input_fd->f_pos));
set_fs(old_fs);
/* Close file descriptors */
filp_close(input_fd,0);
filp_close(output_fd,0);
return 0;
}
I am trying to write a very simple echo Linux driver.
The driver takes a maximum of 250 characters from command-line and just writes it into a dummy device 'mydev'. This is again read back from the device. The front end and driver code is pasted below for reference.
The issue is I am able to write but not read. There is no error on compilation or segmentation fault. But none of the messages in printk in the driver's read are printed. I am puzzled as to what is happening. Can I get some clue here?
I am just sharing the code copy for better clarity:
mydriver.c :
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
MODULE_LICENSE("GPL");
static int major;
static char kbuf[250];
static int dv_open(struct inode *inode, struct file *filp)
{
return 0;
}
static int dv_close(struct inode *inode, struct file *filp)
{
return 0;
}
static ssize_t dv_read(struct file *filp, char __user *buf,
size_t sz, loff_t *fpos)
{
int r;
int L;
printk("READ:Entering\n");
L = strlen(kbuf);
r = copy_to_user(buf, kbuf, L);
printk("READ:Ends\n");
return L;
}
static ssize_t dv_write(struct file *filp, const char __user *buf,
size_t sz, loff_t *fpos)
{
int r, wr_sz;
printk("WRITE:Entering\n");
memset(kbuf,'\0', 250);
if ( sz <= 250 ) {
wr_sz = sz;
} else {
wr_sz = 250;
}
r = copy_from_user(kbuf, buf, wr_sz);
printk("WRITE:Rx buf = %s\n", kbuf);
return 0;
}
static struct file_operations dv_fops = {
.open = dv_open,
.release = dv_close,
.read = dv_read,
.write = dv_write,
.owner = THIS_MODULE,
};
int init_module(void)
{
major = register_chrdev(0, "dvdev", &dv_fops);
if ( major < 0 ) {
printk("Error in registering driver\n");
return -1;
}
else printk("Success. major = %d\n", major);
return 0;
}
void cleanup_module(void)
{
unregister_chrdev(major, "dvdev");
}
myuserapp.c
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
static char buf[250];
static char * wbuf;
int main(int argc, char **argv)
{
int fd;
int option;
int nbr = 0, len;
if ( argc != 2 ) {
printf("usage: front <devName>\n");
return -1;
}
fd = open("mydev", O_RDONLY | O_WRONLY);
if ( fd < 0 ) {
printf("Error opening file. %s does not exist\n", argv[1]);
return -2;
}
wbuf = argv[1];
len = strlen(wbuf);
nbr = write(fd, wbuf, len);
printf("USR: Buf written = %s, nbr = %d\n", wbuf ,nbr);
nbr = read(fd, buf, 250);
printf("USR RD: %s", buf);
close(fd);
return 0;
}
Your code has at least one error:
fd = open("mydev", O_RDONLY | O_WRONLY);
That is an improper open() call.
The man page for open() specifies that:
Applications shall specify exactly one of the first three values (file access modes) below in the value of oflag:
O_RDONLY Open for reading only.
O_WRONLY Open for writing only.
O_RDWR Open for reading and writing. The result is undefined if this flag is applied to a FIFO.
Instead of specifying only one, you have an expression of two values.
I guess O_RDONLY and O_WRONLY are bits individually, so it would be something like O_RDONLY | O_WRONLY = 10|01 = 11 . Both the bits of Read and write are set.
The bit values are irrelevant, since combining these values is not allowed.
You seem to be ignoring the exclusionary suffix "ONLY".
RDONLY means "allow read and disallow write".
WRONLY means "allow write and disallow read".
"O_RDONLY | O_WRONLY" is a logical contradiction.
If you want to allow both reading and writing, then you have to specify O_RDWR.
And Mark Stevens has provided the correct values and Boolean arithmetic to prove that your inproper expression is not equivalent to O_RDWR.
sawdust gave the right answer, but there's another problem in your code.
If you write 250 bytes to your device, the buffer is not null-terminated. Then, when reading, strlen will read beyond it, leading to an unexpected result.
Each calls to your write function will result in calling memset on the buffer.This is the root cause you are not able to retrieve the message.
i m trying to modify fuse example to mount any directory. I want to mount /home/nikhil in tmp.
i ran it as,
$ ./ni /home/nikhil tmp
It mounts tmp folder, but cannot access it.
$ls -ltr tmp
ls: cannot access tmp: Operation not permitted
$ ls -ltr
ls: cannot access delete: Operation not permitted
total 11716
d????????? ? ? ? ? ? delete
My code is
#define FUSE_USE_VERSION 26
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <limits.h>
#include <unistd.h>
#define MAX 100
char *rootpath;
static void ni_fullpath(char fpath[MAX], const char *path){
strcpy(fpath, rootpath);
strncat(fpath, path, MAX);
}
static int ni_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
char fpath[MAX];
memset(stbuf, 0, sizeof(struct stat));
ni_fullpath(fpath, path);
res = lstat(fpath, stbuf);
return res;
}
static int ni_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
(void) offset;
(void) fi;
// i didnt understand this
filler(buf, ".", NULL, 0);
filler(buf, "..", NULL, 0);
ni_fullpath(fpath, path);
filler(buf, fpath + 1, NULL, 0);
return 0;
}
static int ni_open(const char *path, struct fuse_file_info *fi)
{
int fd;
char fpath[MAX];
ni_fullpath(fpath, path);
if ((fi->flags & 3) != O_RDONLY)
return -EACCES;
fd = open(fpath, fi->flags);
return fd;
}
static int ni_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *fi)
{
return pread(fi->fh, buf, size, offset);
}
static struct fuse_operations ni_oper = {
.getattr = ni_getattr,
.readdir = ni_readdir,
.open = ni_open,
.read = ni_read,
};
void ni_usage(){
fprintf(stderr, "usage ni rootDir mountPoint");
abort();
}
int main(int argc, char *argv[])
{
printf("%s %s \n", argv[1], argv[2]);
rootpath = realpath(argv[1], NULL);
argv[1] = argv[2];
argc--;
return fuse_main(argc, argv, &ni_oper, NULL);
}
Can anybody help what i m doing wrong ?
I m using ubuntu 1104 64 bit.
How about using uninitialized var fpath instead of path?
static int ni_getattr(const char *path, struct stat *stbuf)
{
int res = 0;
char fpath[MAX];
memset(stbuf, 0, sizeof(struct stat));
res = lstat(fpath, stbuf);
return res;
}
You probably missed ni_fullpath(fpath, path);
And as far as I understand the 0 should be returned in open callback if success, so it should look like:
....
fd = open(fpath, fi->flags);
if (fd < 0)
return -errno;
fi->fh = fd;
return 0;
}
List operation should uses readdir callback, and in your case it has very limited application. It'd be better to start code on the basis of fusexmp. Check how readdir is implemented there.