Wrong print out of binary file using _tprintf - c

I must read a binary file, but I have wrong output. I start from a txt file that contains:
1 100000 Romano Antonio 1250
2 150000 Fabrizi Aldo 2245
3 200000 Verdi Giacomo 11115
4 250000 Rossi Luigi 13630
I generate the relative binary file by with program:
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#define BUF_SIZE 1000
/*
* Problem1: use tchar.h and _tmain instead of
* int main (int argc, LPTSTR argv [])
* Sometimes it is needeed to see argv correctly
*/
int _tmain (int argc, LPTSTR argv [])
{
HANDLE hIn, hOut;
DWORD nIn, nOut;
CHAR buffer [BUF_SIZE];
if (argc != 3) {
fprintf (stderr, "Usage: cp file1 file2\n");
return 1;
}
hIn = CreateFile (argv[1], GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); /*Here hIn is created with read access*/
if (hIn == INVALID_HANDLE_VALUE) {
fprintf (stderr,
"Cannot open input file. Error: %x\n", GetLastError ());
return 2;
}
hOut = CreateFile (argv[2], GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hOut == INVALID_HANDLE_VALUE) {
fprintf (stderr,
"Cannot open output file. Error: %x\n", GetLastError ());
CloseHandle(hIn);
return 3;
}
while (ReadFile (hIn, buffer, BUF_SIZE, &nIn, NULL) && nIn > 0) {
/*hIn is the handle to the read file, buffer is a pointer to the buffer that receives the data read
from the file, BUF_SIZE is the maximum number of bytes to be read, &nIn is
the pointer to the variable that receives the n° of bytes read*/
/*
* Problem 2:
* During the last cycle less than BUF_SIZE characters may
* be read from file
* WriteFile (hOut, buffer, BUF_SIZE, &nOut, NULL);
* so write just the number of characters read
*/
WriteFile (hOut, buffer, nIn, &nOut, NULL); /*I write in file related hOut, the content of read file hIn is in buffer,
nIn is the n° of bytes to write, &nOut is a pointer to the variable that receives the number of bytes written*/
if (nIn != nOut) {
fprintf (stderr, "Fatal write error: %x\n", GetLastError ());
CloseHandle(hIn); CloseHandle(hOut);
return 4;
}
}
CloseHandle (hIn);
CloseHandle (hOut);
return 0;
}
Now I think that it gives me a binary file. Then, I have to read this binary file and put the data into a struct. My code is:
#if 1
#define UNICODE
#define _UNICODE
#endif
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#define L 30+1
#define SETFILEPOINTER_OVERLAPPING 1
#define N 3
#define BUF_SIZE 1000
struct myacc {
int id;
long int acc_number;
TCHAR surname[L];
TCHAR name[L];
int amount;
};
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hIn;
OVERLAPPED ov = {0, 0, 0, 0, NULL};
DWORD nIn,n;
//TCHAR c;
//TCHAR buffer[BUF_SIZE];
LARGE_INTEGER filePos;
struct myacc account;
if(argc != N) {
fprintf(stderr, "Error into arguments\n");
return 1;
}
hIn = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hIn == INVALID_HANDLE_VALUE) {
fprintf (stderr,"Cannot open input file. Error: %x\n", GetLastError ());
return 2;
}
n=1;
filePos.QuadPart = (n-1) * sizeof(struct myacc);
#if SETFILEPOINTER_OVERLAPPING
SetFilePointerEx (hIn, filePos, NULL, FILE_BEGIN);
while(ReadFile (hIn, &account, sizeof (struct myacc), &nIn, NULL) && nIn > 0) {
_tprintf (_T("-> %d %ld %s %s %d <-\n"), account.id, account.acc_number, account.surname, account.name, account.amount);
}
#else
ov.Offset = filePos.LowPart; /*Uso l'overlapped structure ov se ho asynchronous I/O*/
ov.OffsetHigh = filePos.HighPart;
while(ReadFile (hIn, &account, sizeof (struct myacc), &nIn, &ov) && nIn > 0) {
_tprintf (_T("-> %d %ld %s %s %d <-\n"), account.id, account.acc_number, account.surname, account.name, account.amount);
}
#endif
return 0;
}
Now, in this part of code
while(ReadFile (hIn, &account, sizeof (struct myacc), &nIn, NULL) && nIn > 0) {
_tprintf (_T("-> %d %ld %s %s %d <-\n"), account.id, account.acc_number, account.surname, account.name, account.amount);
}
the output is wrong, that is:
Why do I get this? I generate wrong bin file? Or I manage bad the output function? I hope you can help me.
Thank you in advance.

