00001 #include <unistd.h>
00002 #include <cstdlib>
00003 #include "compat.h"
00004
00005 #ifdef linux
00006 #include <sys/vfs.h>
00007 #include <sys/sysinfo.h>
00008 #endif
00009
00010 #if CONFIG_DARWIN
00011 #include <mach/mach.h>
00012 #endif
00013
00014 #ifdef BSD
00015 #include <sys/param.h>
00016 #include <sys/mount.h>
00017 #endif
00018
00019 using namespace std;
00020
00021 #include <QList>
00022 #include <QString>
00023 #include <QStringList>
00024
00025 #include "filesysteminfo.h"
00026 #include "mythcoreutil.h"
00027
00028
00029 #define INT_TO_LIST(x) do { list << QString::number(x); } while (0)
00030 #define DATETIME_TO_LIST(x) INT_TO_LIST((x).toTime_t())
00031 #define STR_TO_LIST(x) do { list << (x); } while (0)
00032
00033
00034 #define NEXT_STR() do { if (it == listend) \
00035 { \
00036 LOG(VB_GENERAL, LOG_ALERT, listerror); \
00037 clear(); \
00038 return false; \
00039 } \
00040 ts = *it++; } while (0)
00041 #define INT_FROM_LIST(x) do { NEXT_STR(); (x) = ts.toLongLong(); } while (0)
00042 #define ENUM_FROM_LIST(x, y) do { NEXT_STR(); (x) = ((y)ts.toInt()); } while (0)
00043 #define DATETIME_FROM_LIST(x) \
00044 do { NEXT_STR(); (x).setTime_t(ts.toUInt()); } while (0)
00045 #define STR_FROM_LIST(x) do { NEXT_STR(); (x) = ts; } while (0)
00046
00047 #define LOC QString("FileSystemInfo: ")
00048
00049 FileSystemInfo::FileSystemInfo(void) :
00050 m_hostname(""), m_path(""), m_local(false), m_fsid(-1),
00051 m_grpid(-1), m_blksize(4096), m_total(0), m_used(0), m_weight(0)
00052 {
00053 }
00054
00055 FileSystemInfo::FileSystemInfo(const FileSystemInfo &other)
00056 {
00057 clone(other);
00058 }
00059
00060 FileSystemInfo::FileSystemInfo(QString hostname, QString path, bool local,
00061 int fsid, int groupid, int blksize, int64_t total, int64_t used) :
00062 m_hostname(hostname), m_path(path), m_local(local), m_fsid(fsid),
00063 m_grpid(groupid), m_blksize(blksize), m_total(total), m_used(used),
00064 m_weight(0)
00065 {
00066 }
00067
00068 FileSystemInfo::FileSystemInfo(QStringList::const_iterator &it,
00069 QStringList::const_iterator end)
00070 {
00071 FromStringList(it, end);
00072 }
00073
00074 FileSystemInfo::FileSystemInfo(const QStringList &slist)
00075 {
00076 FromStringList(slist);
00077 }
00078
00079 void FileSystemInfo::clone(const FileSystemInfo &other)
00080 {
00081 m_hostname = other.m_hostname;
00082 m_path = other.m_path;
00083 m_local = other.m_local;
00084 m_fsid = other.m_fsid;
00085 m_grpid = other.m_grpid;
00086 m_blksize = other.m_blksize;
00087 m_total = other.m_total;
00088 m_used = other.m_used;
00089 m_weight = other.m_weight;
00090 }
00091
00092 FileSystemInfo &FileSystemInfo::operator=(const FileSystemInfo &other)
00093 {
00094 clone(other);
00095 return *this;
00096 }
00097
00098 void FileSystemInfo::clear(void)
00099 {
00100 m_hostname = "";
00101 m_path = "";
00102 m_local = false;
00103 m_fsid = -1;
00104 m_grpid = -1;
00105 m_blksize = 4096;
00106 m_total = 0;
00107 m_used = 0;
00108 m_weight = 0;
00109 }
00110
00111 bool FileSystemInfo::ToStringList(QStringList &list) const
00112 {
00113 STR_TO_LIST(m_hostname);
00114 STR_TO_LIST(m_path);
00115 INT_TO_LIST(m_local);
00116 INT_TO_LIST(m_fsid);
00117 INT_TO_LIST(m_grpid);
00118 INT_TO_LIST(m_blksize);
00119 INT_TO_LIST(m_total);
00120 INT_TO_LIST(m_used);
00121
00122 return true;
00123 }
00124
00125 bool FileSystemInfo::FromStringList(const QStringList &slist)
00126 {
00127 QStringList::const_iterator it = slist.constBegin();
00128 return FromStringList(it, slist.constEnd());
00129 }
00130
00131 bool FileSystemInfo::FromStringList(QStringList::const_iterator &it,
00132 QStringList::const_iterator listend)
00133 {
00134 QString listerror = LOC + "FromStringList, not enough items in list.";
00135 QString ts;
00136
00137 STR_FROM_LIST(m_hostname);
00138 STR_FROM_LIST(m_path);
00139 INT_FROM_LIST(m_local);
00140 INT_FROM_LIST(m_fsid);
00141 INT_FROM_LIST(m_grpid);
00142 INT_FROM_LIST(m_blksize);
00143 INT_FROM_LIST(m_total);
00144 INT_FROM_LIST(m_used);
00145
00146 m_weight = 0;
00147
00148 return true;
00149 }
00150
00151 const QList<FileSystemInfo> FileSystemInfo::RemoteGetInfo(MythSocket *sock)
00152 {
00153 FileSystemInfo fsInfo;
00154 QList<FileSystemInfo> fsInfos;
00155 QStringList strlist(QString("QUERY_FREE_SPACE_LIST"));
00156
00157 bool sent;
00158
00159 if (sock)
00160 sent = sock->SendReceiveStringList(strlist);
00161 else
00162 sent = gCoreContext->SendReceiveStringList(strlist);
00163
00164 if (sent)
00165 {
00166 int numdisks = strlist.size()/NUMDISKINFOLINES;
00167
00168 QStringList::const_iterator it = strlist.begin();
00169 for (int i = 0; i < numdisks; i++)
00170 {
00171 fsInfo.FromStringList(it, strlist.end());
00172 fsInfos.append(fsInfo);
00173 }
00174 }
00175
00176 return fsInfos;
00177 }
00178
00179 void FileSystemInfo::Consolidate(QList<FileSystemInfo> &disks,
00180 bool merge, int64_t fuzz)
00181 {
00182 int newid = 0;
00183
00184 QList<FileSystemInfo>::iterator it1, it2;
00185 for (it1 = disks.begin(); it1 != disks.end(); ++it1)
00186 {
00187 if (it1->getFSysID() == -1)
00188 {
00189 it1->setFSysID(newid++);
00190 if (merge)
00191 it1->setPath(it1->getHostname().section(".", 0, 0)
00192 + ":" + it1->getPath());
00193 }
00194
00195 for (it2 = it1+1; it2 != disks.end(); ++it2)
00196 {
00197 if (it2->getFSysID() != -1)
00198 continue;
00199
00200 int bSize = max(32, max(it1->getBlockSize(), it2->getBlockSize())
00201 / 1024);
00202 int64_t diffSize = it1->getTotalSpace() - it2->getTotalSpace();
00203 int64_t diffUsed = it1->getUsedSpace() - it2->getUsedSpace();
00204
00205 if (diffSize < 0)
00206 diffSize = 0 - diffSize;
00207 if (diffUsed < 0)
00208 diffUsed = 0 - diffUsed;
00209
00210 if ((diffSize <= bSize) && (diffUsed <= fuzz))
00211 {
00212 it2->setFSysID(it1->getFSysID());
00213
00214 if (merge)
00215 {
00216 if (!it1->getHostname().contains(it2->getHostname()))
00217 it1->setHostname(it1->getHostname()
00218 + "," + it2->getHostname());
00219 it1->setPath(it1->getPath() + ","
00220 + it2->getHostname().section(".", 0, 0) + ":"
00221 + it2->getPath());
00222 disks.erase(it2);
00223 it2 = it1;
00224 }
00225 }
00226 }
00227 }
00228 }
00229
00230 void FileSystemInfo::PopulateDiskSpace(void)
00231 {
00232 int64_t total = -1, used = -1;
00233 getDiskSpace(getPath().toAscii().constData(), total, used);
00234 setTotalSpace(total);
00235 setUsedSpace(used);
00236 }
00237
00238 void FileSystemInfo::PopulateFSProp(void)
00239 {
00240 struct statfs statbuf;
00241 memset(&statbuf, 0, sizeof(statbuf));
00242
00243 if (!statfs(getPath().toLocal8Bit().constData(), &statbuf))
00244 {
00245 #if CONFIG_DARWIN
00246 char *fstypename = statbuf.f_fstypename;
00247 if ((!strcmp(fstypename, "nfs")) ||
00248 (!strcmp(fstypename, "afpfs")) ||
00249 (!strcmp(fstypename, "smbfs")))
00250 setLocal(false);
00251 #elif __linux__
00252 long fstype = statbuf.f_type;
00253 if ((fstype == 0x6969) ||
00254 (fstype == 0x517B) ||
00255 (fstype == (long)0xFF534D42))
00256 setLocal(false);
00257 #endif
00258 setBlockSize(statbuf.f_bsize);
00259 }
00260 }