Рекурсивная функция для манипулирования заданным путем

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

В принципе, если у меня есть путь a/b/c/d и ссылка от f до a/b, следующие операции должны быть эквивалентны:

CD 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. ilock iunlock используются для безопасного использования инода.

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;
}

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

2 ответа

Решение

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

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

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

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

Я думаю понятно что после запуска 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

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

Другие вопросы по тегам