You believe that second program is wrong, but we don't know if it is wrong because the input for the second program is also wrong.
Input for the second program (also output of the first program) is supposed to be a binary file, but it is actually a text file, identical to the the input of the first program. It is identical because the first program is not making any kind of conversion. All it does is ReadFile(..., buffer, ..., &nIn, ...) immediately followed by WriteFile(..., buffer, nIn, ...). These two lines just copy all the data.
First program should use getline() (like described here, in a second method, line-based parsing) instead of ReadFile(), get all the data, populate one struct myacc object, and WriteFile contents of that object.

Related

Segfault in getline

The following code is supposed to read the file "rules.txt" and write it to a device line by line.
The flow should be:
Read line from rules.txt
Echo it to device
The following code always end in segfault because of readline and I have no idea why:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#define BUFFER_LENGTH 256
int main()
{
char *line;
size_t len = BUFFER_LENGTH;
int fd = open("./rules.txt", O_RDONLY);
if(fd == -1)
{ perror("open failed"); return 0; }
FILE* fout = fopen("/sys/class/Rule_Table_Class/Rule_Table_Class_Rule_Table_Device/sysfs_att", "w+");
if(fout == NULL)
{ close(fd); perror("fopen failed, log.txt is busy!"); return 0; }
while (1)
{
line = (char*) malloc(len*sizeof(char));
if(line==NULL){
perror("malloc failed!"); return 0;
}
int bytesRead = getline(&line, &len, fd);
if (bytesRead == -1)
{
perror("Failed to read the message from the device.");
return errno;
}
sprintf(line,"%s","lala");
printf("line = %s", line);
}
fclose(fout);
close(fd);
return 0;
}
EDIT:
I corrected the code and still get a segfault. Here is the corrected code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#define BUFFER_LENGTH 256
int main()
{
FILE * fp;
char * line = NULL;
size_t len = 0;
ssize_t read;
fp = fopen("./rules.txt", "r");
if(fp == NULL)
{ perror("open failed"); return 0; }
FILE* fout = fopen("/sys/class/Rule_Table_Class/Rule_Table_Class_Rule_Table_Device/sysfs_att", "w+");
if(fout == NULL)
{ perror("fopen failed!"); return 0; }
while (1)
{
ssize_t bytesRead = getline(&line, &len, fp);
if (bytesRead == -1)
{
return 0;
}
printf("line = %s", line);
fprintf(line,"%s",fout);
}
fclose(fout);
fclose(fp);
return 0;
}
First of all, the proper core getline() loop is
/* FILE *in = fopen(..., "r"); */
char *line = NULL;
size_t size = 0;
while (1) {
ssize_t len = getline(&line, &size, in);
if (len < 0)
break;
/* You have 'len' chars at 'line', with line[len] == '\0'. */
}
so, it is not getline() that causes the segfault, it is your fprintf(line, "%s", fout); that should be either fprintf(fout, "%s", line); or just fputs(line, fout);, or fwrite(line, 1, bytesRead, fout); since the line can contain embedded NUL bytes that fprintf() and fputs() consider an end of string mark.
If we modify the code so that the source and target file names are taken as command-line arguments (with - denoting standard input or standard output), this is what I'd personally like to see:
/* SPDX-License-Identifier: CC0-1.0 */
/* This tells the GNU C library to expose POSIX features, including getline(). */
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[])
{
if (argc != 3 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
const char *self = (argc > 0 && argv && argv[0] && argv[0][0]) ? argv[0] : "(this)";
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", self);
fprintf(stderr, " %s SOURCE TARGET\n", self);
fprintf(stderr, "\n");
fprintf(stderr, "This copies all content from SOURCE to TARGET, line by line.\n");
fprintf(stderr, "Use '-' for standard input source or standard output target.\n");
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
const char *srcpath = argv[1];
const char *dstpath = argv[2];
/* If the path is "-", set it to NULL. */
if (srcpath && !strcmp(srcpath, "-"))
srcpath = NULL;
if (dstpath && !strcmp(dstpath, "-"))
dstpath = NULL;
FILE *src, *dst;
/* Open source for reading. If srcpath is NULL, use stdin. */
if (srcpath) {
src = fopen(srcpath, "r");
if (!src) {
fprintf(stderr, "%s: %s.\n", srcpath, strerror(errno));
return EXIT_FAILURE;
}
} else {
src = stdin;
}
/* Open target for writing. If dstpath is NULL, use stdout. */
if (dstpath) {
dst = fopen(dstpath, "w");
if (!dst) {
fprintf(stderr, "%s: %s.\n", dstpath, strerror(errno));
fclose(src);
return EXIT_FAILURE;
}
} else {
dst = stdout;
}
char *line = NULL;
size_t size = 0;
unsigned long linenum = 0;
while (1) {
ssize_t len = getline(&line, &size, src);
if (len < 0)
break;
linenum++;
if (fwrite(line, 1, len, dst) != (size_t)len) {
fprintf(stderr, "%s: Write error on line %lu.\n", dstpath ? dstpath : "(standard output)", linenum);
fclose(dst);
fclose(src);
return EXIT_FAILURE;
}
}
/* Technically, we don't need to release dynamically allocated (non-shared) memory,
because we're just about to exit, and the OS will automagically do that for us.
We can do this at any point we want during the loop, too. */
free(line);
line = NULL;
size = 0;
/* We do not know why getline() returned -1. Check if an error occurred, and whether we're at end of input. */
if (ferror(src) || !feof(src)) {
fprintf(stderr, "%s: Read error on line %lu.\n", srcpath ? srcpath : "(standard input)", linenum);
fclose(dst);
fclose(src);
return EXIT_FAILURE;
}
/* Check if any write errors have occurred. */
if (ferror(dst)) {
fprintf(stderr, "%s: Write error on line %lu.\n", dstpath ? dstpath : "(standard output)", linenum);
fclose(dst);
fclose(src);
}
/* Read errors should not occur at close time, but it costs very little for us to test anyway. */
if (fclose(src)) {
fprintf(stderr, "%s: Read error on line %lu.\n", srcpath ? srcpath : "(standard input)", linenum);
fclose(dst);
return EXIT_FAILURE;
}
/* Write errors can occur at close time, if the output has been buffered, or the target is on
a remote filesystem. Again, it costs us very little to check. */
if (fclose(dst)) {
fprintf(stderr, "%s: Write error on line %lu.\n", dstpath ? dstpath : "(standard output)", linenum);
return EXIT_FAILURE;
}
/* No errors; target is an identical copy of the source file. */
fprintf(stderr, "%lu lines copied successfully.\n", linenum);
return EXIT_SUCCESS;
}
The SPDX-License-Identifier is a common way to indicate the license of the code. I use CC0-1.0, which basically means "use as you wish, just don't blame the author for any issues: no guarantees, no warranties."
The #define _POSIX_C_SOURCE 200809L tells the GNU C library that we want it to expose POSIX.1-2008 features, which include getline(). If you look at man 3 getline, you'll see in the Synopsis section that glibc 2.10 and later require _POSIX_C_SOURCE to be defined to at least 200809L.
Most of the code is to print the usage, and getting the source and target file names from the command line, and handling - as a special name, "standard stream", so that it can be used even in pipes by specifying - as the input and/or output file name.
The getline() loop uses fwrite() to write the line to the target file. This way, if the input contains embedded NUL bytes (\0), the target will still be identical to the source file.
After the loop, we discard the line buffer, although since the program is just about to exit, we could omit that (since the OS will release all dynamically allocated (non-shared) memory when we exit anyway).
I like code that checks with ferror(src) || !feof(src) if an error occurred in src or src did not reach end of input; and that checks the return value of fclose(), in case a delayed (write) error is reported. Granted, fclose() should never fail for a read-only file, and fclose() should only fail for files we've written to in specific circumstances, but it costs very little to check, and this way the user running the program will be told if the program detected loss of data.
I believe it is morally reprehensible to ignore checking for such errors (especially "because they occur so rarely"), since such tests are the only way the human user can know whether the operation was successful, or if some odd problem occurred. It is up to the human to investigate any problems, and up to our programs to report detectable issues.
The getline function takes a FILE * as a parameter, not an int. Replace the following line:
int fd = open("./rules.txt", O_RDONLY);
By;
FILE *fin = fopen("./rules.txt", "r");
Fix the error checking in the following lines accordingly, like you did with fout.
Then replace the line:
int bytesRead = getline(&line, &len, fd);
Instead it should now use fin:
ssize_t bytesRead = getline(&line, &len, fin);
Note that getline returns ssize_t, not int.
You are also never writing to fout, but I guess you're still working on this code.
Make sure to enable compiler warnings, because your compiler would surely have warned you for using an int parameter where a FILE * was expected.

Is there a way to check for string content after a null-terminating byte?

I want to pipe an input to my program that only accepts lines that are valid for my regular expression, i.e. a number of max length 3, followed by at least one white space character, followed by a negative or positive number of max length 7.
The following call
echo -e '1 1\n1 1\x00junk' | ./myProgram
gets through my regular expression but shouldn't.
I guess its cause of getline(), that my regular expression only gets the content in front of the null-terminating byte and ignores everything after.
Is there a way to check for the content after a null-terminating byte without potentially violating the access of the allocated memory of my string, so that the given call ends in an error ?
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <regex.h>
#include <errno.h>
int main() {
int reg;
regex_t regex;
char *regexStr = "^[0-9]{1,3} +-?[0-9]{1,7}(\n|\r|\r\n|0a|0d0a)?$";
int size = 16;
char *buffer = malloc(size * sizeof(char));
size_t len = size;
ssize_t nread;
if (regcomp(&regex, regexStr, REG_EXTENDED)) {
fprintf(stderr, "Couldn't compile regular expression.\n");
return -1;
}
while ((nread = getline(&buffer, &len, stdin)) != EOF) {
if (errno == ENOMEM) { // error if getline() couldnt allocate buffer
fprintf(stderr, "Couldn't allocate enough memory.\n");
return -1;
}
reg = regexec(&regex, buffer, 0, NULL, 0);
if (reg == REG_NOMATCH) { //input invalid if regular expression doesnt match with line
fprintf(stderr, "Input invalid.\n");
return -1;
}
printf("%s", buffer);
}
printf("\n");
printf("Input was valid.\n");
return 0;
}
Matching null bytes with regexec is tricky but could be achieved on some architectures with the optional flag REG_STARTEND as documented by KamilCuk, but this feature is non standard.
There is a simple solution for POSIX systems: unlike fgets(), getline() returns the number of bytes read from the stream, so you can detect if any of these bytes is a null byte by comparing nread with strlen(buffer).
Here is a modified version, with some other fixes:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
#include <errno.h>
int main() {
int reg;
regex_t regex;
const char *regexStr = "^[0-9]{1,3} +-?[0-9]{1,7}(\n|\r|\r\n)?$";
char *buffer = NULL; // no need to pre-allocate buffer
size_t size = 0;
ssize_t nread;
if (regcomp(&regex, regexStr, REG_EXTENDED)) {
fprintf(stderr, "Couldn't compile regular expression.\n");
return -1;
}
for (;;) {
errno = 0; // set errno so we can test it after getline
nread = getline(&buffer, &size, stdin);
if (nread < 0) {
if (errno == ENOMEM) {
// error if getline() couldnt allocate buffer
fprintf(stderr, "Couldn't allocate enough memory.\n");
return -1;
}
break;
}
if (strlen(buffer) != (size_t)nread) {
fprintf(stderr, "Invalid input: contains null bytes\n");
return -1;
}
reg = regexec(&regex, buffer, 0, NULL, 0);
if (reg == REG_NOMATCH) {
// input invalid if regular expression doesn't match line contents
fprintf(stderr, "Input invalid.\n");
return -1;
}
printf("%s", buffer);
}
printf("\n");
printf("Input was valid.\n");
return 0;
}
From man regexec:
REG_STARTEND
Use pmatch[0] on the input string, starting at byte pmatch[0].rm_so and ending before byte pmatch[0].rm_eo. This allows
matching embedded NUL bytes and avoids a strlen(3) on large strings. It does not use nmatch on input, and does not change
REG_NOTBOL or REG_NEWLINE processing. This flag is a BSD extension, not present in POSIX.
Use REG_STARTEND. Like so:
regmatch_t match[1] = {0};
match[0].rm_so = 0;
match[0].rm_eo = nread;
reg = regexec(&regex, buffer, 0, match, REG_STARTEND);
results in:
$ echo -e '1 1\n1 1\x00junk' | ./a.out
1 1
Input invalid.

WIndow CreateFile ReadFile WriteFile

I am a student so I apologize up front for not using the correct forum protocols. I am new to C, and really new to Win32 API. My assignment is to write a small C program that copies the contents of an existing file to a new file, using only Win32 I/O system calls: CreateFile(), ReadFile(), WriteFile(), etc... File names are to be specified on the command line. Right now I'm just trying to get the basics functions in place, I will then focus on error handling. This code compiles, creates a new file, but the data does not get copied to it. Any advice? thanks for taking a look!
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main(int argc, char *argv[])
{
char buff[4096];
DWORD dwBytesRead, dwBytesWritten;
DWORD dwBytesToWrite = (DWORD)strlen(buff);
//open source file and read it
HANDLE source;
// Create a handle for the source file
source=CreateFile(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// Check for errors
if ( source == INVALID_HANDLE_VALUE ){
printf("Error, source file not opened.");
exit(EXIT_FAILURE);
}
else printf("The source file is %s\n", argv[1]);
//create a new file
HANDLE target;
target = CreateFile(argv[2], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if ( target == INVALID_HANDLE_VALUE ){
printf("Error, target file not created.");
exit(EXIT_FAILURE);
}
else printf("The source file is %s\n", argv[2]);
//copy contents
ReadFile(source, buff, 4096, &dwBytesRead, NULL);
WriteFile(target, buff, dwBytesToWrite, &dwBytesWritten, NULL);
//copy complete
CloseHandle(source);
CloseHandle(target);
return 0;
}
As mentioned in comments, your code has a few mistakes in it. Try something more like this instead:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main(int argc, char *argv[])
{
char buff[4096];
DWORD dwBytesRead, dwBytesWritten;
// Open the source file
HANDLE source = CreateFileA(argv[1], GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// Check for error
if (source == INVALID_HANDLE_VALUE) {
printf("Source file not opened. Error %u", GetLastError());
return EXIT_FAILURE;
}
printf("The source file is %s\n", argv[1]);
// Create a new file
HANDLE target = CreateFileA(argv[2], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// Check for error
if (target == INVALID_HANDLE_VALUE) {
printf("Target file not created. Error %u", GetLastError());
CloseHandle(source);
return EXIT_FAILURE;
}
printf("The target file is %s\n", argv[2]);
// Copy contents
bool ok = true;
do {
// Read file, check for error
if (!ReadFile(source, buff, sizeof(buff), &dwBytesRead, NULL)) {
printf("Source file not read from. Error %u", GetLastError());
ok = false;
break;
}
// Check for EOF reached
if (dwBytesRead == 0) {
break;
}
// Write file, check for error
if (!WriteFile(target, buff, dwBytesRead, &dwBytesWritten, NULL)) {
printf("Target file not written to. Error %u", GetLastError());
ok = false;
break;
}
}
while (true);
// Copy complete
CloseHandle(source);
CloseHandle(target);
// Check for error
if (!ok) {
DeleteFileA(argv[2]);
return EXIT_FAILURE;
}
// all OK
return 0;
}

C: reading a file line by line

Input files have one entry per line and be of the form T S where T is the arrival time and S is the sector to be read.
I have a file.txt where it looks like
1 6
2 7
3 8
Would indicate three disk accesses for sectors 6, 7, and 8 arriving at time 1 2 and 3 respectively.
how do i parse it so that the first number goes to T and the second goes to S?
There are many ways to accomplish this task.
The scanf() (or perhaps fscanf()) method mentioned by pmg is perhaps most commonly taught to new programmers by academia.
The readLine() method, referred to by doniyor is an alternate approach which reads one character at a time to assemble a complete line, which then can be parsed as a string.
You might even try using fgets() to read an entire line, and then parse the numbers out of the line buffer.
The above list of methods is by no means complete. There are many other ways to accomplish the task.
Of course, you have probably have a full working understanding of these common methods, and you are looking for something with some zing! Perhaps the following will help you on your way:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main(
int I__argC,
char *I__argV[]
)
{
int rCode=0;
struct stat statBuf;
FILE *fp = NULL;
char *fileBuf = NULL;
size_t fileBufLength;
char *cp;
/* Verify that caller has supplied I__argV[1], which should be the path
* to the datafile.
*/
if(I__argC != 2)
{
rCode=EINVAL;
fprintf(stderr, "Usage: %s {data file path}\n", I__argV[0]);
goto CLEANUP;
}
/* Get the size of the file (in bytes);
* (assuming that we are not dealing with a sparse file, etc...)
*/
errno=0;
if((-1) == stat(I__argV[1], &statBuf))
{
rCode=errno;
fprintf(stderr, "stat(\"%s\", ...) failed. errno[%d]\n", I__argV[1], errno);
goto CLEANUP;
}
/* Open the caller-specified file in read mode. */
errno = 0;
fp=fopen(I__argV[1], "r");
if(NULL == fp)
{
rCode=errno;
fprintf(stderr, "fopen(\"%s\", \"r\") failed. errno[%d]\n", I__argV[1], errno);
goto CLEANUP;
}
/* Allocate a buffer large enough to hold the entire file content. */
fileBuf=malloc(statBuf.st_size);
if(NULL == fileBuf)
{
rCode=ENOMEM;
fprintf(stderr, "malloc(%zd) failed.\n", statBuf.st_size);
goto CLEANUP;
}
/* Read the file into the fileBuf. */
errno=0;
fileBufLength=fread(fileBuf, 1, statBuf.st_size, fp);
if(fileBufLength != statBuf.st_size)
{
rCode=errno;
fprintf(stderr, "fread() failed to read %zd file bytes. errno[%d]\n",
statBuf.st_size - fileBufLength, errno);
goto CLEANUP;
}
/* Parse the fileBuf for specific data. */
for(cp=fileBuf; cp < fileBuf + fileBufLength; ++cp)
{
long arrivalTime;
long sector;
/* Skip leading white-space (if any) */
if(isspace(*cp))
continue;
/* Parse the 'arrival time'. */
arrivalTime=strtol(cp, &cp, 10);
/* Skip leading white-space (if any) */
while(isspace(*cp))
++cp;
/* Parse the 'sector'. */
sector=strtol(cp, &cp, 10);
printf("%ld, %ld\n", arrivalTime, sector);
}
CLEANUP:
/* Free the fileBuf (if it was successfully allocated) */
if(fileBuf)
free(fileBuf);
/* Close the file (if it was successfully opened) */
if(fp)
fclose(fp);
return(rCode);
}

Search in a directory a file with the length equal or greater than a given int in c language in windows

I am trying to make a named Windows pipe in C. The pipe is used by a user and a server. The user sends trough the pipe a random int. Then the server searches in its current directory a file with the size greater or equal with the received int, and then sends back to the user the file name and a maximum of 100 bytes from the file.
My problem is that i don't know how to verify the size of every file from the directory, and then to return the filename and 100 bytes.
This is the function i'm trying to use for measuring a file size:
int fsize(char* file)
{
FILE * f = fopen(file, "r");
fseek(f, 0, SEEK_END);
int len = (unsigned long)ftell(f);
fclose(f);
return len;
}
This is the "client" code:
#include <stdio.h>
#include <windows.h>
#define MAXLINIE 100
int main(int argc, char* argv[]) {
char rcvMsg[100];
char sndMsg[100];
DWORD rez;
HANDLE readHandle, writeHandle;
int r = rand();
char str[15];
sprintf(str, "%d", r);
writeHandle = CreateFile("\\\\.\\PIPE\\FirstPipe", GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
readHandle = CreateFile("\\\\.\\PIPE\\SecondPipe",GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
strcpy(sndMsg, r);
printf("Sending message to server: %s\n", sndMsg);
WriteFile(writeHandle, sndMsg, strlen(sndMsg), &rez, NULL);
printf("Message sent! Waiting for server to read the message!\n");
printf("Waiting for SERVER to write in the pipe...\n");
ReadFile(readHandle, rcvMsg, 100, &rez, NULL);
printf("Client revceived message: %s\n", rcvMsg);
CloseHandle(readHandle);
CloseHandle(writeHandle);
return 1;
}
This is the "server" code, excepting the file parsing part:
>
#include <stdio.h>
#include <windows.h>
#define MAXLINIE 100
//file lenght
int fsize(char* file)
{
FILE * f = fopen(file, "r");
fseek(f, 0, SEEK_END);
int len = (unsigned long)ftell(f);
fclose(f);
return len;
}
int main(int argc, char* argv[]) {
char rcvMsg[100];
char sndMsg[100];
DWORD rez;
HANDLE readHandle, writeHandle;
readHandle = CreateNamedPipe("\\\\.\\PIPE\\FirstPipe", PIPE_ACCESS_INBOUND,
PIPE_TYPE_BYTE|PIPE_WAIT,3,0,0,0,NULL);
writeHandle = CreateNamedPipe("\\\\.\\PIPE\\SecondPipe", PIPE_ACCESS_OUTBOUND,
PIPE_TYPE_BYTE|PIPE_WAIT, 3, 0, 0, 0, NULL);
printf("Waiting for clients to connect...\n");
ConnectNamedPipe(writeHandle, NULL);
ConnectNamedPipe(readHandle, NULL);
printf("Waiting for a CLIENT to write in the pipe...\n");
ReadFile(readHandle, rcvMsg, 100, &rez, NULL);
printf("Server revceived message: %s\n", rcvMsg);
int num = atoi(rcvMsg); //the file lenght i'm looking for
//here i should process the files
strcpy(sndMsg, "File_name + 100 bytes");
printf("Server sends an answer: %s\n", sndMsg);
WriteFile(writeHandle, sndMsg, strlen(sndMsg), &rez, NULL);
printf("Waiting for client to read the message...\n");
// disconnecting and closing the handles
DisconnectNamedPipe(writeHandle);
CloseHandle(writeHandle);
DisconnectNamedPipe(readHandle);
CloseHandle(readHandle);
return 1;
}
FindFirstFile() and FindNextFile() to iterate through files... supports wildcards. When done call FindClose()
http://msdn.microsoft.com/en-us/library/windows/desktop/aa364418(v=vs.85).aspx
Here is example code using FindFirstFile from cprogramming: (look in wfd struct for size attributes)
see other comments below code example
#include <stdio.h>
#include <string.h>
#include <windows.h>
void find(char* path,char* file) //Note: pass the path string appropriate for your scenario
{
static int found =0;
HANDLE fh;
WIN32_FIND_DATA wfd;
int i=0;
int j=0;
fh=FindFirstFile(path,&wfd);
if(fh)
{
if(strcmp(wfd.cFileName,file)==0)
{
path[strlen(path)-3]='\0';
strcat(path,file);
FindClose(fh);
return;
}
else
{
while(FindNextFile(fh,&wfd) && found ==0)
{
if(strcmp(wfd.cFileName,file)==0)
{
path[strlen(path)-3]='\0';
strcat(path,file);
FindClose(fh);
found =1;
return;
}
if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
strcmp(wfd.cFileName,"..")!=0 && strcmp(wfd.cFileName,".")!=0)
{
path[strlen(path)-3]='\0';
strcat(path,wfd.cFileName);
strcat(path,"\\*.*");
find(path,file);
}
}
if(found==0)
{
for(i=strlen(path)-1;i>0;i--)
{
if(j==1 && path[i]=='\\')
{
path[i]='\0';
strcat(path,"\\*.*");
break;
}
if(path[i]=='\\')
j=1;
}
}
}
FindClose(fh);
}
}
int main()
{
TCHAR path[512] = "C:\\*.*"; //Change this as necessary
find(path,"notepad.exe");
printf("%s\n",path);
return 0;
}
The file attributes will give you the file name, and size etc.
You can then write the 100 bytes to a char buffer by passing the name and path of the found file to fopen(): FILE *fp = fopen(fileNamePath, "r"); Then something like char buf[101];for(i=0;i<100;i++){buf[i] = fgetc(fp);}
***Don't forget to use fclose() when you are done with fp.

Resources