كيفية استخدام readlink مع تخصيص الذاكرة الديناميكية

StackOverflow https://stackoverflow.com/questions/9385386

  •  28-10-2019
  •  | 
  •  

سؤال

مشكلة:

على جهاز يعمل بنظام التشغيل Linux، أريد قراءة السلسلة المستهدفة للرابط.لقد وجدت من الوثائق نموذج التعليمات البرمجية التالي (بدون معالجة الأخطاء):

struct stat sb;
ssize_t r;
char * linkname;

lstat("<some link>", &sb);
linkname = malloc(sb.st_size + 1);
r = readlink("/proc/self/exe", linkname, sb.st_size + 1);

المشكلة هي أن sb.st_size يُرجع 0 للروابط الموجودة على نظامي.

إذًا كيف يمكن للمرء تخصيص الذاكرة ديناميكيًا لخط القراءة في مثل هذه الأنظمة؟

تشكرات!


أحد الحلول الممكنة:

للرجوع إليها في المستقبل.باستخدام النقاط التي قدمها جيل:

struct stat sb;
ssize_t r = INT_MAX;
int linkSize = 0;
const int growthRate = 255;

char * linkTarget = NULL;

// get length of the pathname the link points to
if (lstat("/proc/self/exe", &sb) == -1) {   // could not lstat: insufficient permissions on directory?
    perror("lstat");
    return;
}

// read the link target into a string
linkSize = sb.st_size + 1 - growthRate;
while (r >= linkSize) { // i.e. symlink increased in size since lstat() or non-POSIX compliant filesystem
    // allocate sufficient memory to hold the link
    linkSize += growthRate;
    free(linkTarget);
    linkTarget = malloc(linkSize);
    if (linkTarget == NULL) {           // insufficient memory
        fprintf(stderr, "setProcessName(): insufficient memory\n");
        return;
    }

    // read the link target into variable linkTarget
    r = readlink("/proc/self/exe", linkTarget, linkSize);
    if (r < 0) {        // readlink failed: link was deleted?
        perror("lstat");
        return;
    }
}
linkTarget[r] = '\0';   // readlink does not null-terminate the string
هل كانت مفيدة؟

المحلول

يقول بوسيكس st_size يجب تعيين الحقل الخاص بالارتباط الرمزي على طول اسم المسار في الرابط (بدون '\0').ومع ذلك، /proc نظام الملفات على Linux غير متوافق مع POSIX.(إنه يحتوي على انتهاكات أكثر من هذه فقط، كما هو الحال عند قراءة ملفات معينة بايت واحد في كل مرة.)

يمكنك تخصيص مخزن مؤقت بحجم معين، حاول readlink() وأعد المحاولة باستخدام مخزن مؤقت أكبر إذا لم يكن المخزن المؤقت كبيرًا بدرجة كافية (readlink() تم إرجاع أكبر عدد ممكن من البايتات في المخزن المؤقت)، حتى يصبح المخزن المؤقت كبيرًا بدرجة كافية.

بدلا من ذلك يمكنك استخدام PATH_MAX وكسر إمكانية النقل إلى الأنظمة التي لا تكون فيها ثابتًا لوقت الترجمة أو حيث قد يكون اسم المسار أطول من ذلك (يسمح POSIX أيضًا).

نصائح أخرى

الإجابات الأخرى لا تذكر ذلك، ولكن هناك realpath الوظيفة، التي تفعل ما تريده بالضبط، والذي تم تحديده بواسطة POSIX.1-2001.

char *realpath(const char *path, char *resolved_path);

من الصفحة الرئيسية:

مسار حقيقي () يوسع جميع الروابط الرمزية ويحل المراجع إلى أحرف/./ ، /../ و extra '/' في السلسلة المُنهّفة بالفارغ المسمى بواسطة PATH لإنتاج اسم مسار مطلق قانوني.

realpath يتعامل أيضًا مع تخصيص الذاكرة الديناميكية لك، إذا كنت تريد ذلك.مرة أخرى، مقتطف من الصفحة الرئيسية:

إذا تم تحديد solved_path على أنه فارغ ، فإن RealPath () يستخدم malloc (3) لتخصيص مخزن مؤقت لـ Up to Path_max للاحتفاظ باسم المسار الذي تم حله ، ويعيد مؤشرًا إلى هذا المخزن المؤقت.يجب على المتصل توصيل هذا المخزن المؤقت باستخدام Free (3).

كمثال بسيط وكامل:

#include <limits.h>
#include <stdlib.h>
#include <stdio.h>    

int
resolve_link (const char *filename)
{
  char *res = realpath(filename, NULL);
  if (res == NULL)
    {
      perror("realpath failed");
      return -1;
    }

  printf("%s -> %s\n", filename, res);
  free(res);

  return 0;
}

int
main (void)
{
  resolve_link("/proc/self/exe");
  return 0;
}

لا يعطي st_size الإجابة الصحيحة في / proc.

بدلاً من ذلك ، يمكنك malloc PATH_MAX أو pathconf (_PC_PATH_MAX) بايت.يجب أن يكون هذا كافيا لمعظم الحالات.إذا كنت تريد أن تكون قادرًا على التعامل مع مسارات أطول من ذلك ، يمكنك استدعاء readlink في حلقة وإعادة تخصيص المخزن المؤقت إذا كانت قيمة إرجاع readlink تشير إلى أن المخزن المؤقت قصير جدًا.لاحظ أن العديد من وظائف POSIX الأخرى تفترض ببساطة أن PATH_MAX كافٍ.

أنا في حيرة بعض الشيء لماذا st_size هو صفر.لكل بوسيكس:

بالنسبة للروابط الرمزية، يجب أن يحتوي العضو st_mode على معلومات ذات معنى عند استخدامه مع وحدات ماكرو نوع الملف.بتات وضع الملف في st_mode غير محددة.يجب أن يكون لأعضاء البنية st_ino وst_dev وst_uid وst_gid وst_atim وst_ctim وst_mtim قيم ذات معنى ويجب تعيين قيمة عضو st_nlink على عدد الروابط (الصلبة) للارتباط الرمزي.يجب تعيين قيمة العضو st_size على طول اسم المسار الموجود في الرابط الرمزي الذي لا يتضمن أي بايت فارغ منتهي.

مصدر: http://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html

لو st_size لا يعمل، أعتقد أن خيارك الوحيد هو تخصيص مخزن مؤقت ديناميكيًا والاستمرار في تغيير حجمه بشكل أكبر طالما أن القيمة المرجعة لـ readlink يساوي حجم المخزن المؤقت.

ال الصفحة الرئيسية ل readlink(2) يقول أنه سيتم اقتطاعه بصمت إذا كان المخزن المؤقت صغيرًا جدًا.إذا كنت تريد حقًا أن تكون غير محدود (ولا تمانع في دفع بعض التكاليف مقابل العمل الإضافي)، فيمكنك البدء بحجم تخصيص معين والاستمرار في زيادته وإعادة تجربة readlink يتصل.يمكنك التوقف عن زيادة المخزن المؤقت عند الاتصال التالي بـ readlink تقوم بإرجاع نفس السلسلة التي قامت بها في التكرار الأخير.

ما الذي تحاول تحقيقه بالضبط باستخدام نظام الإحصائيات؟

يجب أن تكون قادرًا على تحقيق الهدف من خلال ما يلي فقط Genacodicetagpre

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

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