I am trying to use inotify to monitor a file for any reads or writes.
typical use case would be user runs one of the following commands and I get the appropriate notification.
echo "xyz" > /tmp/the_file # This should give me a write notification
OR
cat /tmp/the_file # This should give me an access notification.
I have tried the following masks :
mask = (IN_MODIFY|IN_ACCESS); //gets correct notification for reads , for writes i get 2 notifications
mask = (IN_CLOSE_WRITE|IN_ACCESS); // gets correct notification for reads , no notification for writes.
what would be the right mask value to get a single notification for every read and write ?
I am using the test application from this blog as reference :
How to Use inotify API in C Language
#include<stdio.h>
#include<sys/inotify.h>
#include<unistd.h>
#include<stdlib.h>
#include<signal.h>
#include<fcntl.h>
#define MAX_EVENTS 1024
#define LEN_NAME 256
#define EVENT_SIZE (sizeof (struct inotify_event))
#define BUF_LEN (MAX_EVENTS * (EVENT_SIZE + LEN_NAME))
int fd,wd;
void sig_handler(int sig){
inotify_rm_watch(fd, wd);
close(fd);
exit(0);
}
int main(int argc, char **argv){
char *path_to_be_watched;
int i=0,length;
char buffer[BUF_LEN];
struct inotify_event *event = (struct inotify_event *) &buffer[i];
path_to_be_watched = argv[1];
signal(SIGINT,sig_handler);
fd = inotify_init();
fcntl(fd, F_SETFL, O_NONBLOCK);
wd = inotify_add_watch(fd, path_to_be_watched, IN_MODIFY | IN_ACCESS);
if(wd==-1){
printf("Could not watch : %s\n", path_to_be_watched);
} else {
printf("Watching : %s\n", path_to_be_watched);
}
while(1){
i=0;
length = read(fd,buffer,BUF_LEN);
while(i<length){
event = (struct inotify_event *) &buffer[i];
if(event->len){
if ( event->mask & IN_MODIFY ) {
printf( "The file %s was modified.\n", event->name );
/* This gets printed twice when I run 'echo "123" > /tmp/this_file' */
}
else if ( event->mask & IN_ACCESS ) {
printf( "The file %s was accessed.\n", event->name );
}
}
i += EVENT_SIZE + event->len;
}
}
return(0);
}
Snippet of strace for echo "hello" > ./a.txt
openat(AT_FDCWD, "./a.txt", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE, 0666) = 3
fcntl64(1, F_GETFD) = 0
fcntl64(1, F_DUPFD, 10) = 10
fcntl64(1, F_GETFD) = 0
fcntl64(10, F_SETFD, FD_CLOEXEC) = 0
dup2(3, 1) = 1
close(3) = 0
write(1, "hello\n", 6) = 6
dup2(10, 1) = 1
fcntl64(10, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(10) = 0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n;
printf("Length? ");
scanf("%d", &n);
getchar();
char* str = (char*)malloc(sizeof(char) * (n+1));
fgets(str,sizeof(str),stdin);
for (int i = 0; i < n; i++)
printf("%c\n", str[i]);
free(str);
}
Process results like this!
Length? 5
abcde
a
b
c
?
(I wanted to upload the result image, but I got rejected since I didn't have 10 reputations)
I can't figure out why 'd' and 'e' won't be showing in the results.
What is the problem with my code??
(wellcome to stackoverflow :) (update #1)
str is a pointer to char instead of a character array therefore sizeof(str) is always 8 on 64-bit or 4 on 32-bit machines, no matter how much space you have allocated.
Demo (compilation succeeds only if X in static_assert(X) holds):
#include <assert.h>
#include <stdlib.h>
int main(void){
// Pointer to char
char *str=(char*)malloc(1024);
#if defined _WIN64 || defined __x86_64__ || defined _____LP64_____
static_assert(sizeof(str)==8);
#else
static_assert(sizeof(str)==4);
#endif
free(str);
// Character array
char arr[1024];
static_assert(sizeof(arr)==1024);
return 0;
}
fgets(char *str, int num, FILE *stream) reads until (num-1) characters have been read
Instead of fgets(str,sizeof(str),stdin) please fgets(str,n+1,stdin)
Fixed version:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
int main(void){
int n=0;
printf("Length? ");
scanf("%d",&n);
getchar();
char *str=(char*)calloc((n+1),sizeof(char));
static_assert(
sizeof(str)==sizeof(char*) && (
sizeof(str)==4 || // 32-bit machine
sizeof(str)==8 // 64-bit machine
)
);
fgets(str,n+1,stdin);
for(int i=0;i<n;++i)
printf("%c\n",str[i]);
free(str);
str=NULL;
}
Length? 5
abcde
a
b
c
d
e
I have a perplexing problem with Visual Studio 2015, C++, macros. I do have a bigger project at the background, but the following toy example illustrates the problem.
I have the following C++ code (oma8.rc, oma8.h, oma8.cpp) to create a toy dialog. It compiles with gcc compiler nicely:
windres -O coff -i oma8.rc -o oma8.res
g++ oma8.cpp oma8.res -o oma8
// oma8.cpp
#include <windows.h>
#include <iostream>
#include <iomanip>
#include <string>
#include <stdio.h>
#include "stdlib.h"
#include "oma8.h"
using namespace std;
string param2;
int b1, b3;
string GetInputText( HWND dlg, int resid ) {
HWND hc = GetDlgItem( dlg, resid );
int n = GetWindowTextLength( hc ) + 1;
string s( n, 0 );
GetWindowText( hc, &s[0], n );
return s;
}
int GetCheck( HWND dlg, int resid) {
HWND hc = GetDlgItem(dlg,resid);
int n = IsDlgButtonChecked( dlg, resid);
return n;
}
BOOL CALLBACK DialogProc( HWND hwnd, UINT message,
WPARAM wp, LPARAM ) {
switch ( message ) {
case WM_COMMAND: {
int ctrl = LOWORD( wp );
int event = HIWORD( wp );
if ( ctrl == IDCANCEL && event == BN_CLICKED ) {
DestroyWindow (hwnd);
return TRUE;
}
else if ( ctrl == IDOK && event == BN_CLICKED ) {
param2 = GetInputText( hwnd, IDC_EDIT1 );
b1 = GetCheck( hwnd, RB1 );
b3 = GetCheck( hwnd, RB3 ); // ignore the other buttons for now
DestroyWindow (hwnd);
return TRUE;
}
return FALSE;
}
case WM_DESTROY:
PostQuitMessage(0);
return TRUE;
case WM_CLOSE:
DestroyWindow (hwnd);
return TRUE;
}
return FALSE;
}
int main() {
HWND dlg = CreateDialog( GetModuleHandle(0),
MAKEINTRESOURCE( IDD_DIALOG1 ),
0, DialogProc );
MSG msg;
while ( GetMessage( & msg, 0, 0, 0 ) ) {
if ( ! IsDialogMessage( dlg, & msg ) ) {
TranslateMessage( & msg );
DispatchMessage( & msg );
}
}
cout << "corner text: " << param2 << " as a number: " << atof(¶m2[0]) << endl;
cout << "radio1: " << b1 << " radio3: " << b3 << endl;
}
// oma8.rc (stripped 3 comment lines from start)
#include <windows.h>
#include "oma8.h"
//#include "winresrc.h" // apparently not needed
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG1 DIALOG 20, 20, TABNR(8), THISLINEHEIGHT(15)
STYLE DS_3DLOOK | DS_SETFONT | WS_CAPTION | WS_SYSMENU | WS_VISIBLE | WS_SIZEBOX
//STYLE DS_CENTER | DS_SHELLFONT | DS_FIXEDSYS | DS_MODALFRAME | WS_VSCROLL | WS_POPUP
CAPTION "Caption here"
FONT 10, "Arial"
{
LTEXT "Corner text",IDC_STATIC,LMARG,UPMARG,60,RHEIGHT
EDITTEXT IDC_EDIT1, 60, UPMARG, 60,FIELDH, ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,TABNR(5),UPMARG,TABW,FIELDH
PUSHBUTTON "Cancel",IDCANCEL,TABNR(6),UPMARG,TABW,FIELDH
LTEXT "Block1, line 1",IDC_STATIC,TABNR(RBCOLUMN),THISLINEHEIGHT(PARAMLINE),TEXTW,RHEIGHT
AUTORADIOBUTTON "B1, line 2",RB1,TABNR(RBCOLUMN),THISLINEHEIGHT(PARAMLINE+1),TEXTW,RHEIGHT,WS_GROUP
AUTORADIOBUTTON "B1, line 3",RB2,TABNR(RBCOLUMN),THISLINEHEIGHT(PARAMLINE+2),TEXTW,RHEIGHT
LTEXT "Block2 col 1",IDC_STATIC,TABNR(SNGLCOLUMN),THISLINEHEIGHT(CHOICELINE),TABW,RHEIGHT
AUTORADIOBUTTON "B2 col 2",RB3,TABNR(SNGLCOLUMN+1),THISLINEHEIGHT(CHOICELINE),TABW,RHEIGHT, WS_GROUP
AUTORADIOBUTTON "B2 col 3",RB4,TABNR(SNGLCOLUMN+2),THISLINEHEIGHT(CHOICELINE),TABW,RHEIGHT
LTEXT "Block3, line 1",IDC_STATIC,TABNR(RANGECOLUMN),THISLINEHEIGHT(TXLINE),TEXTW,RHEIGHT
AUTORADIOBUTTON "B3, line 2",RB5,TABNR(RANGECOLUMN),THISLINEHEIGHT(RXLINE),TEXTW,RHEIGHT,WS_GROUP
AUTORADIOBUTTON "B3, line 3",RB6,TABNR(RANGECOLUMN),THISLINEHEIGHT(SCLINE),TEXTW,RHEIGHT
}
// oma8.h (stripped 2 comment lines from start)
#define IDD_DIALOG1 100
// basic buttons
#ifndef IDC_STATIC
#define IDC_STATIC (-1)
#endif
#ifndef IDOK
#define IDOK 40000
#endif
#ifndef IDCANCEL
#define IDCANCEL 40001
#endif
// measures
#define LMARG 6
#define UPMARG 5
#define TEXTW 120 // rb text width
#define TABW 50 // tab width
#define FIELDW 30 // fill-in field w
#define FIELDH 13 // fill-in field h
#define RHEIGHT 14 // row height
// line numbers
#define PARAMLINE 2
#define NOFPARAMS 2
#define OFFSET2 2
#define OFFSET3 5
#define CHOICELINE (PARAMLINE+NOFPARAMS+OFFSET2)
#define TXLINE (CHOICELINE+1)
#define RXLINE (CHOICELINE+2)
#define SCLINE (CHOICELINE+3)
#define RANGETITLELINE 2
#define RANGEFIELDLINE (RANGETITLELINE+1)
#define DETECTORLINE (CHOICELINE+OFFSET3)
#define THISLINEHEIGHT(x) (UPMARG+(x)*RHEIGHT)
// column numbers
#define TABNR(x) (LMARG+TABW*(x))
#define RBCOLUMN 1
#define RANGECOLUMN 5
#define SNGLCOLUMN 2
#define DTCTCOLUMN 7
// parameter buttons
#define IDC_EDIT1 1002
#define RB1 1010
#define RB2 1011
#define RB3 1012
#define RB4 1013
#define RB5 1014
#define RB6 1015
and oma8.exe (all commands given in a console) opens a dialog that looks exactly as I want it to, hooray. But, I have reasons that I must compile this also with VS2015. (It will be later inserted into a certain boilerplate code, but that's not relevant here.)
When trying to compile the same code with VS2015, I get a bunch of error messages related to the .rc file, especially on its macro functions. The first 4 are
Error RC2112 BEGIN expected in dialog oma8.rc 11
Error RC2135 file not found: 0x00040000L oma8.rc 12
Error RC2135 file not found: here oma8.rc 14
Error RC2135 file not found: 10 oma8.rc 15
Furthermore, if I change the lines
#define THISLINEHEIGHT(x) (UPMARG+(x)*RHEIGHT)
#define TABNR(x) (LMARG+TABW*(x))
into
#define THISLINEHEIGHT(x) (UPMARG + (x) * RHEIGHT)
#define TABNR(x) (LMARG + TABW * (x))
I get just one error message:
Error RC2104 undefined keyword or key name: * oma8.rc 11
I must have something funny with my linker/compiler options? When creating this as a Project From Existing Code, I chose Console App and left all other choices as defaults. (Can't remember what those were, sorry, just lots of acronyms.)
I've spent over a week googling and trying different modifications, but haven't been able to fix this. I don't know what else to try. Where should I look into? Any ideas and further questions would be welcome.
My system is Win7, 64-bit. g++ version says g++ (tdm-1) 5.1.0 (C) 2015 Free Software Foundation Inc.
I have a buffer where the first 4 bytes represents an unsigned 32bit integer.
The buffer looks like this {32, 0, 0, 0, ...}
The following code works under gcc without any problems:
uint32_t size = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
Size is 32 as expected but if i compile the project with msvc size is 538976288 instead of 32.
What is the problem?
EDIT:
full source code for test:
#include <stdint.h>
#include <stdio.h>
int main()
{
int pos = 0;
uint32_t buffer [] = {32, 0, 0, 0};
uint32_t size = buffer[pos++] | (buffer[pos++] << 8) | (buffer[pos++] << 16) | (buffer[pos++] << 24) ;
printf("size=%d\n", size);
return 0;
}
I use
size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
to convert UTF-16BE to GB2312.
inbytesleft is bytes number to be convert. After conversion, inbytesleft is bytes number of not converted.
After one call, I found inbytesleft is -2, according to iconv man page this function should read at most inbytesleft.
Who can tell my why and how to fix this?
code to be convert is
"保单验证"
Thanks
How are you getting the input data into your program?
I've tested the situation using this code and it seems to work:
#include <stdio.h>
#include <iconv.h>
#include <errno.h>
int main(){
char data[10] = {0x4f,0xdd,0x53,0x55,0x9a,0x8c,0x8b,0xc1, 0, 0};
char outdata[20];
char *dataptr;
char *outdataptr;
iconv_t cd;
size_t result;
size_t inbytesleft = 8;
size_t outbytesleft = 20;
int i;
cd = iconv_open("GB2312", "UTF-16BE");
dataptr = data;
outdataptr = outdata;
result = iconv(cd, &dataptr, &inbytesleft, &outdataptr, &outbytesleft);
if(result == -1)
printf("Error: %d\n", errno);
printf(" result: %zd\n", result);
printf(" inbytesleft: %zd\n", inbytesleft);
printf("outbytesleft: %zd\n", outbytesleft);
for(i = 20; i > outbytesleft; i--){
if(i != 20)
printf(",");
printf("0x%02x", *((unsigned char *)&(outdata[20-i])));
}
printf("\n");
return 0;
}
It prints
result: 0
inbytesleft: 0
outbytesleft: 12
0xb1,0xa3,0xb5,0xa5,0xd1,0xe9,0xd6,0xa4
Which appears to be correct.
The array of items in the variable data is the UTF-16BE encoding of 保单验证
If this doesn't help, could you post your code for analysis?