Properly handle cases of multiple inotify events

Bug: 8469799
Change-Id: Ie10242dd05becd142cc84651d5e5795e4c02270d
Signed-off-by: Igor Murashkin <iam@google.com>
Signed-off-by: Adam Hampson <ahampson@google.com>
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 167fa60..b967342 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -223,56 +223,61 @@
     char event_buf[512];
     char path[100];
     int i, ret, done = 0;
-    int j, event_size;
+    int offset = 0;
     int wd;
 
     ret = read(context->fd, event_buf, sizeof(event_buf));
     if (ret >= (int)sizeof(struct inotify_event)) {
-        event = (struct inotify_event *)event_buf;
-        wd = event->wd;
-        if (wd == context->wdd) {
-            if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) {
-                watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
-                done = find_existing_devices(context->cb_added, context->data);
-            } else if ((event->mask & IN_DELETE) && !strcmp(event->name, "bus")) {
-                for (i = 0; i < MAX_USBFS_WD_COUNT; i++) {
-                    if (context->wds[i] >= 0) {
+        while (offset < ret) {
+            event = (struct inotify_event*)&event_buf[offset];
+            done = 0;
+            wd = event->wd;
+            if (wd == context->wdd) {
+                if ((event->mask & IN_CREATE) && !strcmp(event->name, "bus")) {
+                    watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT);
+                    done = find_existing_devices(context->cb_added, context->data);
+                } else if ((event->mask & IN_DELETE) && !strcmp(event->name, "bus")) {
+                    for (i = 0; i < MAX_USBFS_WD_COUNT; i++) {
+                        if (context->wds[i] >= 0) {
+                            inotify_rm_watch(context->fd, context->wds[i]);
+                            context->wds[i] = -1;
+                        }
+                    }
+                }
+            } else if (wd == context->wds[0]) {
+                i = atoi(event->name);
+                snprintf(path, sizeof(path), USB_FS_DIR "/%s", event->name);
+                D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
+                        "new" : "gone", path, i);
+                if (i > 0 && i < MAX_USBFS_WD_COUNT) {
+                    if (event->mask & IN_CREATE) {
+                        ret = inotify_add_watch(context->fd, path,
+                                IN_CREATE | IN_DELETE);
+                        if (ret >= 0)
+                            context->wds[i] = ret;
+                        done = find_existing_devices_bus(path, context->cb_added,
+                                context->data);
+                    } else if (event->mask & IN_DELETE) {
                         inotify_rm_watch(context->fd, context->wds[i]);
                         context->wds[i] = -1;
                     }
                 }
-            }
-        } else if (wd == context->wds[0]) {
-            i = atoi(event->name);
-            snprintf(path, sizeof(path), USB_FS_DIR "/%s", event->name);
-            D("%s subdirectory %s: index: %d\n", (event->mask & IN_CREATE) ?
-                    "new" : "gone", path, i);
-            if (i > 0 && i < MAX_USBFS_WD_COUNT) {
-                if (event->mask & IN_CREATE) {
-                    ret = inotify_add_watch(context->fd, path,
-                            IN_CREATE | IN_DELETE);
-                    if (ret >= 0)
-                        context->wds[i] = ret;
-                    done = find_existing_devices_bus(path, context->cb_added,
-                            context->data);
-                } else if (event->mask & IN_DELETE) {
-                    inotify_rm_watch(context->fd, context->wds[i]);
-                    context->wds[i] = -1;
-                }
-            }
-        } else {
-            for (i = 1; (i < MAX_USBFS_WD_COUNT) && !done; i++) {
-                if (wd == context->wds[i]) {
-                    snprintf(path, sizeof(path), USB_FS_DIR "/%03d/%s", i, event->name);
-                    if (event->mask == IN_CREATE) {
-                        D("new device %s\n", path);
-                        done = context->cb_added(path, context->data);
-                    } else if (event->mask == IN_DELETE) {
-                        D("gone device %s\n", path);
-                        done = context->cb_removed(path, context->data);
+            } else {
+                for (i = 1; (i < MAX_USBFS_WD_COUNT) && !done; i++) {
+                    if (wd == context->wds[i]) {
+                        snprintf(path, sizeof(path), USB_FS_DIR "/%03d/%s", i, event->name);
+                        if (event->mask == IN_CREATE) {
+                            D("new device %s\n", path);
+                            done = context->cb_added(path, context->data);
+                        } else if (event->mask == IN_DELETE) {
+                            D("gone device %s\n", path);
+                            done = context->cb_removed(path, context->data);
+                        }
                     }
                 }
             }
+
+            offset += sizeof(struct inotify_event) + event->len;
         }
     }