fanotify(7)

الاسم
fanotify - مراقبة أحداث نظام الملفات

الوصف
توفر واجهة برمجة تطبيقات fanotify إشعارات واعتراضًا لأحداث نظام الملفات. تشمل حالات الاستخدام فحص الفيروسات وإدارة التخزين الهرمي. في واجهة fanotify الأصلية، دُعمت مجموعة محدودة فقط من الأحداث. على وجه الخصوص، لم يتوفر دعم لأحداث الإنشاء والحذف والنقل. أُضيف الدعم لهذه الأحداث في لينكس 5.1. (انظر inotify(7) لتفاصيل واجهة برمجة التطبيقات التي كانت تُشعر بتلك الأحداث قبل إصدار لينكس 5.1.)

تشمل القدرات الإضافية مقارنة بواجهة inotify(7) القدرة على مراقبة جميع الكائنات في نظام ملفات موصول، والقدرة على اتخاذ قرارات أذونات الوصول، وإمكانية قراءة الملفات أو تعديلها قبل وصول التطبيقات الأخرى إليها.

تُستخدم استدعاءات النظام التالية مع هذه الواجهة: fanotify_init(2)، و fanotify_mark(2)، و read(2)، و write(2)، و close(2).

  fanotify_init()‎، و fanotify_mark()‎، ومجموعات الإشعارات
يُنشئ استدعاء النظام fanotify_init(2) مجموعة إشعارات fanotify ويُهيئها ويعيد واصف ملف يشير إليها.

مجموعة إشعارات fanotify هي كائن داخلي في النواة يحمل قائمة بالملفات، والأدلة، وأنظمة الملفات، والوصولات التي يجب إنشاء أحداث لها.

لكل مدخلة في مجموعة إشعارات fanotify، يوجد قناعان من البتات: قناع mark وقناع ignore. يحدد قناع العلامة (mark) أنشطة الملفات التي يجب إنشاء حدث لها. ويحدد قناع التجاهل (ignore) الأنشطة التي لا يجب توليد أحداث لها. يسمح وجود هذين النوعين من الأقنعة بوسم نظام ملفات أو وصلة أو دليل لاستلام الأحداث، وفي الوقت نفسه تجاهل الأحداث لكائنات محددة تحت تلك الوصلة أو الدليل.

يضيف استدعاء النظام fanotify_mark(2) ملفًا أو دليلاً أو نظام ملفات أو وصلة إلى مجموعة إشعارات ويحدد الأحداث التي يجب الإبلاغ عنها (أو تجاهلها)، أو يزيل أو يعدل مثل هذه المدخلة.

من الاستخدامات الممكنة لقناع التجاهل هي خبيئة الملفات. الأحداث المهمة لخبيئة الملفات هي تعديل الملف وإغلاقه. لذا، يوسم الدليل أو الوصلة المخبأة لاستلام هذه الأحداث. بعد استلام أول حدث يفيد بتعديل ملف ما، ستُبطل مدخلة الخبيئة المقابلة. لا تهم أي أحداث تعديل إضافية لهذا الملف حتى يُغلق. لذا، يمكن إضافة حدث التعديل إلى قناع التجاهل. وعند استلام حدث الإغلاق، يمكن إزالة حدث التعديل من قناع التجاهل وتحديث مدخلة خبيئة الملف.

تشير المدخلات في مجموعات إشعارات fanotify إلى الملفات والأدلة عبر رقم inode الخاص بها وإلى الوصلات عبر معرف الوصلة (mount ID). إذا أُعيدت تسمية الملفات أو الأدلة أو نُقلت ضمن نفس الوصلة، فإن المدخلات المعنية تبقى. أما إذا حُذفت الملفات أو الأدلة أو نُقلت إلى وصلة أخرى أو إذا فُصلت أنظمة الملفات أو الوصلات، فستُحذف المدخلات المقابلة.

  طابور الأحداث
عند وقوع أحداث على كائنات نظام الملفات المراقبة بواسطة مجموعة إشعارات، يولد نظام fanotify أحداثًا تُجمع في طابور. يمكن بعد ذلك قراءة هذه الأحداث (باستخدام read(2) أو ما شابه) من واصف ملف fanotify الذي أعاده fanotify_init(2).

يولَّد نوعان من الأحداث: أحداث إشعار وأحداث إذن. أحداث الإشعار هي معلوماتية فقط ولا تتطلب اتخاذ أي إجراء من قبل التطبيق المستلم باستثناء حالة واحدة: إذا وُفر واصف ملف صالح ضمن حدث عام، فيجب إغلاق واصف الملف هذا. أحداث الإذن هي طلبات للتطبيق المستلم ليقرر ما إذا كان سيُمنح إذن للوصول إلى الملف أم لا. بالنسبة لهذه الأحداث، يجب على المستلم كتابة رد يقرر ما إذا كان سيُسمح بالوصول أم لا.

يُزال الحدث من طابور أحداث مجموعة fanotify عند قراءته. أحداث الإذن التي قُرئت تُحفظ في قائمة داخلية لمجموعة fanotify حتى يتم اتخاذ قرار بشأن الإذن عن طريق الكتابة إلى واصف ملف fanotify أو حتى يُغلق واصف ملف fanotify.

  قراءة أحداث fanotify
استدعاء read(2) لواصف الملف الذي أعاده fanotify_init(2) يحجب (إذا لم يُحدد علم FAN_NONBLOCK في استدعاء fanotify_init(2)) حتى يقع حدث ملف أو يُقاطع الاستدعاء بإشارة (انظر signal(7)).

بعد نجاح read(2)، ستحتوي مخبأة القراءة على بنية واحدة أو أكثر من البنى التالية:

    struct fanotify_event_metadata {
        __u32 event_len;
        __u8 vers;
        __u8 reserved;
        __u16 metadata_len;
        __aligned_u64 mask;
        __s32 fd;
        __s32 pid;
    };

