SHCNE_RENAMEITEM not working - shell

I want to handle ANY changes in 3 folders (user programs, common programs, downloads), so I'm subscribing to FS events like this:
LPITEMIDLIST pidlDownloads = ::ILCreateFromPath(env::FOLDER_Downloads().c_str());
DWORD dwFlags = SHCNE_CREATE | SHCNE_DELETE | SHCNE_MKDIR | SHCNE_RENAMEFOLDER |
SHCNE_RENAMEITEM | SHCNE_RMDIR | SHCNE_UPDATEITEM | SHCNE_UPDATEDIR;
SHChangeNotifyEntry monitoredFolders[3];
monitoredFolders[0].fRecursive = TRUE;
monitoredFolders[0].pidl = pidlCommonPrograms;
monitoredFolders[1].fRecursive = TRUE;
monitoredFolders[1].pidl = pidlPrograms;
monitoredFolders[2].fRecursive = TRUE;
monitoredFolders[2].pidl = pidlDownloads;
dwFSSubscriptionID_ = ::SHChangeNotifyRegister(hWnd_,
SHCNRF_ShellLevel | SHCNRF_InterruptLevel | SHCNRF_NewDelivery,
dwFlags, WM_FOLDER_UPDATED, _countof(monitoredFolders), monitoredFolders);
if (dwFSSubscriptionID_ == 0)
{
LOGERROR << L"FS watchdog failed to start.";
}
Unfortunately, on some machines no message is sent, when I rename files. When I tried to create/delete folders, it was sent, but not when I renamed them. On other machines everything seems to be working. Why?

Related

Cannot read data from terminal until restarted by other process

Before adding O_NOCTTY option, my process was killed once by unknown per every booting. I don't know why the process was killed :( and I thought the initializing has some problems. so that I added O_NOCTTY option, and the process was not killed. But it cannot read any data from the buffer until restarted by other process. Please help me :(
The following is code about initializing and reading.
void Init() {
mFd = open("/dev/ttyS2", O_RDWR | O_NOCTTY);
if (mFd > 0)
{
(void)tcgetattr(mFd, &mTermios_p);
speed = B115200;
mTermios_p.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
mTermios_p.c_oflag &= ~OPOST;
mTermios_p.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
mTermios_p.c_cflag &= ~(CSIZE | PARENB);
mTermios_p.c_cflag |= CS8;
mTermios_p.c_cc[VMIN] = 0U;
mTermios_p.c_cc[VTIME] = 0U;
(void)cfsetispeed(&mTermios_p, speed);
(void)cfsetospeed(&mTermios_p, speed);
(void)tcflush(mFd, TCIOFLUSH);
(void)tcsetattr(mFd, TCSANOW, &mTermios_p);
}
else
{
LOGE("uart open failed %s", strerror(errno));
}
}
int32_t Read() {
int32_t bytes = -1;
if (mFd > 0)
{
(void)pthread_mutex_lock(&mMutexLock);
bytes = static_cast<int32_t>(read(mFd, buf, nMaxRead));
(void)pthread_mutex_unlock(&mMutexLock);
}
if (bytes < 0)
{
LOGE("read failed");
}
return bytes;
}
Your serial terminal initialization is essentially the near-equivalent of cfmakeraw() plus setting the baudrate.
However that is insufficient to fully initialize a serial terminal.
At the very least the receiver also has to be enabled:
mTermios_p.c_cflag |= CREAD;
To eliminate any modem handshake issues (especially when there is no modem):
mTermios_p.c_cflag |= CLOCAL;
To eliminate any hardware handshake issues:
mTermios_p.c_cflag &= ~CRTSCTS;
BTW
mTermios_p.c_cc[VMIN] = 0U;
mTermios_p.c_cc[VTIME] = 0U;
Setting both VMIN and VTIME to zero is an ill-advised configuration.
This guide describes this configuration as one that should be used only if "you really, really know what you're doing."
The code that you posted for reading is not capable of (efficiently) handling the consequences of setting both VMIN and VTIME to zero. Unless your program is synchronized with the transmitting program, your read code is likely to "successfully" read zero bytes, i.e. no data.

IOKIT Detecting BSD(unix) name for USB Serial Device with PID and VID

