Warning, file /utilities/krusader/app/DiskUsage/filelightParts/fileTree.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2004 Max Howell <max.howell@methylblue.com>
0003     SPDX-FileCopyrightText: 2004-2022 Krusader Krew <https://krusader.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #ifndef FILETREE_H
0009 #define FILETREE_H
0010 
0011 #include <QString>
0012 
0013 #include <KIO/Global>
0014 
0015 #include <stdlib.h>
0016 #include <sys/types.h>
0017 #include <time.h>
0018 #include <unistd.h>
0019 
0020 // TODO these are pointlessly general purpose now, make them incredibly specific
0021 
0022 typedef KIO::filesize_t FileSize;
0023 
0024 template<class T>
0025 class Iterator;
0026 template<class T>
0027 class ConstIterator;
0028 template<class T>
0029 class Chain;
0030 
0031 template<class T>
0032 class Link
0033 {
0034 public:
0035     explicit Link(T *const t)
0036         : prev(this)
0037         , next(this)
0038         , data(t)
0039     {
0040     }
0041     Link()
0042         : prev(this)
0043         , next(this)
0044         , data(nullptr)
0045     {
0046     }
0047 
0048     // TODO unlinking is slow and you don't use it very much in this context.
0049     //   ** Perhaps you can make a faster deletion system that doesn't bother tidying up first
0050     //   ** and then you MUST call some kind of detach() function when you remove elements otherwise
0051     ~Link()
0052     {
0053         delete data;
0054         unlink();
0055     }
0056 
0057     friend class Iterator<T>;
0058     friend class ConstIterator<T>;
0059     friend class Chain<T>;
0060 
0061 private:
0062     void unlink()
0063     {
0064         prev->next = next;
0065         next->prev = prev;
0066         prev = next = this;
0067     }
0068 
0069     Link<T> *prev;
0070     Link<T> *next;
0071 
0072     T *data; // ensure only iterators have access to this
0073 };
0074 
0075 template<class T>
0076 class Iterator
0077 {
0078 public:
0079     Iterator()
0080         : link(nullptr)
0081     {
0082     } //**** remove this, remove this REMOVE THIS!!! dangerous as your implementation doesn't test for null links, always assumes they can be dereferenced
0083     explicit Iterator(Link<T> *p)
0084         : link(p)
0085     {
0086     }
0087 
0088     bool operator==(const Iterator<T> &it) const
0089     {
0090         return link == it.link;
0091     }
0092     bool operator!=(const Iterator<T> &it) const
0093     {
0094         return link != it.link;
0095     }
0096     bool operator!=(const Link<T> *p) const
0097     {
0098         return p != link;
0099     }
0100 
0101     // here we have a choice, really I should make two classes one const the other not
0102     const T *operator*() const
0103     {
0104         return link->data;
0105     }
0106     T *operator*()
0107     {
0108         return link->data;
0109     }
0110 
0111     Iterator<T> &operator++()
0112     {
0113         link = link->next;
0114         return *this;
0115     } //**** does it waste time returning in places where we don't use the retval?
0116 
0117     bool isNull() const
0118     {
0119         return (link == 0);
0120     } // REMOVE WITH ABOVE REMOVAL you don't want null iterators to be possible
0121 
0122     void transferTo(Chain<T> &chain)
0123     {
0124         chain.append(remove());
0125     }
0126 
0127     T *remove()
0128     { // remove from list, delete Link, data is returned NOT deleted
0129         T *const d = link->data;
0130         Link<T> *const p = link->prev;
0131 
0132         link->data = nullptr;
0133         delete link;
0134         link = p; // make iterator point to previous element, YOU must check this points to an element
0135 
0136         return d;
0137     }
0138 
0139 private:
0140     Link<T> *link;
0141 };
0142 
0143 template<class T>
0144 class ConstIterator
0145 {
0146 public:
0147     explicit ConstIterator(Link<T> *p)
0148         : link(p)
0149     {
0150     }
0151 
0152     bool operator==(const Iterator<T> &it) const
0153     {
0154         return link == it.link;
0155     }
0156     bool operator!=(const Iterator<T> &it) const
0157     {
0158         return link != it.link;
0159     }
0160     bool operator!=(const Link<T> *p) const
0161     {
0162         return p != link;
0163     }
0164 
0165     const T *operator*() const
0166     {
0167         return link->data;
0168     }
0169 
0170     ConstIterator<T> &operator++()
0171     {
0172         link = link->next;
0173         return *this;
0174     }
0175 
0176 private:
0177     const Link<T> *link;
0178 };
0179 
0180 //**** try to make a generic list class and then a brief full list template that inlines
0181 //     thus reducing code bloat
0182 template<class T>
0183 class Chain
0184 {
0185 public:
0186     Chain()
0187     {
0188     }
0189     virtual ~Chain()
0190     {
0191         empty();
0192     }
0193 
0194     void append(T *const data)
0195     {
0196         Link<T> *const link = new Link<T>(data);
0197 
0198         link->prev = head.prev;
0199         link->next = &head;
0200 
0201         head.prev->next = link;
0202         head.prev = link;
0203     }
0204 
0205     void transferTo(Chain &c)
0206     {
0207         if (isEmpty())
0208             return;
0209 
0210         Link<T> *const first = head.next;
0211         Link<T> *const last = head.prev;
0212 
0213         head.unlink();
0214 
0215         first->prev = c.head.prev;
0216         c.head.prev->next = first;
0217 
0218         last->next = &c.head;
0219         c.head.prev = last;
0220     }
0221 
0222     void empty()
0223     {
0224         while (head.next != &head) {
0225             delete head.next;
0226         }
0227     }
0228 
0229     Iterator<T> iterator() const
0230     {
0231         return Iterator<T>(head.next);
0232     }
0233     ConstIterator<T> constIterator() const
0234     {
0235         return ConstIterator<T>(head.next);
0236     }
0237     const Link<T> *end() const
0238     {
0239         return &head;
0240     }
0241     bool isEmpty() const
0242     {
0243         return (head.next == &head);
0244     }
0245 
0246 private:
0247     Link<T> head;
0248     void operator=(const Chain &)
0249     {
0250     }
0251 };
0252 
0253 class Directory;
0254 
0255 class File
0256 {
0257 protected:
0258     Directory *m_parent; // 0 if this is treeRoot
0259     QString m_name; //< file name
0260     QString m_directory; //< the directory of the file
0261     FileSize m_size; //< size with subdirectories
0262     FileSize m_ownSize; //< size without subdirectories
0263     mode_t m_mode; //< file mode
0264     QString m_owner; //< file owner name
0265     QString m_group; //< file group name
0266     QString m_perm; //< file permissions string
0267     time_t m_time; //< file modification in time_t format
0268     bool m_symLink; //< true if the file is a symlink
0269     QString m_mimeType; //< file mimetype
0270     bool m_excluded; //< flag if the file is excluded from du
0271     int m_percent; //< percent flag
0272 
0273 public:
0274     File(Directory *parentIn,
0275          const QString &nameIn,
0276          const QString &dir,
0277          FileSize sizeIn,
0278          mode_t modeIn,
0279          const QString &ownerIn,
0280          const QString &groupIn,
0281          const QString &permIn,
0282          time_t timeIn,
0283          bool symLinkIn,
0284          const QString &mimeTypeIn)
0285         : m_parent(parentIn)
0286         , m_name(nameIn)
0287         , m_directory(dir)
0288         , m_size(sizeIn)
0289         , m_ownSize(sizeIn)
0290         , m_mode(modeIn)
0291         , m_owner(ownerIn)
0292         , m_group(groupIn)
0293         , m_perm(permIn)
0294         , m_time(timeIn)
0295         , m_symLink(symLinkIn)
0296         , m_mimeType(mimeTypeIn)
0297         , m_excluded(false)
0298         , m_percent(-1)
0299     {
0300     }
0301 
0302     File(const QString &nameIn, FileSize sizeIn)
0303         : m_parent(nullptr)
0304         , m_name(nameIn)
0305         , m_directory(QString())
0306         , m_size(sizeIn)
0307         , m_ownSize(sizeIn)
0308         , m_mode(0)
0309         , m_owner(QString())
0310         , m_group(QString())
0311         , m_perm(QString())
0312         , m_time(-1)
0313         , m_symLink(false)
0314         , m_mimeType(QString())
0315         , m_excluded(false)
0316         , m_percent(-1)
0317     {
0318     }
0319 
0320     virtual ~File()
0321     {
0322     }
0323 
0324     inline const QString &name() const
0325     {
0326         return m_name;
0327     }
0328     inline const QString &directory() const
0329     {
0330         return m_directory;
0331     }
0332     inline FileSize size() const
0333     {
0334         return m_excluded ? 0 : m_size;
0335     }
0336     inline FileSize ownSize() const
0337     {
0338         return m_excluded ? 0 : m_ownSize;
0339     }
0340     inline mode_t mode() const
0341     {
0342         return m_mode;
0343     }
0344     inline const QString &owner() const
0345     {
0346         return m_owner;
0347     }
0348     inline const QString &group() const
0349     {
0350         return m_group;
0351     }
0352     inline const QString &perm() const
0353     {
0354         return m_perm;
0355     }
0356     inline time_t time() const
0357     {
0358         return m_time;
0359     }
0360     inline const QString &mime() const
0361     {
0362         return m_mimeType;
0363     }
0364     inline bool isSymLink() const
0365     {
0366         return m_symLink;
0367     }
0368     virtual bool isDir() const
0369     {
0370         return false;
0371     }
0372     inline bool isExcluded() const
0373     {
0374         return m_excluded;
0375     }
0376     inline void exclude(bool flag)
0377     {
0378         m_excluded = flag;
0379     }
0380     inline int intPercent() const
0381     {
0382         return m_percent;
0383     }
0384     inline const QString percent() const
0385     {
0386         if (m_percent < 0)
0387             return "INV";
0388         QString buf;
0389         buf.asprintf("%d.%02d%%", m_percent / 100, m_percent % 100);
0390         return buf;
0391     }
0392     inline void setPercent(int p)
0393     {
0394         m_percent = p;
0395     }
0396     inline const Directory *parent() const
0397     {
0398         return m_parent;
0399     }
0400 
0401     inline void setSizes(KIO::filesize_t totalSize, KIO::filesize_t ownSize)
0402     {
0403         m_ownSize = ownSize;
0404         m_size = totalSize;
0405     }
0406 
0407     enum UnitPrefix { kilo, mega, giga, tera };
0408 
0409     static const FileSize DENOMINATOR[4];
0410     static const char PREFIX[5][2];
0411 
0412     QString fullPath(const Directory * = nullptr) const;
0413     QString humanReadableSize(UnitPrefix key = mega) const;
0414 
0415     static QString humanReadableSize(FileSize size, UnitPrefix Key = mega);
0416 
0417     friend class Directory;
0418 };
0419 
0420 // TODO when you modify this to take into account hardlinks you should make the Chain layered not inherited
0421 class Directory : public Chain<File>, public File
0422 {
0423 public:
0424     Directory(Directory *parentIn,
0425               const QString &nameIn,
0426               const QString &dir,
0427               FileSize sizeIn,
0428               mode_t modeIn,
0429               const QString &ownerIn,
0430               const QString &groupIn,
0431               const QString &permIn,
0432               time_t timeIn,
0433               bool symLinkIn,
0434               const QString &mimeTypeIn)
0435         : File(parentIn, nameIn, dir, sizeIn, modeIn, ownerIn, groupIn, permIn, timeIn, symLinkIn, mimeTypeIn)
0436         , m_fileCount(0)
0437     {
0438     }
0439 
0440     Directory(const QString &name, QString url)
0441         : File(name, 0)
0442         , m_fileCount(0)
0443     {
0444         m_directory = url;
0445     }
0446 
0447     virtual ~Directory()
0448     {
0449     }
0450     virtual bool isDir() const override
0451     {
0452         return true;
0453     }
0454 
0455     void append(File *p)
0456     {
0457         ++m_fileCount;
0458 
0459         Directory *parent = m_parent;
0460         while (parent) {
0461             parent->m_fileCount++;
0462             parent = parent->m_parent;
0463         }
0464 
0465         Chain<File>::append(p);
0466         p->m_parent = this;
0467     }
0468 
0469     void remove(File *p)
0470     {
0471         for (Iterator<File> it = Chain<File>::iterator(); it != Chain<File>::end(); ++it)
0472             if ((*it) == p) {
0473                 --m_fileCount;
0474 
0475                 Directory *parent = m_parent;
0476                 while (parent) {
0477                     parent->m_fileCount--;
0478                     parent = parent->m_parent;
0479                 }
0480 
0481                 it.remove();
0482                 break;
0483             }
0484     }
0485 
0486     uint fileCount() const
0487     {
0488         return m_fileCount;
0489     }
0490 
0491 private:
0492     Directory(const Directory &);
0493     void operator=(const Directory &);
0494 
0495     uint m_fileCount;
0496 };
0497 
0498 #endif