سجلات المعلومات هي قطع تكميلية من المعلومات التي قد تُوفر جنباً إلى جنب مع بنية fanotify_event_metadata العامة. تؤثر الـ flags الممررة إلى fanotify_init(2) على نوع سجلات المعلومات التي قد تُعاد لحدث ما. على سبيل المثال، إذا هُيئت مجموعة إشعارات باستخدام FAN_REPORT_FID أو FAN_REPORT_DIR_FID، فيجب على مستمعي الأحداث توقع استلام بنية fanotify_event_info_fid مع بنية fanotify_event_metadata، حيث تُستخدم مقابض الملفات لتحديد كائنات نظام الملفات بدلاً من واصفات الملفات. يمكن أيضاً تكديم سجلات المعلومات، مما يعني أن استخدام أعلام FAN_REPORT_* المتنوعة مع بعضها البعض أمر مدعوم. في هذه الحالات، يمكن إعادة سجلات معلومات متعددة لحدث ما. على سبيل المثال، إذا هُيئت مجموعة إشعارات باستخدام FAN_REPORT_TARGET_FID و FAN_REPORT_PIDFD، فيجب على مستمع الأحداث توقع استلام ما يصل إلى سجلي معلومات fanotify_event_info_fid وسجل معلومات fanotify_event_info_pidfd واحد. والأهم من ذلك، لا يوفر fanotify أي ضمانات حول ترتيب سجلات المعلومات عند تهيئة مجموعة إشعارات بتكوين مكدس. لكل سجل معلومات بنية متداخلة من نوع fanotify_event_info_header. من الضروري لمستمعي الأحداث فحص حقل info_type في هذه البنية لتحديد نوع سجل المعلومات الذي استُلم لحدث معين.

في الحالات التي تحدد فيها مجموعة fanotify كائنات نظام الملفات عن طريق مقابض الملفات، يجب على مستمعي الأحداث أيضاً توقع استلام واحد أو أكثر من كائنات سجل المعلومات أدناه مع بنية fanotify_event_metadata العامة داخل مخبأة القراءة:

    struct fanotify_event_info_fid {
        struct fanotify_event_info_header hdr;
        __kernel_fsid_t fsid;
        unsigned char handle[];
    };

في الحالات التي تُهيأ فيها مجموعة fanotify باستخدام FAN_REPORT_PIDFD، يجب على مستمعي الأحداث توقع استلام كائن سجل المعلومات أدناه مع بنية fanotify_event_metadata العامة داخل مخبأة القراءة:

    struct fanotify_event_info_pidfd {
            struct fanotify_event_info_header hdr;
            __s32 pidfd;
    };

في الحالات التي تُهيأ فيها مجموعة fanotify باستخدام FAN_REPORT_MNT، يجب على مستمعي الأحداث توقع استلام كائن سجل المعلومات أدناه مع بنية fanotify_event_metadata العامة داخل مخبأة القراءة. تُعرف هذه البنية كالتالي:

    struct fanotify_event_info_mnt {
        struct fanotify_event_info_header hdr;
        __u64 mnt_id;
    };

في حالة حدث FAN_FS_ERROR، يُعاد سجل معلومات إضافي يصف الخطأ الذي حدث مع بنية fanotify_event_metadata العامة داخل مخبأة القراءة. تُعرف هذه البنية كالتالي:

    struct fanotify_event_info_error {
        struct fanotify_event_info_header hdr;
        __s32 error;
        __u32 error_count;
    };

في حالة أحداث FAN_PRE_ACCESS، يُعاد سجل معلومات إضافي يصف نطاق الوصول مع بنية fanotify_event_metadata العامة داخل مخبأة القراءة. تُعرف هذه البنية كالتالي:

    struct fanotify_event_info_range {
        struct fanotify_event_info_header hdr;
        __u32 pad;
        __u64 offset;
        __u64 count;
    };

تحتوي جميع سجلات المعلومات على بنية متداخلة من نوع fanotify_event_info_header. تحمل هذه البنية معلومات وصفية حول سجل المعلومات الذي قد يكون قد أعيد مع بنية fanotify_event_metadata العامة. تُعرف هذه البنية كالتالي:

    struct fanotify_event_info_header {
    	__u8 info_type;
    	__u8 pad;
    	__u16 len;
    };

لأسباب تتعلق بالأداء، يوصى باستخدام حجم مخبأة كبير (على سبيل المثال، 4096 بايت)، بحيث يمكن جلب أحداث متعددة من خلال استدعاء read(2) واحد.

قيمة الإرجاع لـ read(2) هي عدد البايتات التي وُضعت في المخبأة، أو -1 في حالة حدوث خطأ (لكن انظر قسم BUGS).

حقول بنية fanotify_event_metadata هي كما يلي:

event_len
    هذا هو حجم بيانات الحدث الحالي والإزاحة إلى الحدث التالي في المخبأة. ما لم تحدد المجموعة كائنات نظام الملفات عن طريق مقابض الملفات، فإن قيمة event_len هي دائماً FAN_EVENT_METADATA_LEN. بالنسبة للمجموعة التي تحدد كائنات نظام الملفات عن طريق مقابض الملفات، فإن event_len يشمل أيضاً سجلات معرف الملف ذات الحجم المتغير.

vers
    يحمل هذا الحقل رقم إصدار البنية. يجب مقارنته بـ FANOTIFY_METADATA_VERSION للتحقق من أن البنى التي أُعيدت في وقت التشغيل تطابق البنى المحددة في وقت التصريف. في حالة عدم التطابق، يجب على التطبيق التخلي عن محاولة استخدام واصف ملف fanotify.

reserved
    هذا الحقل غير مستخدم.

metadata_len
    هذا هو حجم البنية. قُدم هذا الحقل لتسهيل تنفيذ ترويسات اختيارية لكل نوع حدث. لا توجد مثل هذه الترويسات الاختيارية في التنفيذ الحالي.

mask
    هذا قناع بتات يصف الحدث (انظر أدناه).

fd  هذا واصف ملف مفتوح للكائن الذي يتم الوصول إليه، أو FAN_NOFD في حالة حدوث طوفان في الطابور. مع مجموعة fanotify التي تحدد كائنات نظام الملفات عن طريق مقابض الملفات، يجب أن تتوقع التطبيقات ضبط هذه القيمة على FAN_NOFD لكل حدث يُستلم. يمكن استخدام واصف الملف للوصول إلى محتويات الملف أو الدليل المراقب. التطبيق القارئ مسؤول عن إغلاق واصف الملف هذا.

    عند استدعاء fanotify_init(2)، قد يحدد المستدعِي (عبر وسيط event_f_flags) أعلام حالة ملف متنوعة ليتم ضبطها على وصف الملف المفتوح الذي يقابل واصف الملف هذا. بالإضافة إلى ذلك، يُضبط علم حالة الملف FMODE_NONOTIFY (الداخلي للنواة) على وصف الملف المفتوح. هذا العلم يكبح توليد أحداث fanotify. ومن ثم، عندما يصل مستلم حدث fanotify إلى الملف أو الدليل المُشعر به باستخدام واصف الملف هذا، لن تُنشأ أي أحداث إضافية.

    عند تهيئة مجموعة fanotify باستخدام FAN_REPORT_FD_ERROR، سيحتوي هذا الحقل على قيمة خطأ سالبة في حالة تعذر فتح واصف ملف، وفي حالة طوفان الطابور، ستكون القيمة -EBADF.

