/*
** Copyright 2000-2004 University of Illinois Board of Trustees
** Copyright 2000-2004 Mark D. Roth
** All rights reserved.
**
** ftpstat.c - FTP file attribute checking code
**
** Mark D. Roth <roth@feep.net>
*/
#include <internal.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <sys/stat.h>
#ifdef STDC_HEADERS
# include <string.h>
#endif
static int
_ftp_stat_aux(FTP *ftp, char *path, struct ftpstat *fsp, unsigned short flags)
{
file_info_t *fip = NULL;
#ifdef DEBUG
printf("==> _ftp_stat_aux(ftp=0x%lx, path=\"%s\", fsp=0x%lx, "
"flags=%hu)\n", ftp, path, fsp, flags);
#endif
if (_ftp_dircache_find_file(ftp, path, flags, &fip) == -1
|| fip == NULL)
return -1;
memcpy(fsp, &(fip->fi_stat), sizeof(struct ftpstat));
return 0;
}
/* stat a symlink */
int
ftp_lstat(FTP *ftp, char *path, struct ftpstat *fsp)
{
return _ftp_stat_aux(ftp, path, fsp, DC_NOFOLLOWLINKS);
}
/* stat a file, dereferencing symlinks */
int
ftp_stat(FTP *ftp, char *path, struct ftpstat *fsp)
{
return _ftp_stat_aux(ftp, path, fsp, 0);
}
/* read the contents of a symbolic link */
int
ftp_readlink(FTP *ftp, char *path, char *buf, size_t bufsize)
{
file_info_t *fip = NULL;
if (_ftp_dircache_find_file(ftp, path, DC_NOFOLLOWLINKS, &fip) == -1
|| fip == NULL)
return -1;
if (! S_ISLNK(fip->fi_stat.fs_mode))
{
errno = EINVAL;
return -1;
}
strlcpy(buf, fip->fi_linkto, bufsize);
return 0;
}
/* determine the absolute pathname of the file or dir specified by path */
int
_ftp_abspath(FTP *ftp, char *path, char *abspath, size_t abspathlen)
{
char buf[MAXPATHLEN];
if (path[0] == '/')
strlcpy(buf, path, sizeof(buf));
else
snprintf(buf, sizeof(buf), "%s/%s", ftp_getcwd(ftp), path);
return fget_cleanpath(buf, abspath, abspathlen);
}
/* resolve symlinks */
static int
_ftp_realpath_aux(FTP *ftp, char *path,
char *resolved_path, size_t resolvelen, int level)
{
char pathbuf[MAXPATHLEN];
char buf[MAXPATHLEN];
char link_target[MAXPATHLEN];
char *nextp, *dirp = NULL;
struct ftpstat fs;
#ifdef DEBUG
printf("==> _ftp_realpath_aux(ftp=(%s), path=\"%s\", "
"resolved_path=0x%lx, resolvelen=%d, level=%d)\n",
ftp->ftp_host, path, resolved_path, resolvelen, level);
#endif
if (level >= MAXSYMLINKS)
{
errno = ELOOP;
return -1;
}
/* initialize to empty string */
resolved_path[0] = '\0';
_ftp_abspath(ftp, path, pathbuf, sizeof(pathbuf));
nextp = pathbuf + 1; /* skip leading slash */
/* iterate through path components */
while ((dirp = strsep(&nextp, "/")) != NULL)
{
strlcat(resolved_path, "/", resolvelen);
strlcat(resolved_path, dirp, resolvelen);
#ifdef DEBUG
printf("dirp=\"%s\"\n", dirp);
printf("nextp=\"%s\"\n", nextp ? nextp : "[NULL]");
printf("resolved_path=\"%s\"\n", resolved_path);
#endif
if (ftp_lstat(ftp, resolved_path, &fs) == -1)
return -1;
if (S_ISLNK(fs.fs_mode))
{
if (ftp_readlink(ftp, resolved_path, link_target,
sizeof(link_target)) == -1)
return -1;
/*
** determine absolute path that the link points to
*/
if (link_target[0] != '/')
snprintf(buf, sizeof(buf), "%s/%s",
dirname(path), link_target);
else
strlcpy(buf, link_target, sizeof(buf));
/*
** append the remaining components from the
** original path
*/
if (nextp != NULL)
{
strlcat(buf, "/", sizeof(buf));
strlcat(buf, nextp, sizeof(buf));
}
/*
** call ourself recursively
*/
return _ftp_realpath_aux(ftp, buf,
resolved_path, resolvelen,
level + 1);
}
}
#ifdef DEBUG
printf("<== _ftp_realpath_aux(): returning \"%s\"\n", resolved_path);
#endif
return 0;
}
int
ftp_realpath(FTP *ftp, char *path, char *resolved_path, size_t resolvelen)
{
return _ftp_realpath_aux(ftp, path, resolved_path, resolvelen, 0);
}
syntax highlighted by Code2HTML, v. 0.9.1