1 #include "QFatFs.h"
2 
3 static QMap<QString,QFat*> cache;
4 
~QFatFsHandler()5 QFatFsHandler::~QFatFsHandler()
6 {
7     QMapIterator<QString,QFat*> i(cache);
8     while (i.hasNext()) {
9         i.next();
10         i.value()->close();
11         delete i.value();
12     }
13 }
14 
create(const QString & fileName) const15 QAbstractFileEngine * QFatFsHandler::create(const QString &fileName) const
16 {
17 
18     QUrl u(fileName);
19     if (!u.isValid())
20             return NULL;
21     if (u.scheme() != "fat")
22         return NULL;
23 
24     QString fatPath;
25     QString path = u.path();
26     if (!u.host().isEmpty())
27         fatPath = u.host() + u.path();
28     else {
29         fatPath = u.path();
30     }
31     if (fatPath.startsWith("/"))
32         fatPath.remove(0, 1);
33 
34     QString name = u.fragment();
35 
36     QMutexLocker locker(&mutex);
37     QFat* fat = cache[fatPath];
38     if(!fat) {
39         fat = new QFat(fatPath, m_clusterCount, m_clusterSize);
40         if(!fat) return 0;
41         if (fat->open() != FatNoError)
42             return 0;
43         cache[fatPath] = fat;
44     }
45     return new QFatEngine(fat,fatPath, name);
46 }
47 
48 /*******************************/
49 
FatIterator(QDir::Filters filters,const QStringList & nameFilters,QFat * fat,const QString & fatpath,const QString & name)50 FatIterator::FatIterator(QDir::Filters filters, const QStringList &nameFilters, QFat *fat, const QString& fatpath, const QString &name)
51     : QAbstractFileEngineIterator(filters,nameFilters)
52     , m_fat(fat)
53     , m_fatpath(fatpath)
54     , m_name(name)
55 
56 {
57     m_curPath = m_name;
58     m_fat->getTocEntries(m_name, m_tocs);
59     m_curIndex = -1;
60 }
61 
getNextIndex() const62 int FatIterator::getNextIndex() const
63 {
64     for (int i=m_curIndex+1; i<m_tocs.size(); ++i) {
65         if (filters() & QDir::AllEntries)
66             return i;
67         else if (filters() & QDir::Dirs) {
68             if (m_tocs[i].flags & FLAG_FOLDER)
69                 return i;
70         } else if (filters() & QDir::Files) {
71             if (m_tocs[i].flags & FLAG_FILE)
72                 return i;
73         }
74     }
75     return m_tocs.size();
76 }
77 
hasNext() const78 bool FatIterator::hasNext() const
79 {
80     return (getNextIndex() < m_tocs.size());
81 }
82 
next()83 QString FatIterator::next()
84 {
85     m_curIndex = getNextIndex();
86     QString path = "fat:///" + m_fatpath + "#" + m_name;
87     if(!path.endsWith("/")) path += "/";
88     return path + m_tocs[m_curIndex].name;
89 }
90 
currentFileName() const91 QString FatIterator::currentFileName() const
92 {
93     return m_tocs[m_curIndex].name;
94 }
95 
96 /**************************/
97 
98 QMutex glob_mutex;
99 
QFatEngine(QFat * fat,const QString & path,const QString & name)100 QFatEngine::QFatEngine(QFat* fat, const QString& path, const QString& name)
101     : m_fat(fat)
102     , m_fatpath(path)
103     , m_name(name)
104     , m_flags(0xffffffff)
105 
106 {
107     m_flags &= (int)m_fat->m_fatFile->permissions();
108     if (m_name.isEmpty() || m_name == "/") {
109         m_flags |= RootFlag;
110         m_flags |= ExistsFlag;
111         m_flags |= DirectoryType;
112     } else {
113         QMutexLocker locker(&glob_mutex);
114         FatError ret = m_fat->getToc(m_name, m_toc);
115         if (ret == FatNoError && m_toc.flags) {
116             m_flags |= ExistsFlag;
117             if (m_toc.flags & FLAG_FILE)
118                 m_flags |= FileType;
119             else if (m_toc.flags & FLAG_FOLDER) {
120                 m_flags |= DirectoryType;
121             }
122         } else {
123             if(m_name.endsWith('/')) {
124                 m_flags|= DirectoryType;
125             } else {
126                 m_flags |= FileType;
127             }
128         }
129     }
130 }
131 
open(QIODevice::OpenMode mode)132 bool QFatEngine::open( QIODevice::OpenMode mode)
133 {
134     QMutexLocker locker(&glob_mutex);
135 
136     fatFile = new QFatFile(m_name, m_fat);
137     if (!fatFile->open(mode)) {
138         delete fatFile;
139         return false;
140     }
141     return true;
142 }
143 
read(char * data,qint64 maxlen)144 qint64 QFatEngine::read( char * data, qint64 maxlen )
145 {
146     QMutexLocker locker(&glob_mutex);
147     return fatFile->read(data,maxlen);
148 }
149 
readLine(char * data,qint64 maxlen)150 qint64 QFatEngine::readLine(char *data, qint64 maxlen)
151 {
152     QMutexLocker locker(&glob_mutex);
153     return fatFile->readLine(data,maxlen);
154 }
155 
write(const char * data,qint64 len)156 qint64 QFatEngine::write(const char *data, qint64 len)
157 {
158     QMutexLocker locker(&glob_mutex);
159     return fatFile->write(data,len);
160 }
161 
close()162 bool QFatEngine::close()
163 {
164     QMutexLocker locker(&glob_mutex);
165     fatFile->close();
166     delete fatFile;
167     return true;
168 }
169 
beginEntryList(QDir::Filters filters,const QStringList & filterNames)170 QAbstractFileEngine::Iterator * QFatEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
171 {
172     QMutexLocker locker(&glob_mutex);
173     return new FatIterator(filters, filterNames, m_fat, m_fatpath, m_name);
174 }
175 
fileTime(QAbstractFileEngine::FileTime time) const176 QDateTime QFatEngine::fileTime(QAbstractFileEngine::FileTime time) const
177 {
178     switch (time) {
179     case QAbstractFileEngine::CreationTime:
180         return QDateTime::fromTime_t(m_toc.creationTimestamp);
181     case QAbstractFileEngine::ModificationTime:
182         return QDateTime::fromTime_t(m_toc.modificationTimestamp);
183     default:
184         return QDateTime();
185     }
186 }
187 
mkdir(const QString & dirName,bool createParentDirectories) const188 bool QFatEngine::mkdir(const QString &dirName, bool createParentDirectories) const
189 {
190     QUrl u(dirName);
191     if (!u.isValid() || u.scheme() != "fat")
192         return false;
193 
194     bool ret;
195 
196     QMutexLocker locker(&glob_mutex);
197 
198     if (createParentDirectories)
199         ret = (m_fat->makeDirRecursive(u.fragment()) == FatNoError) ? true : false;
200     else
201         ret = (m_fat->makeDir(u.fragment()) == FatNoError) ? true : false;
202     m_fat->writeFat();
203 
204     return ret;
205 }
206 
rmdir(const QString & dirName,bool recurseParentDirectories) const207 bool QFatEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
208 {
209     QUrl u(dirName);
210     if (!u.isValid() || u.scheme() != "fat")
211         return false;
212 
213     bool ret;
214 
215     QMutexLocker locker(&glob_mutex);
216 
217     if (recurseParentDirectories)
218         ret = (m_fat->removeDirRecursive(u.fragment()) == FatNoError) ? true : false;
219     else
220         ret = (m_fat->removeDir(u.fragment()) == FatNoError) ? true : false;
221     m_fat->writeFat();
222 
223     return ret;
224 }
225 
226 
extension(QAbstractFileEngine::Extension extension,const QAbstractFileEngine::ExtensionOption * option,QAbstractFileEngine::ExtensionReturn * output)227 bool QFatEngine::extension(QAbstractFileEngine::Extension extension, const QAbstractFileEngine::ExtensionOption *option, QAbstractFileEngine::ExtensionReturn *output)
228 {
229     switch (extension) {
230     case QAbstractFileEngine::AtEndExtension:
231         return fatFile->atEnd();
232     default:
233         return false;
234     }
235 }
236 
remove()237 bool QFatEngine::remove()
238 {
239     QMutexLocker locker(&glob_mutex);
240     if (m_fat->removeFile(m_name) != FatNoError)
241         return false;
242     m_fat->writeFat();
243 
244     return true;
245 }
246 
fileName(QAbstractFileEngine::FileName file) const247 QString QFatEngine::fileName(QAbstractFileEngine::FileName file) const
248 {
249     QStringList tokens;
250     tokens = m_name.split("/");
251     QString name = tokens.takeLast();
252     QString path = tokens.join("/");
253 
254     switch (file) {
255     case QAbstractFileEngine::DefaultName:
256     case QAbstractFileEngine::AbsoluteName:
257     case QAbstractFileEngine::CanonicalName:
258         return "fat:///" + m_fatpath + "#" + m_name;
259     case QAbstractFileEngine::BaseName:
260         return name;
261     case QAbstractFileEngine::PathName:
262     case QAbstractFileEngine::AbsolutePathName:
263     case QAbstractFileEngine::CanonicalPathName:
264         return "fat:///" + m_fatpath + "#" + path;
265     }
266 }
267 
flush()268 bool QFatEngine::flush()
269 {
270     return true;
271 }
272 
seek(qint64 offset)273 bool QFatEngine::seek(qint64 offset)
274 {
275     return fatFile->seek(offset);
276 }
277 
278 
279