pid إذا ضُبط العلم FAN_REPORT_TID في fanotify_init(2)، فهذا هو معرف الخيط (TID) للخيط الذي تسبب في الحدث. وإلا، فهذا هو معرف العملية (PID) للعملية التي تسببت في الحدث.

يمكن لبرنامج يستمع إلى أحداث fanotify مقارنة معرف العملية (PID) هذا بالمعرف الذي يعيده getpid(2)، لتحديد ما إذا كان الحدث ناتجاً عن المستمع نفسه، أو بسبب وصول لملف من قبل عملية أخرى.

يشير قناع البتات في mask إلى الأحداث التي وقعت لكائن نظام ملفات واحد. قد تُضبط بتات متعددة في هذا القناع إذا وقع أكثر من حدث لكائن نظام الملفات المراقب. على وجه الخصوص، قد تُدمج الأحداث المتتالية لنفس كائن نظام الملفات والناتجة عن نفس العملية في حدث واحد، باستثناء أحداث الإذن حيث لا تُدمج أبداً في مدخلة طابور واحدة.

البتات التي قد تظهر في mask هي كما يلي:

FAN_ACCESS
    وُصل إلى ملف أو دليل (قراءة) (لكن انظر قسم BUGS).

FAN_OPEN
    فُتح ملف أو دليل.

FAN_OPEN_EXEC
    فُتح ملف بقصد تنفيذه. انظر قسم NOTES في fanotify_mark(2) لمزيد من التفاصيل.

FAN_ATTRIB
    غُيرت البيانات الوصفية لملف أو دليل.

FAN_CREATE
    أُنشئ ملف أو دليل ابن في دليل أب مراقب.

FAN_DELETE
    حُذف ملف أو دليل ابن في دليل أب مراقب.

FAN_DELETE_SELF
    حُذف ملف أو دليل مراقب.

FAN_RENAME
    نُقل ملف أو دليل من أو إلى دليل أب مراقب.

FAN_MOVED_FROM
    نُقل ملف أو دليل من دليل أب مراقب.

FAN_MOVED_TO
    نُقل ملف أو دليل إلى دليل أب مراقب.

FAN_MOVE_SELF
    نُقل ملف أو دليل مراقب.

FAN_MODIFY
    عُدل ملف.

FAN_CLOSE_WRITE
    أُغلق ملف كان مفتوحاً للكتابة (O_WRONLY أو O_RDWR).

FAN_CLOSE_NOWRITE
    أُغلق ملف أو دليل كان مفتوحاً للقراءة فقط (O_RDONLY).

FAN_MNT_ATTACH
    وُصلت وصلة بمساحة أسماء الوصل.

FAN_MNT_DETACH
    فُصلت وصلة من مساحة أسماء الوصل.

FAN_FS_ERROR
    كُشف عن خطأ في نظام الملفات.

FAN_Q_OVERFLOW
    تجاوز طابور الأحداث الحد المسموح به لعدد الأحداث. يمكن تخطي هذا الحد عن طريق تحديد علم FAN_UNLIMITED_QUEUE عند استدعاء fanotify_init(2).

FAN_ACCESS_PERM
    يريد تطبيق قراءة ملف أو دليل، على سبيل المثال باستخدام read(2) أو readdir(2). يجب على القارئ كتابة رد (كما هو موضح أدناه) يحدد ما إذا كان سيُمنح إذن للوصول إلى كائن نظام الملفات.

FAN_OPEN_PERM
    يريد تطبيق فتح ملف أو دليل. يجب على القارئ كتابة رد يحدد ما إذا كان سيُمنح إذن لفتح كائن نظام الملفات.

FAN_OPEN_EXEC_PERM
    يريد تطبيق ما فتح ملف للتنفيذ. يجب على القارئ كتابة استجابة تحدد ما إذا كان سيُمنح إذن فتح كائن نظام الملفات للتنفيذ. راجع الملاحظات (NOTES) في fanotify_mark(2) لمزيد من التفاصيل.

للتحقق من أي حدث إغلاق، يمكن استخدام قناع البتات التالي:

FAN_CLOSE
    أُغلق ملف. هذا مرادف لـ:

        FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE

للتحقق من أي حدث نقل، يمكن استخدام قناع البتات التالي:

FAN_MOVE
    نُقل ملف أو دليل. هذا مرادف لـ:

        FAN_MOVED_FROM | FAN_MOVED_TO

قد تظهر البتات التالية في mask فقط بالاقتران مع بتات أنواع أحداث أخرى:

FAN_ONDIR
    الأحداث الموضحة في mask وقعت على كائن دليل. يتطلب الإبلاغ عن الأحداث في الأدلة ضبط هذه الراية في قناع العلامة. راجع fanotify_mark(2) لمزيد من التفاصيل. يُبلغ عن الراية FAN_ONDIR في قناع الحدث فقط إذا كانت مجموعة fanotify تحدد كائنات نظام الملفات عن طريق مقابض الملفات.

سجلات المعلومات التي تُوفر جنباً إلى جنب مع هيكل fanotify_event_metadata العام ستحتوي دائماً على هيكل متداخل من نوع fanotify_event_info_header. حقول fanotify_event_info_header هي كما يلي:

info_type
    قيمة عددية فريدة تمثل نوع كائن سجل المعلومات المُستلم لحدث ما. يمكن ضبط قيمة هذا الحقل على أحد الخيارات التالية.

    FAN_EVENT_INFO_TYPE_FID
    FAN_EVENT_INFO_TYPE_DFID
    FAN_EVENT_INFO_TYPE_DFID_NAME
    FAN_EVENT_INFO_TYPE_PIDFD
    FAN_EVENT_INFO_TYPE_ERROR
    FAN_EVENT_INFO_TYPE_RANGE
    FAN_EVENT_INFO_TYPE_MNT

    تعتمد القيمة المضبوطة لهذا الحقل على الرايات التي تم تزويدها لـ fanotify_init(2). ارجع إلى تفاصيل الحقول لكل نوع كائن سجل معلومات أدناه لفهم الحالات المختلفة التي يمكن فيها ضبط قيم info_type.

pad هذا الحقل غير مُستخدم حالياً من قبل أي نوع كائن سجل معلومات، ولذلك يُضبط على الصفر.

len تُضبط قيمة len على حجم كائن سجل المعلومات، بما في ذلك fanotify_event_info_header. لا يُتوقع أن يكون الحجم الإجمالي لجميع سجلات المعلومات الإضافية أكبر من (event_len - metadata_len).

حقول هيكل fanotify_event_info_fid هي كما يلي:

