bfuse.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       bfuse.cc
00003 ///             FUSE filesystem for Blackberry databases, using Barry.
00004 ///
00005 
00006 /*
00007     Copyright (C) 2008-2009, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #define FUSE_USE_VERSION 25
00023 #include <fuse.h>
00024 #include <fuse_opt.h>
00025 
00026 #include <barry/barry.h>
00027 #include <sstream>
00028 #include <getopt.h>
00029 #include <vector>
00030 #include <list>
00031 #include <string>
00032 #include <stdexcept>
00033 #include <memory>
00034 #include <tr1/memory>
00035 #include <errno.h>
00036 #include <sys/types.h>
00037 #include <fcntl.h>
00038 #include <string.h>
00039 
00040 using namespace std;
00041 using namespace std::tr1;
00042 using namespace Barry;
00043 
00044 // Global filenames
00045 const char *error_log_filename = "error.log";
00046 
00047 // Global command line args
00048 string cmdline_pin;
00049 string cmdline_password;
00050 
00051 //
00052 // Data from the command line
00053 //
00054 
00055 /////////////////////////////////////////////////////////////////////////////
00056 // Command line option handling, through fuse
00057 
00058 //struct opt {
00059 //      char
00060 //};
00061 
00062 void Blurb()
00063 {
00064    int major, minor;
00065    const char *Version = Barry::Version(major, minor);
00066 
00067    cerr
00068    << "bfuse - FUSE filesystem for Blackberry databases\n"
00069    << "        Copyright 2008-2009, Net Direct Inc. (http://www.netdirect.ca/)\n"
00070    << "        Using: " << Version << "\n"
00071    << endl;
00072 }
00073 
00074 void Usage()
00075 {
00076    cerr
00077    << "\n"
00078    << "Barry specific options:\n"
00079    << "   -p pin    PIN of device to talk with\n"
00080    << "             If only one device is plugged in, this flag is optional\n"
00081    << "   -P pass   Simplistic method to specify device password\n"
00082    << endl;
00083 /*
00084    << "   -d db     Specify which database to mount.  If no -d options exist\n"
00085    << "             then all databases will be mounted.\n"
00086    << "             Can be used multiple times to mount more than one DB\n"
00087    << "   -h        This help\n"
00088    << "   -n        Use null parser on all databases.\n"
00089 */
00090 }
00091 
00092 /////////////////////////////////////////////////////////////////////////////
00093 // FUSE specific exception
00094 
00095 class fuse_error : public std::runtime_error
00096 {
00097         int m_errno;
00098 public:
00099         fuse_error(int errno_, const std::string &msg)
00100                 : std::runtime_error(msg), m_errno(errno_)
00101         {}
00102 
00103         int get_errno() const { return m_errno; }
00104 };
00105 
00106 
00107 /////////////////////////////////////////////////////////////////////////////
00108 // Barry record parsers
00109 
00110 class DataDumpParser : public Barry::Parser
00111 {
00112         uint32_t m_id;
00113         std::ostream &m_os;
00114 
00115 public:
00116         explicit DataDumpParser(std::ostream &os)
00117                 : m_os(os)
00118         {
00119         }
00120 
00121         virtual void Clear() {}
00122 
00123         virtual void SetIds(uint8_t RecType, uint32_t UniqueId)
00124         {
00125                 m_id = UniqueId;
00126         }
00127 
00128         virtual void ParseHeader(const Barry::Data &, size_t &) {}
00129 
00130         virtual void ParseFields(const Barry::Data &data, size_t &offset,
00131                                 const Barry::IConverter *ic)
00132         {
00133                 m_os << "Raw record dump for record: "
00134                         << std::hex << m_id << std::endl;
00135                 m_os << data << std::endl;
00136         }
00137 
00138         virtual void Store() {}
00139 };
00140 
00141 template <class Record>
00142 struct Store
00143 {
00144         std::ostream &m_os;
00145 
00146         explicit Store(std::ostream &os)
00147                 : m_os(os)
00148         {
00149         }
00150 
00151         // storage operator
00152         void operator()(const Record &rec)
00153         {
00154                 m_os << rec;
00155         }
00156 };
00157 
00158 typedef std::auto_ptr<Barry::Parser>            ParserPtr;
00159 
00160 ParserPtr GetParser(const string &name, std::ostream &os, bool null_parser)
00161 {
00162         if( null_parser ) {
00163                 // use null parser
00164                 return ParserPtr( new DataDumpParser(os) );
00165         }
00166         // check for recognized database names
00167         else if( name == Contact::GetDBName() ) {
00168                 return ParserPtr(
00169                         new RecordParser<Contact, Store<Contact> > (
00170                                 new Store<Contact>(os)));
00171         }
00172         else if( name == Message::GetDBName() ) {
00173                 return ParserPtr(
00174                         new RecordParser<Message, Store<Message> > (
00175                                 new Store<Message>(os)));
00176         }
00177         else if( name == Calendar::GetDBName() ) {
00178                 return ParserPtr(
00179                         new RecordParser<Calendar, Store<Calendar> > (
00180                                 new Store<Calendar>(os)));
00181         }
00182         else if( name == ServiceBook::GetDBName() ) {
00183                 return ParserPtr(
00184                         new RecordParser<ServiceBook, Store<ServiceBook> > (
00185                                 new Store<ServiceBook>(os)));
00186         }
00187 
00188         else if( name == Memo::GetDBName() ) {
00189                 return ParserPtr(
00190                         new RecordParser<Memo, Store<Memo> > (
00191                                 new Store<Memo>(os)));
00192         }
00193         else if( name == Task::GetDBName() ) {
00194                 return ParserPtr(
00195                         new RecordParser<Task, Store<Task> > (
00196                                 new Store<Task>(os)));
00197         }
00198         else if( name == PINMessage::GetDBName() ) {
00199                 return ParserPtr(
00200                         new RecordParser<PINMessage, Store<PINMessage> > (
00201                                 new Store<PINMessage>(os)));
00202         }
00203         else if( name == SavedMessage::GetDBName() ) {
00204                 return ParserPtr(
00205                         new RecordParser<SavedMessage, Store<SavedMessage> > (
00206                                 new Store<SavedMessage>(os)));
00207         }
00208         else if( name == Folder::GetDBName() ) {
00209                 return ParserPtr(
00210                         new RecordParser<Folder, Store<Folder> > (
00211                                 new Store<Folder>(os)));
00212         }
00213         else if( name == Timezone::GetDBName() ) {
00214                 return ParserPtr(
00215                         new RecordParser<Timezone, Store<Timezone> > (
00216                                 new Store<Timezone>(os)));
00217         }
00218         else {
00219                 // unknown database, use null parser
00220                 return ParserPtr( new DataDumpParser(os) );
00221         }
00222 }
00223 
00224 /////////////////////////////////////////////////////////////////////////////
00225 // PathSplit class
00226 
00227 class PathSplit
00228 {
00229         std::string m_pin, m_db, m_record, m_field, m_remainder;
00230 
00231         int m_level;            // the number of slashes, minus the first
00232                                 // i.e. first level is 0
00233         bool m_is_root;
00234 
00235 public:
00236         explicit PathSplit(const char *path)
00237                 : m_level(-1)
00238                 , m_is_root(false)
00239         {
00240                 if( *path != '/' )
00241                         return;         // return in a failed state
00242 
00243                 if( *(path+1) == 0 ) {
00244                         m_is_root = true;
00245                         return;
00246                 }
00247 
00248                 const char *s = path, *e = path;
00249                 while( *e ) {
00250                         while( *e && *e != '/' )
00251                                 e++;
00252 
00253                         m_level++;
00254 
00255                         if( s != e && (s+1) != e ) {
00256                                 string token(s+1, e);
00257 
00258                                 switch( m_level )
00259                                 {
00260                                 case 0: // root level, should not have token here
00261                                         m_level = -1;
00262                                         return; // failed state
00263 
00264                                 case 1: // have pin
00265                                         m_pin = token;
00266                                         break;
00267 
00268                                 case 2: // have db
00269                                         m_db = token;
00270                                         break;
00271 
00272                                 case 3: // have record
00273                                         m_record = token;
00274                                         break;
00275 
00276                                 case 4: // have field
00277                                         m_field = token;
00278                                         break;
00279 
00280                                 default:        // too many, store remainder and done
00281                                         m_remainder = s;        // keeps slash
00282                                         return;
00283                                 }
00284 
00285                                 // next
00286                                 s = e;
00287                                 if( *e )
00288                                         e++;
00289                         }
00290                         else if( *e ) {
00291                                 // next
00292                                 e++;
00293                         }
00294                 }
00295         }
00296 
00297         bool IsRoot() const { return m_is_root; }
00298         const std::string& Pin() const { return m_pin; }
00299         const std::string& DB() const { return m_db; }
00300         const std::string& Record() const { return m_record; }
00301         const std::string& Field() const { return m_field; }
00302         const std::string& Remainder() const { return m_remainder; }
00303         int Level() const { return m_level; }
00304 };
00305 
00306 
00307 /////////////////////////////////////////////////////////////////////////////
00308 // API classes
00309 
00310 class Entry
00311 {
00312 public:
00313         virtual ~Entry() {}
00314 };
00315 
00316 class Directory : public Entry
00317 {
00318 public:
00319         virtual int ReadDir(void *buf, fuse_fill_dir_t filler) = 0;
00320         virtual void FillDirStat(struct stat *st)
00321         {
00322                 st->st_mode = S_IFDIR | 0555;
00323                 st->st_nlink = 2;
00324         }
00325 };
00326 
00327 class File : public Entry
00328 {
00329 public:
00330         virtual void FillFileStat(const char *path, struct stat *st) = 0;
00331         virtual bool AccessOk(int flags)
00332         {
00333                 // default to readonly files
00334                 return (flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDONLY;
00335         }
00336         virtual int ReadFile(const char *path, char *buf, size_t size, off_t offset) = 0;
00337 };
00338 
00339 typedef Directory*                              DirectoryPtr;
00340 typedef File*                                   FilePtr;
00341 typedef std::string                             NameT;
00342 typedef std::map<NameT, DirectoryPtr>           DirMap;
00343 typedef std::map<NameT, FilePtr>                FileMap;
00344 
00345 static DirMap g_dirmap;
00346 static FileMap g_filemap;
00347 
00348 static Directory* FindDir(const NameT &name)
00349 {
00350         DirMap::iterator di = g_dirmap.find(name);
00351         return di == g_dirmap.end() ? 0 : di->second;
00352 }
00353 
00354 static File* FindFile(const NameT &name)
00355 {
00356         FileMap::iterator fi = g_filemap.find(name);
00357         return fi == g_filemap.end() ? 0 : fi->second;
00358 }
00359 
00360 /////////////////////////////////////////////////////////////////////////////
00361 // Context classes
00362 
00363 class Database : public Directory, public File
00364 {
00365 public:
00366         Barry::Mode::Desktop &m_desk;
00367         std::string m_name;
00368         const Barry::DatabaseItem *m_pdb;
00369 
00370 public:
00371         Database(Barry::Mode::Desktop &desktop,
00372                 const std::string &pin, const Barry::DatabaseItem *pdb)
00373                 : m_desk(desktop)
00374                 , m_pdb(pdb)
00375         {
00376                 m_name = string("/") + pin + "/" + m_pdb->Name;
00377 
00378                 // add to directory list
00379                 g_dirmap[ m_name ] = this;
00380         }
00381 
00382         ~Database()
00383         {
00384                 // remove any entries that point to us
00385                 FileMap::iterator b = g_filemap.begin(), e = g_filemap.end();
00386                 for( ; b != e; ++b ) {
00387                         if( b->second == this ) {
00388                                 g_filemap.erase(b);
00389                         }
00390                 }
00391 
00392                 // erase ourselves from the directory list
00393                 g_dirmap.erase( m_name );
00394         }
00395 
00396         void AddFile(const std::string &recordId)
00397         {
00398                 // FIXME - this is a hack to redirect all record files
00399                 // to this database class... next step is to possibly
00400                 // split out records into field files if we have a
00401                 // parser, or just dump the hex if we don't
00402                 string name = m_name + "/" + recordId;
00403                 g_filemap[ name ] = this;
00404         }
00405 
00406         virtual int ReadDir(void *buf, fuse_fill_dir_t filler)
00407         {
00408                 filler(buf, ".", NULL, 0);
00409                 filler(buf, "..", NULL, 0);
00410 
00411                 // list all records in database, by recordId
00412                 Barry::RecordStateTable rst;
00413                 m_desk.GetRecordStateTable(m_pdb->Number, rst);
00414 
00415                 Barry::RecordStateTable::StateMapType::iterator
00416                         b = rst.StateMap.begin(),
00417                         e = rst.StateMap.end();
00418                 for( ; b != e; ++ b ) {
00419                         ostringstream oss;
00420                         oss << hex << b->second.RecordId;
00421                         filler(buf, oss.str().c_str(), NULL, 0);
00422 
00423                         AddFile(oss.str());
00424                 }
00425                 return 0;
00426         }
00427 
00428         virtual void FillFileStat(const char *path, struct stat *st)
00429         {
00430                 // use the path to find the proper record
00431                 PathSplit ps(path);
00432 
00433                 string constructed = string("/") + ps.Pin() + "/" + ps.DB();
00434                 if( constructed != m_name ) {
00435                         // FIXME - this is shoddy error handling
00436                         throw std::logic_error("Constructed != name");
00437                 }
00438 
00439                 string data = GetRecordData(ps.Record());
00440 
00441                 st->st_mode = S_IFREG | 0444;
00442                 st->st_nlink = 1;
00443                 st->st_size = data.size();
00444         }
00445 
00446         virtual int ReadFile(const char *path, char *buf, size_t size, off_t offset)
00447         {
00448                 // use the path to find the proper record
00449                 PathSplit ps(path);
00450 
00451                 string constructed = string("/") + ps.Pin() + "/" + ps.DB();
00452                 if( constructed != m_name ) {
00453                         // FIXME - this is shoddy error handling
00454                         throw std::logic_error("Constructed != name");
00455                 }
00456 
00457                 string data = GetRecordData(ps.Record());
00458 
00459                 size_t len = data.size();
00460                 if( offset < len ) {
00461                         if( (offset + size) > len )
00462                                 size = len - offset;
00463                         memcpy(buf, data.data() + offset, size);
00464                 }
00465                 else {
00466                         size = 0;
00467                 }
00468                 return size;
00469         }
00470 
00471         const std::string& GetDBName() const { return m_pdb->Name; }
00472 
00473         std::string GetRecordData(const std::string &recordId)
00474         {
00475                 string data;
00476 
00477                 Barry::RecordStateTable rst;
00478                 m_desk.GetRecordStateTable(m_pdb->Number, rst);
00479 
00480                 uint32_t recid = strtoul(recordId.c_str(), NULL, 16);
00481                 RecordStateTable::IndexType index;
00482                 if( rst.GetIndex(recid, &index) ) {
00483                         ostringstream oss;
00484                         ParserPtr parser = GetParser(m_pdb->Name, oss, false);
00485                         m_desk.GetRecord(m_pdb->Number, index, *parser);
00486                         data = oss.str();
00487                 }
00488 
00489                 return data;
00490         }
00491 };
00492 
00493 class DesktopCon : public Directory
00494 {
00495 public:
00496         typedef std::tr1::shared_ptr<Database>                  DatabasePtr;
00497         typedef std::list<DatabasePtr>                          DBList;
00498 public:
00499         Barry::Controller m_con;
00500         Barry::Mode::Desktop m_desk;
00501         std::string m_pin;
00502         DBList m_dblist;
00503 
00504         DesktopCon(const Barry::ProbeResult &result, const std::string &pin)
00505                 : m_con(result)
00506                 , m_desk(m_con)
00507                 , m_pin(pin)
00508         {
00509                 // add to directory list
00510                 g_dirmap[ string("/") + pin ] = this;
00511         }
00512 
00513         ~DesktopCon()
00514         {
00515                 // remove from directory list
00516                 g_dirmap.erase( string("/") + m_pin );
00517         }
00518 
00519         virtual int ReadDir(void *buf, fuse_fill_dir_t filler)
00520         {
00521                 filler(buf, ".", NULL, 0);
00522                 filler(buf, "..", NULL, 0);
00523 
00524                 // list all databases in list
00525                 DBList::const_iterator b = m_dblist.begin(), e = m_dblist.end();
00526                 for( ; b != e; ++ b ) {
00527                         filler(buf, (*b)->GetDBName().c_str(), NULL, 0);
00528                 }
00529                 return 0;
00530         }
00531 
00532         void Open(const char *password = 0)
00533         {
00534                 // open our device
00535                 m_desk.Open(password);
00536 
00537                 // add all databases as directories
00538                 DatabaseDatabase::DatabaseArrayType::const_iterator
00539                         dbi = m_desk.GetDBDB().Databases.begin(),
00540                         dbe = m_desk.GetDBDB().Databases.end();
00541                 for( ; dbi != dbe; ++dbi ) {
00542                         DatabasePtr db = DatabasePtr(
00543                                 new Database(m_desk, m_pin, &(*dbi)) );
00544                         m_dblist.push_back(db);
00545                 }
00546         }
00547 };
00548 
00549 class Context : public Directory, public File
00550 {
00551 public:
00552         typedef std::auto_ptr<Barry::Probe>                     ProbePtr;
00553         typedef std::tr1::shared_ptr<DesktopCon>                DesktopConPtr;
00554         typedef std::string                                     PinT;
00555         typedef std::map<PinT, DesktopConPtr>                   PinMap;
00556 
00557         ProbePtr m_probe;
00558         PinMap m_pinmap;
00559 
00560         string m_error_log;
00561 
00562         string m_limit_pin;             // only mount device with this pin
00563         string m_password;              // use this password when connecting
00564 
00565 public:
00566         Context(const string &limit_pin = "", const string &password = "")
00567                 : m_limit_pin(limit_pin)
00568                 , m_password(password)
00569         {
00570                 g_dirmap["/"] = this;
00571                 g_filemap[string("/") + error_log_filename] = this;
00572 
00573                 m_error_log = "Hello FUSE world.  This is Barry.  Pleased to meet you.\n";
00574         }
00575 
00576         ~Context()
00577         {
00578                 g_dirmap.erase("/");
00579                 g_filemap.erase(string("/") + error_log_filename);
00580         }
00581 
00582         virtual int ReadDir(void *buf, fuse_fill_dir_t filler)
00583         {
00584                 filler(buf, ".", NULL, 0);
00585                 filler(buf, "..", NULL, 0);
00586                 filler(buf, error_log_filename, NULL, 0);
00587 
00588                 // list all pins in map
00589                 PinMap::const_iterator b = m_pinmap.begin(), e = m_pinmap.end();
00590                 for( ; b != e; ++ b ) {
00591                         filler(buf, b->first.c_str(), NULL, 0);
00592                 }
00593                 return 0;
00594         }
00595 
00596         virtual void FillFileStat(const char *path, struct stat *st)
00597         {
00598                 st->st_mode = S_IFREG | 0444;
00599                 st->st_nlink = 1;
00600                 st->st_size = m_error_log.size();
00601         }
00602 
00603         virtual int ReadFile(const char *path, char *buf, size_t size, off_t offset)
00604         {
00605                 size_t len = m_error_log.size();
00606                 if( offset < len ) {
00607                         if( (offset + size) > len )
00608                                 size = len - offset;
00609                         memcpy(buf, m_error_log.data() + offset, size);
00610                 }
00611                 else {
00612                         size = 0;
00613                 }
00614                 return size;
00615         }
00616 
00617         void Log(const std::string &msg)
00618         {
00619                 m_error_log += msg;
00620                 m_error_log += "\n";
00621         }
00622 
00623         const std::string& GetLog() const { return m_error_log; }
00624 
00625         void ProbeAll()
00626         {
00627                 // probe the USB bus for Blackberry devices
00628                 m_probe.reset( new Probe );
00629 
00630                 // connect to all PINs found, and add them to our map
00631                 for( int i = 0; i < m_probe->GetCount(); i++ ) {
00632                         ostringstream oss;
00633                         oss << hex << m_probe->Get(i).m_pin;
00634 
00635                         // don't add a blank or pre-existing pin
00636                         if( !oss.str().size() || m_pinmap.find(oss.str()) != m_pinmap.end() ) {
00637                                 continue;
00638                         }
00639 
00640                         // don't add non-PIN device if pin specified
00641                         if( m_limit_pin.size() && oss.str() != m_limit_pin ) {
00642                                 continue;
00643                         }
00644 
00645                         DesktopConPtr dev = DesktopConPtr (
00646                                 new DesktopCon(m_probe->Get(i), oss.str()) );
00647                         dev->Open(m_password.c_str());
00648                         m_pinmap[ oss.str() ] = dev;
00649                 }
00650         }
00651 
00652         DesktopCon* FindPin(PinT pin)
00653         {
00654                 PinMap::iterator pi = m_pinmap.find(pin);
00655                 return pi == m_pinmap.end() ? 0 : pi->second.get();
00656         }
00657 };
00658 
00659 
00660 /////////////////////////////////////////////////////////////////////////////
00661 // FUSE API hooks
00662 
00663 static void* bfuse_init()
00664 {
00665         // Initialize the barry library.  Must be called before
00666         // anything else.
00667         Barry::Init(false);
00668 
00669         Context *ctx = 0;
00670 
00671         try {
00672                 ctx = new Context(cmdline_pin, cmdline_password);
00673                 ctx->ProbeAll();
00674         }
00675         catch( std::exception &e ) {
00676                 if( ctx ) {
00677                         ctx->Log(e.what());
00678                 }
00679         }
00680 
00681         return ctx;
00682 }
00683 
00684 static void bfuse_destroy(void *data)
00685 {
00686         if( data ) {
00687                 Context *ctx = (Context*) data;
00688                 delete ctx;
00689         }
00690 }
00691 
00692 static int bfuse_getattr(const char *path, struct stat *st)
00693 {
00694         memset(st, 0, sizeof(*st));
00695 
00696         if( Directory *dir = FindDir(path) ) {
00697                 dir->FillDirStat(st);
00698                 return 0;
00699         }
00700         else if( File *file = FindFile(path) ) {
00701                 file->FillFileStat(path, st);
00702                 return 0;
00703         }
00704         else
00705                 return -ENOENT;
00706 }
00707 
00708 static int bfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
00709                          off_t /*offset*/, struct fuse_file_info * /*fi*/)
00710 {
00711         Directory *dir = FindDir(path);
00712         if( !dir )
00713                 return -ENOENT;
00714         return dir->ReadDir(buf, filler);
00715 }
00716 
00717 static int bfuse_open(const char *path, struct fuse_file_info *fi)
00718 {
00719         File *file = FindFile(path);
00720         if( !file )
00721                 return -ENOENT;
00722 
00723         if( !file->AccessOk(fi->flags) )
00724                 return -EACCES;
00725 
00726         return 0;
00727 }
00728 
00729 static int bfuse_read(const char *path, char *buf, size_t size, off_t offset,
00730                       struct fuse_file_info *fi)
00731 {
00732         File *file = FindFile(path);
00733         if( !file )
00734                 return -ENOENT;
00735 
00736         return file->ReadFile(path, buf, size, offset);
00737 }
00738 
00739 // static struct here automatically zeros data
00740 static struct fuse_operations bfuse_oper;
00741 
00742 
00743 /////////////////////////////////////////////////////////////////////////////
00744 // main
00745 
00746 int main(int argc, char *argv[])
00747 {
00748         cout.sync_with_stdio(true);     // leave this on, since libusb uses
00749                                         // stdio for debug messages
00750 
00751         Blurb();
00752 
00753         // initialize the operation hooks
00754         bfuse_oper.init         = bfuse_init;
00755         bfuse_oper.destroy      = bfuse_destroy;
00756         bfuse_oper.getattr      = bfuse_getattr;
00757         bfuse_oper.readdir      = bfuse_readdir;
00758         bfuse_oper.open         = bfuse_open;
00759         bfuse_oper.read         = bfuse_read;
00760 
00761         // process command line options before FUSE does
00762         // FUSE does its own command line processing, and
00763         // doesn't seem to have a way to plug into it,
00764         // so do our own first
00765         int fuse_argc = 0;
00766         char **fuse_argv = new char*[argc];
00767 
00768         for( int i = 0; i < argc; i++ ) {
00769                 if( argv[i][0] == '-' ) {
00770 
00771                         switch( argv[i][1] )
00772                         {
00773 //                      case 'd':       // mount dbname
00774 //                              dbNames.push_back(string(optarg));
00775 //                              break;
00776 
00777 //                      case 'n':       // use null parser
00778 //                              null_parser = true;
00779 //                              break;
00780 
00781                         case 'p':       // Blackberry PIN
00782                                 if( i+1 < argc ) {
00783                                         cmdline_pin = argv[++i];
00784                                 }
00785                                 continue;
00786 
00787                         case 'P':       // Device password
00788                                 if( i+1 < argc ) {
00789                                         cmdline_password = argv[++i];
00790                                 }
00791                                 continue;
00792 
00793                         case 'h':       // help
00794                                 Usage();
00795                                 break;
00796                         }
00797                 }
00798 
00799                 // if we get here, add this option to FUSE's
00800                 fuse_argv[fuse_argc] = argv[i];
00801                 fuse_argc++;
00802         }
00803 
00804         int ret = fuse_main(fuse_argc, fuse_argv, &bfuse_oper);
00805         delete [] fuse_argv;
00806         return ret;
00807 }
00808 

Generated on Sat Aug 29 00:01:52 2009 for Barry by  doxygen 1.5.6