I am working with USB serial devices on macOS.
How can I detect BSD(unix) name have for my USB Serial device on macOS using IOKit?
I want to get device name like : "IODialinDevice" = "/dev/tty.usbmodemMyDeviceName"
My USB device is USB serial COM port.
Also I want to detect when device was attached to machine.
I can detect when new USB device with my VID and PID was connected.
This code allow me to do it
CFMutableDictionaryRef keywordDict = IOServiceMatching(kIOSerialBSDServiceValue);
kern_return_t result = IOServiceGetMatchingServices(kIOMasterPortDefault, keywordDict, &iterator);
while ((port = IOIteratorNext(iterator)))
{
io_object_t parent = 0;
io_object_t current_device = port;
while (KERN_SUCCESS == IORegistryEntryGetParentEntry(current_device, kIOServicePlane, &parent))
{
CFTypeRef vendor_Id = IORegistryEntryCreateCFProperty(parent, CFSTR(kUSBVendorID), kCFAllocatorDefault, 0);
CFTypeRef pr_Id = IORegistryEntryCreateCFProperty(parent, CFSTR(kUSBProductID), kCFAllocatorDefault, 0);
if((vendor_id==MY_VENDOR_ID) && (pr_ID==MY_PRODUCT_ID))
{
// MY SERIAL DEVICE DETECTED !!
CFTypeRef deviceName = IORegistryEntryCreateCFProperty(device, key, CFSTR(kIOTTYDeviceKey), 0);
CFTypeRef callOutDevice = IORegistryEntryCreateCFProperty(device, key, CFSTR(kIOCalloutDeviceKey), 0);
CFTypeRef dialInDevice = IORegistryEntryCreateCFProperty(device, key, CFSTR(kIODialinDeviceKey), 0);
}
}
}
But the problem that this code not allows me to detect the new device.
I just enumerate existing kIOSerialBSDServiceValue devices here and then I check parents VID and PID
If parent have MY_VID and MY_PID I assume that I have found correct serial device.
Another code allows me to detect new USB device
This is Apple example LUSBPrivateDataSample.c
I can detect my device using VID and PID with the following code
int main()
{
...
...
...
// Create a CFNumber for the idVendor and set the value in the dictionary
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor);
CFDictionarySetValue(matchingDict,
CFSTR(kUSBVendorID),
numberRef);
CFRelease(numberRef);
// Create a CFNumber for the idProduct and set the value in the dictionary
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbProduct);
CFDictionarySetValue(matchingDict,
CFSTR(kUSBProductID),
numberRef);
CFRelease(numberRef);
...
...
...
// Now set up a notification to be called when a device is first matched by I/O Kit.
kr = IOServiceAddMatchingNotification(gNotifyPort, // notifyPort
kIOFirstMatchNotification, // notificationType
matchingDict, // matching
DeviceAdded, // callback
NULL, // refCon
&gAddedIter // notification
);
}
void DeviceAdded(void *refCon, io_iterator_t iterator)
{
io_service_t usbDevice;
while ((usbDevice = IOIteratorNext(iterator)))
{
// I have device here but I can't get IODialinDevice device name
}
}
The problem with this code that I can't get IODialinDevice device name
I have also checked all child nodes for this usbDevice.
None of them contain IODialinDevice property or none of them is kIOSerialBSDServiceValue device.
Looks like I am doing it wrong.
Looks like serial devices and USB live in different IOKit registry branches.
The question is how can go from USB device identified by VID and PID to serial device (kIOSerialBSDServiceValue) with IODialinDevice ("/dev/tty.usbmodemMyDeviceName") property .
Any help appreciated!
Update:
This is ioreg tree:
I can detect CDC ACM Data device in my application. (top device in this tree)
In ioreg I see this picture. So there are children, AppleUSBACMData and IOSerialBSDClient who has IODialinDevice property.
But I can't detect AppleUSBACMData and IOSerialBSDClient in my application . Probably because AppleUSBACMData and IOSerialBSDClient are not devices, but USB Interfaces or USB Endpoints.
So this is my problem.
+-o CDC ACM Data#3 <class IOUSBHostInterface, id 0x100090fff, registered, matched, active, busy 0 (514 ms), retain 7>
| {
| "USBPortType" = 0
| "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
| "Product Name" = "DevName"
| "bcdDevice" = 1044
| "USBSpeed" = 3
| "idProduct" = 260
| "bConfigurationValue" = 1
| "bInterfaceSubClass" = 0
| "locationID" = 338886656
| "IOGeneralInterest" = "IOCommand is not serializable"
| "IOServiceLegacyMatchingRegistryID" = 4295561221
| "IOClassNameOverride" = "IOUSBInterface"
| "AppleUSBAlternateServiceRegistryID" = 4295561221
| "idVendor" = 7777
| "bInterfaceProtocol" = 0
| "bAlternateSetting" = 0
| "bInterfaceNumber" = 3
| "bInterfaceClass" = 10
| }
|
+-o AppleUSBACMData <class AppleUSBACMData, id 0x100091018, registered, matched, active, busy 0 (0 ms), retain 6>
| {
| "IOClass" = "AppleUSBACMData"
| "CFBundleIdentifier" = "com.apple.driver.usb.cdc.acm"
| "IOProviderClass" = "IOUSBHostInterface"
| "IOTTYBaseName" = "usbmodem"
| "idProduct" = 260
| "IOProbeScore" = 49999
| "bInterfaceSubClass" = 0
| "HiddenPort" = Yes
| "IOMatchCategory" = "IODefaultMatchCategory"
| "idVendor" = 7777
| "IOTTYSuffix" = "DevName_B3"
| "bInterfaceClass" = 10
| }
|
+-o IOSerialBSDClient <class IOSerialBSDClient, id 0x100091020, registered, matched, active, busy 0 (0 ms), retain 5>
{
"IOClass" = "IOSerialBSDClient"
"CFBundleIdentifier" = "com.apple.iokit.IOSerialFamily"
"IOProviderClass" = "IOSerialStreamSync"
"IOTTYBaseName" = "usbmodem"
"IOSerialBSDClientType" = "IORS232SerialStream"
"IOProbeScore" = 1000
"IOCalloutDevice" = "/dev/cu.usbmodemDevName_B3"
"IODialinDevice" = "/dev/tty.usbmodemDevName_B3"
"IOMatchCategory" = "IODefaultMatchCategory"
"IOTTYDevice" = "usbmodemDevName_B3"
"IOResourceMatch" = "IOBSD"
"IOTTYSuffix" = "DevName_B3"
}
The solution is quite simple.
It always was on my desk.
You should subscribe to receive notifications about new kIOSerialBSDServiceValue devices appears in system
Like this. This code also based on Apple USBPrivateDataSample.c
https://developer.apple.com/library/archive/samplecode/USBPrivateDataSample/Introduction/Intro.html#//apple_ref/doc/uid/DTS10000456
CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOSerialBSDServiceValue);
....
// Now set up a notification to be called when a device is first matched by I/O Kit.
kr = IOServiceAddMatchingNotification(gNotifyPort, // notifyPort
kIOFirstMatchNotification, // notificationType
matchingDict, // matching
DeviceAdded, // callback
NULL, // refCon
&gAddedIter // notification
);
When you get kIOSerialBSDServiceValue (in DeviceAdded() function) traverse up ( using IORegistryEntryGetParentEntry ) on the IOKit tree until your
find your VID and PID. (See my first code fragment in question.)
If you can't find and device tree is over this is not your device.