hdr هذا هيكل من نوع fanotify_event_info_header. على سبيل المثال، عندما يُنشأ واصف ملف fanotify باستخدام FAN_REPORT_FID، يُتوقع إرفاق سجل معلومات واحد بالحدث مع قيمة حقل info_type هي FAN_EVENT_INFO_TYPE_FID. عندما يُنشأ واصف ملف fanotify باستخدام مزيج من FAN_REPORT_FID و FAN_REPORT_DIR_FID، قد يكون هناك سجلان للمعلومات مرفقان بالحدث: أحدهما بقيمة حقل info_type هي FAN_EVENT_INFO_TYPE_DFID، للتعريف بكائن دليل أب، والآخر بقيمة حقل info_type هي FAN_EVENT_INFO_TYPE_FID، للتعريف بكائن ابن. لاحظ أنه بالنسبة لأحداث تعديل مدخلات الدليل FAN_CREATE و FAN_DELETE و FAN_MOVE و FAN_RENAME، لا يُبلغ عن سجل معلومات يحدد الكائن الابن المنشأ/المحذوف/المنقول إلا إذا بُدئت مجموعة fanotify باستخدام الراية FAN_REPORT_TARGET_FID.

fsid
    هذا معرف فريد لنظام الملفات الذي يحتوي على الكائن المرتبط بالحدث. هو هيكل من نوع __kernel_fsid_t ويحتوي على نفس قيمة f_fsid عند استدعاء statfs(2). لاحظ أن بعض أنظمة الملفات (مثل fuse(4)) تبلغ عن fsid بصفر. في هذه الحالات، لا يمكن استخدام fsid لربط الحدث بمثيل معين لنظام الملفات، لذا فإن مراقبة مثيلات أنظمة ملفات مختلفة تبلغ عن fsid بصفر باستخدام نفس مجموعة fanotify غير مدعومة.

handle
    يحتوي هذا الحقل على هيكل متغير الحجم من نوع struct file_handle. هو مقبض مبهم يتوافق مع كائن محدد في نظام ملفات كما يعيده name_to_handle_at(2). يمكن استخدامه لتعريف ملف بشكل فريد في نظام ملفات ويمكن تمريره كمعامل لـ open_by_handle_at(2). إذا كانت قيمة حقل info_type هي FAN_EVENT_INFO_TYPE_DFID_NAME، يتبع مقبض الملف سلسلة نصية منتهية بصفر تحدد اسم مدخل الدليل المنشأ/المحذوف/المنقول. بالنسبة للأحداث الأخرى مثل FAN_OPEN و FAN_ATTRIB و FAN_DELETE_SELF و FAN_MOVE_SELF، إذا كانت قيمة حقل info_type هي FAN_EVENT_INFO_TYPE_FID، فإن handle يحدد الكائن المرتبط بالحدث. إذا كانت قيمة حقل info_type هي FAN_EVENT_INFO_TYPE_DFID، فإن handle يحدد كائن الدليل المرتبط بالحدث أو الدليل الأب لكائن ليس دليلاً ومرتبط بالحدث. إذا كانت قيمة حقل info_type هي FAN_EVENT_INFO_TYPE_DFID_NAME، فإن handle يحدد نفس كائن الدليل الذي سيُبلغ عنه باستخدام FAN_EVENT_INFO_TYPE_DFID، ويتبع مقبض الملف سلسلة نصية منتهية بصفر تحدد اسم مدخل الدليل في ذلك الدليل، أو '.' لتعريف كائن الدليل نفسه.

حقول هيكل fanotify_event_info_pidfd هي كما يلي:

hdr هذا هيكل من نوع fanotify_event_info_header. عندما تُبدأ مجموعة fanotify باستخدام FAN_REPORT_PIDFD، تُضبط قيمة حقل info_type في fanotify_event_info_header على FAN_EVENT_INFO_TYPE_PIDFD.

pidfd
    هذا واصف ملف عملية يشير إلى العملية المسؤولة عن توليد الحدث. واصف ملف العملية المُعاد لا يختلف عن ذلك الذي يمكن الحصول عليه يدوياً إذا استدعي pidfd_open(2) على fanotify_event_metadata.pid. في حالة مواجهة خطأ أثناء إنشاء pidfd، قد يُعاد أحد نوعي أخطاء محتملين ممثلين بقيمة صحيحة سالبة في حقل pidfd هذا. في الحالات التي تنتهي فيها العملية المسؤولة عن توليد الحدث قبل أن يتمكن مستمع الأحداث من قراءة الأحداث من طابور الإشعارات، يُعاد FAN_NOPIDFD. يُنفذ إنشاء pidfd للحدث فقط في وقت قراءة الأحداث من طابور الإشعارات. تُمثل جميع إخفاقات إنشاء pidfd المحتملة الأخرى بـ FAN_EPIDFD. بمجرد أن يتعامل مستمع الحدث مع الحدث ولم يعد الـ pidfd مطلوباً، يجب إغلاق الـ pidfd عبر close(2).

    عند بدء مجموعة fanotify باستخدام FAN_REPORT_FD_ERROR، سيحتوي هذا الحقل على قيمة خطأ سالبة في حالة فشل إنشاء pidfd وفي حالة العملية المنتهية، ستكون القيمة -ESRCH.

حقول هيكل fanotify_event_info_mnt هي كما يلي:

.hdr
    هذا هيكل من نوع fanotify_event_info_header. يُضبط حقل .info_type على FAN_EVENT_INFO_TYPE_MNT.

.mnt_id
    يحدد الوصل المرتبط بالحدث. هو معرف وصل فريد 64-بت كالذي يعيده statx(2) مع الراية STATX_MNT_ID_UNIQUE.

حقول هيكل fanotify_event_info_error هي كما يلي:

hdr هذا هيكل من نوع fanotify_event_info_header. يُضبط حقل info_type على FAN_EVENT_INFO_TYPE_ERROR.

error
    يحدد نوع الخطأ الذي حدث.

error_count
    هذا عداد لعدد الأخطاء التي كُتمت منذ آخر قراءة للخطأ.

حقول هيكل fanotify_event_info_range هي كما يلي:

hdr هذا هيكل من نوع fanotify_event_info_header. يُضبط حقل info_type على FAN_EVENT_INFO_TYPE_RANGE.

count
    عدد البايتات التي تُقرأ أو تُكتب في الملف.

offset
    الإزاحة التي تُقرأ منها أو تُكتب فيها البايتات في الملف.

تتوفر وحدات الماكرو التالية للتكرار عبر مخزن يحتوي على بيانات وصفية لأحداث fanotify أعادها read(2) من واصف ملف fanotify:

