Рекурсивная функция для манипулирования заданным путем
Я работаю над модификацией дидактической ОС 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
, поскольку на данный момент вы не знаете, является ли предоставленный путь абсолютным.