Monitoring directory using ReadDirectoryChangesW API - c

I am trying to monitor a directory e:\test using ReadDirectoryChangesW API.
My Code :
#define UNICODE
#define WIN32_WINNT 0x0500
#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
HANDLE hDir;
int _tmain(int argc, _TCHAR* argv[])
{
FILE_NOTIFY_INFORMATION fniDir;
DWORD i = 0;
hDir = CreateFile(_T("e:\\test"), GENERIC_READ , FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
ReadDirectoryChangesW(hDir, &fniDir, sizeof(fniDir), TRUE, FILE_NOTIFY_CHANGE_FILE_NAME, &i, NULL, NULL);
while(TRUE)
{
if(i>0)
wprintf(L"%s", fniDir.FileName);
}
CloseHandle(hDir);
return 0;
}
I don't know what's wrong with my code as I haven't understood ReadDirectoryChangesW documentation completely, specially the LPOVERLAPPED parameters.
When I run the code I don't get any output, except for a blank console window. Can someone point me in a right direction?
Thanks.

You only need the overlapped struct if you plan on catching the changes notifications asynchronously. In your code you don't need it.
Here's how you do it.
HANDLE hDir = CreateFile(
p.string().c_str(), /* pointer to the file name */
FILE_LIST_DIRECTORY, /* (this is important to be FILE_LIST_DIRECTORY!) access (read-write) mode */
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, /* (file share write is needed, or else user is not able to rename file while you hold it) share mode */
NULL, /* security descriptor */
OPEN_EXISTING, /* how to create */
FILE_FLAG_BACKUP_SEMANTICS, /* file attributes */
NULL /* file with attributes to copy */
);
if(hDir == INVALID_HANDLE_VALUE){
throw runtime_error(string("Could not open ").append(p.string()).append(" for watching!"));
}
FILE_NOTIFY_INFORMATION buffer[1024];
DWORD BytesReturned;
while( ReadDirectoryChangesW(
hDir, /* handle to directory */
&buffer, /* read results buffer */
sizeof(buffer), /* length of buffer */
TRUE, /* monitoring option */
FILE_NOTIFY_CHANGE_LAST_WRITE, /* filter conditions */
&BytesReturned, /* bytes returned */
NULL, /* overlapped buffer */
NULL)){
do{
//CANT DO THIS! FileName is NOT \0 terminated
//wprintf("file: %s\n",buffer.FileName);
buffer += buffer.NextEntryOffset;
}while(buffer.NextEntryOffset);
}

Related

How to modify file attributes without race conditions?

I want to modify a single attribute on a file (e.g the read-only attribute). In order to do that, it looks like I have to query the current file attributes with either GetFileAttributes or GetFileInformationByHandle, then set the new attributes with either SetFileAttributes or SetFileInformationByHandle: https://learn.microsoft.com/en-us/windows/win32/fileio/retrieving-and-changing-file-attributes
However that is inherently racy, as the file attributes may change between the query and the update. Is there a method to update file attributes atomically? I would expect there to be an API like ModifyFileAttributes(DWORD addAttributes, DWORD rmAttributes) which would do its best to work atomically. Transactional NTFS is not an option for me because a) it's deprecated b) only works on NTFS.
Thanks!
As mentioned in the comment, FILE_SHARE_READ is a trade-off. The following code is adapted from SetFileInformationByHandle function. SetFileInformationByHandle for hFile2 is ERROR_ACCESS_DENIED.
#include <Windows.h>
#include <Tchar.h>
int main()
{
//...
HANDLE hFile1 = CreateFile(TEXT("tempfile"),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
0,
NULL);
HANDLE hFile2 = CreateFile(TEXT("tempfile"),
GENERIC_READ,
FILE_SHARE_READ| FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
0,
NULL);
if (hFile1 != INVALID_HANDLE_VALUE && hFile2 != INVALID_HANDLE_VALUE)
{
HANDLE hFile = hFile1;
//HANDLE hFile = hFile2;
FILE_BASIC_INFO fdi{};
fdi.FileAttributes = FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_NORMAL;
BOOL fResult = SetFileInformationByHandle(hFile,
FileBasicInfo,
&fdi,
sizeof(FILE_BASIC_INFO));
if (fResult)
{
// File will be deleted upon CloseHandle.
_tprintf(TEXT("SetFileInformationByHandle marked tempfile for deletion\n"));
// ...
// Now use the file for whatever temp data storage you need,
// it will automatically be deleted upon CloseHandle or
// application termination.
// ...
}
else
{
_tprintf(TEXT("error %lu: SetFileInformationByHandle could not mark tempfile for deletion\n"),
GetLastError());
}
CloseHandle(hFile);
// At this point, the file is closed and deleted by the system.
}
else
{
_tprintf(TEXT("error %lu: could not create tempfile\n"),
GetLastError());
}
//...
}