FAN_EVENT_OK(meta, size)
    يتحقق هذا الماكرو من الحجم المتبقي size للمخزن meta مقابل حجم هيكل البيانات الوصفية وحقل event_len لأول هيكل بيانات وصفية في المخزن.

FAN_EVENT_NEXT(meta, size)
    يستخدم هذا الماكرو الحجم المشار إليه في حقل event_len لهيكل البيانات الوصفية الذي يشير إليه meta لحساب عنوان هيكل البيانات الوصفية التالي الذي يلي meta. يمثل size عدد بايتات البيانات الوصفية المتبقية حالياً في المخزن. يعيد الماكرو مؤشراً إلى هيكل البيانات الوصفية التالي الذي يلي meta، ويقلل size بمقدار عدد البايتات في هيكل البيانات الوصفية الذي تُخطي (أي يطرح meta->event_len من size).

بالإضافة إلى ذلك، هناك:

FAN_EVENT_METADATA_LEN
    يعيد هذا الماكرو حجم (بالبايتات) الهيكل fanotify_event_metadata. هذا هو الحد الأدنى للحجم (والحجم الوحيد حالياً) لأي بيانات وصفية للحدث.

  مراقبة واصف ملف fanotify بحثاً عن أحداث
عند وقوع حدث fanotify، يشير واصف ملف fanotify إلى أنه قابل للقراءة عند تمريره إلى epoll(7) أو poll(2) أو select(2).

  التعامل مع أحداث الأذونات
بالنسبة لأحداث الأذونات، يجب على التطبيق استدعاء write(2) لهيكل بالشكل التالي في واصف ملف fanotify:

    struct fanotify_response {
        __s32 fd;
        __u32 response;
    };

حقول هذا الهيكل هي كالتالي:

fd  هذا هو واصف الملف من الهيكل fanotify_event_metadata.

response
    يشير هذا الحقل إلى ما إذا كان سيُمنح الإذن أم لا. يجب أن تحتوي قيمته إما على الراية FAN_ALLOW للسماح بعملية الملف أو FAN_DENY لرفضها.

إذا رُفض الوصول، سيتلقى استدعاء التطبيق الطالب خطأ EPERM. منذ لينكس 6.13، إذا بُدئت مجموعة إشعارات بالفئة FAN_CLASS_PRE_CONTENT، يمكن رفض عملية الملف بأخطاء غير EPERM. على سبيل المثال، لكي يحصل التطبيق الطالب على خطأ EIO، يمكن لمستمع الحدث كتابة الاستجابة FAN_DENY_ERRNO(EIO). في وقت الكتابة، يمكن إعادة قيم الأخطاء التالية فقط إلى التطبيق باستخدام ماكرو FAN_DENY_ERRNO(e): EPERM و EIO و EBUSY و ETXTBSY و EAGAIN و ENOSPC و EDQUOT.

بالإضافة إلى ذلك، إذا أُنشئت مجموعة الإشعارات مع الراية FAN_ENABLE_AUDIT، فيمكن حينئذٍ ضبط الراية FAN_AUDIT في حقل response. في هذه الحالة، سيقوم نظام التدقيق الفرعي بتسجيل معلومات حول قرار الوصول في سجلات التدقيق.

منذ لينكس 6.3، يمكن ضبط الراية FAN_INFO في حقل .response. تشير هذه الراية إلى أن سجل استجابة إضافي متغير الطول يتبع هيكل fanotify_response. تبدأ سجلات الاستجابة الإضافية بترويسة مشتركة:

    struct fanotify_response_info_header {
        __u8 type;
        __u8 pad;
        __u16 len;
    };

تحدد قيمة .type تنسيق سجل الاستجابة الإضافي.

FAN_RESPONSE_INFO_AUDIT_RULE
    يُتوقع سجل الاستجابة التالي مع تفاصيل إضافية لسجل التدقيق:

        struct fanotify_response_info_audit_rule {
            struct fanotify_response_info_header hdr;
            __u32 rule_number;
            __u32 subj_trust;
            __u32 obj_trust;
        };

  مراقبة أنظمة الملفات بحثاً عن أخطاء
يُخزن حدث FAN_FS_ERROR واحد لكل نظام ملفات في المرة الواحدة. تُكتم رسائل الأخطاء الإضافية وتُحسب في حقل error_count لسجل حدث FAN_FS_ERROR الموجود، ولكن تُفقد تفاصيل تلك الأخطاء.

الأخطاء التي يبلغ عنها FAN_FS_ERROR هي قيم errno عامة، ولكن لا يُبلغ عن جميع أنواع الأخطاء من قبل جميع أنظمة الملفات.

الأخطاء غير المرتبطة مباشرة بملف (أي تلف الكتلة الفائقة) يُبلغ عنها بـ handle غير صالح. لهذه الأخطاء، سيُضبط حقل handle_type في handle على FILEID_INVALID، ويُضبط حجم مخزن المقبض على 0.

  إغلاق واصف ملف fanotify
عند إغلاق جميع واصفات الملفات التي تشير إلى مجموعة إشعارات fanotify، تُحرر مجموعة fanotify وتُخلى مواردها ليعيد الـ kernel استخدامها. عند close(2)، ستُضبط أحداث الأذونات المعلقة على مسموح بها.

  واجهات /proc
يحتوي الملف /proc/pid/fdinfo/fd على معلومات حول علامات fanotify لواصف الملف fd للعملية pid. راجع proc(5) للتفاصيل.

منذ لينكس 5.13 (و 5.10.220)، يمكن استخدام الواجهات التالية للتحكم في كمية موارد الـ kernel التي يستهلكها fanotify:

/proc/sys/fs/fanotify/max_queued_events
    تُستخدم القيمة الموجودة في هذا الملف عندما يستدعي تطبيق ما fanotify_init(2) لضبط حد أقصى لعدد الأحداث التي يمكن وضعها في طابور مجموعة fanotify المقابلة. تُسقط الأحداث التي تتجاوز هذا الحد، ولكن يُولد دائماً حدث FAN_Q_OVERFLOW. قبل نواة لينكس 5.13، كان الحد المبرمج صلباً هو 16384 حدثاً.

/proc/sys/fs/fanotify/max_user_group
    يحدد هذا حداً أقصى لعدد مجموعات fanotify التي يمكن إنشاؤها لكل معرف مستخدم حقيقي. قبل نواة لينكس 5.13، كان الحد المبرمج صلباً هو 128 مجموعة لكل مستخدم.

/proc/sys/fs/fanotify/max_user_marks
    يحدد هذا حداً أقصى لعدد علامات fanotify التي يمكن إنشاؤها لكل معرف مستخدم حقيقي. قبل نواة لينكس 5.13، كان الحد المبرمج صلباً هو 8192 علامة لكل مجموعة (وليس لكل مستخدم).

