home *** CD-ROM | disk | FTP | other *** search
- #include <errno.h>
- #include <dirent.h>
- #include <fcntl.h>
- #include <glob.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/sysmacros.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <unistd.h>
-
- #include "idmap.h"
- #include "ls.h"
-
- struct fileInfo {
- char * name;
- struct stat sb;
- };
-
- static void permsString(int mode, char * perms);
- static int statFile(char * dir, char * fn, int flags, struct stat * sbp);
- static int implicitListFile(int sock, char * path,
- char * fn, struct stat * sbp, int flags);
- static int nameCmp(const void * a, const void * b);
- static int sizeCmp(const void * a, const void * b);
- static int mtimeCmp(const void * a, const void * b);
- static void multicolumnListing(int sock, struct fileInfo * files,
- int filesCount, int flags);
- static int sendDirContents(int sock, char * path,
- char * fn, int flags);
-
- static void permsString(int mode, char * perms) {
- strcpy(perms, "----------");
-
- if (mode & S_ISVTX) perms[9] = 't';
-
- if (mode & S_IRUSR) perms[1] = 'r';
- if (mode & S_IWUSR) perms[2] = 'w';
- if (mode & S_IXUSR) perms[3] = 'x';
-
- if (mode & S_IRGRP) perms[4] = 'r';
- if (mode & S_IWGRP) perms[5] = 'w';
- if (mode & S_IXGRP) perms[6] = 'x';
-
- if (mode & S_IROTH) perms[7] = 'r';
- if (mode & S_IWOTH) perms[8] = 'w';
- if (mode & S_IXOTH) perms[9] = 'x';
-
- if (mode & S_ISUID) {
- if (mode & S_IXUSR)
- perms[3] = 's';
- else
- perms[3] = 'S';
- }
-
- if (mode & S_ISGID) {
- if (mode & S_IXGRP)
- perms[6] = 's';
- else
- perms[6] = 'S';
- }
-
- if (S_ISDIR(mode))
- perms[0] = 'd';
- else if (S_ISLNK(mode)) {
- perms[0] = 'l';
- }
- else if (S_ISFIFO(mode))
- perms[0] = 'p';
- else if (S_ISSOCK(mode))
- perms[0] = 'l';
- else if (S_ISCHR(mode)) {
- perms[0] = 'c';
- } else if (S_ISBLK(mode)) {
- perms[0] = 'b';
- }
- }
-
- static int statFile(char * dir, char * fn, int flags, struct stat * sbp) {
- char * filename;
-
- if (dir) {
- filename = alloca(strlen(dir) + strlen(fn) + 2);
- sprintf(filename, "%s/%s", dir, fn);
- } else
- filename = fn;
-
- if (!(flags & SENDDIR_FOLLOWLINKS) || stat(filename, sbp)) {
- if (lstat(filename, sbp)) {
- return 1;
- }
- }
-
- return 0;
- }
-
- char * fileStatStr(char * dir, char * fn, struct stat * sbp, int flags) {
- char * info;
- char perms[12];
- char sizefield[15];
- char ownerfield[9], groupfield[9];
- char timefield[20] = "";
- char * linkto;
- char * namefield = fn;
- time_t themtime;
- time_t currenttime;
- char * name;
- int thisYear = 0;
- int thisMonth = 0;
- struct tm * tstruct;
- int i;
- char * filename;
-
- if (!sbp) {
- sbp = alloca(sizeof(*sbp));
- if (statFile(dir, fn, flags, sbp))
- return NULL;
- }
-
- permsString(sbp->st_mode, perms);
-
- currenttime = time(NULL);
- tstruct = localtime(¤ttime);
- thisYear = tstruct->tm_year;
- thisMonth = tstruct->tm_mon;
-
- name = idSearchByUid(sbp->st_uid);
- if (name)
- sprintf(ownerfield, "%-8s", name);
- else
- sprintf(ownerfield, "%-8d", (int) sbp->st_uid);
-
- name = idSearchByGid(sbp->st_gid);
- if (name)
- sprintf(groupfield, "%-8s", name);
- else
- sprintf(groupfield, "%-8d", (int) sbp->st_gid);
-
- if (S_ISLNK(sbp->st_mode)) {
- /* they don't reall want to see "opt -> /usr/opt@" */
-
- linkto = alloca(1024);
- strcpy(linkto, "(link)");
-
- filename = alloca(strlen(dir) + strlen(fn) + 2);
- sprintf(filename, "%s/%s", dir, fn);
-
- i = readlink(filename, linkto, 1023);
- if (i < 1)
- strcpy(linkto, "(cannot read symlink)");
- else
- linkto[i] = 0;
-
- namefield = alloca(strlen(fn) + strlen(linkto) + 10);
- sprintf(namefield, "%s -> %s", fn, linkto);
-
- sprintf(sizefield, "%d", i);
- } else if (S_ISCHR(sbp->st_mode)) {
- perms[0] = 'c';
- sprintf(sizefield, "%3d, %3d", major(sbp->st_rdev),
- minor(sbp->st_rdev));
- } else if (S_ISBLK(sbp->st_mode)) {
- perms[0] = 'b';
- sprintf(sizefield, "%3d, %3d", major(sbp->st_rdev),
- minor(sbp->st_rdev));
- } else {
- sprintf(sizefield, "%8ld", sbp->st_size);
- }
-
- /* this is important if sizeof(int_32) ! sizeof(time_t) */
- themtime = sbp->st_mtime;
- tstruct = localtime(&themtime);
-
- if (tstruct->tm_year == thisYear ||
- ((tstruct->tm_year + 1) == thisYear && tstruct->tm_mon > thisMonth))
- strftime(timefield, sizeof(timefield) - 1, "%b %d %H:%M", tstruct);
- else
- strftime(timefield, sizeof(timefield) - 1, "%b %d %Y", tstruct);
-
- info = malloc(strlen(namefield) + strlen(timefield) + 85);
-
- sprintf(info, "%s %3d %8s %8s %8s %s %s", perms, (int) sbp->st_nlink,
- ownerfield, groupfield, sizefield, timefield, namefield);
-
- return info;
- }
-
- /* Like listFiles(), but don't explode directories or wildcards */
- static int implicitListFile(int sock, char * path,
- char * fn, struct stat * sbp, int flags) {
- char * info;
- char fileType;
-
- if (flags & SENDDIR_LONG) {
- info = fileStatStr(path, fn, sbp, flags);
- if (info) {
- write(sock, info, strlen(info));
- free(info);
- }
- } else {
- write(sock, fn, strlen(fn));
- }
-
- if (flags & SENDDIR_FILETYPE) {
- if (S_ISSOCK(sbp->st_mode)) {
- fileType = '=';
- } else if (S_ISFIFO(sbp->st_mode)) {
- fileType = '|';
- } else if (S_ISDIR(sbp->st_mode)) {
- fileType = '/';
- } else if (S_IRWXO & sbp->st_mode) {
- fileType = '*';
- } else {
- fileType = '\0';
- }
-
- if (fileType) write(sock, &fileType, 1);
- }
-
- write(sock, "\n", 1);
-
- return 0;
- }
-
- static int nameCmp(const void * a, const void * b) {
- const struct fileInfo * one = a;
- const struct fileInfo * two = b;
-
- return (strcmp(one->name, two->name));
- }
-
- static int sizeCmp(const void * a, const void * b) {
- const struct fileInfo * one = a;
- const struct fileInfo * two = b;
-
- /* list newer files first */
-
- if (one->sb.st_size < two->sb.st_size)
- return 1;
- else if (one->sb.st_size > two->sb.st_size)
- return -1;
-
- return 0;
- }
-
- static int mtimeCmp(const void * a, const void * b) {
- const struct fileInfo * one = a;
- const struct fileInfo * two = b;
-
- if (one->sb.st_mtime < two->sb.st_mtime)
- return -1;
- else if (one->sb.st_mtime > two->sb.st_mtime)
- return 1;
-
- return 0;
- }
-
- static void multicolumnListing(int sock, struct fileInfo * files,
- int filesCount, int flags) {
- int i, j, k;
- int maxWidth = 0;
- char format[20];
- char * fileType = " ";
- char * buf, * name = NULL;
- int rows, columns;
-
- if (!filesCount) return;
-
- for (i = 0; i < filesCount; i++) {
- j = strlen(files[i].name);
- if (j > maxWidth) maxWidth = j;
- }
-
- maxWidth += 3;
- buf = alloca(maxWidth + 1);
-
- if (flags & SENDDIR_FILETYPE)
- name = alloca(maxWidth);
-
- columns = 80 / maxWidth;
- if (columns == 0) columns = 1;
-
- sprintf(format, "%%-%ds", 80 / columns);
-
- rows = filesCount / columns;
- if (filesCount % columns) rows++;
-
- for (i = 0; i < rows; i++) {
- j = i;
- while (j < filesCount) {
- if (flags & SENDDIR_FILETYPE) {
- if (S_ISDIR(files[j].sb.st_mode))
- fileType = "/";
- else if (S_ISSOCK(files[j].sb.st_mode))
- fileType = "=";
- else if (S_ISFIFO(files[j].sb.st_mode))
- fileType = "|";
- else if (S_ISLNK(files[j].sb.st_mode))
- fileType = "@";
- else
- fileType = " ";
-
- strcpy(name, files[j].name);
- strcat(name, fileType);
- } else
- name = files[j].name;
-
- if ((j + rows) < filesCount)
- k = sprintf(buf, format, name);
- else
- k = sprintf(buf, "%s", name);
-
- j += rows;
-
- write(sock, buf, k);
- }
-
- write(sock, "\n", 1);
- }
- }
-
- static int sendDirContents(int sock, char * path, char * fn, int flags) {
- struct dirent * ent;
- int start, direction;
- DIR * dir;
- int filesAlloced, filesCount, i;
- struct fileInfo * files, * newfiles;
- int failed = 0;
- int total = 0;
- char buf[20];
- char * fullpath;
- char * subdir;
-
- filesAlloced = 15;
- filesCount = 0;
- files = malloc(sizeof(*files) * filesAlloced);
-
- if (fn) {
- fullpath = alloca(strlen(path) + strlen(fn) + 2);
- sprintf(fullpath, "%s/%s", path, fn);
- } else
- fullpath = path;
-
- dir = opendir(fullpath);
-
- do {
- errno = 0;
- ent = readdir(dir);
- if (errno) {
- fprintf(stderr, "Error reading directory entry: %s",
- strerror(errno));
- failed = 1;
- } else if (ent && (*ent->d_name != '.' || (flags & SENDDIR_ALL))) {
- if (filesCount == filesAlloced) {
- filesAlloced += 15;
- newfiles = realloc(files, sizeof(*files) * filesAlloced);
- files = newfiles;
- }
-
- if (!failed) {
- files[filesCount].name = strdup(ent->d_name);
-
- if (statFile(fullpath, files[filesCount].name, flags,
- &files[filesCount].sb)) {
- fprintf(stderr, "stat of %s failed: %s" ,
- files[filesCount].name, strerror(errno));
- failed = 1;
- } else {
- total += files[filesCount].sb.st_size /
- 1024;
- }
-
- filesCount++;
- }
- }
- } while (ent && !failed);
-
- closedir(dir);
-
- if (!failed) {
- if (flags & SENDDIR_SORTMTIME) {
- qsort(files, filesCount, sizeof(*files), mtimeCmp);
- } else if (flags & SENDDIR_SORTSIZE) {
- qsort(files, filesCount, sizeof(*files), sizeCmp);
- } else if (!(flags & SENDDIR_SORTNONE)) {
- qsort(files, filesCount, sizeof(*files), nameCmp);
- }
-
- if (flags & SENDDIR_SORTREVERSE) {
- direction = -1;
- start = filesCount - 1;
- } else {
- direction = 1;
- start = 0;
- }
-
- if (fn) {
- write(sock, fn, strlen(fn));
- write(sock, ":\n", 2);
- }
-
- if (flags & SENDDIR_MULTICOLUMN) {
- multicolumnListing(sock, files, filesCount, flags);
- } else {
- if (flags & SENDDIR_LONG) {
- i = sprintf(buf, "total %d\n", total);
- write(sock, buf, i);
- }
-
- for (i = start; i >= 0 && i < filesCount; i += direction) {
- implicitListFile(sock, fullpath, files[i].name,
- &files[i].sb, flags);
- }
- }
-
- if (flags & SENDDIR_RECURSE) {
- for (i = start; i >= 0 && i < filesCount && !failed;
- i += direction) {
- if (S_ISDIR(files[i].sb.st_mode) &&
- strcmp(files[i].name, ".") &&
- strcmp(files[i].name, "..")) {
- write(sock, "\n", 1);
-
- if (fn) {
- subdir = malloc(strlen(fn) + strlen(files[i].name) + 2);
- sprintf(subdir, "%s/%s", fn, files[i].name);
- } else {
- subdir = files[i].name;
- }
-
- failed = sendDirContents(sock, path, subdir, flags);
-
- if (fn) free(subdir);
- }
- }
- }
- }
-
- for (i = 0; i < filesCount; i++) {
- free(files[i].name);
- }
- free(files);
-
- return failed;
- }
-
- /* implements 'ls' */
- void listFiles(char * path, char * fn, int flags) {
- struct stat sb;
- int i, rc;
- char * filename, * this;
- int isExplicit = 1;
- glob_t matches;
- int failed = 0;
-
- if (!fn) {
- fn = ".";
- isExplicit = 0;
- }
-
- filename = malloc(strlen(fn) + strlen(path) + 2);
- sprintf(filename, "%s/%s", path, fn);
-
- rc = glob(filename, GLOB_NOSORT, NULL, &matches);
- if (rc == GLOB_NOMATCH) {
- fprintf(stderr, "File not found.");
- return;
- }
- free(filename);
-
- for (i = 0; i < matches.gl_pathc && !failed; i++) {
- this = matches.gl_pathv[i] + strlen(path);
- if (*this)
- this++;
- else
- this = ".";
-
- if (!statFile(path, this, flags, &sb)) {
- if (S_ISDIR(sb.st_mode) && !(flags & SENDDIR_SIMPLEDIRS)) {
- filename = malloc(strlen(path) + strlen(this) + 2);
- sprintf(filename, "%s/%s", path, this);
-
- failed = sendDirContents(1, filename, NULL, flags);
- free(filename);
- } else {
- implicitListFile(1, path, this, &sb, flags);
- }
- } else {
- write(1, matches.gl_pathv[i], strlen(matches.gl_pathv[i]));
- write(1, ": file not found.\n", 18);
- }
- }
-
- globfree(&matches);
-
- close(1);
- }
-