Understanding the "Why" of a file access code snippet

I have been trying to make sense of a code snippet for past some days. You can find the gist here
Overview
The code reads MFT of a Windows drive, creates a struct of maps of files in the MFT. Then it goes on reading the USN Journal to detect what has changed of those files.
Problem
There are some logical operations happening in the script. I can understand what the code part is doing but why is it doing so is what has been haunting me for past couple of days. I stumbled upon various Windows docs like this but even then, it did not make much sense to me.
For example -
switch mode & (O_RDONLY | O_WRONLY | O_RDWR) {
case O_RDONLY:
access = GENERIC_READ
case O_WRONLY:
access = GENERIC_WRITE
case O_RDWR:
access = GENERIC_READ | GENERIC_WRITE
}
if mode&O_CREAT != 0 {
access |= GENERIC_WRITE
}
if mode&O_APPEND != 0 {
access &^= GENERIC_WRITE
access |= FILE_APPEND_DATA
}
Why are we doing these logical operations? There are other instances of such parts in the code also. If anyone can point me to the direction or help me why these operations are done, it'd be really helpful. Thanks
It is a conversion from the Linux (POSIX) API open (man 2 open; http://man7.org/linux/man-pages/man2/open.2.html) to the Windows API CreateFile (https://learn.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilew).
For the original code, see src/syscall/syscall_windows.go (https://go.googlesource.com/go):
func Open(path string, mode int, perm uint32) (fd Handle, err error) {
if len(path) == 0 {
return InvalidHandle, ERROR_FILE_NOT_FOUND
}
pathp, err := UTF16PtrFromString(path)
if err != nil {
return InvalidHandle, err
}
var access uint32
switch mode & (O_RDONLY | O_WRONLY | O_RDWR) {
case O_RDONLY:
access = GENERIC_READ
case O_WRONLY:
access = GENERIC_WRITE
case O_RDWR:
access = GENERIC_READ | GENERIC_WRITE
}
if mode&O_CREAT != 0 {
access |= GENERIC_WRITE
}
if mode&O_APPEND != 0 {
access &^= GENERIC_WRITE
access |= FILE_APPEND_DATA
}
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)
var sa *SecurityAttributes
if mode&O_CLOEXEC == 0 {
sa = makeInheritSa()
}
var createmode uint32
switch {
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
createmode = CREATE_NEW
case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
createmode = CREATE_ALWAYS
case mode&O_CREAT == O_CREAT:
createmode = OPEN_ALWAYS
case mode&O_TRUNC == O_TRUNC:
createmode = TRUNCATE_EXISTING
default:
createmode = OPEN_EXISTING
}
h, e := CreateFile(pathp, access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
return h, e
}

Using Win32, GetModuleBaseName() and GetModuleFileNameEx() fail with GetLastError() = 6 when using valid handle

First some simple code snippet:
m_hProcessHandle = ::OpenProcess((PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_DUP_HANDLE | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION), FALSE, m_dwProcessIdentifier);
if (NULL != m_hProcessHandle)
{
if (FALSE != ::OpenProcessToken(m_hProcessHandle, (TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE), &m_hImpersonizationToken))
{
wchar_t wszFullExecutableFileName[MAX_PATH];
if (0 == ::GetModuleBaseName(m_hProcessHandle, NULL, wszFullExecutableFileName, (sizeof(wszFullExecutableFileName)/sizeof(wchar_t))))
{
__DebugMessage(L"GetModuleBaseName() failed with GetLastError() = %d", ::GetLastError());
}
else
{
if (0 == ::GetModuleFileNameEx(m_hProcessHandle, NULL, wszFullExecutableFileName, (sizeof(wszFullExecutableFileName)/sizeof(wchar_t))))
{
__DebugMessage(L"GetModuleFileNameEx() failed with GetLastError() = %d", ::GetLastError());
}
else
{
m_strFullFileName = wszFullExecutableFileName;
}
}
}
}
The OpenProcess() returns a valid handle as does the OpenProcessToken(), but when I call the subsequent GetModuleBaseName() and GetModuleFileNameEx() functions, I get GetLastError() = 6 (The handle is invalid). I am running that code as admin on Windows 7. What gives?
cheers,
GumbyTheBorg
You must run this program as administrator in order for it to work correctly. I just tested it working and GetLastError() = 0 after each line, which means there were no problems.

OSX semaphores: Invalid argument in sem_open

While trying to open a semaphore sem_open fails. errno is 22 (), which perror describes as "Invalid argument". I've checked the format of the name (which I think is correct), as well as the flags (O_CREAT and O_EXCL seem pretty hard to mess up. What am I not seeing?
Platform is OS X 10.7. I would have preferred to use a nameless semaphore, but the OS doesn't support sem_init.
int name_counter = 0;
// In order to create a unique semaphore, we iterate until we find a name that
// does not already exist.
do {
char name[48] = {0};
sprintf(name, "xyz_sem_%d", name_counter++);
job_semaphore = sem_open(name, O_CREAT | O_EXCL, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, 0);
} while(errno == EEXIST);
if(0 != errno)
perror("Error opening xyz semaphore");
assert(0 == errno);
I've tried both
sem_open(name, O_CREAT | O_EXCL);
and
sem_open(name, O_CREAT | O_EXCL, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH, 0);
to open the semaphore, but get the same result with each. What am I missing?
EDIT: the version above with only two parameters is wrong- the man page says that when including O_CREAT, you must provide all 4 parameters.
EDIT2: errno is only valid when the function returns an error code. In this case, I should have looked at errno only when sem_open returned SEM_FAILED. I didn't do this, and was examining errno when a perfectly good semaphore had been returned. Problem solved.
Before trying sem_open, try sem_unlink()
name should have a leading slash. Try put a "/" in front of name.
ie. sprintf(name, "/xyz_sem_%d", name_counter++);

Resources