How to open named pipe when process is started using uri scheme

I am developing a uri scheme registering library in C. I need to redirect the second call of the application to the first one so that only one is opened at a time. I decided to use windows named pipes for that. When I start the second instance like start testuri://example it works fine and the first instance receives the value testuri://example. However, when I start it like explorer testuri://example it fails to open the pipe to write.
This is my code for pipes (it is a wrapper for the winapi since I want the code to be cross platform and a Linux version also exists)
#include <windows.h>
#define READONLY GENERIC_READ
#define WRITEONLY GENERIC_WRITE
#define READWRITE GENERIC_WRITE | GENERIC_READ
#define CREATE_EXCLUSIVE CREATE_NEW
#define CREATE CREATE_ALWAYS
typedef struct file_desc {
char* name;
HANDLE hPipe;
int isReadPipe;
} file_desc;
void pipe_create(file_desc* pipe, const char* name) {
pipe->name = (char*) malloc(strlen(name) + 10);
memcpy(pipe->name, "\\\\.\\pipe\\", 10);
strcat(pipe->name, name);
pipe->hPipe = CreateNamedPipe(
TEXT(pipe->name),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1,
1024 * 16,
1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL
);
}
int pipe_open(file_desc* pipe, int mode) {
if (mode == READONLY) {
pipe->isReadPipe = TRUE;
return ConnectNamedPipe(pipe->hPipe, NULL);
} return file_open(pipe, pipe->name, mode, 1);
}
void pipe_close(file_desc* pipe) {
if (pipe->isReadPipe) {
DisconnectNamedPipe(pipe->hPipe);
} else file_close(pipe);
}
int file_open(file_desc* pipe, const char* name, int mode, int lock) {
if (!lock) pipe->hPipe = CreateFile(TEXT(name), mode, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL);
else pipe->hPipe = CreateFile(TEXT(name), mode, 0, NULL, OPEN_ALWAYS, 0, NULL);
return pipe->hPipe != INVALID_HANDLE_VALUE;
}
char* file_read(file_desc* pipe, char buf[], unsigned int size) {
DWORD dwRead;
ReadFile(pipe->hPipe, buf, size, &dwRead, NULL);
}
void file_write(file_desc* pipe, const char* str) {
DWORD dwWritten;
WriteFile(pipe->hPipe,str, strlen(str) + 1, &dwWritten, NULL);
}
void file_close(file_desc* pipe) {
CloseHandle(pipe->hPipe);
}
The way I create the pipes is something like this
file_desc* pipe;
pipe_create(pipe, "mypipe");
if (firstInstance) {
pipe_open(pipe, READONLY);
char buf[200];
file_read(pipe, buf, 200);
pipe_close(pipe);
} else {
pipe_open(pipe, WRITEONLY);
file_write(pipe, "test");
pipe_close(pipe);
}
Full code is at https://github.com/germaniuss/libschemehandler just create an obj folder and execute make in MinGW. Then run myapp.exe
I found a solution!
I tried looking at the error code at it returned error 5, access is denied. I found the problem. When opening the first instance I did that with elevated privileges, however, when opening an app using explorer testuri://example a new terminal window without elevated privileges pops up. This causes a problem since the pipe was created as administrator and is being accessed without.
I looked for info on this topic and found this forum exchange https://forums.codeguru.com/showthread.php?548311-RESOLVED-Writing-to-a-named-pipe-coming-from-a-service-(session-0)-without-admin-rights which was exactly what I needed. I just needed to create an all access security descriptor for the named pipe.
I feel like the fact that the pipe is created by default as with admin only access should be more clearly stated, since it says full access is granted by default
A pointer to a SECURITY_ATTRIBUTES structure that specifies a security
descriptor for the new named pipe and determines whether child
processes can inherit the returned handle. If lpSecurityAttributes is
NULL, the named pipe gets a default security descriptor and the handle
cannot be inherited. The ACLs in the default security descriptor for a
named pipe grant full control to the LocalSystem account,
administrators, and the creator owner. They also grant read access to
members of the Everyone group and the anonymous account.
Source MSDN
In the end my pipe_open functions ended up like so
void pipe_create(file_desc* pipe, const char* name) {
// all access secutrity descriptor
PSECURITY_DESCRIPTOR psd = NULL;
BYTE sd[SECURITY_DESCRIPTOR_MIN_LENGTH];
psd = (PSECURITY_DESCRIPTOR)sd;
InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(psd, TRUE, (PACL)NULL, FALSE);
SECURITY_ATTRIBUTES sa = {sizeof(sa), psd, FALSE};
pipe->name = (char*) malloc(strlen(name) + 10);
memcpy(pipe->name, "\\\\.\\pipe\\", 10);
strcat(pipe->name, name);
pipe->hPipe = CreateNamedPipe(
TEXT(pipe->name),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1,
1024 * 16,
1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
&sa
);
}