الأخطاء
بالإضافة إلى الأخطاء المعتادة لـ read(2)، يمكن أن تحدث الأخطاء التالية عند القراءة من واصف ملف fanotify:

EINVAL
    الخبيئة أصغر من أن تتسع لهذا الحدث.

EMFILE
    بُلغ الحد الأقصى لعدد الملفات المفتوحة لكل عملية. انظر وصف RLIMIT_NOFILE في getrlimit(2).

ENFILE
    بُلغ الحد الأقصى لعدد الملفات المفتوحة على مستوى النظام بأكمله. انظر /proc/sys/fs/file-max في proc(5).

ETXTBSY
    يُرجع الاستدعاء read(2) هذا الخطأ إذا حُدد O_RDWR أو O_WRONLY في المعامل event_f_flags عند استدعاء fanotify_init(2) ووقع حدث لملف مراقب يجري تنفيذه حاليًا.

بالإضافة إلى الأخطاء المعتادة للاستدعاء write(2)، يمكن أن تقع الأخطاء التالية عند الكتابة في واصف ملف fanotify:

EINVAL
    أذونات الوصول لـ Fanotify غير مفعّلة في ضبط النواة أو أن قيمة response في بنية الاستجابة غير صالحة.

ENOENT
    واصف الملف fd في بنية الاستجابة غير صالح. قد يحدث هذا عندما تكون استجابة حدث الإذن قد كُتبت بالفعل.

المعايير
لينكس.

التاريخ
قُدمت واجهة برمجة تطبيقات fanotify في لينكس 2.6.36 وفُعّلت في لينكس 2.6.37. أُضيف دعم fdinfo في لينكس 3.8.

ملاحظات
واجهة برمجة تطبيقات fanotify متاحة فقط إذا بُنيت النواة مع تفعيل خيار الضبط CONFIG_FANOTIFY. بالإضافة إلى ذلك، فإن معالجة أذونات fanotify متاحة فقط إذا فُعّل خيار الضبط CONFIG_FANOTIFY_ACCESS_PERMISSIONS.

  القيود والتحذيرات
يبلغ fanotify فقط عن الأحداث التي يطلقها برنامج في مساحة المستخدم عبر واجهة برمجة تطبيقات نظام الملفات. ونتيجة لذلك، فإنه لا يلتقط الأحداث البعيدة التي تقع في أنظمة الملفات الشبكية.

لا تبلغ واجهة برمجة تطبيقات fanotify عن عمليات الوصول إلى الملفات وتعديلها التي قد تحدث بسبب mmap(2) و msync(2) و munmap(2).

تُنشأ أحداث الأدلة فقط إذا فُتح الدليل نفسه وقُرئ وأُغلق. إضافة أو إزالة أو تغيير أبناء دليل موسوم لا يُنشئ أحداثًا للدليل المراقب نفسه.

مراقبة fanotify للأدلة ليست عودية: لمراقبة الأدلة الفرعية تحت دليل ما، يجب إنشاء وسوم إضافية. يمكن استخدام حدث FAN_CREATE لاكتشاف وقت إنشاء دليل فرعي تحت دليل موسوم. يجب بعد ذلك وضع وسم إضافي على الدليل الفرعي المنشأ حديثًا. هذا النهج عرضة لظروف السباق (racy)، لأنه قد يفقد الأحداث التي وقعت داخل الدليل الفرعي المنشأ حديثًا قبل إضافة وسم عليه. توفر مراقبة نقاط الوصل القدرة على مراقبة شجرة أدلة كاملة بطريقة خالية من السباق. توفر مراقبة أنظمة الملفات القدرة على مراقبة التغييرات التي تجري من أي وصل لمثيل نظام ملفات بطريقة خالية من السباق.

قد يفيض طابور الأحداث. في هذه الحالة، تُفقد الأحداث.

العلل
قبل لينكس 3.19، لم يكن fallocate(2) يولد أحداث fanotify. منذ لينكس 3.19، تولد استدعاءات fallocate(2) أحداث FAN_MODIFY.

بدءًا من لينكس 3.17، توجد العلل التالية:

•   في لينكس، يمكن الوصول إلى كائن نظام ملفات عبر مسارات متعددة، على سبيل المثال، قد يُعاد وصل جزء من نظام ملفات باستخدام خيار --bind للأمر mount(8). المستمع الذي وسم وصلًا سيُخطر فقط بالأحداث التي أُطلقت لكائن نظام ملفات باستخدام الوصل نفسه. أي حدث آخر سيمر دون ملاحظة.

•   عند توليد حدث، لا يُجرى أي فحص لمعرفة ما إذا كان معرف المستخدم للعملية المستلمة لديه تفويض للقراءة أو الكتابة في الملف قبل تمرير واصف ملف لذلك الملف. يمثل هذا خطرًا أمنيًا، عندما تُضبط إمكانية CAP_SYS_ADMIN للبرامج التي ينفذها مستخدمون غير مفوضين.

•   إذا عالج استدعاء read(2) أحداثًا متعددة من طابور fanotify وحدث خطأ، فستكون القيمة المرجعة هي الحجم الإجمالي للأحداث التي نُسخت بنجاح إلى خبيئة مساحة المستخدم قبل وقوع الخطأ. لن تكون القيمة المرجعة -1، ولن يُضبط errno. وبالتالي، لا تملك التطبيقات القارئة أي وسيلة لاكتشاف الخطأ.

أمثلة
يوضح البرنامجان المثالان أدناه استخدام واجهة برمجة تطبيقات fanotify.

  برنامج مثال: fanotify_example.c
البرنامج الأول هو مثال لاستخدام fanotify مع تمرير معلومات كائن الحدث الخاص به في شكل واصف ملف. يوسم البرنامج نقطة الوصل الممررة كمعامل في سطر الأوامر وينتظر أحداثًا من النوع FAN_OPEN_PERM و FAN_CLOSE_WRITE. عند وقوع حدث إذن، تُعطى استجابة FAN_ALLOW.

