/*MT* MediaTomb - http://www.mediatomb.cc/ filesystem.cc - this file is part of MediaTomb. Copyright (C) 2005 Gena Batyan , Sergey 'Jin' Bostandzhyan Copyright (C) 2006-2007 Gena Batyan , Sergey 'Jin' Bostandzhyan , Leonhard Wimmer MediaTomb is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. MediaTomb is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License version 2 along with MediaTomb; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. $Id: filesystem.cc 1124 2007-02-17 21:49:15Z lww $ */ /// \file filesystem.cc #ifdef HAVE_CONFIG_H #include "autoconfig.h" #endif #include #include #include #include "common.h" #include "config_manager.h" #include "content_manager.h" #include "filesystem.h" #include "mxml/mxml.h" #include "tools.h" using namespace zmm; using namespace mxml; int FsObjectComparator(void *arg1, void *arg2) { FsObject *o1 = (FsObject *)arg1; FsObject *o2 = (FsObject *)arg2; if (o1->isDirectory) { if (o2->isDirectory) return strcmp(o1->filename.c_str(), o2->filename.c_str()); else return -1; } else { if (o2->isDirectory) return 1; else return strcmp(o1->filename.c_str(), o2->filename.c_str()); } } Filesystem::Filesystem() : Object() { includeRules = Ref >(new Array()); Ref cm = ConfigManager::getInstance(); Ref rules = cm->getElement(_("filter")); if (rules == nil) return; for (int i = 0; i < rules->childCount(); i++) { Ref rule = rules->getChild(i); String pat = rule->getAttribute(_("pattern")); /// \todo make patterns from simple wildcards instead of /// taking the pattern attribute directly as regexp Ref pattern(new RExp()); try { pattern->compile(pat); includeRules->append(pattern); } catch (Exception e) { e.printStackTrace(); } } } Ref > Filesystem::readDirectory(String path, int mask, int childMask) { if (path.charAt(0) != '/') { throw _Exception(_("Filesystem: relative paths not allowed: ") + path); } if (! fileAllowed(path)) throw _Exception(_("Filesystem: file blocked: ") + path); struct stat statbuf; int ret; Ref > files(new Array()); DIR *dir; struct dirent *dent; dir = opendir(path.c_str()); if (! dir) { throw _Exception(_("could not list directory ") + path + " : " + strerror(errno)); } while ((dent = readdir(dir)) != NULL) { char *name = dent->d_name; if (name[0] == '.') { if (name[1] == 0) { continue; } else if (name[1] == '.' && name[2] == 0) { continue; } else if (!(mask & FS_MASK_HIDDEN)) continue; } String childPath; if (path == FS_ROOT_DIRECTORY) childPath = path + name; else childPath = path + "/" + name; if (fileAllowed(childPath)) { bool isDirectory = false; bool hasContent = false; ret = stat(childPath.c_str(), &statbuf); if (ret != 0) continue; if (S_ISREG(statbuf.st_mode)) { if (! (mask & FS_MASK_FILES)) continue; } else if (S_ISDIR(statbuf.st_mode)) { if (! (mask & FS_MASK_DIRECTORIES)) continue; isDirectory = true; if (childMask) { try { hasContent = have(childPath, childMask); } catch (Exception e) { //continue; } } } else continue; // special file Ref obj(new FsObject()); obj->filename = String(name); obj->isDirectory = isDirectory; obj->hasContent = hasContent; files->append(obj); } } closedir(dir); quicksort((COMPARABLE *)files->getObjectArray(), files->size(), FsObjectComparator); return files; } bool Filesystem::have(String path, int mask) { /* if (path.charAt(0) != '/') { throw _Exception(_("Filesystem relative paths not allowed: ") + path); } */ if (! fileAllowed(path)) return false; struct stat statbuf; int ret; Ref > files(new Array()); DIR *dir; struct dirent *dent; dir = opendir(path.c_str()); if (! dir) { throw _Exception(_("could not list directory ")+ path + " : " + strerror(errno)); } bool result = false; while ((dent = readdir(dir)) != NULL) { char *name = dent->d_name; if (name[0] == '.') { if (name[1] == 0) { continue; } else if (name[1] == '.' && name[2] == 0) { continue; } else if (!(mask & FS_MASK_HIDDEN)) continue; } String childPath; if (path == FS_ROOT_DIRECTORY) childPath = path + name; else childPath = path + "/" + name; if (fileAllowed(childPath)) { ret = stat(childPath.c_str(), &statbuf); if (ret != 0) continue; if (S_ISREG(statbuf.st_mode) && mask & FS_MASK_FILES) { result = true; break; } else if (S_ISDIR(statbuf.st_mode) && mask & FS_MASK_DIRECTORIES) { result = true; break; } else continue; // special file } } closedir(dir); return result; } bool Filesystem::haveFiles(String dir) { return have(dir, FS_MASK_FILES); } bool Filesystem::haveDirectories(String dir) { return have(dir, FS_MASK_DIRECTORIES); } bool Filesystem::fileAllowed(String path) { if (path == ConfigManager::getInstance()->getConfigFilename()) return false; return true; /* for (int i = 0; i < include_rules->size(); i++) { Ref rule = include_rules->get(i); if (rule->matches(path)) return true; } return false; */ }