Mapping files into virtual memory in C on Windows

On POSIX systems, I am able to use the mmap function to read the contents of a file faster than getline, getc, etc. This is important in the program that I am developing as it is expected to read very large files into memory; iteratively collecting lines using getline is too costly. Portability is also a requirement of my software, so if I use mmap, I need to find a way to memory map files using the WinApi, as I'd rather not compile through cygwin/msys. From a cursory search I identified this MSDN article which describes very briefly a way to map files into memory, however, from trawling through documentation I can't make head nor tails of how to actually implement it, and I'm stuck on finding example snippets of code, like there are for POSIX mmap.
How do I use the WinApi's memory mapping options to read a file into a char*?
How do I use the WinApi's memory mapping options to read a file into a
char*?
Under Windows, when you map a file in memory, you get a pointer to the memory location where the first byte of the file has been mapped. You can cast that pointer to whatever datatype you like, including char*.
In other words, it is Windows which decide where the mapped data will be in memory. You cannot provide a char* and expect Windows will load data there.
This means that if you already have a char* and want the data from the file in the location pointed by that char*, then you have to copy it. Not a good idea in terms of performances.
Here is a simple program dumping a text file by mapping the file into memory and then displaying all ASCII characters. Tested with MSVC2019.
#include <stdio.h>
#include <Windows.h>
int main(int argc, char *argv[])
{
TCHAR *lpFileName = TEXT("hello.txt");
HANDLE hFile;
HANDLE hMap;
LPVOID lpBasePtr;
LARGE_INTEGER liFileSize;
hFile = CreateFile(lpFileName,
GENERIC_READ, // dwDesiredAccess
0, // dwShareMode
NULL, // lpSecurityAttributes
OPEN_EXISTING, // dwCreationDisposition
FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
0); // hTemplateFile
if (hFile == INVALID_HANDLE_VALUE) {
fprintf(stderr, "CreateFile failed with error %d\n", GetLastError());
return 1;
}
if (!GetFileSizeEx(hFile, &liFileSize)) {
fprintf(stderr, "GetFileSize failed with error %d\n", GetLastError());
CloseHandle(hFile);
return 1;
}
if (liFileSize.QuadPart == 0) {
fprintf(stderr, "File is empty\n");
CloseHandle(hFile);
return 1;
}
hMap = CreateFileMapping(
hFile,
NULL, // Mapping attributes
PAGE_READONLY, // Protection flags
0, // MaximumSizeHigh
0, // MaximumSizeLow
NULL); // Name
if (hMap == 0) {
fprintf(stderr, "CreateFileMapping failed with error %d\n", GetLastError());
CloseHandle(hFile);
return 1;
}
lpBasePtr = MapViewOfFile(
hMap,
FILE_MAP_READ, // dwDesiredAccess
0, // dwFileOffsetHigh
0, // dwFileOffsetLow
0); // dwNumberOfBytesToMap
if (lpBasePtr == NULL) {
fprintf(stderr, "MapViewOfFile failed with error %d\n", GetLastError());
CloseHandle(hMap);
CloseHandle(hFile);
return 1;
}
// Display file content as ASCII charaters
char *ptr = (char *)lpBasePtr;
LONGLONG i = liFileSize.QuadPart;
while (i-- > 0) {
fputc(*ptr++, stdout);
}
UnmapViewOfFile(lpBasePtr);
CloseHandle(hMap);
CloseHandle(hFile);
printf("\nDone\n");
}