تُظهر جلسة الصدفة التالية مثالًا على تشغيل هذا البرنامج. تضمنت هذه الجلسة تحرير الملف /home/user/temp/notes. قبل أن يُفتح الملف، وقع حدث FAN_OPEN_PERM. بعد إغلاق الملف، وقع حدث FAN_CLOSE_WRITE. ينتهي تنفيذ البرنامج عندما يضغط المستخدم على مفتاح ENTER.

    # ./fanotify_example /home;
    اضغط على مفتاح ENTER للإنهاء.
    الاستماع للأحداث.
    FAN_OPEN_PERM: File /home/user/temp/notes
    FAN_CLOSE_WRITE: File /home/user/temp/notes

    توقف الاستماع للأحداث.

  مصدر البرنامج: fanotify_example.c
    #define _GNU_SOURCE     /* مطلوب للحصول على تعريف O_LARGEFILE */
    #include <errno.h>
    #include <fcntl.h>
    #include <limits.h>
    #include <poll.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/fanotify.h>
    #include <unistd.h>

    /* اقرأ جميع أحداث fanotify المتاحة من واصف الملف 'fd'.  */

    static void
    handle_events(int fd)
    {
        const struct fanotify_event_metadata *metadata;
        struct fanotify_event_metadata buf[200];
        ssize_t size;
        char path[PATH_MAX];
        ssize_t path_len;
        char procfd_path[PATH_MAX];
        struct fanotify_response response;

        /* التكرار طالما يمكن قراءة الأحداث من واصف ملف fanotify.  */

        for (;;) {

            /* قراءة بعض الأحداث.  */

            size = read(fd, buf, sizeof(buf));
            if (size == -1 && errno != EAGAIN) {
                perror("read");
                exit(EXIT_FAILURE);
            }

            /* التحقق مما إذا كان قد وصل إلى نهاية البيانات المتاحة.  */

            if (size <= 0)
                break;

            /* الإشارة إلى الحدث الأول في الخبيئة.  */

            metadata = buf;

            /* التكرار عبر كافة الأحداث في الخبيئة.  */

            while (FAN_EVENT_OK(metadata, size)) {

                /* التحقق من تطابق بنيات وقت التشغيل ووقت التجميع.  */

                if (metadata->vers != FANOTIFY_METADATA_VERSION) {
                    fprintf(stderr,
                            "Mismatch of fanotify metadata version.\n");
                    exit(EXIT_FAILURE);
                }

                /* metadata->fd يحتوي إما على FAN_NOFD، مما يشير إلى
                   فيضان الطابور، أو واصف ملف (عدد صحيح غير سالب).
                   هنا، نتجاهل ببساطة فيضان الطابور.  */

                if (metadata->fd >= 0) {

                    /* معالجة حدث إذن الفتح.  */

                    if (metadata->mask & FAN_OPEN_PERM) {
                        printf("FAN_OPEN_PERM: ");

                        /* السماح بفتح الملف.  */

                        response.fd = metadata->fd;
                        response.response = FAN_ALLOW;
                        write(fd, &response, sizeof(response));
                    }

                    /* معالجة حدث إغلاق ملف قابل للكتابة.  */

                    if (metadata->mask & FAN_CLOSE_WRITE)
                        printf("FAN_CLOSE_WRITE: ");

                    /* جلب وطباعة اسم المسار للملف الذي تم الوصول إليه.  */

                    snprintf(procfd_path, sizeof(procfd_path),
                             "/proc/self/fd/%d", metadata->fd);
                    path_len = readlink(procfd_path, path,
                                        sizeof(path) - 1);
                    if (path_len == -1) {
                        perror("readlink");
                        exit(EXIT_FAILURE);
                    }

                    path[path_len] = '\0';
                    printf("File %s\n", path);

                    /* إغلاق واصف الملف الخاص بالحدث.  */

                    close(metadata->fd);
                }

                /* الانتقال إلى الحدث التالي.  */

                metadata = FAN_EVENT_NEXT(metadata, size);
            }
        }
    }

    int
    main(int argc, char *argv[])
    {
        char buf;
        int fd, poll_num;
        nfds_t nfds;
        struct pollfd fds[2];

        /* التحقق من توفير نقطة الوصل.  */

        if (argc != 2) {
            fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
            exit(EXIT_FAILURE);
        }

        printf("Press enter key to terminate.\n");

        /* إنشاء واصف الملف للوصول إلى واجهة برمجة تطبيقات fanotify.  */

        fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
                           O_RDONLY | O_LARGEFILE);
        if (fd == -1) {
            perror("fanotify_init");
            exit(EXIT_FAILURE);
        }

        /* وسم نقطة الوصل لـ:
           - أحداث الإذن قبل فتح الملفات
           - أحداث الإشعار بعد إغلاق واصف ملف
             مفعّل للكتابة.  */

        if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
                          FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD,
                          argv[1]) == -1) {
            perror("fanotify_mark");
            exit(EXIT_FAILURE);
        }

        /* التحضير للاستطلاع (polling).  */

        nfds = 2;

        fds[0].fd = STDIN_FILENO;       /* إدخال الكونسول */
        fds[0].events = POLLIN;

        fds[1].fd = fd;                 /* إدخال Fanotify */
        fds[1].events = POLLIN;

        /* هذا هو التكرار لانتظار الأحداث القادمة.  */

        printf("Listening for events.\n");

        for (;;) {
            poll_num = poll(fds, nfds, -1);
            if (poll_num == -1) {
                if (errno == EINTR)     /* قُطع بواسطة إشارة */
                    continue;           /* إعادة تشغيل poll() */

                perror("poll");         /* خطأ غير متوقع */
                exit(EXIT_FAILURE);
            }

            if (poll_num > 0) {
                if (fds[0].revents & POLLIN) {

                    /* إدخال الكونسول متاح: إفراغ stdin والخروج.  */

                    while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n')
                        continue;
                    break;
                }

                if (fds[1].revents & POLLIN) {

                    /* أحداث Fanotify متاحة.  */

                    handle_events(fd);
                }
            }
        }

        printf("Listening for events stopped.\n");
        exit(EXIT_SUCCESS);
    }

  برنامج مثال: fanotify_fid.c
البرنامج الثاني هو مثال لاستخدام fanotify مع مجموعة تحدد الكائنات بواسطة مقابض الملفات. يوسم البرنامج كائن نظام الملفات الذي يُمرر كمعامل سطر أوامر وينتظر حتى يقع حدث من النوع FAN_CREATE. يشير قناع الحدث إلى نوع كائن نظام الملفات—إما ملف أو دليل—الذي أُنشئ. وبمجرد قراءة جميع الأحداث من الخبيئة ومعالجتها وفقًا لذلك، ينتهي البرنامج ببساطة.

تُظهر جلسات الصدفة التالية استدعاءين مختلفين لهذا البرنامج، مع تنفيذ إجراءات مختلفة على كائن مراقب.

