Merge lp:~carlos-mazieri/ubuntu-filemanager-app/samba-browsing-04 into lp:ubuntu-filemanager-app

Proposed by Carlos Jose Mazieri
Status: Merged
Approved by: Arto Jalkanen
Approved revision: 392
Merged at revision: 406
Proposed branch: lp:~carlos-mazieri/ubuntu-filemanager-app/samba-browsing-04
Merge into: lp:ubuntu-filemanager-app
Prerequisite: lp:~carlos-mazieri/ubuntu-filemanager-app/samba-browsing-03
Diff against target: 1135 lines (+1013/-5)
11 files modified
debian/control (+2/-0)
src/plugin/folderlistmodel/CMakeLists.txt (+25/-1)
src/plugin/folderlistmodel/folderlistmodel.pri (+2/-2)
src/plugin/folderlistmodel/location.cpp (+2/-0)
src/plugin/folderlistmodel/locationurl.cpp (+2/-1)
src/plugin/folderlistmodel/locationurl.h (+2/-1)
src/plugin/folderlistmodel/net/netutil.cpp (+89/-0)
src/plugin/folderlistmodel/net/netutil.h (+36/-0)
src/plugin/folderlistmodel/smb/qsambaclient/qsambaclient.pri (+14/-0)
src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.cpp (+709/-0)
src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.h (+130/-0)
To merge this branch: bzr merge lp:~carlos-mazieri/ubuntu-filemanager-app/samba-browsing-04
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Arto Jalkanen Approve
Review via email: mp+252220@code.launchpad.net

Commit message

Intoduces the SmbUtil class which provides the basic open/close/listing operations for Samba items.

Description of the change

Intoduces the SmbUtil class which provides the basic open/close/listing operations for Samba items.

it comes separated in a "qsambaclient" directory which is intended to be a generic Qt Samba client library.

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
391. By Carlos Jose Mazieri

Added libsmbclient dependency

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Arto Jalkanen (ajalkane) wrote :

Few comments. But nothing blocking.

review: Approve
Revision history for this message
Carlos Jose Mazieri (carlos-mazieri) wrote :

Thanks. I will do small changes to match what you requested. Please wait.

Regarding SmbUtil comment: "No users no password" - "If no user or no password is provided"
At line 336/337 from this listing there is:
      static QByteArray s_user("guest");
      static QByteArray s_passwd;
SmbUtil itself uses the "s_user" and "s_passwd" static variables.
There are different constructors to provide some flexibility, the SmbUtil::SmbUtil(void) from here in lines 346-349 initializes with the current user. It is only necessary when'guests' are not allowed in shares.
SmbLocation will provide its authentication function to SmbUtil, this function will use an array of pairs user/password.

392. By Carlos Jose Mazieri

