I wrote a toy program to learn file I/O in C, the following is part of my code, and the output from this program is just wrong - I've no idea what is wrong in my code.
int fd = open(path_to_file, O_RDWR | O_APPEND | O_CREAT, 0777);
int size = 100;
int offset = 0;
write(fd, &size, sizeof(int));
write(fd, &offset, sizeof(int));
lseek(fd, 0, SEEK_SET); /* start reading from the beginning */
int *size = malloc(sizeof(int));
int *offset = malloc(sizeof(int));
read(fd, size, sizeof(int));
read(fd, offset, sizeof(int));
printf("size is %d, offset is %d \n", *size, *offset);
free(size);
free(offset);
The output I got is:
size is 1953719668, offset is 1684497779
These numbers are so huge, but they should be 100, and 0, respectively. I don't understand how this happens. Could someone offer help with understanding this?
Ingo has it right, if the file already exists you append to it...
Mallocing for 1 single int is not very efficient, but that should work.
I guess you copied and pasted your code, the same names on variables prevent it from compiling.
Working example even if the file exists:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
int fd = open("test.dat", O_RDWR | O_CREAT, 0777);
int size = 100;
int offset = 0;
write(fd, &size, sizeof(int));
write(fd, &offset, sizeof(int));
lseek(fd, 0, SEEK_SET); /* start reading from the beginning */
int *result_size = malloc(sizeof(int));
int *result_offset = malloc(sizeof(int));
read(fd, result_size, sizeof(int));
read(fd, result_offset, sizeof(int));
printf("size is %d, offset is %d \n", *result_size, *result_offset);
free(result_size);
free(result_offset);
}
Related
I have the following program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(int argc, char* argv[]) {
int fd;
char buffer[100];
// open notes file
fd = open("/var/testfile", O_RDONLY);
if(fd == -1) {
error("in main() while opening file for reading");
}
int readBytes = 0;
// read 10 bytes the first time
readBytes = read(fd, buffer, 10);
buffer[10] = 0;
printf("before lseek: %s\n readBytes: %d\n", buffer, readBytes);
// reset buffer
int i = 0;
for(i = 0; i < 10; i++) {
buffer[i] = 0;
}
// go back 10 bytes
lseek(fd, -10, SEEK_CUR);
// read bytes second time
readBytes = read(fd, buffer, 10);
buffer[10] = 0;
printf("after lseek: %s\n readBytes: %d\n", buffer, readBytes);
}
And the following content in the /var/testfile:
This is a test.
A second test line.
The output of the program:
before lseek: This is a
readBytes: 10
after lseek:
readBytes: 0
I don't unerstand why after the lseek() call the read() function does not read any bytes. What is the reason for this? I would expect the same result as I get from the first read() function call.
My compiler says "xxc.c:33:5: warning: implicit declaration of function ‘lseek’ [-Wimplicit-function-declaration]"
This means that the second argument will be assumed to be an integer (probably 32bits), but the definition is actually for the type "off_t" which on Linux or Windows will be a longer 64bit integer.
This means the offset you're giving it is likely to be VERY large and well past the end of your testfile.
The manual says that for lseek() you need the headers:
#include <sys/types.h>
#include <unistd.h>
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.
When I use mmap and memcpy to write a file, and then I use fread to read the data.
Below is my code, The problem is the first time i can read the a, but the second time i can't read a.
I guess there is something like seek position in fread function, when I use memcpy to write file, It may change the seek position.
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
int main()
{
int fd = open("./aa", O_CREAT | O_RDWR | O_TRUNC, 0644);
FILE* f = fopen("./aa", "r");
if (ftruncate(fd, 1024) < 0) {
printf("ftruncate error\n");
}
void* base;
if ((base = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
printf("mmap error\n");
}
char* file_ptr = (char *)base;
char buffer[256];
char scratch[256];
buffer[0] = 'a';
memcpy(file_ptr, buffer, 1);
file_ptr += 1;
size_t n = fread(scratch, 1, 1, f);
printf("size n %zu\n", n); // this output size n 1
printf("scratch %c\n", scratch[0]); // this output scratch a
memcpy(file_ptr, buffer, 1);
file_ptr += 1;
n = fread(scratch, 1, 1, f);
printf("size n %zu\n", n); // this output size n 1
printf("scratch %c\n", scratch[0]); // but this output scratch
return 0;
}
The output is :
size n 1
scratch a
size n 1
scratch
First of all, #wildplasser is right, your program may work, but if you go on mixing mmap and stdio you'll need to make sure that writes done via mmap get committed (use the msync() function) and that fread isn't buffering stale data (fseek()ing to the current position should do the trick).
Coming to your question: your program doesn't print "scratch", it prints "scratch \0" :)
Seriously, what you do is initialize the size of the "aa" file via ftruncate(), which is the same as filling the missing bytes up to 1024 '\0'; you write an 'a', and read it; then you read another character, and you get one of the NULs.
Try printing the ascii character of scratch[0] and you'll see it's zero; if you're still not convinced, try adding something like
for(i = 0; i < 6; i++)
file_ptr[i] = "QWERTY"[i];
right before the first memcpy and see what happens.
code:
#include <fcntl.h>
#include <linux/fs.h>
#include <stdio.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
void write_zero(char * file, unsigned long bytes)
{
printf("Zeroing %s\n", file);
unsigned int wrote = 0, total = 0;
int fd, i, buf;
char obj = 0x00;
fd = open(file, O_RDWR, DEFFILEMODE);
lseek(fd, 0, SEEK_SET);
write(fd, &obj, bytes);
}
int main(int argc, char * * argv)
{
int fd;
unsigned long blocks = 0;
char check = 0x0;
fd = open(argv[1], O_RDONLY);
ioctl(fd, BLKGETSIZE, &blocks);
close(fd);
printf("Blocks: %lu\tBytes: %lu\tGB: %.2f\n",
blocks, blocks * 512, (double)blocks * 512.0 / (1024 * 1024 * 1024));
do
{
printf("Write 0x0 to %s? [y/N] ", argv[1]);
fflush(stdout);
}
while (scanf("%c", &check) < 1);
if (check == 'y')
{
write_zero(argv[1], blocks * 512);
}
}
I get nothing actually written to the device.. I copied my open line from the 'dd' source code, thinking maybe it was not opened right. dd can zero the device, but this program does not. Any ideas?
It seems like this has been beaten to death but
char obj = 0x00;
fd = open(file, O_RDWR, DEFFILEMODE);
lseek(fd, 0, SEEK_SET);
write(fd, &obj, bytes);
Is not going to write zeros. It's going to write garbage from the stack.
I am writing a simple program to flip all the bits in a file, but right now it only does the first 1000 bytes until I get that much working. Why does my call to read() ignore \r characters? When I run this code on a file that only contains \r\n\r\n, the read call returns 2 and the buffer contains \n\n. The \r characters are completely ignored. I'm running this on Windows (this wouldn't even be an issue on Linux machines)
Why does read(2) skip over the \r character when it finds it? Or is that what is happening?
EDIT: Conclusion is that windows defaults to opening files in "text" mode as opposed to "binary" mode. For this reason, when calling open, we must specify O_BINARY as the mode.
Thanks, code below.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
void invertBytes(size_t amount, char* buffer);
int main(int argv, char** argc)
{
int fileCount = 1;
char* fileName;
int fd = 0;
size_t bufSize = 1000;
size_t amountRead = 0;
char* text;
int offset = 0;
if(argv <= 1)
{
printf("Usages: encode [filenames...]\n");
return 0;
}
text = (char *)malloc(sizeof(char) * bufSize);
for(fileCount = 1; fileCount < argv; fileCount++)
{
fileName = argc[fileCount];
fd = open(fileName, O_RDWR);
printf("fd: %d\n", fd);
amountRead = read(fd, (void *)text, bufSize);
printf("Amount read: %d\n", amountRead);
invertBytes(amountRead, text);
offset = (int)lseek(fd, 0, SEEK_SET);
printf("Lseek to %d\n", offset);
offset = write(fd, text, amountRead);
printf("write returned %d\n", offset);
close(fd);
}
return 0;
}
void invertBytes(size_t amount, char* buffer)
{
int byteCount = 0;
printf("amount: %d\n", amount);
for(byteCount = 0; byteCount < amount; byteCount++)
{
printf("%x, ", buffer[byteCount]);
buffer[byteCount] = ~buffer[byteCount];
printf("%x\r\n", buffer[byteCount]);
}
printf("byteCount: %d\n", byteCount);
}
fd = open(fileName, O_RDWR);
should be
fd = open(fileName, O_RDWR | O_BINARY);
See read() only reads a few bytes from file for details.
Try opening with O_BINARY to use binary mode, text mode may be default and may ignore \r.
open(fileName, O_RDWR|O_BINARY);