4f294c247f
This patch mainly copies and modifies files existing in the current libc implementing minix specific functions. To keep consisten with the NetBSD libc, we remove namespace stubs and we use "namespace.h" and weak links.
140 lines
2.9 KiB
C
140 lines
2.9 KiB
C
/* getcwd() - get the name of the current working directory.
|
|
* Author: Kees J. Bot
|
|
* 30 Apr 1989
|
|
*/
|
|
|
|
#define chdir _chdir
|
|
#include <sys/cdefs.h>
|
|
#include "namespace.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <dirent.h>
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
|
|
static int addpath(const char *path, char **ap, const char *entry)
|
|
/* Add the name of a directory entry at the front of the path being built.
|
|
* Note that the result always starts with a slash.
|
|
*/
|
|
{
|
|
const char *e= entry;
|
|
char *p= *ap;
|
|
|
|
while (*e != 0) e++;
|
|
|
|
while (e > entry && p > path) *--p = *--e;
|
|
|
|
if (p == path) return -1;
|
|
*--p = '/';
|
|
*ap= p;
|
|
return 0;
|
|
}
|
|
|
|
static int recover(char *p)
|
|
/* Undo all those chdir("..")'s that have been recorded by addpath. This
|
|
* has to be done entry by entry, because the whole pathname may be too long.
|
|
*/
|
|
{
|
|
int e= errno, slash;
|
|
char *p0;
|
|
|
|
while (*p != 0) {
|
|
p0= ++p;
|
|
|
|
do p++; while (*p != 0 && *p != '/');
|
|
slash= *p; *p= 0;
|
|
|
|
if (chdir(p0) < 0) return -1;
|
|
*p= slash;
|
|
}
|
|
errno= e;
|
|
return 0;
|
|
}
|
|
|
|
int __getcwd(char *path, size_t size)
|
|
{
|
|
struct stat above, current, tmp;
|
|
struct dirent *entry;
|
|
DIR *d;
|
|
char *p, *up, *dotdot;
|
|
int cycle;
|
|
|
|
if (path == NULL || size <= 1) { errno= EINVAL; return -1; }
|
|
|
|
p= path + size;
|
|
*--p = 0;
|
|
|
|
if (stat(".", ¤t) < 0) return -1;
|
|
|
|
while (1) {
|
|
dotdot= "..";
|
|
if (stat(dotdot, &above) < 0) { recover(p); return -1; }
|
|
|
|
if (above.st_dev == current.st_dev
|
|
&& above.st_ino == current.st_ino)
|
|
break; /* Root dir found */
|
|
|
|
if ((d= opendir(dotdot)) == NULL) { recover(p); return -1; }
|
|
|
|
/* Cycle is 0 for a simple inode nr search, or 1 for a search
|
|
* for inode *and* device nr.
|
|
*/
|
|
cycle= above.st_dev == current.st_dev ? 0 : 1;
|
|
|
|
do {
|
|
char name[3 + NAME_MAX + 1];
|
|
|
|
tmp.st_ino= 0;
|
|
if ((entry= readdir(d)) == NULL) {
|
|
switch (++cycle) {
|
|
case 1:
|
|
rewinddir(d);
|
|
continue;
|
|
case 2:
|
|
closedir(d);
|
|
errno= ENOENT;
|
|
recover(p);
|
|
return -1;
|
|
}
|
|
}
|
|
if (strcmp(entry->d_name, ".") == 0) continue;
|
|
if (strcmp(entry->d_name, "..") == 0) continue;
|
|
|
|
switch (cycle) {
|
|
case 0:
|
|
/* Simple test on inode nr. */
|
|
if (entry->d_ino != current.st_ino) continue;
|
|
/*FALL THROUGH*/
|
|
|
|
case 1:
|
|
/* Current is mounted. */
|
|
strcpy(name, "../");
|
|
strcpy(name+3, entry->d_name);
|
|
if (stat(name, &tmp) < 0) continue;
|
|
break;
|
|
}
|
|
} while (tmp.st_ino != current.st_ino
|
|
|| tmp.st_dev != current.st_dev);
|
|
|
|
up= p;
|
|
if (addpath(path, &up, entry->d_name) < 0) {
|
|
closedir(d);
|
|
errno = ERANGE;
|
|
recover(p);
|
|
return -1;
|
|
}
|
|
closedir(d);
|
|
|
|
if (chdir(dotdot) < 0) { recover(p); return -1; }
|
|
p= up;
|
|
|
|
current= above;
|
|
}
|
|
if (recover(p) < 0) return -1; /* Undo all those chdir("..")'s. */
|
|
if (*p == 0) *--p = '/'; /* Cwd is "/" if nothing added */
|
|
if (p > path) strcpy(path, p); /* Move string to start of path. */
|
|
return 0;
|
|
}
|