Removed some extra spaces and fixed some identation
SmbUtil::getStatInfo() added brackets and improved comments to explain "else if (errno != EACCES && errno != ECONNREFUSED )"

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2014-11-11 13:28:07 +0000
3+++ debian/control 2015-04-08 23:33:34 +0000
4@@ -11,6 +11,7 @@
5 python3-all,
6 libtag1-dev,
7 libpam0g-dev,
8+ libsmbclient-dev,
9 Standards-Version: 3.9.5
10 Section: misc
11 Homepage: https://launchpad.net/ubuntu-filemanager-app
12@@ -29,6 +30,7 @@
13 qtdeclarative5-u1db1.0,
14 qtdeclarative5-ubuntu-ui-toolkit-plugin | qt-components-ubuntu,
15 qtdeclarative5-ubuntu-content0.1,
16+ libsmbclient,
17 Description: File Manager application
18 Core File Manager application
19
20
21=== modified file 'src/plugin/folderlistmodel/CMakeLists.txt'
22--- src/plugin/folderlistmodel/CMakeLists.txt 2015-03-01 15:32:42 +0000
23+++ src/plugin/folderlistmodel/CMakeLists.txt 2015-04-08 23:33:34 +0000
24@@ -3,6 +3,8 @@
25 disk
26 trash
27 net
28+ smb
29+ smb/qsambaclient/src
30 )
31
32 set(PLUGIN_DIR org/nemomobile/folderlistmodel)
33@@ -55,8 +57,12 @@
34 trash/trashiteminfo.h
35 trash/trashlocation.cpp
36 trash/trashlocation.h
37+ smb/qsambaclient/src/smbutil.cpp
38+ smb/qsambaclient/src/smbutil.h
39 net/netauthenticationdata.cpp
40- net/netauthenticationdata.h
41+ net/netauthenticationdata.h
42+ net/netutil.cpp
43+ net/netutil.h
44 )
45
46 add_library(nemofolderlistmodel MODULE
47@@ -65,6 +71,24 @@
48
49 qt5_use_modules(nemofolderlistmodel Gui Qml Quick Widgets)
50
51+## samba requires libsmbclient
52+find_path(SAMBA_INCLUDE_DIR
53+ NAMES libsmbclient.h
54+ HINTS /usr/include/smbclient /usr/include/samba /usr/include/samba-3.0 /usr/include/samba-4.0
55+ )
56+find_library(SAMBA_LIBRARIES NAMES smbclient )
57+message(STATUS "samba include=${SAMBA_INCLUDE_DIR}")
58+message(STATUS "samba lib=${SAMBA_LIBRARIES}=${SAMBA_LIBRARIES}")
59+
60+if(SAMBA_INCLUDE_DIR AND SAMBA_LIBRARIES)
61+ message(STATUS "Found samba: include=${SAMBA_INCLUDE_DIR} library=${SAMBA_LIBRARIES}")
62+ INCLUDE_DIRECTORIES(${SAMBA_INCLUDE_DIR})
63+ TARGET_LINK_LIBRARIES(nemofolderlistmodel ${SAMBA_LIBRARIES})
64+else(SAMBA_INCLUDE_DIR AND SAMBA_LIBRARIES)
65+ message(FATAL_ERROR "Could not find Samba libsmbclient")
66+endif(SAMBA_INCLUDE_DIR AND SAMBA_LIBRARIES)
67+mark_as_advanced(SAMBA_INCLUDE_DIR SAMBA_LIBRARIES)
68+## end samba confiuration
69
70 # Copy the plugin, the qmldir file and other assets to the build dir for running in QtCreator
71 if(NOT "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
72
73=== modified file 'src/plugin/folderlistmodel/folderlistmodel.pri'
74--- src/plugin/folderlistmodel/folderlistmodel.pri 2015-03-01 15:32:42 +0000
75+++ src/plugin/folderlistmodel/folderlistmodel.pri 2015-04-08 23:33:34 +0000
76@@ -40,8 +40,8 @@
77 HEADERS += $$PWD/trash/qtrashdir.h $$PWD/trash/trashiteminfo.h \
78 $$PWD/trash/qtrashutilinfo.h $$PWD/trash/trashlocation.h
79
80-SOURCES += $$PWD/net/netauthenticationdata.cpp
81-HEADERS += $$PWD/net/netauthenticationdata.h
82+SOURCES += $$PWD/net/netutil.cpp $$PWD/net/netauthenticationdata.cpp
83+HEADERS += $$PWD/net/netutil.h $$PWD/net/netauthenticationdata.h
84
85 INCLUDEPATH += $$PWD $$PWD/trash $$PWD/disk $$PWD/net
86
87
88=== modified file 'src/plugin/folderlistmodel/location.cpp'
89--- src/plugin/folderlistmodel/location.cpp 2015-03-01 15:32:42 +0000
90+++ src/plugin/folderlistmodel/location.cpp 2015-04-08 23:33:34 +0000
91@@ -43,6 +43,8 @@
92 #include "ioworkerthread.h"
93 #include "netauthenticationdata.h"
94
95+#include <QDebug>
96+
97 Q_GLOBAL_STATIC(IOWorkerThread, ioWorkerThread)
98
99
100
101=== modified file 'src/plugin/folderlistmodel/locationurl.cpp'
102--- src/plugin/folderlistmodel/locationurl.cpp 2014-05-02 10:42:48 +0000
103+++ src/plugin/folderlistmodel/locationurl.cpp 2015-04-08 23:33:34 +0000
104@@ -23,8 +23,9 @@
105
106 const QString LocationUrl::TrashRootURL("trash:///");
107 const QString LocationUrl::DiskRootURL("file:///");
108+const QString LocationUrl::SmbURL("smb://");
109+const QString LocationUrl::CifsURL("cifs://");
110 #if 0
111-QString LocationURL::SmbURL("smb://");
112 QString LocationURL::FishURL("fish:///");
113 #endif
114
115
116=== modified file 'src/plugin/folderlistmodel/locationurl.h'
117--- src/plugin/folderlistmodel/locationurl.h 2014-05-02 10:42:48 +0000
118+++ src/plugin/folderlistmodel/locationurl.h 2015-04-08 23:33:34 +0000
119@@ -29,8 +29,9 @@
120 public:
121 static const QString DiskRootURL;
122 static const QString TrashRootURL;
123+ static const QString SmbURL;
124+ static const QString CifsURL;
125 #if 0
126- static const QString SmbURL;
127 static const QString FishURL;
128 #endif
129 private:
130
131=== added file 'src/plugin/folderlistmodel/net/netutil.cpp'
132--- src/plugin/folderlistmodel/net/netutil.cpp 1970-01-01 00:00:00 +0000
133+++ src/plugin/folderlistmodel/net/netutil.cpp 2015-04-08 23:33:34 +0000
134@@ -0,0 +1,89 @@
135+/**************************************************************************
136+ *
137+ * Copyright 2014 Canonical Ltd.
138+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
139+ *
140+ * This program is free software; you can redistribute it and/or modify
141+ * it under the terms of the GNU Lesser General Public License as published by
142+ * the Free Software Foundation; version 3.
143+ *
144+ * This program is distributed in the hope that it will be useful,
145+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
146+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
147+ * GNU Lesser General Public License for more details.
148+ *
149+ * You should have received a copy of the GNU Lesser General Public License
150+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
151+ *
152+ * File: netutil.cpp
153+ * Date: 29/11/2014
154+ */
155+
156+#include "netutil.h"
157+#include <QHostAddress>
158+#include <QHostInfo>
159+#include <QUrl>
160+
161+#include <QDebug>
162+
163+NetUtil::NetUtil()
164+{
165+}
166+
167+
168+QString NetUtil::normalizeHostName(const QString& name)
169+{
170+ QString host(name.toLower());
171+ bool isLoopBack = false;
172+ QHostInfo info = QHostInfo::fromName(host);
173+ // take advantage of network with Bonjour/Avahi
174+ // as winbind looks like harder to configure or does not work
175+ if (info.error() == QHostInfo::HostNotFound)
176+ {
177+ host += QLatin1String(".local");
178+ info = QHostInfo::fromName(host);
179+ }
180+ if (info.error() == QHostInfo::NoError)
181+ {
182+ host = info.hostName();
183+ QList<QHostAddress> addrs = info.addresses();
184+ int counter = addrs.count();
185+ while (!isLoopBack && counter--)
186+ {
187+ isLoopBack = addrs.at(counter).isLoopback();
188+ }
189+ }
190+ if (isLoopBack)
191+ {
192+ host = QLatin1String("localhost");
193+ }
194+ return host;
195+}
196+
197+/*!
198+ * \brief NetUtil::urlConvertHostnameToIP() Tries to convert an url like protocol://hostname/blavbla to protocol://ip-address/blavbla
199+ * \param url
200+ * \return the url using IP numbers or an empty string saying that was not possible to get its IP number
201+ */
202+QString NetUtil::urlConvertHostnameToIP(const QString &url)
203+{
204+ QString ret;
205+ QUrl tmpUrl(url);
206+ if (tmpUrl.isValid() && !tmpUrl.host().isEmpty() && tmpUrl.host() != QLatin1String("localhost"))
207+ {
208+ QString host = tmpUrl.host();
209+ QHostInfo info = QHostInfo::fromName(host);
210+ if (info.error() == QHostInfo::HostNotFound)
211+ {
212+ // take advantage of network with Bonjour/Avahi
213+ // as winbind looks like harder to configure or does not work
214+ info = QHostInfo::fromName(host + QLatin1String(".local"));
215+ }
216+ if (info.error() == QHostInfo::NoError)
217+ {
218+ tmpUrl.setHost(info.addresses().at(0).toString());
219+ ret = tmpUrl.toString();
220+ }
221+ }
222+ return ret;
223+}
224
225=== added file 'src/plugin/folderlistmodel/net/netutil.h'
226--- src/plugin/folderlistmodel/net/netutil.h 1970-01-01 00:00:00 +0000
227+++ src/plugin/folderlistmodel/net/netutil.h 2015-04-08 23:33:34 +0000
228@@ -0,0 +1,36 @@
229+/**************************************************************************
230+ *
231+ * Copyright 2014 Canonical Ltd.
232+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
233+ *
234+ * This program is free software; you can redistribute it and/or modify
235+ * it under the terms of the GNU Lesser General Public License as published by
236+ * the Free Software Foundation; version 3.
237+ *
238+ * This program is distributed in the hope that it will be useful,
239+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
240+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
241+ * GNU Lesser General Public License for more details.
242+ *
243+ * You should have received a copy of the GNU Lesser General Public License
244+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
245+ *
246+ * File: netutil.h
247+ * Date: 29/11/2014
248+ */
249+
250+#ifndef NETUTIL_H
251+#define NETUTIL_H
252+
253+#include <QString>
254+
255+class NetUtil
256+{
257+private:
258+ NetUtil();
259+public:
260+ static QString normalizeHostName(const QString& name);
261+ static QString urlConvertHostnameToIP(const QString& url);
262+};
263+
264+#endif // NETUTIL_H
265
266=== added directory 'src/plugin/folderlistmodel/smb'
267=== added directory 'src/plugin/folderlistmodel/smb/qsambaclient'
268=== added file 'src/plugin/folderlistmodel/smb/qsambaclient/qsambaclient.pri'
269--- src/plugin/folderlistmodel/smb/qsambaclient/qsambaclient.pri 1970-01-01 00:00:00 +0000
270+++ src/plugin/folderlistmodel/smb/qsambaclient/qsambaclient.pri 2015-04-08 23:33:34 +0000
271@@ -0,0 +1,14 @@
272+
273+SOURCES += $$PWD/src/smbutil.cpp
274+
275+
276+
277+HEADERS += $$PWD/src/smbutil.h
278+
279+
280+QT *= core network
281+
282+CONFIG *= link_pkgconfig
283+PKGCONFIG *= smbclient
284+
285+INCLUDEPATH += $$PWD/src
286
287=== added directory 'src/plugin/folderlistmodel/smb/qsambaclient/src'
288=== added file 'src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.cpp'
289--- src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.cpp 1970-01-01 00:00:00 +0000
290+++ src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.cpp 2015-04-08 23:33:34 +0000
291@@ -0,0 +1,709 @@
292+/**************************************************************************
293+ *
294+ * Copyright 2014 Canonical Ltd.
295+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
296+ *
297+ * This program is free software; you can redistribute it and/or modify
298+ * it under the terms of the GNU Lesser General Public License as published by
299+ * the Free Software Foundation; version 3.
300+ *
301+ * This program is distributed in the hope that it will be useful,
302+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
303+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304+ * GNU Lesser General Public License for more details.
305+ *
306+ * You should have received a copy of the GNU Lesser General Public License
307+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
308+ *
309+ * File: smbutil.cpp
310+ * Date: 20/11/2014
311+ */
312+
313+#include "smbutil.h"
314+#include "locationurl.h"
315+#include "netutil.h"
316+#include <sys/stat.h>
317+#include <sys/statfs.h>
318+#include <errno.h>
319+
320+#include <QUrl>
321+#include <QDebug>
322+#include <QRegExp>
323+
324+// set debug level at compilation time
325+#ifndef SMB_DEBUG_LEVEL
326+#define SMB_DEBUG_LEVEL 0
327+#endif
328+
329+
330+#if defined(SHOW_MESSAGES)
331+# define DBG(more_items) qDebug() << Q_FUNC_INFO more_items
332+#else
333+#define DBG(none)
334+#endif
335+
336+static QByteArray s_user("guest");
337+static QByteArray s_passwd;
338+static QByteArray s_workGroup("WORKGROUP");
339+
340+//===============================================================================================
341+/*!
342+ * \brief SmbUtil::SmbUtil() This is the default constructor that provides the default authentication method
343+ *
344+ * The user is the current user, password is "passwd" and the authentication function is \ref authenticateCallBack()
345+ */
346+SmbUtil::SmbUtil()
347+{
348+ init(::qgetenv("USER"), QLatin1String("passwd"), &SmbUtil::authenticateCallBack);
349+}
350+
351+
352+//===============================================================================================
353+/*!
354+ * \brief SmbUtil::SmbUtil() This constructor accepts an \a user and \a password for authentication
355+ *
356+ * The authentication function is \ref authenticateCallBack()
357+ *
358+ * \param authUser
359+ * \param authPassword
360+ */
361+SmbUtil::SmbUtil(const QString& authUser, const QString& authPassword)
362+{
363+ init(authUser, authPassword, &SmbUtil::authenticateCallBack);
364+}
365+
366+
367+//===============================================================================================
368+/*!
369+ * \brief SmbUtil::SmbUtil() This constructor accepts another authentication function other than the default
370+ *
371+ * No users no password is providedm the function should be able to provide everything
372+ *
373+ * \param ptAuthenticateCallBack
374+ */
375+SmbUtil::SmbUtil(Smb::AuthenticationFunction ptAuthenticateCallBack):
376+ m_authCallBack(ptAuthenticateCallBack)
377+{
378+
379+}
380+
381+
382+//===============================================================================================
383+/*!
384+ * \brief SmbUtil::SmbUtil() This is the more complete constructor where user and password can come from the \a smbUrl
385+ * \param smbUrl
386+ * \param fn
387+ */
388+SmbUtil::SmbUtil(const QUrl& smbUrl, Smb::AuthenticationFunction fn)
389+{
390+ m_authCallBack = fn ? fn : &SmbUtil::authenticateCallBack;
391+ if (!smbUrl.userName().isEmpty())
392+ {
393+ init(smbUrl.userName(), smbUrl.password(), m_authCallBack);
394+ }
395+}
396+
397+
398+//===============================================================================================
399+/*!
400+ * \brief SmbUtil::~SmbUtil() destructor
401+ */
402+SmbUtil::~SmbUtil()
403+{
404+}
405+
406+
407+//===============================================================================================
408+/*!
409+ * \brief SmbUtil::authenticateCallBack() Default authentication function, it uses static variables to keep user/password
410+ * \param server
411+ * \param share
412+ * \param wrkgrp
413+ * \param wrkgrplen
414+ * \param user
415+ * \param userlen
416+ * \param passwd
417+ * \param passwdlen
418+ */
419+void SmbUtil::authenticateCallBack( const char *server,
420+ const char *share,
421+ char *wrkgrp,
422+ int wrkgrplen,
423+ char *user,
424+ int userlen,
425+ char *passwd,
426+ int passwdlen)
427+{
428+ Q_UNUSED(server);
429+ Q_UNUSED(share);
430+ DBG(<< "server:" << server << "share:" << share << "wrkgrp:" << wrkgrp << "user:" << user << "passwd:" << passwd);
431+
432+#if 0
433+ //this may not be necessary
434+ ::strncpy(wrkgrp, s_workGroup.constData(), --wrkgrplen);
435+#else
436+ Q_UNUSED(wrkgrp);
437+ Q_UNUSED(wrkgrplen);
438+#endif
439+
440+ // check some environment variables to help test authentication
441+#if defined(REGRESSION_TEST_QSAMBACLIENT)
442+ QByteArray env = ::qgetenv("SMB_DEFAULT_USER");
443+ if (env.size() > 0)
444+ {
445+ s_user = env;
446+ }
447+ env = ::qgetenv("SMB_DEFAULT_PASSWORD");
448+ if (env.size() > 0)
449+ {
450+ s_passwd = env;
451+ }
452+#endif
453+
454+ ::strncpy(user, s_user.constData(), --userlen);
455+ ::strncpy(passwd, s_passwd.constData(), --passwdlen);
456+}
457+
458+
459+
460+//===============================================================================================
461+/*!
462+ * \brief SmbUtil::init() Just stores user/password and authentication function
463+ * \param user
464+ * \param password
465+ * \param fn
466+ */
467+void SmbUtil::init(const QString &user, const QString &password, Smb::AuthenticationFunction fn)
468+{
469+ s_user = user.toLocal8Bit();
470+ s_passwd = password.toLocal8Bit();
471+ m_authCallBack = fn;
472+}
473+
474+
475+
476+//===============================================================================================
477+/*!
478+ * \brief SmbUtil::createContext() It creates a SMB context which is necessary to all operations
479+ *
480+ * It sets the current authentication function callback
481+ *
482+ * \return the context created
483+ */
484+Smb::Context SmbUtil::createContext()
485+{
486+ Smb::Context ctx = smbc_new_context();
487+ if (ctx)
488+ {
489+ smbc_setDebug(ctx, SMB_DEBUG_LEVEL);
490+ smbc_setFunctionAuthData(ctx, m_authCallBack);
491+ if (smbc_init_context(ctx) == NULL)
492+ {
493+ smbc_free_context(ctx, 1);
494+ ctx = 0;
495+ }
496+ }
497+ DBG(<< "ctx:" << ctx);
498+ return ctx;
499+}
500+
501+
502+//===============================================================================================
503+/*!
504+ * \brief SmbUtil::deleteContext() Just deletes a context created by \ref createContext()
505+ * \param context
506+ */
507+void SmbUtil::deleteContext(Smb::Context context)
508+{
509+ smbc_getFunctionPurgeCachedServers(context)(context);
510+ smbc_free_context(context, 1);
511+ DBG();
512+}
513+
514+
515+//===============================================================================================
516+/*!
517+ * \brief SmbUtil::openFile() opens a file
518+ * \param context
519+ * \param smb_path it must point to a file full pathname
520+ * \param flags
521+ * \param mode
522+ * \return the FileHandler or NULL when it is not possible to open the file
523+ */
524+Smb::FileHandler
525+SmbUtil::openFile(Smb::Context context, const QString &smb_path, int flags , mode_t mode)
526+{
527+ Smb::FileHandler fd = ::smbc_getFunctionOpen(context)
528+ (context, smb_path.toLocal8Bit().constData(), flags, mode);
529+
530+ if (fd == 0 && errno != EISDIR)
531+ {
532+ QString ipUrl = NetUtil::urlConvertHostnameToIP(smb_path);
533+ if (!ipUrl.isEmpty())
534+ {
535+ fd = ::smbc_getFunctionOpen(context)
536+ (context, ipUrl.toLocal8Bit().constData(), flags, mode);
537+ }
538+ }
539+ if (fd == 0)
540+ {
541+ qWarning() << Q_FUNC_INFO << "errno:" << errno << smb_path;
542+ }
543+ return fd;
544+}
545+
546+
547+//===============================================================================================
548+/*!
549+ * \brief SmbUtil::openDir() opens a directory
550+ * \param context
551+ * \param smb_string it must point to a directory full pathname
552+ * \return the FileHandler or NULL when it is not possible to open the directory
553+ */
554+Smb::FileHandler
555+SmbUtil::openDir(Smb::Context context, const QString &smb_string)
556+{
557+ Smb::FileHandler fd = ::smbc_getFunctionOpendir(context)
558+ (context, smb_string.toLocal8Bit().constData());
559+
560+ if (fd == 0)
561+ {
562+ //try to use an IP address if possible
563+ QString ipUrl = NetUtil::urlConvertHostnameToIP(smb_string);
564+ if (!ipUrl.isEmpty())
565+ {
566+ fd = ::smbc_getFunctionOpendir(context)
567+ (context, ipUrl.toLocal8Bit().constData());
568+ }
569+ }
570+ if (fd == 0)
571+ {
572+ qWarning() << Q_FUNC_INFO << "errno:" << errno << smb_string;
573+ }
574+ return fd;
575+}
576+
577+
578+//===============================================================================================
579+/*!
580+ * \brief SmbUtil::closeHandle() closes a open FileHandler created by \ref openDir() or \ref openFile()
581+ * \param context
582+ * \param fd
583+ */
584+void SmbUtil::closeHandle(Smb::Context context, Smb::FileHandler fd)
585+{
586+ if (fd)
587+ {
588+ ::smbc_getFunctionClose(context)(context, fd);
589+ }
590+}
591+
592+//===============================================================================================
593+/*!
594+ * \brief SmbUtil::setAuthenticationCallback() Just sets the authentication function
595+ * \param fn
596+ */
597+void SmbUtil::setAuthenticationCallback(Smb::AuthenticationFunction fn)
598+{
599+ m_authCallBack = fn;
600+}
601+
602+//===============================================================================================
603+/*!
604+ * \brief SmbUtil::getStatInfo() It gets information about files and directories, similar to POSIX stat(2)
605+ *
606+ * It looks like smbclient brings no information for directories, it works only for files, in this case the caller
607+ * must set valid information in the struct stat.
608+ *
609+ * The distintion between files and directories is made by \ref openDir() and \ref openFile(), as just one
610+ * of them should open the \a smb_path.
611+ * For directories which it is supposed to have a content it is necessary to know if it is a
612+ * host/share/workgroup or a single directory, for this the \ref guessDirType() is used.
613+ *
614+ * \param smb_path it must point to a file full pathname file or directory
615+ * \param st pointer to a struct stat which will receive the information
616+ * \return one of the \ref StatReturn
617+ */
618+SmbUtil::StatReturn
619+SmbUtil::getStatInfo(const QString &smb_path, struct stat* st)
620+{
621+ Smb::Context context = createContext();
622+ Q_ASSERT(context);
623+ ::memset(st,0,sizeof(struct stat));
624+ StatReturn ret = StatInvalid;
625+ int slashes = smb_path.count(QDir::separator());
626+ Smb::FileHandler fd = 0;
627+ // smb:// -> slahes=2 smb/workgroup -> slahes=2 smb://host/share -> slashes=3
628+ if ((fd=openDir(context, smb_path)))
629+ {
630+ if ((ret = guessDirType(context,fd)) == StatDir && slashes == 3)
631+ {
632+ ret = StatShare;
633+ }
634+ if (slashes > 2 && (ret == StatShare || ret == StatDir))
635+ {
636+ /* smbc_getFunctionFstatdir does not work
637+ ret = static_cast<StatReturn>(::smbc_getFunctionFstatdir(context)(context,fd, st));
638+ */
639+ QString ipUrl = NetUtil::urlConvertHostnameToIP(smb_path);
640+ if (ipUrl.isEmpty())
641+ {
642+ ipUrl = smb_path;
643+ }
644+ (void)static_cast<StatReturn> (::smbc_getFunctionStat(context)(context,ipUrl.toLocal8Bit().constData(), st));
645+ }
646+ }
647+ else
648+ {
649+ // there is no indication of what the item is, directory or file
650+ // if openDir() failed it may be a file, try openFile()
651+ // do not try openFile() when: EACCES means it needs authentication, ECONNREFUSED means path does not exist
652+ if (errno != EACCES && errno != ECONNREFUSED )
653+ {
654+ if ((fd = openFile(context,smb_path)))
655+ {
656+ ret = static_cast<StatReturn> (::smbc_getFunctionFstat(context)(context,fd, st));
657+ }
658+ }
659+ }
660+
661+ if (fd)
662+ {
663+ closeHandle(context, fd);
664+ }
665+ else
666+ {
667+ qDebug() << Q_FUNC_INFO << "path:" << smb_path << "errno:" << errno << strerror(errno);
668+ switch(errno)
669+ {
670+ case EACCES:
671+ ret = StatNoAccess; //authentication should have failed
672+ break;
673+ case ENOENT:
674+ case ENODEV:
675+ case ECONNREFUSED:
676+ ret = StatDoesNotExist; //item does not exist
677+ break;
678+ default:
679+ break;
680+ }
681+ }
682+ deleteContext(context);
683+ return ret;
684+}
685+
686+
687+//===============================================================================================
688+/*!
689+ * \brief SmbUtil::guessDirType() gets the first directory item to guess the content type
690+ * \param context
691+ * \param fd an already opened FileHandler of a directory
692+ * \return the item type in \ref StatReturn
693+ */
694+SmbUtil::StatReturn
695+SmbUtil::guessDirType(Smb::Context context, Smb::FileHandler fd)
696+{
697+ struct smbc_dirent *dirent=0;
698+ StatReturn ret = StatDone;
699+ while (ret == StatDone &&
700+ (dirent = smbc_getFunctionReaddir(context)(context, fd)) )
701+ {
702+ if (!dirent->name[0] && dirent->smbc_type != SMBC_SERVER )
703+ {
704+ continue;
705+ }
706+ switch(dirent->smbc_type)
707+ {
708+ //current item is a Host
709+ case SMBC_FILE_SHARE:
710+ ret = StatHost;
711+ break;
712+ //current item is a Workgroup
713+ case SMBC_SERVER:
714+ ret = StatWorkgroup;
715+ break;
716+ //current item is Root smb://
717+ case SMBC_WORKGROUP:
718+ break;
719+ //ignore system shares
720+ case SMBC_PRINTER_SHARE:
721+ case SMBC_COMMS_SHARE:
722+ case SMBC_IPC_SHARE:
723+ break;
724+ //current item is Common directory
725+ // or a share, shares are handdled by the caller
726+ default:
727+ ret = StatDir;
728+ break;
729+ }
730+ }
731+ return ret;
732+}
733+
734+//===============================================================================================
735+/*!
736+ * \brief SmbUtil::listContent() Just lists the content of a directory/share/workgroup/hostname
737+ * \param smb_path it must point to full pathname directory/share/workgroup/hostname
738+ * \param recursive
739+ * \param filters a QDir like filter
740+ * \return The string list that matches \a filters
741+ */
742+QStringList SmbUtil::listContent(QString smb_path, bool recursive, QDir::Filters filters , const QStringList &filterNames)
743+{
744+ QStringList content;
745+ Smb::Context context = createContext();
746+ Q_ASSERT(context);
747+ Smb::FileHandler fd = openDir(context,smb_path);
748+ if (fd)
749+ {
750+ struct smbc_dirent *dirent = 0;
751+ const char *cur_name = 0;
752+ while ((dirent = smbc_getFunctionReaddir(context)(context, fd)) )
753+ {
754+ //first check for hidden files
755+ if (!(filters & QDir::Hidden) && dirent->name[0] == '.')
756+ {
757+ continue;
758+ }
759+ if ( !dirent->name[0] && dirent->smbc_type != SMBC_SERVER)
760+ {
761+ //it may be a libsmbclient bug
762+ continue;
763+ }
764+ cur_name = dirent->name;
765+ QString path;
766+ bool itemHasContent = false;
767+ switch(dirent->smbc_type)
768+ {
769+ case SMBC_PRINTER_SHARE:
770+ case SMBC_COMMS_SHARE:
771+ case SMBC_IPC_SHARE:
772+ continue;
773+ break;
774+ case SMBC_WORKGROUP:
775+ case SMBC_SERVER:
776+ itemHasContent = true;
777+ path = LocationUrl::SmbURL;
778+ if (dirent->smbc_type == SMBC_SERVER)
779+ {
780+ QString goodHostName = findSmBServer(*dirent);
781+ //path += NetUtil::normalizeHostName(goodHostName);
782+ path += goodHostName;
783+ }
784+ else
785+ {
786+ path += cur_name;
787+ }
788+ break;
789+ case SMBC_DIR:
790+ if (filters & QDir::Dirs)
791+ {
792+ bool isDot = ::strcmp(".", cur_name) == 0;
793+ bool isDotDot = ::strcmp("..", cur_name) == 0;
794+ if( !((filters & QDir::NoDot) && isDot)
795+ && !((filters & QDir::NoDotDot) && isDotDot) )
796+ {
797+ path = smb_path + QDir::separator() + cur_name;
798+ if (!isDot && !isDotDot)
799+ {
800+ itemHasContent = true;
801+ }
802+ }
803+ }
804+ break;
805+ case SMBC_FILE:
806+ case SMBC_LINK:
807+ if (filters & QDir::Files)
808+ {
809+ path = smb_path + QDir::separator() + cur_name;
810+ }
811+ break;
812+ case SMBC_FILE_SHARE:
813+ if (checkValidShareName(cur_name))
814+ {
815+ itemHasContent = true;
816+ path = smb_path + QDir::separator() + cur_name;
817+ }
818+ break;
819+ }//switch
820+ if (!path.isEmpty())
821+ {
822+ if (filterNames.isEmpty() || namesMatchFilter(cur_name, filterNames))
823+ {
824+ content.append(path);
825+ }
826+ if (recursive && itemHasContent )
827+ {
828+ content += listContent(path, true, filters, filterNames);
829+ }
830+ }
831+ }//while
832+ closeHandle(context, fd);
833+ }//if (fd)
834+ else
835+ {
836+ qDebug() << Q_FUNC_INFO << "could not open directory" << smb_path << "errno:" << errno;
837+ }
838+ deleteContext(context);
839+ return content;
840+}
841+
842+
843+//===============================================================================================
844+/*!
845+ * \brief SmbUtil::lisShares() Brings the list of all available file shares in the network
846+ * \return all available file shares
847+ */
848+QStringList SmbUtil::lisShares()
849+{
850+ return walkForShares(LocationUrl::SmbURL);
851+}
852+
853+//===============================================================================================
854+/*!
855+ * \brief SmbUtil::walkForShares() Just a helper function that can be recursive, called by \ref lisShares()
856+ * \param smb_path
857+ * \return list of shares from a single hostname
858+ */
859+QStringList SmbUtil::walkForShares(QString smb_path)
860+{
861+ QStringList content;
862+ Smb::Context context = createContext();
863+ Q_ASSERT(context);
864+ Smb::FileHandler fd = openDir(context,smb_path);
865+ if (fd)
866+ {
867+ struct smbc_dirent *dirent = 0;
868+ const char *cur_name = 0;
869+ QString path;
870+ while ((dirent = smbc_getFunctionReaddir(context)(context, fd)))
871+ {
872+ cur_name = dirent->name;
873+ if ( !dirent->name[0] && dirent->smbc_type != SMBC_SERVER)
874+ {
875+ //it may be a libsmbclient bug
876+ continue;
877+ }
878+ switch(dirent->smbc_type)
879+ {
880+ case SMBC_WORKGROUP:
881+ case SMBC_SERVER:
882+ path = LocationUrl::SmbURL;
883+ if (dirent->smbc_type == SMBC_SERVER)
884+ {
885+ QString goodHostName = findSmBServer(*dirent);
886+ //path += NetUtil::normalizeHostName(goodHostName);
887+ path += goodHostName;
888+ }
889+ else
890+ {
891+ path += cur_name;
892+ }
893+ content += walkForShares(path);
894+ break;
895+ case SMBC_FILE_SHARE:
896+ if (checkValidShareName(cur_name))
897+ {
898+ path = smb_path + QDir::separator() + cur_name;
899+ content.append(path);
900+ }
901+ break;
902+ }//switch
903+ }//while
904+ }//if (fd)
905+ deleteContext(context);
906+ return content;
907+}
908+
909+
910+//===============================================================================================
911+/*!
912+ * \brief SmbUtil::checkValidShareName() Helper function to ignore some system shares that should not contain any file
913+ *
914+ * It is used for \ref lisShares() and \ref listContent()
915+ *
916+ * \param shareName
917+ * \return TRUE if the share has a good name (should contain files), FALSE if it is supposed to be a system share
918+ */
919+bool SmbUtil::checkValidShareName(const char *shareName)
920+{
921+ if (::strcmp(shareName, "print$") == 0)
922+ {
923+ return false;
924+ }
925+
926+ return true;
927+}
928+
929+
930+//===============================================================================================
931+/*!
932+ * \brief SmbUtil::getStatvfsInfo
933+ * \param smb_path it must point to a file full pathname file or directory
934+ * \param st pointer to a struct statvfs
935+ * \return StatDone in case of success or StatInvalid.
936+ */
937+SmbUtil::StatReturn
938+SmbUtil::getStatvfsInfo(const QString &smb_path, struct statvfs *st)
939+{
940+ Smb::Context context = createContext();
941+ Q_ASSERT(context);
942+ ::memset(st,0,sizeof(struct statvfs));
943+ StatReturn ret = StatInvalid;
944+ Smb::FileHandler fd = openDir(context,smb_path);
945+ if (fd == 0)
946+ {
947+ fd = openFile(context, smb_path);
948+ }
949+ if (fd)
950+ {
951+ ret = static_cast<StatReturn> (::smbc_getFunctionFstatVFS(context)(context,fd, st));
952+ closeHandle(context, fd);
953+ }
954+ deleteContext(context);
955+ return ret;
956+}
957+
958+
959+bool SmbUtil::namesMatchFilter(const QString & str, const QStringList &filterNames)
960+{
961+ bool ret = true;
962+ int counter = filterNames.count();
963+ while (ret && counter--)
964+ {
965+ QRegExp regExp(filterNames.at(counter), Qt::CaseSensitive, QRegExp::Wildcard);
966+ ret = regExp.exactMatch(str);
967+ }
968+ return ret;
969+}
970+
971+/*!
972+ * \brief SmbUtil::findSmBServer() Helper function to find the server name
973+ * \param dirent smbc_dirent & dirent result of smbc_getFunctionReaddir()
974+ *
975+ * 1. Some smbclient versions (or host configuration) bring dirent.name empty when browsing localhost
976+ *
977+ * 2. When dirent.name brings the hostname, usually it is limited to 16 characters which will not reacheable in the network
978+ * in this case try to get the name from the comment
979+ *
980+ * \return the hostname
981+ */
982+QString SmbUtil::findSmBServer(const smbc_dirent & dirent)
983+{
984+ QString host("localhost");
985+ if (dirent.name[0] != 0)
986+ {
987+ QString name(dirent.name);
988+ host = name;
989+ QString comment(dirent.comment);
990+ if (!comment.isEmpty())
991+ {
992+ QString fullName = comment.split(QLatin1Char(' '), QString::SkipEmptyParts).first();
993+ if (!fullName.isEmpty() && fullName.startsWith(name), Qt::CaseSensitive)
994+ {
995+ host = fullName;
996+ }
997+ }
998+ }
999+ return host.toLower();
1000+}
1001
1002=== added file 'src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.h'
1003--- src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.h 1970-01-01 00:00:00 +0000
1004+++ src/plugin/folderlistmodel/smb/qsambaclient/src/smbutil.h 2015-04-08 23:33:34 +0000
1005@@ -0,0 +1,130 @@
1006+/**************************************************************************
1007+ *
1008+ * Copyright 2014 Canonical Ltd.
1009+ * Copyright 2014 Carlos J Mazieri <carlos.mazieri@gmail.com>
1010+ *
1011+ * This program is free software; you can redistribute it and/or modify
1012+ * it under the terms of the GNU Lesser General Public License as published by
1013+ * the Free Software Foundation; version 3.
1014+ *
1015+ * This program is distributed in the hope that it will be useful,
1016+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1017+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1018+ * GNU Lesser General Public License for more details.
1019+ *
1020+ * You should have received a copy of the GNU Lesser General Public License
1021+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1022+ *
1023+ * File: smbutil.h
1024+ * Date: 20/11/2014
1025+ */
1026+
1027+#ifndef SMBUTIL_H
1028+#define SMBUTIL_H
1029+
1030+#include <libsmbclient.h>
1031+
1032+#include <QStringList>
1033+#include <QDir>
1034+
1035+class QUrl;
1036+class NetAuthenticationData;
1037+class NetAuthenticationDataList;
1038+struct stat;
1039+
1040+
1041+namespace Smb
1042+{
1043+ typedef SMBCCTX * Context;
1044+ typedef SMBCFILE * FileHandler;
1045+ typedef void (*AuthenticationFunction) (const char *server,
1046+ const char *share,
1047+ char *wrkgrp,
1048+ int wrkgrplen,
1049+ char *user,
1050+ int userlen,
1051+ char *passwd,
1052+ int passwdlen);
1053+}
1054+
1055+
1056+/*!
1057+ * \brief The SmbUtil class provides the interface through the libsmbclient functions
1058+ *
1059+ * Some documentation can found at:
1060+ * \link http://www.samba.org/samba/docs/man/manpages-3/libsmbclient.7.html
1061+ * \link https://github.com/Zentyal/samba/tree/master/examples/libsmbclient
1062+ *
1063+ */
1064+class SmbUtil
1065+{
1066+public:
1067+ SmbUtil();
1068+ SmbUtil(Smb::AuthenticationFunction fn);
1069+ SmbUtil(const QString& authUser, const QString& authPassword);
1070+ SmbUtil(const QUrl& smbUrl, Smb::AuthenticationFunction fn = 0); //may have smb:://user::password@host/..
1071+ ~SmbUtil();
1072+
1073+public:
1074+ enum StatReturn
1075+ {
1076+ StatInvalid = -3,
1077+ StatDoesNotExist= -2,
1078+ StatNoAccess= -1,
1079+ StatDone=0, // already done
1080+ StatDir,
1081+ StatHost,
1082+ StatWorkgroup,
1083+ StatShare
1084+ };
1085+
1086+public:
1087+ Smb::Context createContext();
1088+ void deleteContext(Smb::Context context);
1089+ void setAuthenticationCallback(Smb::AuthenticationFunction fn);
1090+ StatReturn getStatInfo(const QString &smb_path, struct stat *st);
1091+ StatReturn getStatvfsInfo(const QString& smb_path, struct statvfs *st);
1092+ Smb::FileHandler openDir(Smb::Context context, const QString& smb_string);
1093+ Smb::FileHandler openFile(Smb::Context context,const QString& smb_path,
1094+ int flags = O_RDONLY, mode_t mode = 0);
1095+ void closeHandle(Smb::Context context, Smb::FileHandler fd);
1096+ QStringList lisShares();
1097+ QStringList listContent(QString smb_path,
1098+ bool recursive = false,
1099+ QDir::Filters filters = QDir::AllEntries | QDir::NoDotAndDotDot,
1100+ const QStringList& filterNames = QStringList());
1101+
1102+
1103+private:
1104+ StatReturn guessDirType(Smb::Context context, Smb::FileHandler fd);
1105+ bool checkValidShareName(const char *shareName);
1106+ QStringList walkForShares(QString smb_path);
1107+ QString findSmBServer(const smbc_dirent&);
1108+
1109+
1110+private:
1111+ static void authenticateCallBack(
1112+ const char *server,
1113+ const char *share,
1114+ char *wrkgrp,
1115+ int wrkgrplen,
1116+ char *user,
1117+ int userlen,
1118+ char *passwd,
1119+ int passwdlen);
1120+
1121+protected:
1122+ void init(const QString& user, const QString& password, Smb::AuthenticationFunction fn);
1123+ bool namesMatchFilter(const QString& str, const QStringList& filterNames);
1124+
1125+private:
1126+ Smb::AuthenticationFunction m_authCallBack;
1127+
1128+
1129+#if defined(REGRESSION_TEST_QSAMBACLIENT)
1130+ friend class TestQSambaSuite;
1131+#endif
1132+
1133+};
1134+
1135+#endif // SMBUTIL_H

Subscribers

People subscribed via source and target branches