تُظهر الجلسة الأولى وضع وسم على /home/user. ويتبع ذلك إنشاء ملف عادي، /home/user/testfile.txt. ينتج عن هذا توليد حدث FAN_CREATE والإبلاغ عنه مقابل كائن الدليل الأب المراقب للملف ومع اسم الملف المنشأ. ينتهي تنفيذ البرنامج بمجرد معالجة جميع الأحداث الملتقطة داخل الخبيئة.

    # ./fanotify_fid /home/user;
    الاستماع للأحداث.
    FAN_CREATE (أُنشئ ملف):
            عُدّل الدليل /home/user.
            المدخل 'testfile.txt' ليس دليلاً فرعيًا.
    عولجت جميع الأحداث بنجاح. يخرج البرنامج.

    $ touch /home/user/testfile.txt;              # في طرفية أخرى

تُظهر الجلسة الثانية وضع وسم على /home/user. ويتبع ذلك إنشاء دليل، /home/user/testdir. ينتج عن هذا الإجراء المحدد توليد حدث FAN_CREATE ويُبلغ عنه مع تعيين علم FAN_ONDIR ومع اسم الدليل المنشأ.

    # ./fanotify_fid /home/user;
    الاستماع للأحداث.
    FAN_CREATE | FAN_ONDIR (أُنشئ دليل فرعي):
            عُدّل الدليل /home/user.
            المدخل 'testdir' هو دليل فرعي.
    عولجت جميع الأحداث بنجاح. يخرج البرنامج.

    $ mkdir -p /home/user/testdir;          # في طرفية أخرى

  مصدر البرنامج: fanotify_fid.c
    #define _GNU_SOURCE
    #include <errno.h>
    #include <fcntl.h>
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/fanotify.h>
    #include <unistd.h>

    #define BUF_SIZE 256

    int
    main(int argc, char *argv[])
    {
        int fd, ret, event_fd, mount_fd;
        ssize_t size, path_len;
        char path[PATH_MAX];
        char procfd_path[PATH_MAX];
        char events_buf[BUF_SIZE];
        struct file_handle *file_handle;
        struct fanotify_event_metadata *metadata;
        struct fanotify_event_info_fid *fid;
        const char *file_name;
        struct stat sb;

        if (argc != 2) {
            fprintf(stderr, "Invalid number of command line arguments.\n");
            exit(EXIT_FAILURE);
        }

        mount_fd = open(argv[1], O_DIRECTORY | O_RDONLY);
        if (mount_fd == -1) {
            perror(argv[1]);
            exit(EXIT_FAILURE);
        }

        /* إنشاء واصف ملف fanotify مع FAN_REPORT_DFID_NAME كـ
           علم حتى يتمكن البرنامج من استقبال أحداث fid مع اسم
           مدخل الدليل.  */

        fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME, 0);
        if (fd == -1) {
            perror("fanotify_init");
            exit(EXIT_FAILURE);
        }

        /* وضع وسم على كائن نظام الملفات الموفر في argv[1].  */

        ret = fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_ONLYDIR,
                            FAN_CREATE | FAN_ONDIR,
                            AT_FDCWD, argv[1]);
        if (ret == -1) {
            perror("fanotify_mark");
            exit(EXIT_FAILURE);
        }

        printf("Listening for events.\n");

        /* قراءة الأحداث من طابور الأحداث إلى خبيئة.  */

        size = read(fd, events_buf, sizeof(events_buf));
        if (size == -1 && errno != EAGAIN) {
            perror("read");
            exit(EXIT_FAILURE);
        }

        /* معالجة جميع الأحداث داخل الخبيئة.  */

        for (metadata = (struct fanotify_event_metadata *) events_buf;
                FAN_EVENT_OK(metadata, size);
                metadata = FAN_EVENT_NEXT(metadata, size)) {
            fid = (struct fanotify_event_info_fid *) (metadata + 1);
            file_handle = (struct file_handle *) fid->handle;

            /* التأكد من أن معلومات الحدث من النوع الصحيح.  */

            if (fid->hdr.info_type == FAN_EVENT_INFO_TYPE_FID ||
                fid->hdr.info_type == FAN_EVENT_INFO_TYPE_DFID) {
                file_name = NULL;
            } else if (fid->hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME) {
                file_name = file_handle->f_handle +
                            file_handle->handle_bytes;
            } else {
                fprintf(stderr, "Received unexpected event info type.\n");
                exit(EXIT_FAILURE);
            }

            if (metadata->mask == FAN_CREATE)
                printf("FAN_CREATE (file created):\n");

            if (metadata->mask == (FAN_CREATE | FAN_ONDIR))
                printf("FAN_CREATE | FAN_ONDIR (subdirectory created):\n");

    	/* يُضبط metadata->fd على FAN_NOFD عندما تحدد المجموعة
    	   الكائنات بواسطة مقابض الملفات. للحصول على واصف ملف
    	   لكائن الملف المقابل لحدث ما، يمكنك استخدام
    	   struct file_handle الموفرة داخل
    	   fanotify_event_info_fid بالاقتران مع استدعاء
    	   النظام open_by_handle_at(2). يُجرى فحص لـ ESTALE
    	   لاستيعاب الموقف الذي حُذف فيه مقبض الملف
    	   للكائن قبل استدعاء النظام هذا.  */

            event_fd = open_by_handle_at(mount_fd, file_handle, O_RDONLY);
            if (event_fd == -1) {
                if (errno == ESTALE) {
                    printf("File handle is no longer valid.  "
                            "File has been deleted\n");
                    continue;
                } else {
                    perror("open_by_handle_at");
                    exit(EXIT_FAILURE);
                }
            }

            snprintf(procfd_path, sizeof(procfd_path), "/proc/self/fd/%d",
                    event_fd);

            /* جلب وطباعة مسار dentry المعدل.  */

            path_len = readlink(procfd_path, path, sizeof(path) - 1);
            if (path_len == -1) {
                perror("readlink");
                exit(EXIT_FAILURE);
            }

            path[path_len] = '\0';
            printf("\tDirectory '%s' has been modified.\n", path);

            if (file_name) {
                ret = fstatat(event_fd, file_name, &sb, 0);
                if (ret == -1) {
                    if (errno != ENOENT) {
                        perror("fstatat");
                        exit(EXIT_FAILURE);
                    }
                    printf("\tEntry '%s' does not exist.\n", file_name);
                } else if ((sb.st_mode & S_IFMT) == S_IFDIR) {
                    printf("\tEntry '%s' is a subdirectory.\n", file_name);
                } else {
                    printf("\tEntry '%s' is not a subdirectory.\n",
                            file_name);
                }
            }

            /* إغلاق واصف الملف المرتبط بهذا الحدث.  */

            close(event_fd);
        }

        printf("All events processed successfully.  Program exiting.\n");
        exit(EXIT_SUCCESS);
    }

انظر أيضًا
fanotify_init(2)، fanotify_mark(2)، inotify(7)

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.