ReadFile function returns ERROR_INVALID_PARAMETER

I'm trying to get to work ReadFile function. Here's my code:
#define BUFFERSIZE 5
int main(int argc, char* argv[])
{
OVERLAPPED overlapIn = {};
HANDLE tHandle;
char buf[BUFFERSIZE] = {};
DWORD lpNumberOfBytesRead;
tHandle = CreateFile(
L"\\\\.\\D:",
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (tHandle == INVALID_HANDLE_VALUE)
{
DWORD error = GetLastError();
assert(0);
}
if (ReadFile(tHandle, &buf, BUFFERSIZE - 1, &lpNumberOfBytesRead, NULL) == 0)
{
int error = GetLastError();
printf("Terminal failure: Unable to read from disk.\n GetLastError=%d\n", error);
CloseHandle(tHandle);
return 1;
}
The GetLastError function returns code 87, which is ERROR_INVALID_PARAMETER.
It's clear that one of the parameters is wrong, but I have no idea which one, since I tried to do everything like it's written in the documentation.
This is described in the documentation for CreateFile:
Volume handles can be opened as noncached at the discretion of the particular file system, even when the noncached option is not specified in CreateFile. You should assume that all Microsoft file systems open volume handles as noncached.
The MSDN article on File Buffering describes the requirements for noncached handles:
File access sizes, including the optional file offset in the OVERLAPPED structure, if specified, must be for a number of bytes that is an integer multiple of the volume sector size. For example, if the sector size is 512 bytes, an application can request reads and writes of 512, 1,024, 1,536, or 2,048 bytes, but not of 335, 981, or 7,171 bytes.
File access buffer addresses for read and write operations should be physical sector-aligned, which means aligned on addresses in memory that are integer multiples of the volume's physical sector size. Depending on the disk, this requirement may not be enforced.
Rigorous code should check the sector size for the file system in question, then use this approach to allocate the memory. However, in my experience, the sector size has always been less than or equal to the allocation granularity, so you can get away with just using VirtualAlloc() to allocate a memory block.
buffer size needs to be aligned with hdd sectorsize
WIN32_FIND_DATA atr = {0};
DWORD BYTES_PER_SECTOR;
char path[MAX_PATH];
/* get path length current dir */
const size_t len = GetCurrentDirectory(0, 0);
/* set path to path char array */
GetCurrentDirectory(len, path);
/* windows function to get disk details */
GetDiskFreeSpace(NULL, NULL, &BYTES_PER_SECTOR, NULL, NULL);
/* find first file in dir */
find = FindFirstFile(path, &atr);
for(;find != INVALID_HANDLE_VALUE;){
/* get the file size */
DWORD filesize = atr.nFileSizeLow;
if(atr.nFileSizeHigh > 0){
filesize = atr.nFileSizeHigh;
filesize = (filesize << 31);
filesize = atr.nFileSizeLow;
}
/* sector size aligned file size */
size_t buffer_size = ((BYTES_PER_SECTOR + ((filesize + BYTES_PER_SECTOR)-1)) & ~(BYTES_PER_SECTOR -1));
/* create buffer */
DWORD buffer[buffer_size];
/* create a new file or open an existing file */
handle = CreateFile(&path[0], GENERIC_READ | GENERIC_WRITE, 0 , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL))!=INVALID_HANDLE_VALUE)
/* read the file in to buffer */
ReadFile(handle, (void*)&buffer, buffer_size, &bytesread, NULL)
if(FindNextFile(find, &atr)==0){ printf("last file processed, leaving\n");break;};
}
CloseHandle(file);
FindClose(find);

