MythTV  master
filesysteminfo.cpp
Go to the documentation of this file.
1 #include <unistd.h>
2 #include <cstdlib>
3 #include "compat.h"
4 
5 #ifdef linux
6 #include <sys/vfs.h>
7 #include <sys/sysinfo.h>
8 #endif
9 
10 #if CONFIG_DARWIN
11 #include <mach/mach.h>
12 #endif
13 
14 #ifdef BSD
15 #include <sys/param.h>
16 #include <sys/mount.h> // for struct statfs
17 #endif
18 
19 using namespace std;
20 
21 #include <QList>
22 #include <QString>
23 #include <QStringList>
24 #include <utility>
25 
26 #include "filesysteminfo.h"
27 #include "mythcoreutil.h"
28 
29 // for serialization
30 #define INT_TO_LIST(x) do { list << QString::number(x); } while (false)
31 #define STR_TO_LIST(x) do { list << (x); } while (false)
32 
33 // for deserialization
34 #define NEXT_STR() do { if (it == listend) \
35  { \
36  LOG(VB_GENERAL, LOG_ALERT, listerror); \
37  clear(); \
38  return false; \
39  } \
40  ts = *it++; } while (false)
41 #define INT_FROM_LIST(x) do { NEXT_STR(); (x) = ts.toLongLong(); } while (false)
42 #define ENUM_FROM_LIST(x, y) do { NEXT_STR(); (x) = ((y)ts.toInt()); } while (false)
43 #define STR_FROM_LIST(x) do { NEXT_STR(); (x) = ts; } while (false)
44 
45 #define LOC QString("FileSystemInfo: ")
46 
48 {
49  FileSystemInfo::clone(other);
50 }
51 
52 FileSystemInfo::FileSystemInfo(QString hostname, QString path, bool local,
53  int fsid, int groupid, int blksize, int64_t total, int64_t used) :
54  m_hostname(std::move(hostname)), m_path(std::move(path)), m_local(local), m_fsid(fsid),
55  m_grpid(groupid), m_blksize(blksize), m_total(total), m_used(used)
56 {
57 }
58 
59 FileSystemInfo::FileSystemInfo(QStringList::const_iterator &it,
60  const QStringList::const_iterator& end)
61 {
62  FromStringList(it, end);
63 }
64 
65 FileSystemInfo::FileSystemInfo(const QStringList &slist)
66 {
67  FromStringList(slist);
68 }
69 
71 {
72  m_hostname = other.m_hostname;
73  m_path = other.m_path;
74  m_local = other.m_local;
75  m_fsid = other.m_fsid;
76  m_grpid = other.m_grpid;
77  m_blksize = other.m_blksize;
78  m_total = other.m_total;
79  m_used = other.m_used;
80  m_weight = other.m_weight;
81 }
82 
84 {
85  clone(other);
86  return *this;
87 }
88 
90 {
91  m_hostname = "";
92  m_path = "";
93  m_local = false;
94  m_fsid = -1;
95  m_grpid = -1;
96  m_blksize = 4096;
97  m_total = 0;
98  m_used = 0;
99  m_weight = 0;
100 }
101 
102 bool FileSystemInfo::ToStringList(QStringList &list) const
103 {
112 
113  return true;
114 }
115 
116 bool FileSystemInfo::FromStringList(const QStringList &slist)
117 {
118  QStringList::const_iterator it = slist.constBegin();
119  return FromStringList(it, slist.constEnd());
120 }
121 
122 bool FileSystemInfo::FromStringList(QStringList::const_iterator &it,
123  const QStringList::const_iterator& listend)
124 {
125  QString listerror = LOC + "FromStringList, not enough items in list.";
126  QString ts;
127 
136 
137  m_weight = 0;
138 
139  return true;
140 }
141 
142 QList<FileSystemInfo> FileSystemInfo::RemoteGetInfo(MythSocket *sock)
143 {
144  FileSystemInfo fsInfo;
145  QList<FileSystemInfo> fsInfos;
146  QStringList strlist(QString("QUERY_FREE_SPACE_LIST"));
147 
148  bool sent;
149 
150  if (sock)
151  sent = sock->SendReceiveStringList(strlist);
152  else
153  sent = gCoreContext->SendReceiveStringList(strlist);
154 
155  if (sent)
156  {
157  int numdisks = strlist.size()/NUMDISKINFOLINES;
158 
159  QStringList::const_iterator it = strlist.begin();
160  for (int i = 0; i < numdisks; i++)
161  {
162  fsInfo.FromStringList(it, strlist.end());
163  fsInfos.append(fsInfo);
164  }
165  }
166 
167  return fsInfos;
168 }
169 
170 void FileSystemInfo::Consolidate(QList<FileSystemInfo> &disks,
171  bool merge, int64_t fuzz)
172 {
173  int newid = 0;
174 
175  QList<FileSystemInfo>::iterator it1, it2;
176  for (it1 = disks.begin(); it1 != disks.end(); ++it1)
177  {
178  if (it1->getFSysID() == -1)
179  {
180  it1->setFSysID(newid++);
181  if (merge)
182  it1->setPath(it1->getHostname().section(".", 0, 0)
183  + ":" + it1->getPath());
184  }
185 
186  for (it2 = it1+1; it2 != disks.end(); ++it2)
187  {
188  if (it2->getFSysID() != -1) // disk has already been matched
189  continue;
190 
191  int bSize = max(32, max(it1->getBlockSize(), it2->getBlockSize())
192  / 1024);
193  int64_t diffSize = it1->getTotalSpace() - it2->getTotalSpace();
194  int64_t diffUsed = it1->getUsedSpace() - it2->getUsedSpace();
195 
196  if (diffSize < 0)
197  diffSize = 0 - diffSize;
198  if (diffUsed < 0)
199  diffUsed = 0 - diffUsed;
200 
201  if ((diffSize <= bSize) && (diffUsed <= fuzz))
202  {
203  it2->setFSysID(it1->getFSysID());
204 
205  if (merge)
206  {
207  if (!it1->getHostname().contains(it2->getHostname()))
208  it1->setHostname(it1->getHostname()
209  + "," + it2->getHostname());
210  it1->setPath(it1->getPath() + ","
211  + it2->getHostname().section(".", 0, 0) + ":"
212  + it2->getPath());
213  disks.erase(it2);
214  it2 = it1;
215  }
216  }
217  }
218  }
219 }
220 
222 {
223  int64_t total = -1, used = -1;
224  getDiskSpace(getPath().toLatin1().constData(), total, used);
225  setTotalSpace(total);
226  setUsedSpace(used);
227 }
228 
230 {
231  struct statfs statbuf;
232  memset(&statbuf, 0, sizeof(statbuf));
233 
234  if (statfs(getPath().toLocal8Bit().constData(), &statbuf) == 0)
235  {
236 #if CONFIG_DARWIN
237  char *fstypename = statbuf.f_fstypename;
238  if ((!strcmp(fstypename, "nfs")) || // NFS|FTP
239  (!strcmp(fstypename, "afpfs")) || // AppleShare
240  (!strcmp(fstypename, "smbfs"))) // SMB
241  setLocal(false);
242 #elif __linux__
243  long fstype = statbuf.f_type;
244  if ((fstype == 0x6969) || // NFS
245  (fstype == 0x517B) || // SMB
246  (fstype == (long)0xFF534D42)) // CIFS
247  setLocal(false);
248 #endif
249  setBlockSize(statbuf.f_bsize);
250  }
251 }
void setTotalSpace(int64_t size)
void clear(void)
void setBlockSize(int size)
static void Consolidate(QList< FileSystemInfo > &disks, bool merge=true, int64_t fuzz=14000)
QString m_hostname
#define STR_TO_LIST(x)
void PopulateFSProp(void)
FileSystemInfo & operator=(const FileSystemInfo &other)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define INT_FROM_LIST(x)
virtual void clone(const FileSystemInfo &other)
#define INT_TO_LIST(x)
void PopulateDiskSpace(void)
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
int statfs(const char *path, struct statfs *buffer)
Definition: compat.h:177
#define STR_FROM_LIST(x)
static QList< FileSystemInfo > RemoteGetInfo(MythSocket *sock=nullptr)
Definition: compat.h:165
string hostname
Definition: caa.py:17
QString getPath(void) const
bool ToStringList(QStringList &slist) const
int64_t getDiskSpace(const QString &file_on_disk, int64_t &total, int64_t &used)
void setUsedSpace(int64_t size)
FileSystemInfo()=default
long f_bsize
Definition: compat.h:167
#define NUMDISKINFOLINES
Definition: filesysteminfo.h:3
Class for communcating between myth backends and frontends.
Definition: mythsocket.h:26
bool SendReceiveStringList(QStringList &list, uint min_reply_length=0, uint timeoutMS=kLongTimeout)
Definition: mythsocket.cpp:336
void setLocal(bool local=true)
#define LOC
bool FromStringList(const QStringList &slist)