readdir()-›d_name дает странные значения

Я пытаюсь получить имя родительского каталога, используя этот код:

dirp=opendir(cur_spot);
printf("parent name: %s\n", readdir(dirp)->d_name);
closedir(dirp);

cur_spot содержит '..'.

я делаю это в цикле, и он продолжает подниматься по каталогам к корню, последовательность моего вывода:

.
.bash_logout
.
.
srv

Я знаю, что он проходит правильно, потому что я проверяю индексные дескрипторы по пути.

Нужно ли мне использовать что-то отличное от d_name?

Спасибо


person Troy Cosentino    schedule 07.12.2012    source источник
comment
Нет абсолютно никакой гарантии, в каком порядке readdir вернет записи каталога. Так что ожидается '.' или '..' быть первым - ошибка.   -  person goji    schedule 07.12.2012


Ответы (2)


Я придумал это на основе идей в комментариях под ответом sjs:

#include <dirent.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <sys/stat.h>
#include <limits.h>
#include <errno.h>

int LookupName(const char* parent, ino_t ino, char *name, size_t size)
{
  DIR *dp = opendir(parent);
  if (!dp) return -1;

  int ret = -1;
  struct dirent *de;
  while (de = readdir(dp))
  {
    if (de->d_ino == ino)
    {
      strncpy(name, de->d_name, size);
      ret = 0;
      break;
    }
  }

  closedir(dp);
  if (ret == -1) errno = ENOENT;
  return ret;
}

int GetWorkdir(char *workdir, size_t size)
{
  struct stat st;
  if (stat(".", &st)) return -1;

  char path[PATH_MAX];
  strncpy(path, "..", sizeof(path));

  memset(workdir, '\0', sizeof(workdir));

  char name[PATH_MAX];
  while (1)
  {
    if (LookupName(path, st.st_ino, name, sizeof(name))) return -1;
    if (!strcmp(name, "..") || !strcmp(name, "."))
    {
      strncpy(name, "/", sizeof(name));
      strncat(name, workdir, sizeof(name));
      strncpy(workdir, name, size);
      break;
    }

    if (workdir[0] != '\0')
    {
      strncat(name, "/", sizeof(name));
    }

    strncat(name, workdir, sizeof(name));
    strncpy(workdir, name, size);

    if (stat(path, &st)) return -1;

    strncat(path, "/..", sizeof(path));
  }

  return 0;
}

int main(int argc, char **argv)
{
  char workDir[PATH_MAX];

  assert(!GetWorkdir(workDir, sizeof(workDir)));
  printf("%s\n", workDir);
}
person goji    schedule 07.12.2012
comment
я получаю: a.out: pwd1.c:73: main: Утверждение `!GetWorkdir(workDir, sizeof(workDir))' не удалось. Прервано - person Troy Cosentino; 07.12.2012
comment
взял! из утверждения, и теперь он работает, но './' повторяется примерно 600 раз перед фактическим pwd - person Troy Cosentino; 07.12.2012
comment
да, я даже не могу найти место, где можно было бы добавлять './' к нему снова и снова - person Troy Cosentino; 07.12.2012
comment
Возможно, имя поиска возвращает «.», Вы проверяли его, так как caf сделал обновление, добавив дополнительную проверку? - person goji; 07.12.2012

readdir читает каталог, поэтому, когда вы говорите

printf("parent name: %s\n", readdir(dirp)->d_name);

на самом деле вы просите, чтобы для вас было напечатано имя первой записи внутри .., а не имя каталога ...

В зависимости от того, что вы пытаетесь сделать, возможно, анализ вывода getcwd может быть лучшим подходом?

person sjs    schedule 07.12.2012
comment
к сожалению, я пытаюсь реализовать getcwd без его использования - person Troy Cosentino; 07.12.2012
comment
@TroyCosentino А, хорошо. Думая от верхней части моей головы здесь. Как насчет того, если вы используете readdir для получения номера инода текущего каталога (т.е. .), затем открываете родительский каталог, .., и выполняете поиск, пока не найдете элемент с таким же номером инода. Затем у вас будет базовое имя текущего рабочего каталога, и вы можете повторить этот процесс, чтобы получить имена родителей. - person sjs; 07.12.2012
comment
извините, пытаюсь следовать тому, что вы сказали. Итак, в настоящее время я делаю то, что вы описали, я продолжаю добавлять «/..» к тому, что я проверяю, чтобы он продолжал подниматься, пока я не найду, где родительский индекс и текущий индекс являются то же самое, что означает, что это корень. Оттуда, как я могу преобразовать индекс в правильное имя? или как это дает мне базовое имя? - person Troy Cosentino; 07.12.2012
comment
разобрался, думаю, я буду отслеживать иноды, когда я перемещаюсь вверх, а затем, возвращаясь вниз, я могу проверить, совпадают ли они ... должно работать как шарм - person Troy Cosentino; 07.12.2012
comment
@TroyCosentino Похоже, у вас есть это, но просто чтобы уточнить, что я сказал: начните с звонка opendir на .. Повторно вызывайте readdir, пока не получите предмет с названием .. Теперь у вас есть номер инода для текущего каталога. Следующий звонок opendir на ... Повторно вызывайте readdir, пока не найдете элемент с номером инода, который вы нашли ранее. Теперь у вас есть имя текущего каталога. Повторите этот процесс, чтобы получить имя родительского каталога... и так далее, пока не получите имя каждого родительского каталога вплоть до корня файловой системы. - person sjs; 07.12.2012