I want to receive data CONTINUOUSLY from a COM port & simultaneously want to write to file

I want to read serial COM port and to write the data to a file in LINUX. Actually I'm sending data from hyperterminal from other PC.
The problem is without while loop I can write only one line.
But with while(1) loop I can't write anything to file.
Or else I have to send BIG file, then application exits/terminates and writes to the file.
My application should write the data (it may 2 lines or any thing); after that it has to wait for next data.
So please help me out.....
Here is my Code
=========================================
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#define BAUDRATE B115200
#define MODEMDEVICE "/dev/ttyS0"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
void signal_handler_IO (int status); /* definition of signal handler */
int wait_flag=TRUE; /* TRUE while no signal received */
struct timeval timeout;
char n;
fd_set rdfs;
/*Some variables*/
int num, offset = 0, bytes_expected = 255;
main()
{
int fd,c, res,i;
char In1;
struct termios oldtio,newtio;
struct sigaction saio; /* definition of signal action */
char buf[255];
FILE *fp;
/* open the device to be non-blocking (read will return immediatly) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == -1)
{
perror("open_port: Unable to open /dev/ttyS0 - ");
return 1;
}
else
{
fcntl(fd, F_SETFL, 0);
n = select(fd + 1, &rdfs, NULL, NULL, &timeout);
}
fp = fopen("/root/Desktop/gccAkash/OutputLOG.txt","a+");
assert(fp != NULL);
/* install the signal handler before making the device asynchronous */
saio.sa_handler = signal_handler_IO;
sigemptyset(&saio.sa_mask);
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
/* allow the process to receive SIGIO */
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&oldtio); /* save current port settings */
/* set new port settings for canonical input processing */
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
newtio.c_cc[VMIN]=0; //it will wait for one byte at a time.
newtio.c_cc[VTIME]=10; // it will wait for 0.1s at a time.
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
while (STOP==FALSE)
{
if (wait_flag==FALSE) //if input is available
{
do {
res = read(fd,buf+offset,255);
offset += res;
} while (offset < bytes_expected);
if (offset!=0)
{
for (i=0; i<offset; i++) //for all chars in string
{
In1 = buf[i];
fputc ((int) In1, fp);
printf("charecter:%c\n\r",In1);
} //EOFor
}//EOIf
buf[res]=0;
printf("Received Data is:%s\n\r",buf);
if (res==0)
STOP=TRUE; //stop loop if only a CR was input
wait_flag = TRUE; // wait for new input
}
} //while stop==FALSE
while(readchar)
/* restore old port settings */
tcsetattr(fd,TCSANOW,&oldtio);
close(fd);
}
/************************************************** *************************
* signal handler. sets wait_flag to FALSE, to indicate above loop that *
* characters have been received. *
************************************************** *************************/
void signal_handler_IO (int status)
{
printf("received SIGIO signal.\n");
wait_flag = FALSE;
}
You shouldn't be using SIGIO. I've never found any good documentation for using it to do anything, and there are better ways. There's poll, select, and epoll families of functions that would work much better for this. It looks to me like your program is busy waiting on data to become available, which means it's eating up CPU time. The alternatives let your program go to sleep when there's nothing to do. You could use pause to get this effect though, and the program would go to sleep until it received a signal (like SIGIO). You could also just use have the tty file opened in blocking mode and let read block you until there is something read.
You shouldn't be using printf from both a signal handler and regular code. Usually you shouldn't ever be using stdio operations from a signal handler at all because it can sleep, but you can often get away with it during testing. Using it from both a signal handler and regular code (or in multiple signal handlers if one signal isn't blocking others) is bad because then the functions will be accessing the same data. Essentially printf in your regular code might be interrupted by SIGIO and then the printf in there is called and both printfs are wanting access to FILE stdout's internal data -- either that or the locks (which are intended to stop to block different threads, not the same thread calling a second time) will block the SIGIO handler's call to printf, which will block the whole program. The problem here is called a race condition and may or may not happen depending on timing.
In the code:
_
do {
res = read(fd,buf+offset,255);
offset += res;
} while (offset < bytes_expected);
_
You are continually passing 255 as the length you want, even though you may already have filled part of the buffer. If you the first time through the loop you get 254 bytes of data and then call again asking for 255 bytes again and get more than 1 byte you have overrun your buffer. Additionally you never drop offset back to 0 so it just grows and grows, so so you have an overflow of the buffer if your program ever reads more than 255 bytes.
You also aren't checking that the read return value isn't -1. If it were -1 then your program does very bad things.
Also, there is no real reason (that I can see) to try to try to accumulate 255 bytes of data before you write the data you have already read back out. Even if you only want to handle the first 255 bytes that come in the serial port then you could go ahead and write the first ones as the last ones were coming in, and then exit the loop after the 255 limit had been reached.
You are only setting one value in struct sigaction saio, but it has other fields. These should be set to something or you are just throwing random bits in as flags and masks.
_
struct sigaction saio = {0};
saio.sa_handler = signal_handler_IO;
/* Now you don't have to worry about the flags and mask b/c those both are
zeroed out and I'm pretty sure those are decent values for your purposes,
but you could still set them explicitly. */
_
You pass newtio to tcsetattr, but it is possible that you have not totally initialized it. You should have done:
_
tcgetattr(fd,&oldtio); /* save current port settings */
memcpy(&newtio, oldtio, sizeof(struct termios) ); /* !! <-- This line !! */
before you set the other flags. This way you can just use the values that were already there for any fields that you weren't setting explicitly.
Additionally, you seem to be setting all of the BAUDRATE flags.
/* set new port settings for canonical input processing */
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
This isn't correct, most likely. BAUDRATE is used for masking out the baud code like this :
tcflag_t baud_code = tio.c_cflag & BAUDRATE;
And now baud_code has just the bits that correspond to the baud set, without the CRTSCTS and CLOCAL stuff set. You should be using one of the baud codes that look like B9600 and B115200 here instead of BAUDRATE, unless you want to:
tcflag_t non_baud_flags = tio.c_cflag | ~BAUDRATE;
tcflag_t new_flags = non_baud_flags | B9600;
which would only change the baud rate and leave the rest of the flags alone. This is what int cfsetspeed(struct termios *termios_p, speed_t speed); is for.
I'm also not sure about the order in which you are doing some things. I think that you may open yourself up to receiving SIGIO before you have set up the serial port, which will probably get you some junk data. Should probably do:
_
/* I swapped these two lines */
tcsetattr(fd,TCSANOW,&newtio);
tcflush(fd, TCIFLUSH); /* Now the settings are correct before you flush, so no junk */
/* And moved these from above */
sigaction(SIGIO,&saio,NULL); /* There was no real reason for this to be up there,
but no real harm, either. It just goes better here,
but does need to be set before you set the file as
async. */
/* allow the process to receive SIGIO */
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, FASYNC); /* Now SIGIO won't be called on behalf of this file until after
the serial port has be set up and flushed. */
I don't know where you got this code, but it looks over-complicated for what you actually want to achieve. It looks like copy pasting to me.
What is the problem with a loop like this ?
while() {
len = read(serialfd, somebuf, wanted_len);
write to file
}
What exactly is your question ? How to find the good test to exit from the loop ?
Do you want to exit when you receive some char, after a certain time has elapsed ?
For answer on the possible value of len, you can look at the tcgetattr man page.
Maybe your tty options are not suited to what you want to achieve ?
Sorry but neither your question nor your code is clear, maybe you could first describe whet you want to achieve with your program.

Resources