What solves a ‘inotify_add_watch’ error ‘no such file or directory’ on recursively adding sub directories?

  Kiến thức lập trình

This example should add an ‘inotify_add_watch’ functionality for a newly created subsequent directory within a given path (for example: /tmp), but does not add that watch function for the newly created directory (for example: /tmp/subdir1/subdir2).

Only for the root path directory (/tmp) level, given by argv[1], it is functional (for example: /tmp/subdir1). The returned watch descriptor (variable ‘watch_fd’) is increased.
For a directory created in a more distant tree position (/tmp/subdir1/subdir2) from root directory (/tmp), there’s that ‘no such file or directory’ error. The returned watch descriptor ‘watch_fd’ then is -1.

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <limits.h>
#include <string.h>

#define EVENT_SIZE (sizeof(struct inotify_event))
#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))

// Function to add inotify watch recursively up to a specified depth
void add_watch_recursive(int inotify_fd, const char *base_path, int depth, int current_depth) {
    if (current_depth > depth) {
        return;
    }

    printf("base_path %s t", base_path);
    int watch_fd = inotify_add_watch(inotify_fd, base_path, IN_CREATE | IN_DELETE);
    printf("watch_fd %d n", watch_fd);
    if (watch_fd < 0) {
        perror("inotify_add_watch");
        printf("ttt 'inotify_add_watch: No such file or directory' watch_fd %dn", watch_fd);
        return;
    }


    DIR *dir = opendir(base_path);
    if (!dir) {
        perror("opendir");
        return;
    }

    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        char path[PATH_MAX];
        snprintf(path, PATH_MAX, "%s/%s", base_path, entry->d_name);

        struct stat statbuf;
        if (stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
            add_watch_recursive(inotify_fd, path, depth, current_depth + 1);
        }
    }

    closedir(dir);
}

int main(int argc, char *argv[]) {
    if (argc < 3) {
        fprintf(stderr, "Usage: %s <path> <depth>n", argv[0]);
        return EXIT_FAILURE;
    }

    const char *path = argv[1];
    int depth = atoi(argv[2]);

    if (depth < 0) {
        fprintf(stderr, "Error: Depth must be a non-negative integern");
        return EXIT_FAILURE;
    }

    // Print the path to verify it
    printf("Attempting to open directory: %sn", path);

    // Check if the directory exists
    struct stat statbuf;
    if (stat(path, &statbuf) != 0) {
        perror("stat");
        return EXIT_FAILURE;
    }

    // Check if it is a directory
    if (!S_ISDIR(statbuf.st_mode)) {
        fprintf(stderr, "Error: %s is not a directoryn", path);
        return EXIT_FAILURE;
    }

    // Initialize inotify
    int inotify_fd = inotify_init();
    if (inotify_fd < 0) {
        perror("inotify_init");
        return EXIT_FAILURE;
    }

    // Add watch on the specified directory and its subdirectories up to the specified depth
    add_watch_recursive(inotify_fd, path, depth, 0);

    printf("Watching directory: %s and its subdirectories up to depth: %dn", path, depth);

    // Buffer to store inotify events
    char buffer[EVENT_BUF_LEN];

    // Event loop
    while (1) {
        int length = read(inotify_fd, buffer, EVENT_BUF_LEN);
        if (length < 0) {
            perror("read");
            break;
        }

        int i = 0;
        while (i < length) {
            struct inotify_event *event = (struct inotify_event *) &buffer[i];
            if (event->len) {
                char event_path[PATH_MAX];
                snprintf(event_path, PATH_MAX, "%s/%s", path, event->name);

                if (event->mask & IN_CREATE) {
                    if (event->mask & IN_ISDIR) {
                        printf("Directory created: %sn", event_path);
                        // Add watch to the new directory if within the specified depth
                        add_watch_recursive(inotify_fd, event_path, depth, 1);
                    } else {
                        printf("File created: %sn", event_path);
                    }
                } else if (event->mask & IN_DELETE) {
                    if (event->mask & IN_ISDIR) {
                        printf("Directory deleted: %sn", event_path);
                    } else {
                        printf("File deleted: %sn", event_path);
                    }
                }
            }
            i += EVENT_SIZE + event->len;
        }
    }

    // Clean up
    close(inotify_fd);

    return EXIT_SUCCESS;
}

This example code for a C program for Linux system is compiled with
gcc inotifyaddwatch_subdirs.c -o inotifyaddwatch_subdirs and
started with
./inotifyaddwatch_subdirs /tmp 5 .

Only with restarting the program, a subsequent directory is added from startup, but not within the running program.

If it is a pointer error for a sub directory’s singular path reference within the line
int watch_fd = inotify_add_watch(inotify_fd, base_path, IN_CREATE | IN_DELETE);
for the variable ‘base_path’, then it would need an additional exception handling.

The man pages for ‘inotify_add_watch’ explains for this error return value
“ENOENT A directory component in pathname does not exist or is a dangling symbolic link.”,
but i did not succeed in adding that sub directory path (proved to exist and being recognized within that program) to that pathname pointer array.

Theme wordpress giá rẻ Theme wordpress giá rẻ Thiết kế website

LEAVE A COMMENT