سؤال

بالنظر إلى مسار إلى ملف أو دليل ، كيف يمكنني تحديد نقطة التثبيت لهذا الملف؟ على سبيل المثال ، إذا /tmp تم تركيبه على أنه أ tmpfs نظام الملفات ثم أعطى اسم الملف /tmp/foo/bar أريد أن أعرف أنه تم تخزينه على tmpfs متجذر في /tmp.

سيكون هذا في C ++ وأرغب في تجنب استدعاء الأوامر الخارجية عبر system(). يجب أن يكون القانون قويًا-ليس بالضرورة ضد العبث المتعمد ولكن بالتأكيد في مواجهة نقاط التثبيت المتداخلة ، والروابط ، إلخ.

لم أتمكن من العثور على مكالمة نظام بسيطة للقيام بذلك. يبدو أنني سأضطر إلى كتابة الشيك بنفسي. إليك مخططًا تقريبيًا لما أخطط له.

  1. قم بتعيين اسم الملف A la the readlink أمر شل. كيف؟
  2. اقرأ /etc/mtab مع getmntent() & co.
  3. تحديد إدخال جبل المقابل للملف. كيف؟

بالنسبة إلى #1 ، هل هناك مكالمة نظام بسيطة أو أحتاج إلى قراءة كل مكون من مكونات الدليل وحلها readlink(2) إذا كانت تصفح؟ والتعامل مع . و .. نفسي؟ يبدو وكأنه ألم.

بالنسبة لـ #3 ، لدي أفكار مختلفة حول كيفية القيام بذلك. لست متأكدا ما هو الأفضل.

  1. open() الملف ، والديه ، والد الوالد ، وما إلى ذلك باستخدام openat(fd, "..") حتى أصل إلى واحد من /etc/mtab إدخالات. ((كيف أعرف متى أفعل؟ fstat() لهم ومقارنة أرقام inode؟)
  2. ابحث عن أطول اسم دليل في جدول Mount ، وهو عبارة عن سلسلة فرعية لاسم ملفي.

أنا أميل نحو الخيار الأول ، لكن قبل أن أقوم بترميز كل شيء ، أريد أن أتأكد من أنني لا أطل على أي شيء-وظيفة مدمجة حقًا تقوم بذلك بالفعل!

هل كانت مفيدة؟

المحلول

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

struct mntent *mountpoint(char *filename, struct mntent *mnt, char *buf, size_t buflen)
{
    struct stat s;
    FILE *      fp;
    dev_t       dev;

    if (stat(filename, &s) != 0) {
        return NULL;
    }

    dev = s.st_dev;

    if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
        return NULL;
    }

    while (getmntent_r(fp, mnt, buf, buflen)) {
        if (stat(mnt->mnt_dir, &s) != 0) {
            continue;
        }

        if (s.st_dev == dev) {
            endmntent(fp);
            return mnt;
        }
    }

    endmntent(fp);

    // Should never reach here.
    errno = EINVAL;
    return NULL;
}

بفضل RichardPennington للرؤوس على realpath(), وعند مقارنة أرقام الجهاز بدلاً من أرقام inode.

نصائح أخرى

يمكنك أن تبدأ بـ RealPath وتعمل في طريقك للتحقق من كل دليل مع Stat لمعرفة ما إذا كان على نفس الجهاز. يبدو أنه يجب أن يكون هناك طريقة أبسط.


يحرر:

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    char *p;
    char path[PATH_MAX];
    struct stat buf;
    dev_t dev;

    if (realpath(argv[1], path) == NULL) {
        fprintf(stderr, "can't find %s\n", argv[1]);
        exit(1);
    }

    if (stat(path, &buf) != 0) {
        fprintf(stderr, "can't statind %s\n", path);
    exit(1);
    }

    dev = buf.st_dev;
    while((p = strrchr(path, '/'))) {
        *p = '\0';
        stat(path, &buf);
        if (buf.st_dev != dev) {
            printf("mount point = %s\n", path);
            exit(0);
        }
   }
    printf("mount point = /\n");
}

شكرًا على الهاء ؛-)

هذا عمل بالنسبة لي على OSX ، والذي لا يوفر وظائف mntent. في C ++:

struct stat fileStat;
int result = stat(path, &fileStat);
if (result != 0) {
    // handle error
}    

struct statfs* mounts;
int numMounts = getmntinfo(&mounts, MNT_WAIT);
if (numMounts == 0) {
    // handle error
}    

for (int i = 0; i < numMounts; i++) {
    if (fileStat.st_dev == mounts[i].f_fsid.val[0])
        // mounts[i].f_mntonname is the mount path
}

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

من الواضح أن Symlinks يمكن أن ترمي وجع في هذه العملية برمتها. يجب تحويل أي مسار ملف يتضمن Symlink إلى مسار "فعلي" قبل معالجته. نأمل أن تكون هناك طريقة للقيام بذلك دون التحقق بشكل فردي من ملف وكل من والديه ، ولكن يمكنك دائمًا أن تحظى به إذا كان عليك ذلك. ربما تريد استخدامها realpath لإزالة symlinks.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top