2012-06-27 4 views
1

Я работаю над модификацией дидактической ОС xv6 (написанной в с) для поддержки символических ссылок (быстрых клавиш AKA). Символическая ссылка представляет собой файл типа T_SYM, который содержит путь к его назначению. Для этого я написал рекурсивную функцию, которая получает путь и буфер и заполняет буфер «реальным» путем (т. Е. Если путь содержит ссылку, он должен быть заменен реальным путем, и может произойти ссылка на любом уровне пути).Рекурсивная функция для управления заданным путем

В принципе, если у меня есть путь A/B/C/D, и ссылку от F к/б, следующие операции должны быть эквивалентны:

кд A/B/C/D

cd f/c/d

Теперь код написан, но проблема, которую я пытаюсь решить, - это проблема запуска пути с помощью «/» (это означает, что путь является абсолютным, а не относительным). Прямо сейчас, если я запускаю его с помощью пути с именем/dir1, он обрабатывает его как dir1 (относительный, а не абсолютный).

Это основная функция, которая вызывает рекурсивную функцию. pathname - это заданный путь, buf будет содержать реальный путь.

int readlink(char *pathname, char *buf, size_t bufsize){ 
    char name[DIRSIZ]; 
    char realpathname[100]; 

    memset(realpathname,0,100); 
    realpathname[0] = '/'; 

    if(get_real_path(pathname, name, realpathname, 0, 0)){ 
     memmove(buf, realpathname, strlen(realpathname)); 
     return strlen(realpathname); 
    } 

    return -1; 
} 

Это рекурсивная часть. функция возвращает структуру inode (которая представляет файл или каталог в системе). он строит реальный путь внутри realpath. Иконки iunlock используются для безопасного использования inode.

struct inode* get_real_path(char *path, char *name, char* realpath, int position){ 
    struct inode *ip, *next; 
    char buf[100]; 
    char newpath[100]; 

    if(*path == '/') 
     ip = iget(ROOTDEV, ROOTINO);// ip gets the root directory 
    else 
     ip = idup(proc->cwd); // ip gets the current working directory 

    while((path = skipelem(path, name)) != 0){name will get the next directory in the path, path will get the rest of the directories 
     ilock(ip); 
     if(ip->type != T_DIR){//if ip is a directory 
      realpath[position-1] = '\0'; 
      iunlockput(ip); 
      return 0; 
     } 

     if((next = dirlookup(ip, name, 0)) == 0){//next will get the inode of the next directory 
      realpath[position-1] = '\0'; 
      iunlockput(ip); 
      return 0; 
     } 
     iunlock(ip); 

     ilock(next); 

     if (next->type == T_SYM){ //if next is a symbolic link 
      readi(next, buf, 0, next->size); //buf contains the path inside the symbolic link (which is a path) 
      buf[next->size] = 0; 
      iunlockput(next); 

      next = get_real_path(buf, name, newpath, 0);//call it recursively (might still be a symbolic link) 

      if(next == 0){ 
       realpath[position-1] = '\0'; 
       iput(ip); 

       return 0; 
      } 

      name = newpath; 
      position = 0; 
     }  
     else 
     iunlock(next); 

     memmove(realpath + position, name, strlen(name)); 
     position += strlen(name); 
     realpath[position++]='/'; 
     realpath[position] = '\0'; 

     iput(ip); 

     ip = next; 
    } 
    realpath[position-1] = '\0'; 

    return ip; 
} 

Я пробовал много способов сделать это правильно, но без успеха. Если кто-нибудь увидит проблему, я буду рад услышать решение. Спасибо, Эяль

+3

так что происходит с этим кодом? это сокрушает? или дать неправильный ответ? или просто продолжает ничего говорить? – Qnan

+0

Без знания ошибки, с которой вы сталкиваетесь, трудно сделать конкретные предложения; но я скептически отношусь к как (а) рекурсивной функции в ядре, так и (б) построению полных путей внутри ядра. Если вы продолжите использовать рекурсивную функцию, вам в конечном итоге нужно будет ограничить глубину рекурсии, чтобы избежать продувки всей доступной памяти ядра. Я также удивлен, что вы редактируете пути на лету - каждый отдельный компонент пути в один момент кажется мне более правдоподобным, чем создание потенциально огромной новой строки для описания «реального» пути ... – sarnold

+0

@ Михаила Кожевникова - код дает неправильный ответ (как я объяснил, при вводе пути, начинающегося с косой черты, что является абсолютным путем, это неправильно) – Eyal

ответ

0

Хорошо, нашел проблему ... Проблема была глубже, чем я думал ... Как-то Realpath было изменено иногда без видимой причины ... но причина была линия: имя = NewPath;

решение должно было изменить эту строку на strcpy (name, newpath);

предыдущая строка сделала привязку между именем и realpath ... что может быть в порядке, если мы не имеем дело с программными ссылками. При разыменовании подпути, это связывание разрушало все.

Спасибо за попытки

0

Я думаю, ясно, что после запуска get_real_path(pathname, name, realpathname, 0, 0)realpathname не может начинаться с косой чертой.

При условии, что функция выполняется успешно, то memmove(realpath + position, name, strlen(name)) гарантирует, что realpath начинается с name, так как переменная position всегда содержит нуль при первом вызове memmove. Я бы предложил что-то вроде

if(*path == '/') { 
    ip = iget(ROOTDEV, ROOTINO); // ip gets the root 
    realpath[position++] = '/'; 
} else 
    ip = idup(proc->cwd); // ip gets the current working directory 

P.S. Я не уверен, почему вы поместили косую черту в realpathname перед выполнением get_real_path, так как на данный момент вы действительно не знаете, является ли предоставленный путь абсолютным.

Смежные вопросы