adbncfs  0.9.1
adbncfs.cpp
Go to the documentation of this file.
1 /*
2  * $Id: adbncfs.cpp 5 2015-12-06 18:57:22Z wejaeger $
3  *
4  * File: adbncfs.cpp
5  * Author: Werner Jaeger
6  *
7  * Created on November 17, 2015, 1:28 PM
8  *
9  * Copyright 2015 Werner Jaeger.
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24 #include <sstream>
25 
26 #include <sys/statvfs.h>
27 #include <execinfo.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <pthread.h>
31 #include "adbncfs.h"
32 #include "fileInfoCache.h"
33 #include "spawn.h"
34 #include "userInfo.h"
35 #include "mountInfo.h"
36 
37 #define DBG(line) if (fDebug) cout << "--*-- " << line << endl
38 #define INF(line) cout << "--*-- " << line << endl
39 #define ERR(line) cerr << "--*-- " << line << endl
40 
44 #ifdef ADBNCTEST
45 #define static
46 #endif
47 
48 using namespace std;
49 
51 static const int iForwardPort(4444);
52 
53 static const char* pcDone = "---eoc---"; // end of command marker
54 
56 static const char* pcTempDirTemplate = "/tmp/adbncfs-XXXXXX";
57 
63 static const char* pcSdCardMountEntry = "sdcardfs on /storage/emulated/legacy type sdcardfs (rw,nosuid,nodev,relatime,uid=1023,gid=1023)";
64 
69 static string strTempDirPath;
70 
72 static bool fDebug(false);
73 
75 static Spawn* pNetCat = NULL;
76 
79 
84 static map<string, deque<string> > openDirs;
85 
87 static UserInfo* pUserInfo = NULL;
88 
90 static MountInfo* pMountInfo = NULL;
91 
93 static pthread_mutex_t ncCmdMutex;
94 
96 static pthread_mutex_t openMutex;
97 
101 static pthread_mutex_t inReleaseDirMutex;
102 
106 static pthread_cond_t inReleaseDirCond;
107 
109 static bool fInReleaseDirCond(false);
110 
119 static void sig11Handler(int iSig)
120 {
121  void *pvArray[10];
122 
123  // get void*'s for all entries on the stack
124  const int iSize(::backtrace(pvArray, sizeof(*pvArray)));
125 
126  // print out all the frames to stderr
127  ::fprintf(stderr, "Error: signal %d:\n", iSig);
128  ::backtrace_symbols_fd(pvArray, iSize, 2);
129  adbnc_destroy(NULL);
130  ::exit(1);
131 }
132 
140 static Spawn& initNetCat()
141 {
142  if (!pNetCat)
143  {
144  ostringstream strForward;
145  strForward << iForwardPort;
146  const char* const argv[] = { "nc", "localhost", strForward.str().c_str(), NULL };
147 
148  cout << "--*-- " << "spawn: ";
149  for (int i = 0; argv[i]; i++)
150  {
151  cout << argv[i];
152  if (argv[i+1])
153  cout << ", ";
154  }
155  cout << endl;
156 
157  pNetCat = new Spawn(argv, false, true);
158  }
159 
160  return(*pNetCat);
161 }
162 
166 static void destroyNetCat()
167 {
168  if (pNetCat)
169  {
170  pNetCat->sendEof();
171  INF("Waiting to terminate netcat...");
172  INF("Status: " << pNetCat->wait());
173  delete pNetCat;
174  pNetCat = NULL;
175  }
176 }
177 
189 static void stringReplacer(string& strSource, const string& strFind, const string& strReplace)
190 {
191  const int iLen(strFind.length());
192  size_t j(0);
193  for (; (j = strSource.find(strFind, j)) != string::npos ;)
194  {
195  strSource.replace(j, iLen, strReplace);
196  j += strReplace.length();
197  }
198 }
199 
210 static string makeLocalPath(const string& strPath)
211 {
212  string strLocalPath(strTempDirPath);
213  string strRemotePath(strPath);
214  stringReplacer(strRemotePath, "/", "-");
215  strLocalPath.append(strRemotePath);
216  return(strLocalPath);
217 }
218 
229 static string parent(const string& strPath)
230 {
231  string strParent(strPath);
232  const size_t uiLen(strParent.length());
233 
234  /* if strPath == / we are done*/
235  if (uiLen != 1 || strParent[0] != '/')
236  {
237  if (uiLen > 0)
238  {
240  if (strParent[uiLen - 1] == '/')
241  strParent = strParent.substr(0, uiLen - 1);
242 
243  const std::size_t uiPos(strParent.rfind('/'));
244  if (uiPos != string::npos)
245  strParent = strParent.substr(0, uiPos == 0 ? 1 : uiPos);
246 
247  if (strParent == strPath)
248  strParent = ".";
249  }
250  else
251  strParent = ".";
252  }
253 
254  return(strParent);
255 }
256 
271 static vector<string> tokenize(const string& strData)
272 {
273  vector<string> tokens;
274 
275  const char* pcDelimiters = " \t";
276  const int iLen(strData.length() + 1);
277 
278  char acTokens[iLen];
279  ::strncpy(acTokens, strData.c_str(), iLen);
280 
281  char *pcSave;
282  char* pch = ::strtok_r(acTokens, pcDelimiters, &pcSave);
283  while (pch != NULL)
284  {
285  tokens.push_back(pch);
286  pch = ::strtok_r(NULL, pcDelimiters, &pcSave);
287  }
288 
289  return(tokens);
290 }
291 
301 static bool fileExists(const char* pcName)
302 {
303  struct stat buffer;
304  return (::stat(pcName, &buffer) == 0);
305 }
306 
314 static deque<string>execCommandViaNetCat(const string& strCommand)
315 {
316  ::pthread_mutex_lock(&ncCmdMutex);
317 
318  DBG("execCommandViaNetCat: " << strCommand);
319 
320  pNetCat->outStream() << strCommand << endl << "echo '" << pcDone << "'" << endl;
321 
322  deque<string> output;
323 
324  string strTmpString;
325  while (!getline(pNetCat->inStream(), strTmpString).eof())
326  {
327  if (strTmpString.find(pcDone) != string::npos)
328  break;
329 
330  output.push_back(strTmpString);
331  }
332 
333  if (!output.empty())
334  DBG("output: " << output.front());
335  else
336  DBG("output: EMPTY");
337 
338  ::pthread_mutex_unlock(&ncCmdMutex);
339 
340  return(output);
341 }
342 
362 static deque<string> execProg(const char* const argv[], const bool fUseStdErr = false, int* const piError = NULL)
363 {
364  if (fDebug)
365  {
366  cout << "--*-- ";
367  for (int i = 0; argv[i]; i++)
368  {
369  cerr << argv[i];
370  if (argv[i+1])
371  cout << " ";
372  }
373  cout << endl;
374  }
375 
376  deque<string> output;
377 
378  try
379  {
380  Spawn cmd(argv, fUseStdErr, true);
381 
382  string strTmpString;
383  while (!getline(cmd.inStream(), strTmpString).eof())
384  {
385  if (fUseStdErr)
386  {
387  if (strTmpString.find(": Permission denied") != string::npos)
388  {
389  if (piError)
390  *piError = -EACCES;
391 
392  break;
393  }
394  else if (strTmpString.find("does not exist") != string::npos)
395  {
396  if (piError)
397  *piError = -ENOENT;
398 
399  break;
400  }
401  }
402 
403  output.push_back(strTmpString);
404  }
405 
406  if (!output.empty())
407  DBG("output: " << output.front());
408  else
409  DBG("output: EMPTY");
410 
411  cmd.sendEof();
412 
413  int iExitCode(cmd.wait());
414  if (WIFEXITED(iExitCode))
415  {
416  iExitCode = WEXITSTATUS(iExitCode);
417  if (iExitCode == ENOENT)
418  ERR("Error: program \"" << argv[0] << "\" not found");
419 
420  if (piError)
421  *piError = iExitCode;
422  }
423  }
424  catch (const runtime_error& error)
425  {
426  ERR(error.what());
427  if (piError)
428  *piError = -EIO;
429  }
430 
431  return(output);
432 }
433 
445 static deque<string> adbncShell(const string& strCommand)
446 {
447  string strActualCommand(strCommand);
448  strActualCommand.insert(0, "busybox ");
449  return(execCommandViaNetCat(strActualCommand));
450 }
451 
462 static int adbncPushPullCmd(const bool fPush, const string& strLocalPath, const string& strRemotePath)
463 {
464  string strCmdPath1("'");
465  strCmdPath1.append((fPush ? strLocalPath : strRemotePath));
466  strCmdPath1.append("'");
467 
468  string strCmdPath2("'");
469  strCmdPath2.append((fPush ? strRemotePath : strLocalPath));
470  strCmdPath2.append("'");
471 
472  const char* argv[5];
473  argv[0] = "adb";
474  argv[1] = fPush ? "push" : "pull";
475  argv[2] = fPush ? strLocalPath.c_str() : strRemotePath.c_str();
476  argv[3] = fPush ? strRemotePath.c_str() : strLocalPath.c_str();
477  argv[4] = NULL;
478 
479  int iRes(adbnc_access(fPush ? parent(strRemotePath).c_str() : strRemotePath.c_str(), fPush ? W_OK : R_OK));
480  if (!iRes)
481  {
482  /*
483  * uses stderr instead of stdout (second arg is true) because we need
484  * the error messages which adb writes to stderr.
485  *
486  * Beside error messages adb also writes performance statistics to
487  * stderr (e.g 238 KB/s (19074 bytes in 0.078s). This way we always have
488  * at least one output line.
489  *
490  * Exit status is unfortunately not useful, it seems to be 256 always.
491  */
492  execProg(argv, true, &iRes);
493  }
494 
495  return(iRes);
496 }
497 
512 static int adbncPull(const string& strRemoteSource, const string& strLocalDestination)
513 {
514  return(adbncPushPullCmd(false, strLocalDestination, strRemoteSource));
515 }
516 
528 int adbncPush(const string& strLocalSource, const string& strRemoteDestination)
529 {
530  return(adbncPushPullCmd(true, strLocalSource, strRemoteDestination));
531 }
532 
542 static int doStat(const char *pcPath, vector<string>* pOutputTokens = NULL)
543 {
544  deque<string> output;
545  const deque<string>* pOutput(fileCache.getStat(pcPath));
546 
547  if (!pOutput)
548  {
549  string strCommand("stat -t '");
550  strCommand.append(pcPath);
551  strCommand.append("'");
552 
553  output = adbncShell(strCommand);
554  fileCache.putStat(pcPath, output);
555  }
556  else
557  {
558  // from cache
559  output = *pOutput;
560  if (!output.empty())
561  DBG("from cache " << output.front());
562  else
563  DBG("from cache EMPTY");
564  }
565 
566  if (output.empty())
567  return -ENOENT;
568 
569  if (output.size() > 1)
570  {
571  deque<string>::iterator it(output.begin());
572  while (it != output.end())
573  output.front() += *it++;
574  }
575 
576  if (pOutputTokens)
577  {
578  *pOutputTokens = tokenize(output.front());
579  if (pOutputTokens->size() < 13)
580  return -ENOENT;
581 
582  while (pOutputTokens->size() > 15)
583  pOutputTokens->erase(pOutputTokens->begin());
584  }
585 
586  return(0);
587 }
588 
595 static const string androidNetCatStartCommand()
596 {
597  ostringstream strCmdStream;
598  strCmdStream << "nc -ll -p " << iForwardPort << " -e /system/xbin/bash";
599 
600  return(strCmdStream.str());
601 }
602 
609 {
610  int iPid(0);
611 
612  const char* const argv[] = { "adb", "shell", "su", "-c", "busybox", "ps", "|", "grep", androidNetCatStartCommand().c_str(), NULL };
613 
614  deque<string> output(execProg(argv));
615 
616  while (output.size() > 0)
617  {
618  if (output.front().find("grep") == string::npos)
619  {
620  vector<string> tokens(tokenize(output.front()));
621  iPid = stoi(tokens[0].c_str());
622  break;
623  }
624  else
625  output.pop_front();
626  }
627 
628  return(iPid);
629 }
630 
636 static void androidKillNetCat()
637 {
638  int iPid(androidNetcatStarted());
639 
640  if (iPid > 0)
641  {
642  const string strPid(to_string(iPid));
643  const char* const argv[] = { "adb", "shell", "su", "-c", "busybox", "kill", strPid.c_str(), NULL };
644  execProg(argv);
645  }
646 
647  iPid = androidNetcatStarted();
648  if (iPid == 0)
649  INF("Netcat successfully stopped on android device");
650  else
651  INF("Failed to kill NetCat on android device");
652 }
653 
661 static int androidStartNetcat()
662 {
663  if (!androidNetcatStarted())
664  {
665  const char* const argv[] = { "adb", "shell", "su", "-c", "busybox", "nohup", androidNetCatStartCommand().c_str(), "2>/dev/null", "1>/dev/null", "&", NULL };
666  execProg(argv);
667  }
668 
669  const int iStarted(androidNetcatStarted());
670  if (!iStarted)
671  INF("error: could not start netcat on android device");
672  else
673  INF("Netcat successfully started on android device");
674 
675  return(iStarted ? 0 : 3);
676 }
677 
684 {
685  int iRes(1);
686 
687  // check if a android device is connected
688  int iError(0);
689 
690  const char* const argv[] = { "adb", "devices", NULL };
691  deque<string> output(execProg(argv, false, &iError));
692 
693  if (!iError)
694  {
695  if (output.size() > 2)
696  {
697  const string strDeviceId(output[output.size() - 2].substr(0, 8));
698 
699  if (strDeviceId != "List of ")
700  {
701  INF("Using android device " << strDeviceId);
702  iRes = 0;
703  } // error message already written by adb
704  } // error message already written by adb
705  }
706 
707  return(iRes);
708 }
709 
721 static bool isAndroidPortForwarded(const string& strForwardArg)
722 {
723  bool fRes(false);
724 
725  const char* const argv[] = { "adb", "forward", "--list", NULL };
726  deque<string> output(execProg(argv));
727 
728  for(deque<string>::iterator it = output.begin(); it != output.end(); ++it)
729  {
730  if((*it).find(strForwardArg) != string::npos)
731  {
732  fRes = true;
733  break;
734  }
735  }
736 
737  return(fRes);
738 }
739 
746 {
747  int iRes(2);
748 
749  ostringstream strForwardPort;
750  strForwardPort << "tcp:" << iForwardPort;
751 
752  ostringstream strForwardArg;
753  strForwardArg << strForwardPort.str() << " " << strForwardPort.str();
754 
755  if (!isAndroidPortForwarded(strForwardArg.str()))
756  {
757  const char* const argv[] = { "adb", "forward", strForwardPort.str().c_str(), strForwardPort.str().c_str(), NULL };
758  execProg(argv);
759  }
760 
761  if (isAndroidPortForwarded(strForwardArg.str()))
762  {
763  INF("Port " << strForwardPort.str() << " successfully forwarded to android device");
764  iRes = 0;
765  }
766  else
767  INF("Failed to forward Port " << strForwardPort.str() << " to android device");
768 
769  return(iRes);
770 }
771 
781 {
782  ostringstream strForwardPort;
783  strForwardPort << "tcp:" << iForwardPort;
784 
785  ostringstream strForwardArg;
786  strForwardArg << strForwardPort.str() << " " << strForwardPort.str();
787 
788  if (isAndroidPortForwarded(strForwardArg.str()))
789  {
790  const char* const argv[] = { "adb", "forward", "--remove", strForwardPort.str().c_str(), NULL };
791  execProg(argv);
792  }
793 
794  bool fRet(!isAndroidPortForwarded(strForwardArg.str()));
795  if (fRet)
796  INF("Forward port " << strForwardPort.str() << " to android device successfully removed");
797  else
798  INF("Failed to remove forward port " << strForwardPort.str() << " from android device");
799 
800  return(fRet);
801 }
802 
806 static void cleanupTempDir(void)
807 {
808  const char* const argv[] = { "rm", "-rf", strTempDirPath.c_str(), NULL };
809  execProg(argv);
810 }
811 
819 static int makeTempDir(void)
820 {
821  char acTempDirTemplate[::strlen(pcTempDirTemplate) + 1];
822  ::strncpy(acTempDirTemplate, pcTempDirTemplate, sizeof(acTempDirTemplate));
823  const char * pcTempDir = ::mkdtemp(&acTempDirTemplate[0]);
824 
825  if (pcTempDir)
826  {
827  strTempDirPath.assign(pcTempDir);
828  strTempDirPath.append("/");
829  }
830 
831  return(pcTempDir ? 0 : errno);
832 }
833 
845 static int queryUserInfo()
846 {
847  const char* const argv[] = { "adb", "shell", "busybox id", NULL };
848  deque<string> output(execProg(argv));
849 
850  int iRes(!(output.size() == 1));
851  if (!iRes && output.front().length() > 5 && output.front()[0] == 'u')
852  pUserInfo = new UserInfo(output.front().c_str());
853  else
854  INF("Failed to query user info from device");
855 
856  return(iRes);
857 }
858 
870 static int queryMountInfo()
871 {
872  const char* const argv[] = { "adb", "shell", "busybox mount", NULL };
873  deque<string> output(execProg(argv));
874 
875  int iRes(!(output.size() > 0));
876  if (!iRes)
877  {
878  /*
879  * Big Hack, coz. I don't know how to get mount info for sdcard from device.
880  *
881  * @todo get rid of that
882  */
883  output.push_back(pcSdCardMountEntry);
884  pMountInfo = new MountInfo(output);
885  }
886  else
887  INF("Failed to query mount info from device");
888 
889  return(iRes);
890 }
891 
906 int initAdbncFs(const int argc, char** const argv)
907 {
908  ::signal(SIGSEGV, sig11Handler); // install our handler
909 
910  bool fInitRequired(true);
911 
912  // check if debug option is set or -h/--help or -V/--version
913  for (int i = 1; i < argc; i++)
914  {
915  if (::strcmp(argv[i], "-d") == 0)
916  fDebug = true;
917 
918  if (::strcmp(argv[i], "-h") == 0)
919  fInitRequired = false;
920 
921  if (::strcmp(argv[i], "--help") == 0)
922  fInitRequired = false;
923 
924  if (::strcmp(argv[i], "-V") == 0)
925  fInitRequired = false;
926 
927  if (::strcmp(argv[i], "--version") == 0)
928  fInitRequired = false;
929  }
930 
931  int iRes(0);
932 
933  if (fInitRequired)
934  {
935  iRes =makeTempDir();
936 
937  if (!iRes)
938  {
939  iRes = isAndroidDeviceConnected();
940 
941  if (!iRes)
942  {
943  iRes = setAndroidPortForwarding();
944 
945  if (!iRes)
946  {
947  iRes = androidStartNetcat();
948  if (!iRes)
949  {
950  iRes = queryUserInfo();
951  if (!iRes)
952  {
953  iRes = queryMountInfo();
954  initNetCat();
955  }
956  }
957  }
958  }
959  }
960  }
961 
962  return(iRes);
963 }
964 
975 void* adbnc_init(struct fuse_conn_info *pConn)
976 {
977  DBG("adbnc_init()");
978 
979 // pConn->async_read = 0;
980 // pConn->want &= ~ FUSE_CAP_ASYNC_READ; // clear async read flag
981  pConn->want |= FUSE_CAP_EXPORT_SUPPORT; // set . and .. not handled by us
982 
983  ::pthread_mutex_init(&ncCmdMutex, NULL);
984  ::pthread_mutex_init(&openMutex, NULL);
985  ::pthread_mutex_init(&inReleaseDirMutex, NULL);
986  ::pthread_cond_init (&inReleaseDirCond, NULL);
987 
988  return(NULL);
989 }
990 
1003 void adbnc_destroy(void* private_data)
1004 {
1005  DBG("adbnc_destroy()");
1006 
1007  ::pthread_mutex_destroy(&ncCmdMutex);
1008  ::pthread_mutex_destroy(&openMutex);
1009  ::pthread_mutex_destroy(&inReleaseDirMutex);
1010  ::pthread_cond_destroy(&inReleaseDirCond);
1011 
1012  destroyNetCat();
1015  cleanupTempDir();
1016 
1017  if (pMountInfo)
1018  {
1019  delete pMountInfo;
1020  pMountInfo = NULL;
1021  }
1022 
1023  if (pUserInfo)
1024  {
1025  delete pUserInfo;
1026  pUserInfo = NULL;
1027  }
1028 }
1029 
1041 int adbnc_statfs(const char *pcPath, struct statvfs* pFst)
1042 {
1043  DBG("adbnc_statfs(" << pcPath << ")");
1044 
1045  ::memset(pFst, 0, sizeof(struct statvfs));
1046 
1047  int iRes(0);
1048 
1049  if (::strcmp(pcPath, "/") != 0)
1050  {
1051  // fist get block info
1052  string strCommand("df -P -B 4096 '");
1053  strCommand.append(pcPath);
1054  strCommand.append("'");
1055  deque<string> output(adbncShell(strCommand));
1056 
1057  iRes = (output.size() > 1 ? 0 : -EIO);
1058  if (!iRes)
1059  {
1060  /*
1061  Filesystem 4K-blocks Used Available Use% Mounted on
1062  tmpfs 355740 35 355705 0% /dev
1063  */
1064  output.pop_front(); // remove header
1065  vector<string> tokens(tokenize(output.front()));
1066  if (tokens.size() >= 6)
1067  {
1068  try
1069  {
1070  pFst->f_bsize = 4096;
1071  pFst->f_blocks = stoul(tokens[1]); // Total number of blocks on the file system
1072  pFst->f_frsize = pFst->f_bsize; // Fundamental file system block size (fragment size).
1073  pFst->f_bfree = stoul(tokens[3]); // Total number of free blocks.
1074  pFst->f_bavail = pFst->f_bfree; // Total number of free blocks available to non-privileged processes.
1075  }
1076  catch (const exception& e)
1077  {
1078  ERR("Exception thrown in adbnc_statfs(" << pcPath << ")" << ": " << e.what());
1079 
1080  for (int i = 0; i < tokens.size(); i++)
1081  ERR("Token[" << i << "] :" << tokens[i]);
1082 
1083  iRes = -EIO;
1084  }
1085  }
1086  }
1087 
1088  if (!iRes)
1089  {
1090  // now get inode info
1091  strCommand.assign("df -P -i '");
1092  strCommand.append(pcPath);
1093  strCommand.append("'");
1094  output = adbncShell(strCommand);
1095 
1096  iRes = (output.size() > 1 ? 0 : -EIO);
1097  if (!iRes)
1098  {
1099  /*
1100  Filesystem Inodes Used Available Capacity Mounted on
1101  /dev/block/platform/msm_sdcc.1/by-name/efs 896 99 797 11% /efs
1102  */
1103  output.pop_front(); // remove header
1104  vector<string> tokens(tokenize(output.front()));
1105  if (tokens.size() >= 6)
1106  {
1107  try
1108  {
1109  pFst->f_files = stoul(tokens[1]); // Total number of file nodes (inodes) on the file system.
1110  pFst->f_ffree = stoul(tokens[3]); // Total number of free file nodes (inodes).
1111  pFst->f_favail = pFst->f_ffree; // Total number of free file nodes (inodes) available to non-privileged processes.
1112  }
1113  catch (const exception& e)
1114  {
1115  ERR("Exception thrown in adbnc_statfs(" << pcPath << ")" << ": " << e.what());
1116 
1117  for (int i = 0; i < tokens.size(); i++)
1118  ERR("Token[" << i << "] :" << tokens[i]);
1119 
1120  iRes = -EIO;
1121  }
1122  }
1123  }
1124 
1125  // global / guessed info
1126  pFst->f_namemax = 1024; // Maximum length of a file name (path element).
1127  }
1128  }
1129 
1130  return(iRes);
1131 }
1132 
1143 int adbnc_getattr(const char *pcPath, struct stat *pStatBuf)
1144 {
1145  DBG("adbnc_getattr(" << pcPath << ")");
1146 
1147  int iRes(0);
1148  ::memset(pStatBuf, 0, sizeof(struct stat));
1149  vector<string> tokens;
1150  iRes = doStat(pcPath, &tokens);
1151 
1152  if (!iRes)
1153  {
1154  /*
1155  stat -t Explained:
1156  file name (%n)
1157  total size (%s)
1158  number of blocks (%b)
1159  raw mode in hex (%f)
1160  UID of owner (%u)
1161  GID of file (%g)
1162  device number in hex (%D)
1163  inode number (%i)
1164  number of hard links (%h)
1165  major device type in hex (%t)
1166  minor device type in hex (%T)
1167  last access time as seconds since the Unix Epoch (%X)
1168  last modification as seconds since the Unix Epoch (%Y)
1169  last change as seconds since the Unix Epoch (%Z)
1170  I/O block size (%o)
1171  */
1172 
1173  try
1174  {
1175  pStatBuf->st_ino = stoul(tokens[7].c_str()); /* inode number */
1176  const unsigned int uiRawMode(stoul(tokens[3], NULL, 16));
1177  pStatBuf->st_mode = uiRawMode | 0700; /* protection */
1178  pStatBuf->st_nlink = 1; /* number of hard links */
1179  pStatBuf->st_uid = stoul(tokens[4].c_str()); /* user ID of owner */
1180  pStatBuf->st_gid = stoul(tokens[5].c_str()); /* group ID of owner */
1181 
1182  const unsigned int uiDeviceId(stoul(tokens[6], NULL, 16));
1183  pStatBuf->st_rdev = uiDeviceId; // device ID (if special file)
1184 
1185  pStatBuf->st_size = stoul(tokens[1].c_str()); /* total size, in bytes */
1186  pStatBuf->st_blksize = stol(tokens[14].c_str()); /* blocksize for filesystem I/O */
1187  pStatBuf->st_blocks = stoul(tokens[2].c_str()); /* number of blocks allocated */
1188  pStatBuf->st_atime = stol(tokens[11].c_str()); /* time of last access */
1189  pStatBuf->st_mtime = stol(tokens[12].c_str()); /* time of last modification */
1190  pStatBuf->st_ctime = stol(tokens[13].c_str()); /* time of last status change */
1191  }
1192  catch (const exception& e)
1193  {
1194  ERR("Exception thrown in adbnc_getattr(" << pcPath << ")" << ": " << e.what());
1195 
1196  for (int i = 0; i < tokens.size(); i++)
1197  ERR("Token[" << i << "] :" << tokens[i]);
1198 
1199  iRes = -EIO;
1200  }
1201  }
1202 
1203  return(iRes);
1204 }
1205 
1220 int adbnc_open(const char *pcPath, struct fuse_file_info *pFi)
1221 {
1222  ::pthread_mutex_lock(&openMutex);
1223 
1224  int iRes(0);
1225 
1226  DBG("adbnc_open(" << pcPath << ")");
1227 
1228  string strLocalPath(makeLocalPath(pcPath));
1229 
1230  if (!fileStatus.truncated(pcPath))
1231  {
1232  iRes = doStat(pcPath);
1233  if (!iRes && !fileExists(pcPath))
1234  iRes = adbncPull(pcPath, strLocalPath);
1235  }
1236  else
1237  fileStatus.truncated(pcPath, false);
1238 
1239  if (!iRes)
1240  {
1241  pFi->fh = ::open(strLocalPath.c_str(), pFi->flags);
1242  if (pFi->fh == -1)
1243  iRes = -errno;
1244  }
1245 
1246  ::pthread_mutex_unlock(&openMutex);
1247 
1248  return(iRes);
1249 }
1250 
1263 int adbnc_opendir(const char *pcPath, struct fuse_file_info *pFi)
1264 {
1265  int iRes(0);
1266 
1267  ::pthread_mutex_lock(&inReleaseDirMutex);
1268 
1269  /* wait until directory is released */
1270  while (fInReleaseDirCond)
1271  ::pthread_cond_wait(&inReleaseDirCond, &inReleaseDirMutex);
1272 
1273  DBG("adbnc_opendir(" << pcPath << ")");
1274 
1275  string strCommand("ls -1a '");
1276  strCommand.append(pcPath);
1277  strCommand.append("'");
1278  deque<string> output(adbncShell(strCommand));
1279 
1280  if (!output.empty())
1281  {
1282  const map<string, deque<string> >::iterator it(openDirs.find(pcPath));
1283  if (it == openDirs.end())
1284  openDirs.insert(make_pair(pcPath, output));
1285  }
1286  else
1287  iRes = -EIO; // could also be EACCES
1288 
1289  ::pthread_mutex_unlock(&inReleaseDirMutex);
1290 
1291  return(iRes);
1292 }
1293 
1311 int adbnc_readdir(const char *pcPath, void *vpBuf, fuse_fill_dir_t filler, off_t iOffset, struct fuse_file_info *pFi)
1312 {
1313  int iRes(0);
1314 
1315  DBG("adbnc_readdir(" << pcPath << ")");
1316 
1317  const map<string, deque<string> >::const_iterator it(openDirs.find(pcPath));
1318  if (it != openDirs.end())
1319  {
1320  int iNumDirectoryEntries(it->second.size());
1321  for (int i(0); i < iNumDirectoryEntries; i++)
1322  {
1323  // Skip dot and dot-dot entries
1324  if (i < 2)
1325  continue;
1326 
1327  /* Skip this entry if we weren't asked for it */
1328  if (i < iOffset)
1329  continue;
1330 
1331  DBG("entry: " << it->second[i]);
1332 
1333  string strFullEntryPath(pcPath);
1334  if (strFullEntryPath != "/")
1335  strFullEntryPath.append("/");
1336 
1337  strFullEntryPath.append(it->second[i]);
1338 
1339  /* Skip this entry if file no longer exists */
1340  struct stat statBuf;
1341  if (adbnc_getattr(strFullEntryPath.c_str(), &statBuf) != 0)
1342  continue;
1343 
1344  /* Add this to our response until we are asked to stop */
1345  if (filler(vpBuf, it->second[i].c_str(), &statBuf, i+1))
1346  break;
1347  }
1348  /* All done because we were asked to stop or because we finished */
1349  }
1350  else
1351  iRes = -EBADF;
1352 
1353  return(iRes);
1354 }
1355 
1366 int adbnc_releasedir(const char *pcPath, struct fuse_file_info *pFi)
1367 {
1368  int iRes(0);
1369 
1370  ::pthread_mutex_lock(&inReleaseDirMutex);
1371 
1372  fInReleaseDirCond = true;
1373 
1374  DBG("adbnc_releasedir(" << pcPath << ")");
1375 
1376  openDirs.erase(pcPath);
1377 
1378  /* signal waiting thread directory is released */
1379  ::pthread_cond_signal(&inReleaseDirCond);
1380 
1381  fInReleaseDirCond = false;
1382 
1383  ::pthread_mutex_unlock(&inReleaseDirMutex);
1384 
1385  return(iRes);
1386 }
1387 
1400 int adbnc_readlink(const char *pcPath, char *pcBuf, size_t iSize)
1401 {
1402  DBG("adbnc_readlink(" << pcPath << ")");
1403 
1404  deque<string> output;
1405  const deque<string>* pOutput(fileCache.getReadLink(pcPath));
1406 
1407  if (!pOutput)
1408  {
1409  string strCommand("readlink -f '");
1410  strCommand.append(pcPath);
1411  strCommand.append("'");
1412 
1413  output = adbncShell(strCommand);
1414 
1415  fileCache.putReadLink(pcPath, output);
1416  }
1417  else
1418  {
1419  // from cache
1420  output = *pOutput;
1421  if (!output.empty())
1422  DBG("from cache " << output.front());
1423  else
1424  DBG("from cache EMPTY");
1425  }
1426 
1427  if(output.empty())
1428  return -ENOENT;
1429 
1430  string strRes(output.front());
1431  if (strRes[0] == '/')
1432  {
1433  int iPos(0);
1434  int iDepth(-1);
1435  while (pcPath[iPos] != '\0')
1436  {
1437  if (pcPath[iPos++] == '/')
1438  iDepth++;
1439  }
1440 
1441  strRes.erase(0, 1);
1442  while (iDepth > 0)
1443  {
1444  string strDotDot("..");
1445  strDotDot.append("/");
1446  strRes.insert(0, strDotDot);
1447  iDepth--;
1448  }
1449  }
1450 
1451  size_t iMySize(strRes.size());
1452  if (iMySize >= iSize)
1453  return -ENOSYS;
1454 
1455  ::memcpy(pcBuf, strRes.c_str(), iMySize + 1);
1456  return(0);
1457 }
1458 
1474 int adbnc_access(const char *pcPath, int iMask)
1475 {
1476  DBG("adbnc_access(" << pcPath << ")");
1477 
1478  /* Does it exist */
1479  vector<string> tokens;
1480  int iRes(doStat(pcPath, &tokens));
1481  if (iRes && iMask == F_OK)
1482  iRes = -ENOENT;
1483 
1484  if (!iRes && (iMask != F_OK))
1485  {
1486  unsigned int uiRawMode(0);
1487  int iUid(0);
1488  int iGid(0);
1489 
1490  try
1491  {
1492  /* Has it the right permission ?*/
1493  uiRawMode = stoul(tokens[3], NULL, 16);
1494  iUid = stoi(tokens[4].c_str());
1495  iGid = stoi(tokens[5].c_str());
1496  }
1497  catch (const exception& e)
1498  {
1499  ERR("Exception thrown in adbnc_access(" << pcPath << ")" << ": " << e.what());
1500 
1501  for (int i = 0; i < tokens.size(); i++)
1502  ERR("Token[" << i << "] :" << tokens[i]);
1503 
1504  iRes = -EIO;
1505  }
1506 
1507  if (!iRes && pUserInfo)
1508  {
1509  iRes = -pUserInfo->access(iUid, iGid, uiRawMode, iMask);
1510  if (!iRes && pMountInfo)
1511  {
1512  if (iMask & W_OK)
1513  {
1514  if (pMountInfo->isMountedRo(pcPath))
1515  iRes = -EACCES; // we are asked for write access but mounted ro
1516  }
1517 
1518  if (!iRes && (iMask & X_OK))
1519  {
1520  if (pMountInfo->isMountedNoexec(pcPath))
1521  iRes = -EACCES; // we are asked for execute access but mounted noexec
1522  }
1523  }
1524  }
1525  }
1526 
1527  return(iRes);
1528 }
1529 
1541 int adbnc_flush(const char *pcPath, struct fuse_file_info *pFi)
1542 {
1543  int iRes(0);
1544 
1545  DBG("adbnc_flush(" << pcPath << ")");
1546 
1547  iRes = ::fsync(pFi->fh);
1548  if (!iRes || errno == EBADF)
1549  {
1550  string strLocalPath(makeLocalPath(pcPath));
1551  int iFlags(pFi->flags);
1552 
1553  DBG("flag is: " << iFlags);
1554 
1555  if (fileStatus.pendingOpen(pcPath))
1556  fileCache.invalidate(pcPath);
1557 
1558  iRes = fileStatus.flush(pcPath, strLocalPath);
1559  }
1560  else
1561  iRes = -errno;
1562 
1563  return(iRes);
1564 }
1565 
1566 int adbnc_fsync(const char* pcPath, int iIsdatasync, struct fuse_file_info* pFi)
1567 {
1568  DBG("adbnc_fsync(" << pcPath << ")");
1569 
1570  int iRes(::fsync(pFi->fh));
1571  if (!iRes)
1572  {
1573  if (fileStatus.pendingOpen(pcPath))
1574  {
1575  iRes = adbncPush(makeLocalPath(pcPath), pcPath);
1576  fileStatus.pendingOpen(pcPath, false, false);
1577  fileCache.invalidate(pcPath);
1578  }
1579  }
1580  else
1581  iRes = -errno;
1582 
1583  return(iRes);
1584 }
1585 
1598 int adbnc_release(const char *pcPath, struct fuse_file_info *pFi)
1599 {
1600  DBG("adbnc_release(" << pcPath << ")");
1601 
1602  return(fileStatus.release(pcPath, pFi->fh));
1603 }
1604 
1619 int adbnc_read(const char *pcPath, char *pcBuf, size_t iSize, off_t iOffset, struct fuse_file_info *pFi)
1620 {
1621  int iRes(-EBADF);
1622 
1623  DBG("adbnc_read(" << pcPath << ")");
1624 
1625  fileStatus.pendingOpen(pcPath, true, false);
1626 
1627  if (pFi->fh != -1)
1628  {
1629  iRes = ::pread(pFi->fh, pcBuf, iSize, iOffset);
1630  if (iRes == -1)
1631  iRes = -errno;
1632  }
1633 
1634  return(iRes);
1635 }
1636 
1637 int adbnc_write(const char *pcPath, const char *pcBuf, size_t iSize, off_t iOffset, struct fuse_file_info *pFi)
1638 {
1639  DBG("adbnc_write(" << pcPath << ")");
1640 
1641  fileStatus.pendingOpen(pcPath, true, true);
1642 
1643  int iRes(::pwrite(pFi->fh, pcBuf, iSize, iOffset));
1644 
1645  return(iRes == -1 ? -errno : iRes);
1646 }
1647 
1648 int adbnc_utimens(const char *pcPath, const struct timespec ts[2])
1649 {
1650  DBG("adbnc_utimens(" << pcPath << ")");
1651 
1652  fileCache.invalidate(pcPath);
1653 
1654  string command("touch \"");
1655  command.append(pcPath);
1656  command.append("\"");
1657 
1658  adbncShell(command);
1659 
1660  return(0);
1661 }
1662 
1663 int adbnc_truncate(const char *pcPath, off_t iSize)
1664 {
1665  DBG("adbnc_truncate(" << pcPath << ")");
1666 
1667  int iRes(doStat(pcPath));
1668  if (!iRes)
1669  {
1670  const string strLocalPath(makeLocalPath(pcPath));
1671 
1672  iRes = ::truncate(strLocalPath.c_str(), iSize);
1673  if (!iRes)
1674  {
1675  DBG("truncate[path=" << strLocalPath << "][size=" << iSize << "]");
1676 
1677  fileStatus.truncated(pcPath, true);
1678  fileCache.invalidate(pcPath);
1679  }
1680  else
1681  iRes = -errno;
1682  }
1683 
1684  return(iRes);
1685 }
1686 
1687 int adbnc_mknod(const char *pcPath, mode_t mode, dev_t rdev)
1688 {
1689  DBG("adbnc_mknod(" << pcPath << ")");
1690 
1691  const string strLocalPath(makeLocalPath(pcPath));
1692 
1693  DBG("mknod for " << strLocalPath);
1694 
1695  int iRes(::mknod(strLocalPath.c_str(), mode, rdev));
1696  if (!iRes)
1697  {
1698  iRes = adbncPush(strLocalPath, pcPath);
1699  if (!iRes)
1700  adbncShell("sync");
1701 
1702  fileCache.invalidate(pcPath);
1703  }
1704  else
1705  iRes = -errno;
1706 
1707  return(iRes);
1708 }
1709 
1710 int adbnc_mkdir(const char *pcPath, mode_t mode)
1711 {
1712  DBG("adbnc_mkdir(" << pcPath << ")");
1713 
1714  fileCache.invalidate(pcPath);
1715  string strCommand("mkdir '");
1716  strCommand.append(pcPath);
1717  strCommand.append("'");
1718 
1719  DBG("Making directory " << pcPath);
1720 
1721  adbncShell(strCommand);
1722  return(0);
1723 }
1724 
1725 int adbnc_rename(const char *pcFrom, const char *pcTo)
1726 {
1727  DBG("adbnc_rename(" << pcFrom << ", " << pcTo << ")");
1728 
1729  string strCommand("mv '");
1730  strCommand.append(pcFrom);
1731  strCommand.append("' '");
1732  strCommand.append(pcTo);
1733  strCommand.append("'");
1734 
1735  DBG("Renaming " << pcFrom << " to " << pcTo);
1736 
1737  adbncShell(strCommand);
1738 
1739  // invalidate to cache I don't check here if from File is different to toFile
1740  fileCache.invalidate(pcTo);
1741 
1742  // from file no longer exists -> invalidate in cache
1743  fileCache.invalidate(pcFrom);
1744 
1745  if (fileStatus.pendingOpen(pcFrom))
1746  {
1747  // transfer existing pending open to renamed
1748  fileStatus.pendingOpen(pcTo, makeLocalPath(pcFrom));
1749  }
1750 
1751  return(0);
1752 }
1753 
1754 int adbnc_rmdir(const char *pcPath)
1755 {
1756  DBG("adbnc_rmdir(" << pcPath << ")");
1757 
1758  fileCache.invalidate(pcPath);
1759  string strCommand("rmdir '");
1760  strCommand.append(pcPath);
1761  strCommand.append("'");
1762 
1763  DBG("Removing directory " << pcPath);
1764 
1765  adbncShell(strCommand);
1766 
1767  return(0);
1768 }
1769 
1781 int adbnc_unlink(const char *pcPath)
1782 {
1783  DBG("adbnc_unlink(" << pcPath << ")");
1784 
1785  fileCache.invalidate(pcPath);
1786 
1787  string strCommand("rm '");
1788  strCommand.append(pcPath);
1789  strCommand.append("'");
1790 
1791  DBG("Deleting " << pcPath);
1792 
1793  ::unlink(makeLocalPath(pcPath).c_str());
1794  adbncShell(strCommand);
1795 
1796  return(0);
1797 }
1798 
Keep track of files opened and truncated files.
static Spawn * pNetCat
Pointer to the netcat process initialized in initNetCat()
Definition: adbncfs.cpp:75
static vector< string > tokenize(const string &strData)
Splits the given data string into tokens.
Definition: adbncfs.cpp:271
static const string androidNetCatStartCommand()
Return the command line used to start netcat process on android device.
Definition: adbncfs.cpp:595
static bool fInReleaseDirCond(false)
Waited for condition variable.
static FileStatus fileStatus
Definition: adbncfs.cpp:78
void adbnc_destroy(void *private_data)
FUSE callback function, called when the file system exits.
Definition: adbncfs.cpp:1003
int initAdbncFs(const int argc, char **const argv)
Initialize the file system application.
Definition: adbncfs.cpp:906
A class to manage informations obtained from the output of the busybox applet mount command...
Definition: mountInfo.h:41
static pthread_cond_t inReleaseDirCond
Condition to block adbnc_opendir() until adbnc_releasedir() is finished.
Definition: adbncfs.cpp:106
static int isAndroidDeviceConnected()
Tests if any android device is connected to a local host's usb port.
Definition: adbncfs.cpp:683
void putStat(const char *pcPath, const deque< string > &statOutput)
Caches the output of doStat().
int adbnc_mkdir(const char *pcPath, mode_t mode)
Definition: adbncfs.cpp:1710
bool isMountedNoexec(const char *pcPath) const
Test if the given path is located on a mount point that is mounted with the noexec option...
Definition: mountInfo.cpp:218
static const char * pcSdCardMountEntry
Big Hack, don't now how to figure out wher sdcard on a phone is mounted.
Definition: adbncfs.cpp:63
void putReadLink(const char *pcPath, const deque< string > &readLinkOutput)
Caches the output of adbnc_readlink().
static pthread_mutex_t ncCmdMutex
Mutex to synchronize thread access to execCommandViaNetCat()
Definition: adbncfs.cpp:93
int adbnc_readdir(const char *pcPath, void *vpBuf, fuse_fill_dir_t filler, off_t iOffset, struct fuse_file_info *pFi)
FUSE callback to retrieve directory entries.
Definition: adbncfs.cpp:1311
static pthread_mutex_t inReleaseDirMutex
Mutex to synchronize thread access to adbnc_opendir() and adbnc_releasedir()
Definition: adbncfs.cpp:101
int adbnc_readlink(const char *pcPath, char *pcBuf, size_t iSize)
FUSE callback function to resolve a link.
Definition: adbncfs.cpp:1400
void pendingOpen(const char *pcPath, const bool fPendingOpen, const bool fForWrite)
Notes that on the given path a read or write operation has been performed.
static bool isAndroidPortForwarded(const string &strForwardArg)
Tests if tcp socket connections from local port to remote port on the android device is in place...
Definition: adbncfs.cpp:721
int adbnc_statfs(const char *pcPath, struct statvfs *pFst)
FUSE callback function to retrieve statistics about the file system.
Definition: adbncfs.cpp:1041
static int doStat(const char *pcPath, vector< string > *pOutputTokens=NULL)
Execute a stat command on android file or directory denoted by pcPath.
Definition: adbncfs.cpp:542
static int adbncPushPullCmd(const bool fPush, const string &strLocalPath, const string &strRemotePath)
Execute an adb push or pull command with given paths.
Definition: adbncfs.cpp:462
static pthread_mutex_t openMutex
Mutex to synchronize thread access to adbnc_open()
Definition: adbncfs.cpp:96
#define ERR(line)
Definition: adbncfs.cpp:39
static bool fDebug(false)
Debug mode as set in initAdbncFs()
int wait()
Wait until child process has terminated.
Definition: spawn.cpp:172
static int queryMountInfo()
Query mount information form android device.
Definition: adbncfs.cpp:870
int adbnc_releasedir(const char *pcPath, struct fuse_file_info *pFi)
FUSE callback to release given directory.
Definition: adbncfs.cpp:1366
static void androidKillNetCat()
Kills the running netcat process on android device.
Definition: adbncfs.cpp:636
int adbnc_access(const char *pcPath, int iMask)
FUSE callback to check whether file pcPath can be accessed.
Definition: adbncfs.cpp:1474
std::istream & inStream()
Access the child process stdout as in stream to read from.
Definition: spawn.h:77
A cache for file attributes and resolved links.
Definition: fileInfoCache.h:38
static map< string, deque< string > > openDirs
Map to store directory listing retrieved with adbnc_opendir() from android device.
Definition: adbncfs.cpp:84
static void cleanupTempDir(void)
Recursively deletes the temporary directory created in makeTempDir().
Definition: adbncfs.cpp:806
static int androidNetcatStarted()
Test if netcat is started on the android device.
Definition: adbncfs.cpp:608
int adbnc_getattr(const char *pcPath, struct stat *pStatBuf)
FUSE callback function to retrieve file attributes.
Definition: adbncfs.cpp:1143
int adbnc_write(const char *pcPath, const char *pcBuf, size_t iSize, off_t iOffset, struct fuse_file_info *pFi)
Definition: adbncfs.cpp:1637
static void sig11Handler(int iSig)
Segmentation fault handler.
Definition: adbncfs.cpp:119
static bool removeAndroidPortForwarding()
Tries to remove android port forwarding.
Definition: adbncfs.cpp:780
static Spawn & initNetCat()
Spawns a netcat process on the local host with the local forward port.
Definition: adbncfs.cpp:140
int adbnc_release(const char *pcPath, struct fuse_file_info *pFi)
FUSE callback called when FUSE is completely done with a file.
Definition: adbncfs.cpp:1598
int adbnc_unlink(const char *pcPath)
FUSE callback function to remove (delete) the given file, symbolic link, hard link, or special node.
Definition: adbncfs.cpp:1781
static int androidStartNetcat()
Starts a netcat process on the android device.
Definition: adbncfs.cpp:661
static string makeLocalPath(const string &strPath)
Converts the given android path to a path on the local host.
Definition: adbncfs.cpp:210
void sendEof()
Definition: spawn.cpp:152
std::ostream & outStream()
Access the child process stdin as out stream to write to the process.
Definition: spawn.h:84
#define DBG(line)
Definition: adbncfs.cpp:37
static const int iForwardPort(4444)
Local and remote adb forward port.
static string strTempDirPath
Path to the temporary directory used by the instance of this application initialized in makeTempDir()...
Definition: adbncfs.cpp:69
static void stringReplacer(string &strSource, const string &strFind, const string &strReplace)
Replace all instances of string strFind with string strReplace in the given string strSource...
Definition: adbncfs.cpp:189
static bool fileExists(const char *pcName)
Tests whether the file or directory denoted by pcName exists on the local host.
Definition: adbncfs.cpp:301
static string parent(const string &strPath)
Returns the parent pathname string of the given strPath.
Definition: adbncfs.cpp:229
int adbnc_utimens(const char *pcPath, const struct timespec ts[2])
Definition: adbncfs.cpp:1648
static deque< string > adbncShell(const string &strCommand)
Execute a shell command on the android device.
Definition: adbncfs.cpp:445
bool isMountedRo(const char *pcPath) const
Test if the given path is located on a mount point that is mounted read only.
Definition: mountInfo.cpp:203
int access(const int iUid, const int iGid, const unsigned int uiRawMode, const int iMask) const
This is the similar to the access(2) system call.
Definition: userInfo.cpp:94
int adbnc_rmdir(const char *pcPath)
Definition: adbncfs.cpp:1754
Spawn a child process.
Definition: spawn.h:66
static const char * pcTempDirTemplate
Template used to makeTempDir()
Definition: adbncfs.cpp:56
#define INF(line)
Definition: adbncfs.cpp:38
static deque< string > execCommandViaNetCat(const string &strCommand)
Execute the given command string via netcat.
Definition: adbncfs.cpp:314
int adbnc_fsync(const char *pcPath, int iIsdatasync, struct fuse_file_info *pFi)
Definition: adbncfs.cpp:1566
static int setAndroidPortForwarding()
Enable adb port forwarding for our local and remote port.
Definition: adbncfs.cpp:745
void * adbnc_init(struct fuse_conn_info *pConn)
FUSE callback function to initialize the file system.
Definition: adbncfs.cpp:975
static FileCache fileCache
Definition: adbncfs.cpp:77
int adbnc_open(const char *pcPath, struct fuse_file_info *pFi)
FUSE callback to open a file.
Definition: adbncfs.cpp:1220
void invalidate(const char *pcPath)
Renders the cashed data for the given file as invalid.
const deque< string > * getReadLink(const char *pcPath) const
int adbnc_read(const char *pcPath, char *pcBuf, size_t iSize, off_t iOffset, struct fuse_file_info *pFi)
FUSE callback to read iSize bytes from the given file into the buffer pcBuf, beginning at iOffset byt...
Definition: adbncfs.cpp:1619
int adbnc_truncate(const char *pcPath, off_t iSize)
Definition: adbncfs.cpp:1663
static void destroyNetCat()
Kills the netcat process spawned in initNetCat().
Definition: adbncfs.cpp:166
static deque< string > execProg(const char *const argv[], const bool fUseStdErr=false, int *const piError=NULL)
Execute a program.
Definition: adbncfs.cpp:362
int adbncPush(const string &strLocalSource, const string &strRemoteDestination)
Copy (using adb push) a file from the local host to the Android device.
Definition: adbncfs.cpp:528
static MountInfo * pMountInfo
Pointer to mount info instance initialized in queryMountInfo()
Definition: adbncfs.cpp:90
int adbnc_rename(const char *pcFrom, const char *pcTo)
Definition: adbncfs.cpp:1725
int release(const char *pcPath, const int iFh)
A class to manage informations obtained from the output of the busybox applet id command.
Definition: userInfo.h:37
int adbnc_flush(const char *pcPath, struct fuse_file_info *pFi)
FUSE callback function called on each close so that the file system has a chance to report delayed er...
Definition: adbncfs.cpp:1541
static UserInfo * pUserInfo
Pointer to user info instance initialized in queryUserInfo()
Definition: adbncfs.cpp:87
int adbnc_mknod(const char *pcPath, mode_t mode, dev_t rdev)
Definition: adbncfs.cpp:1687
const deque< string > * getStat(const char *pcPath) const
static const char * pcDone
Definition: adbncfs.cpp:53
static int queryUserInfo()
Query user information (uid, gid, groups) form android device.
Definition: adbncfs.cpp:845
int flush(const char *pcPath, const string &strFromLocalPath)
int adbnc_opendir(const char *pcPath, struct fuse_file_info *pFi)
FUSE callback to open a directory for reading.
Definition: adbncfs.cpp:1263
static int adbncPull(const string &strRemoteSource, const string &strLocalDestination)
Copy (using adb pull) a file from the Android device to the local host.
Definition: adbncfs.cpp:512
void truncated(const char *pcPath, const bool fTruncated)
static int makeTempDir(void)
Create a temporary directory and stores the path in strTempDirPath variable.
Definition: adbncfs.cpp:819