+Path readlink(const Path &link)
+{
+#ifdef WIN32
+ (void)link;
+ throw Exception("No symbolic links on win32");
+#else
+ char buf[4096];
+ int len = ::readlink(link.str().c_str(), buf, sizeof(buf));
+ if(len==-1)
+ throw SystemError("readlink failed", errno);
+ return string(buf, len);
+#endif
+}
+
+Path realpath(const Path &path)
+{
+#ifdef WIN32
+ if(path.is_absolute())
+ return path;
+ else
+ return getcwd()/path;
+#else
+ list<string> queue(path.begin(), path.end());
+ if(!path.is_absolute())
+ {
+ Path cwd = getcwd();
+ queue.insert(queue.begin(), cwd.begin(), cwd.end());
+ }
+
+ Path real;
+ unsigned n_links = 0;
+ while(!queue.empty())
+ {
+ Path next = real/queue.front();
+ queue.pop_front();
+
+ struct stat st = lstat(next);
+ if(S_ISLNK(st.st_mode))
+ {
+ if(++n_links>64)
+ throw Exception("Ludicrous amount of symlinks detected in realpath, giving up");
+ Path link = readlink(next);
+ queue.insert(queue.begin(), link.begin(), link.end());
+ }
+ else
+ real = next;
+ }
+
+ return real;
+#endif
+}
+
+void rename(const Path &from, const Path &to)
+{
+ if(::rename(from.str().c_str(), to.str().c_str())==-1)
+ throw SystemError("rename failed", errno);
+}
+