#ifndef FILE_H #define FILE_H /* * @(#)File.h * * This file is part of webCDwriter - Network CD Writing. * * Copyright (C) 1999-2004 Jörg P. M. Haeger * * webCDwriter is free software. See CDWserver.cpp for details. */ #include #include #include #include #include #include #include #include #include "String.h" #include "StringBuffer.h" /** * An abstract file class similar to java.io.File. * * @version 20041104 * @author Jörg P. M. Haeger */ class File { String pathName; String *nameMem, *parentMem; public: File(const char *pathName): pathName(pathName) { init(); } File(String *pathName): pathName(pathName) { init(); } File(String &pathName): pathName(pathName) { init(); } File(File *file) { pathName = file->pathName; delete file; init(); } File(const char *parent, const char *child) { pathName = pathName + parent + '/' + child; init(); } File(const char *parent, String &child) { pathName = pathName + parent + '/' + child; init(); } File(const char *parent, String *child) { pathName = pathName + parent + '/' + *child; delete child; init(); } File(String &parent, const char *child) { pathName = parent; pathName = pathName + '/' + child; init(); } File(File &parent, const char *child) { pathName = parent.pathName; pathName = pathName + '/' + child; init(); } File(File &parent, String &child) { pathName = parent.pathName; pathName = pathName + '/' + child; init(); } File(File *parent, const char *child) { if (parent == NULL) pathName = child; else { pathName = parent->pathName; pathName = pathName + '/' + child; // delete parent; } init(); } ~File() { if (nameMem != NULL) delete nameMem; if (parentMem != NULL) delete parentMem; } File &operator=(File *file) { pathName = file->pathName; delete file; if (nameMem != NULL) { delete nameMem; nameMem = NULL; } if (parentMem != NULL) { delete parentMem; parentMem = NULL; } return *this; } bool canRead() { return access(pathName.getBytes(), R_OK) == 0; } bool canWrite() { return access(pathName.getBytes(), W_OK) == 0; } int checkOwner(uid_t owner) { return checkOwner(pathName.getBytes(), owner, 0); } void chmod(int mode) { ::chmod(pathName.getBytes(), mode); } void chown(uid_t owner, gid_t group) { chown(pathName.getBytes(), owner, group); } const char *complete() { if (pathName.indexOf("/") >= 0) return pathName.getBytes(); const char *path = getenv("PATH"); if (path == NULL) return pathName.getBytes(); while (1) { char dir[strlen(path) + 1 + strlen(pathName.getBytes()) + 1]; const char *ptr = strchr(path, ':'); if (ptr == NULL) strcpy(dir, path); else { strncpy(dir, path, ptr - path); dir[ptr - path] = 0; path = ptr + 1; } if (dir[0] != 0) strcat(dir, "/"); strcat(dir, pathName.getBytes()); struct stat statBuf; if (stat(dir, &statBuf) == 0) { pathName = dir; break; } if (ptr == NULL) break; } return pathName.getBytes(); } int exists() { struct stat statBuf; return stat(pathName.getBytes(), &statBuf) == 0; } public: String &getName() { if (nameMem == NULL) nameMem = pathName.substring( pathName.lastIndexOf("/") + 1); return *nameMem; } public: String &getParent() { if (parentMem == NULL) { int pos = pathName.lastIndexOf("/"); if (pos <= 0) parentMem = new String("/"); else parentMem = pathName.substring(0, pos); } return *parentMem; } String &getPath() { return pathName; } off_t getSize() { return length(); } int getTreeSizeKB() { int filesCounter = 0; return getTreeSizeKB(pathName.getBytes(), filesCounter); } int getTreeSizeKB(int &filesCounter) { return getTreeSizeKB(pathName.getBytes(), filesCounter); } uid_t getUser() { struct stat statBuf; if (stat(pathName.getBytes(), &statBuf) != 0) return 0; return statBuf.st_uid; } private: void init() { int pos = pathName.length(); while (pos > 1 && pathName.charAt(pos - 1) == '/') pos--; if (pos < pathName.length()) pathName = pathName.substring(0, pos); nameMem = parentMem = NULL; } public: int isDirectory() const { String pathName2 = pathName; struct stat statBuf; if (stat(pathName2.getBytes(), &statBuf) != 0) return 0; return S_ISDIR(statBuf.st_mode); } int isLink() { struct stat statBuf; if (lstat(pathName.getBytes(), &statBuf) != 0) return 0; return S_ISLNK(statBuf.st_mode); } int isReadAndWritable(uid_t owner, gid_t group, int depth = 1024) { return isReadAndWritable(pathName.getBytes(), owner, group, depth); } int lastModified() const { String pathName(File::pathName); struct stat statBuf; if (stat(pathName.getBytes(), &statBuf) == 0) return statBuf.st_mtime; else return 0; } off_t length() { struct stat statBuf; if (stat(pathName.getBytes(), &statBuf) != 0) return 0; return statBuf.st_size; } int mkdir() { return ::mkdir(pathName.getBytes(), S_IRWXU) == 0; } int mkdirs() { StringBuffer str = ""; for (int i = 0; ; i++) { char ch; if (i < pathName.length()) ch = pathName.charAt(i); else if (i == pathName.length()) ch = '/'; else break; str.append(ch); if (ch == '/') { File dir = new File(new String(str)); if (!dir.exists()) if (!dir.mkdir()) return 0; } } return 1; } int mkdirsParent() { File parent = new File(getParent()); return parent.mkdirs(); } void remove() { remove(pathName.getBytes()); } public: bool renameTo(File &dest) { rename(pathName.getBytes(), dest.getPath().getBytes()) == 0; } int setLastModified(int time) { struct utimbuf buf; buf.actime = buf.modtime = time; return utime(pathName.getBytes(), &buf) == 0; } private: static int checkOwner(const char *pathName, uid_t owner, int level) { struct stat statBuf; if (level <= 1) { // follow links on the first or second level if (stat(pathName, &statBuf) != 0) return -1; } else if (lstat(pathName, &statBuf) != 0) return -1; if (statBuf.st_uid != owner) return -1; if (!S_ISDIR(statBuf.st_mode)) return 0; DIR *dir = opendir(pathName); if (dir == NULL) return -1; int result = 0; struct dirent *dirEntry; while ((dirEntry = readdir(dir)) != NULL) { if (strcmp(dirEntry->d_name, ".") == 0 || strcmp(dirEntry->d_name, "..") == 0) continue; File f = new File(pathName, dirEntry->d_name); if (checkOwner(f.getPath().getBytes(), owner, level + 1) != 0) { result = -1; break; } } closedir(dir); return result; } static void chown(const char *pathName, uid_t owner, gid_t group) { struct stat statBuf; if (stat(pathName, &statBuf) != 0) return; ::chown(pathName, owner, group); if (!S_ISDIR(statBuf.st_mode)) return; DIR *dir = opendir(pathName); if (dir == NULL) return; struct dirent *dirEntry; while ((dirEntry = readdir(dir)) != NULL) { if (strcmp(dirEntry->d_name, ".") == 0 || strcmp(dirEntry->d_name, "..") == 0) continue; char tmpPathName[strlen(pathName) + 1 + strlen(dirEntry->d_name) + 1]; sprintf(tmpPathName, "%s/%s", pathName, dirEntry->d_name); chown(tmpPathName, owner, group); } closedir(dir); } static int getTreeSizeKB( const char *pathName, int &filesCounter, int level = 0) { if (level >= 10) return 0; struct stat statBuf; if (stat(pathName, &statBuf) != 0) return 0; if (!S_ISDIR(statBuf.st_mode)) { filesCounter++; return (statBuf.st_size + 1023) / 1024; } DIR *dir = opendir(pathName); if (dir == NULL) return 0; int sum = 0; struct dirent *dirEntry; while ((dirEntry = readdir(dir)) != NULL) { if (strcmp(dirEntry->d_name, ".") == 0 || strcmp(dirEntry->d_name, "..") == 0) continue; char tmpPathName[strlen(pathName) + 1 + strlen(dirEntry->d_name) + 1]; sprintf(tmpPathName, "%s/%s", pathName, dirEntry->d_name); sum += getTreeSizeKB(tmpPathName, filesCounter, level + 1); } closedir(dir); return sum; } static int isReadAndWritable(const char *pathName, uid_t owner, gid_t group, int depth = 1024) { struct stat statBuf; if (stat(pathName, &statBuf) != 0) return -1; if (statBuf.st_uid == owner) { if ((statBuf.st_mode & S_IRUSR) == 0 || (statBuf.st_mode & S_IWUSR) == 0) return -1; } else if (statBuf.st_gid == group) { if ((statBuf.st_mode & S_IRGRP) == 0 || (statBuf.st_mode & S_IWGRP) == 0) return -1; } else if ((statBuf.st_mode & S_IROTH) == 0 || (statBuf.st_mode & S_IWOTH) == 0) return -1; if (!S_ISDIR(statBuf.st_mode) || depth <= 0) return 0; DIR *dir = opendir(pathName); if (dir == NULL) return -1; struct dirent *dirEntry; while ((dirEntry = readdir(dir)) != NULL) { if (strcmp(dirEntry->d_name, ".") == 0 || strcmp(dirEntry->d_name, "..") == 0) continue; char tmpPathName[strlen(pathName) + 1 + strlen(dirEntry->d_name) + 1]; sprintf(tmpPathName, "%s/%s", pathName, dirEntry->d_name); if (isReadAndWritable(tmpPathName, owner, group, depth - 1) != 0) return -1; } closedir(dir); return 0; } static void remove(const char *pathName) { struct stat statBuf; if (lstat(pathName, &statBuf) != 0) return; if (!S_ISDIR(statBuf.st_mode)) { unlink(pathName); return; } DIR *dir = opendir(pathName); if (dir == NULL) return; struct dirent *dirEntry; while ((dirEntry = readdir(dir)) != NULL) { if (strcmp(dirEntry->d_name, ".") == 0 || strcmp(dirEntry->d_name, "..") == 0) continue; char tmpPathName[strlen(pathName) + 1 + strlen(dirEntry->d_name) + 1]; sprintf(tmpPathName, "%s/%s", pathName, dirEntry->d_name); remove(tmpPathName); } closedir(dir); rmdir(pathName); } }; #endif