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