dafuse.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include <platform.h>
  14. #include "jlib.hpp"
  15. #include "jiface.hpp"
  16. #include "jlog.hpp"
  17. #include "jprop.hpp"
  18. #include "jfile.hpp"
  19. #include "jlzw.hpp"
  20. #include "jexcept.hpp"
  21. #include "jmutex.hpp"
  22. #include "jthread.hpp"
  23. #include "rmtfile.hpp"
  24. #include "daclient.hpp"
  25. #include "dautils.hpp"
  26. #include "dadfs.hpp"
  27. #include "dasds.hpp"
  28. #include "mplog.hpp"
  29. #define FUSE_USE_VERSION 26
  30. #include <fuse.h>
  31. #define FUSE_UNIMPLEMENTED(f) assertex(!"Unimplemented function: " f);
  32. #define FUSE_USE(f) ops.f = __##f;
  33. #define MAXPARAM 256
  34. class CFuseBase // base NB singleton
  35. {
  36. static CriticalSection crit;
  37. static CFuseBase *self;
  38. protected:
  39. static int __getattr(const char *path, struct stat *stbuf)
  40. {
  41. CriticalBlock block(crit);
  42. return self->fuse_getattr(path,stbuf);
  43. }
  44. static int __readlink (const char *path, char *out, size_t sz)
  45. {
  46. CriticalBlock block(crit);
  47. return self->fuse_readlink(path,out,sz);
  48. }
  49. static int __mkdir (const char *path, mode_t mode)
  50. {
  51. CriticalBlock block(crit);
  52. return self->fuse_mkdir(path,mode);
  53. }
  54. static int __unlink (const char *path)
  55. {
  56. CriticalBlock block(crit);
  57. return self->fuse_unlink(path);
  58. }
  59. static int __rmdir (const char *path)
  60. {
  61. CriticalBlock block(crit);
  62. return self->fuse_rmdir(path);
  63. }
  64. static int __rename (const char *from, const char *to)
  65. {
  66. CriticalBlock block(crit);
  67. return self->fuse_rename(from,to);
  68. }
  69. static int __truncate (const char *path, off_t pos)
  70. {
  71. CriticalBlock block(crit);
  72. return self->fuse_truncate(path,pos);
  73. }
  74. static int __open (const char *path, struct fuse_file_info *info)
  75. {
  76. CriticalBlock block(crit);
  77. return self->fuse_open(path,info);
  78. }
  79. static int __read (const char *path, char *dst, size_t sz, off_t pos, struct fuse_file_info *info)
  80. {
  81. CriticalBlock block(crit);
  82. return self->fuse_read(path,dst,sz,pos,info);
  83. }
  84. static int __write (const char *path, const char *src, size_t sz, off_t pos, struct fuse_file_info *info)
  85. {
  86. CriticalBlock block(crit);
  87. return self->fuse_write(path,src,sz,pos,info);
  88. }
  89. static int __statfs (const char *path, struct statvfs *stbuf)
  90. {
  91. CriticalBlock block(crit);
  92. return self->fuse_statfs(path,stbuf);
  93. }
  94. static int __flush (const char *path, struct fuse_file_info *info)
  95. {
  96. CriticalBlock block(crit);
  97. return self->fuse_flush(path,info);
  98. }
  99. static int __release (const char *path, struct fuse_file_info *info)
  100. {
  101. CriticalBlock block(crit);
  102. return self->fuse_release(path,info);
  103. }
  104. static int __fsync (const char *path, int m, struct fuse_file_info *info)
  105. {
  106. CriticalBlock block(crit);
  107. return self->fuse_fsync(path,m,info);
  108. }
  109. static int __opendir (const char *path, struct fuse_file_info *info)
  110. {
  111. CriticalBlock block(crit);
  112. return self->fuse_opendir(path,info);
  113. }
  114. static int __readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t pos, struct fuse_file_info *info)
  115. {
  116. CriticalBlock block(crit);
  117. return self->fuse_readdir(path,buf,filler,pos,info);
  118. }
  119. static int __releasedir (const char *path, struct fuse_file_info *info)
  120. {
  121. CriticalBlock block(crit);
  122. return self->fuse_releasedir(path,info);
  123. }
  124. static void *__init (struct fuse_conn_info *conn)
  125. {
  126. CriticalBlock block(crit);
  127. return self->fuse_init(conn);
  128. }
  129. static void __destroy (void *p)
  130. {
  131. CriticalBlock block(crit);
  132. self->fuse_destroy(p);
  133. }
  134. static int __access (const char *path, int m)
  135. {
  136. CriticalBlock block(crit);
  137. return self->fuse_access(path,m);
  138. }
  139. static int __create (const char *path, mode_t mode, struct fuse_file_info *info)
  140. {
  141. CriticalBlock block(crit);
  142. return self->fuse_create(path,mode,info);
  143. }
  144. static int __ftruncate (const char *path, off_t pos, struct fuse_file_info *info)
  145. {
  146. CriticalBlock block(crit);
  147. return self->fuse_ftruncate(path,pos,info);
  148. }
  149. static int __fgetattr (const char *path, struct stat *stbuf, struct fuse_file_info *info)
  150. {
  151. CriticalBlock block(crit);
  152. return self->fuse_fgetattr(path,stbuf,info);
  153. }
  154. static int __utimens (const char *path, const struct timespec tv[2])
  155. {
  156. CriticalBlock block(crit);
  157. return self->fuse_utimens(path,tv);
  158. }
  159. fuse_operations ops;
  160. public:
  161. CFuseBase()
  162. {
  163. assertex(!self); // can only be one
  164. self = this;
  165. memset(&ops,0,sizeof(ops));
  166. ops.getattr = __getattr;
  167. ops.readdir = __readdir;
  168. ops.open = __open;
  169. }
  170. ~CFuseBase()
  171. {
  172. assertex(self); // can only be one
  173. self = NULL;
  174. }
  175. int main(int argc, char *argv[])
  176. {
  177. #ifdef _WIN32
  178. fprintf(stderr,"FUSE not supported on Windows\n");
  179. return 0;
  180. #else
  181. return fuse_main(argc, argv, &ops, NULL);
  182. #endif
  183. }
  184. // required
  185. virtual int fuse_getattr(const char *path, struct stat *stbuf) = 0;
  186. virtual int fuse_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t pos, struct fuse_file_info *info) = 0;
  187. virtual int fuse_open (const char *path, struct fuse_file_info *info) = 0;
  188. // optional
  189. virtual int fuse_readlink (const char *path, char *out, size_t sz)
  190. {
  191. FUSE_UNIMPLEMENTED("fuse_readlink");
  192. return -1;
  193. }
  194. virtual int fuse_mkdir (const char *path, mode_t mode)
  195. {
  196. FUSE_UNIMPLEMENTED("fuse_mkdir");
  197. return -1;
  198. }
  199. virtual int fuse_unlink (const char *path)
  200. {
  201. FUSE_UNIMPLEMENTED("fuse_unlink");
  202. return -1;
  203. }
  204. virtual int fuse_rmdir (const char *path)
  205. {
  206. FUSE_UNIMPLEMENTED("fuse_rmdir");
  207. return -1;
  208. }
  209. virtual int fuse_rename (const char *from, const char *to)
  210. {
  211. FUSE_UNIMPLEMENTED("fuse_rename");
  212. return -1;
  213. }
  214. virtual int fuse_truncate (const char *path, off_t pos)
  215. {
  216. FUSE_UNIMPLEMENTED("fuse_truncate");
  217. return -1;
  218. }
  219. virtual int fuse_read (const char *path, char *dst, size_t sz, off_t pos, struct fuse_file_info *info)
  220. {
  221. FUSE_UNIMPLEMENTED("fuse_read");
  222. return -1;
  223. }
  224. virtual int fuse_write (const char *path, const char *src, size_t sz, off_t pos, struct fuse_file_info *info)
  225. {
  226. FUSE_UNIMPLEMENTED("fuse_write");
  227. return -1;
  228. }
  229. virtual int fuse_statfs (const char *path, struct statvfs *s)
  230. {
  231. FUSE_UNIMPLEMENTED("fuse_statfs");
  232. return -1;
  233. }
  234. virtual int fuse_flush (const char *path, struct fuse_file_info *info)
  235. {
  236. FUSE_UNIMPLEMENTED("fuse_flush");
  237. return -1;
  238. }
  239. virtual int fuse_release (const char *path, struct fuse_file_info *info)
  240. {
  241. FUSE_UNIMPLEMENTED("fuse_release");
  242. return -1;
  243. }
  244. virtual int fuse_fsync (const char *path, int m, struct fuse_file_info *info)
  245. {
  246. FUSE_UNIMPLEMENTED("fuse_fsync");
  247. return -1;
  248. }
  249. virtual int fuse_opendir (const char *path, struct fuse_file_info *info)
  250. {
  251. FUSE_UNIMPLEMENTED("fuse_opendir");
  252. return -1;
  253. }
  254. virtual int fuse_releasedir (const char *path, struct fuse_file_info *info)
  255. {
  256. FUSE_UNIMPLEMENTED("fuse_releasedir");
  257. return -1;
  258. }
  259. virtual void *fuse_init (struct fuse_conn_info *conn)
  260. {
  261. FUSE_UNIMPLEMENTED("fuse_init");
  262. return NULL;
  263. }
  264. virtual void fuse_destroy (void *p)
  265. {
  266. FUSE_UNIMPLEMENTED("fuse_destroy");
  267. }
  268. virtual int fuse_access (const char *path, int m)
  269. {
  270. FUSE_UNIMPLEMENTED("fuse_access");
  271. return -1;
  272. }
  273. virtual int fuse_create (const char *path, mode_t mode, struct fuse_file_info *info)
  274. {
  275. FUSE_UNIMPLEMENTED("fuse_create");
  276. return -1;
  277. }
  278. virtual int fuse_ftruncate (const char *path, off_t pos, struct fuse_file_info *info)
  279. {
  280. FUSE_UNIMPLEMENTED("fuse_ftruncate");
  281. return -1;
  282. }
  283. virtual int fuse_fgetattr (const char *path, struct stat *s, struct fuse_file_info *info)
  284. {
  285. FUSE_UNIMPLEMENTED("fuse_fgetattr");
  286. return -1;
  287. }
  288. virtual int fuse_utimens (const char *path, const struct timespec tv[2])
  289. {
  290. FUSE_UNIMPLEMENTED("fuse_utimens");
  291. return -1;
  292. }
  293. };
  294. CriticalSection CFuseBase::crit;
  295. CFuseBase *CFuseBase::self=NULL;
  296. #define FH_SALT 100
  297. #define DIRCACHE_MAX 100 // TBD configurable
  298. #define DIRCACHE_TIMEOUT 1 // min
  299. class CDirCacheItem: public CInterface
  300. {
  301. int err;
  302. public:
  303. CDateTime dt;
  304. StringAttr path;
  305. StringArray scopes;
  306. StringArray supers;
  307. StringArray files;
  308. bool donefiles;
  309. CDirCacheItem()
  310. {
  311. donefiles = false;
  312. err = -ENOENT;
  313. }
  314. int init(const char *caller,const char *_path, bool allscopes,bool allfiles)
  315. {
  316. if (_path==NULL)
  317. path.set("");
  318. else
  319. path.set(_path);
  320. err = 0;
  321. try {
  322. if (!queryDistributedFileDirectory().loadScopeContents(_path,allscopes?&scopes:NULL,allfiles?&supers:NULL,allfiles?&files:NULL,true))
  323. err = -ENOENT;
  324. else
  325. if (allfiles)
  326. donefiles = true;
  327. }
  328. catch (IException *e) {
  329. EXCLOG(e,caller);
  330. err = -EFAULT;
  331. }
  332. return err;
  333. }
  334. const char *get(unsigned idx,bool &isscope)
  335. {
  336. if (idx<scopes.ordinality()) {
  337. isscope = true;
  338. return scopes.item(idx);
  339. }
  340. idx -= scopes.ordinality();
  341. isscope = false;
  342. if (idx<supers.ordinality())
  343. return supers.item(idx);
  344. idx -= supers.ordinality();
  345. if (idx<files.ordinality())
  346. return files.item(idx);
  347. return NULL;
  348. }
  349. };
  350. class CFuseDaliDFS: public CFuseBase
  351. {
  352. IUserDescriptor *user;
  353. StringAttr daliServer;
  354. PointerArray openfiles;
  355. CIArrayOf<CDirCacheItem> dircache;
  356. bool checkUser()
  357. {
  358. fuse_context *context = fuse_get_context();
  359. }
  360. class DaFuseCmdThread: public Thread
  361. {
  362. public:
  363. DaFuseCmdThread()
  364. : Thread("DaFuseCmdThread")
  365. {
  366. }
  367. } *DaFuseCmdThread;
  368. CDirCacheItem *findDirCache(const char *path)
  369. {
  370. if (path==NULL)
  371. path = "";
  372. CDateTime cutoff;
  373. cutoff.setNow();
  374. cutoff.adjustTime(-DIRCACHE_TIMEOUT);
  375. ForEachItemInRev(i,dircache) {
  376. CDirCacheItem &item = dircache.item(i);
  377. if (item.dt.compare(cutoff)<0)
  378. dircache.remove(i);
  379. else if (strcmp(path,item.path)==0)
  380. return &item;
  381. }
  382. return NULL;
  383. }
  384. void addDirCache(CDirCacheItem *val)
  385. {
  386. CDateTime now;
  387. now.setNow();
  388. CDateTime cutoff(now);
  389. cutoff.adjustTime(-DIRCACHE_TIMEOUT);
  390. ForEachItemInRev(i,dircache) {
  391. CDirCacheItem &item = dircache.item(i);
  392. if (item.dt.compare(cutoff)<0)
  393. dircache.remove(i);
  394. }
  395. if (val) {
  396. if (dircache.ordinality()>=DIRCACHE_MAX)
  397. dircache.remove(0);
  398. dircache.append(*val);
  399. val->dt = now;
  400. }
  401. }
  402. bool pathToLFN(const char *path,CDfsLogicalFileName &lfn)
  403. {
  404. StringBuffer fn;
  405. StringArray dirs;
  406. dirs.appendList(path, "/");
  407. ForEachItemIn(i,dirs) {
  408. const char *dir = dirs.item(i);
  409. if (dir&&*dir) {
  410. if (fn.length())
  411. fn.append("::");
  412. fn.append(dir);
  413. }
  414. }
  415. if (!fn.length())
  416. fn.append('.');
  417. return lfn.setValidate(fn.str());
  418. }
  419. int fuse_getattr(const char *path, struct stat *stbuf)
  420. {
  421. PROGLOG("fuse_getattr(%s,)",path);
  422. int res = 0;
  423. memset(stbuf, 0, sizeof(struct stat));
  424. if (!path||!*path)
  425. return -ENOENT;
  426. CDfsLogicalFileName lfn;
  427. const char *lfnstr = NULL;
  428. if (strcmp(path,"/")!=0) {
  429. if (!pathToLFN(path,lfn))
  430. return -ENOENT;
  431. lfnstr = lfn.get();
  432. }
  433. // this is a bit extreme (scanning all) but needed to count sub entries
  434. try {
  435. CDirCacheItem *dci = findDirCache(lfnstr);
  436. if (!dci) {
  437. dci = new CDirCacheItem();
  438. int err = dci->init("fuse_getattr",lfnstr,true,false);
  439. if (err) {
  440. dci->Release();
  441. dci = NULL;
  442. if (err!=-ENOENT)
  443. return err;
  444. }
  445. else
  446. addDirCache(dci);
  447. }
  448. if (dci) {
  449. stbuf->st_mode = S_IFDIR | 0755;
  450. stbuf->st_nlink = dci->scopes.ordinality()+2;
  451. }
  452. else {
  453. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lfn,user,AccessMode::tbdRead,false,false,nullptr,defaultPrivilegedUser);
  454. if (file) {
  455. stbuf->st_mode = S_IFREG | 0444;
  456. stbuf->st_nlink = 1;
  457. #ifdef _WIN32
  458. stbuf->st_size = (_off_t)file->getFileSize(true,false);
  459. #else
  460. stbuf->st_size = file->getFileSize(true,false);
  461. #endif
  462. CDateTime dt;
  463. if (file->getModificationTime(dt)) {
  464. stbuf->st_ctime = timetFromIDateTime(&dt);
  465. stbuf->st_mtime = stbuf->st_ctime;
  466. stbuf->st_atime = stbuf->st_ctime;
  467. }
  468. if (file->getAccessedTime(dt)) {
  469. stbuf->st_atime = timetFromIDateTime(&dt);
  470. }
  471. }
  472. else
  473. res = -ENOENT;
  474. }
  475. }
  476. catch (IException *e) {
  477. EXCLOG(e,"fuse_getattr");
  478. res = -EFAULT;
  479. }
  480. return res;
  481. }
  482. int fuse_readdir (const char *path, void *buf, fuse_fill_dir_t filler, off_t pos, struct fuse_file_info *info)
  483. {
  484. PROGLOG("fuse_readdir(%s,)",path);
  485. CDfsLogicalFileName lfn;
  486. const char *lfnstr = NULL;
  487. if (strcmp(path,"/")!=0) {
  488. if (!pathToLFN(path,lfn))
  489. return -ENOENT;
  490. lfnstr = lfn.get();
  491. }
  492. CDirCacheItem *dci = findDirCache(lfnstr);
  493. if (!dci) {
  494. dci = new CDirCacheItem();
  495. int err = dci->init("fuse_readdir",lfnstr,true,true);
  496. if (err) {
  497. dci->Release();
  498. dci = NULL;
  499. if (err!=-ENOENT)
  500. return err;
  501. }
  502. else
  503. addDirCache(dci);
  504. }
  505. else if (!dci->donefiles) {
  506. int err = dci->init("fuse_readdir",lfnstr,false,true); // scopes already done
  507. if (err) {
  508. dircache.zap(*dci);
  509. return err;
  510. }
  511. }
  512. struct stat s;
  513. memset(&s,0,sizeof(s));
  514. s.st_mode = (S_IFDIR | 0755);
  515. if (pos==0)
  516. if (filler(buf, ".", &s, ++pos))
  517. return 0;
  518. if (pos==1)
  519. if (filler(buf, "..", &s, ++pos))
  520. return 0;
  521. for (;;) {
  522. bool isscope;
  523. const char *fn = dci->get((unsigned)pos-2,isscope);
  524. if (!fn)
  525. break;
  526. s.st_mode = isscope?(S_IFDIR | 0755):(S_IFREG | 0444);
  527. PROGLOG("filler('%s',%d,%s)",fn,(unsigned)pos,isscope?"scope":"file");
  528. if (!filler(buf,fn,&s,++pos))
  529. break;
  530. }
  531. PROGLOG("fuse_readdir(%s,) exit",path);
  532. return 0;
  533. }
  534. int fuse_open (const char *path, struct fuse_file_info *info)
  535. {
  536. PROGLOG("fuse_open(%s,) flags=%d",path,info?info->flags:-1);
  537. CDfsLogicalFileName lfn;
  538. if (!pathToLFN(path,lfn))
  539. return -ENOENT;
  540. try {
  541. Owned<IDistributedFile> file = queryDistributedFileDirectory().lookup(lfn,user,AccessMode::tbdRead,false,false,nullptr,defaultPrivilegedUser);
  542. if (!file)
  543. return -ENOENT;
  544. if((info->flags & 3) != O_RDONLY )
  545. return -EACCES;
  546. ForEachItemIn(i,openfiles) {
  547. if (openfiles.item(i)==NULL) {
  548. openfiles.replace(file.getClear(),i);
  549. info->fh = i+FH_SALT;
  550. return 0;
  551. }
  552. }
  553. info->fh = openfiles.ordinality()+FH_SALT;
  554. openfiles.append(file.getClear());
  555. }
  556. catch (IException *e) {
  557. EXCLOG(e,"fuse_open");
  558. return -EFAULT;
  559. }
  560. return 0;
  561. }
  562. int fuse_read (const char *path, char *dst, size_t _sz, off_t _pos, struct fuse_file_info *info)
  563. {
  564. offset_t pos = _pos;
  565. size32_t sz = _sz;
  566. PROGLOG("fuse_read(%s,,%d,%" I64F "d,)",path,sz,pos);
  567. int ret = 0;
  568. try {
  569. unsigned h = (unsigned)info->fh;
  570. Owned<IDistributedFile> file;
  571. if ((h>=FH_SALT)&&(h<FH_SALT+openfiles.ordinality()))
  572. file.set((IDistributedFile *)openfiles.item(h-FH_SALT));
  573. else { // don't think this should happen but...
  574. CDfsLogicalFileName lfn;
  575. if (!pathToLFN(path,lfn))
  576. return -ENOENT;
  577. file.setown(queryDistributedFileDirectory().lookup(lfn,user,AccessMode::tbdRead,false,false,nullptr,defaultPrivilegedUser));
  578. if (!file)
  579. return -ENOENT;
  580. }
  581. offset_t base;
  582. unsigned pn = file->getPositionPart(pos,base);
  583. for (;;) {
  584. if (pn==NotFound)
  585. break;
  586. IDistributedFilePart &part = file->queryPart(pn);
  587. offset_t psz = part.getFileSize(true,false);
  588. size32_t toread = (psz-pos-base<(offset_t)sz)?((size32_t)(psz-pos-base)):sz;
  589. PROGLOG("reading %d from part %d size %" I64F "d pos = %" I64F "d base=%" I64F "d",toread,pn,psz,pos,base);
  590. RemoteFilename rfn;
  591. part.getFilename(rfn,0);
  592. Owned<IFile> partfile = createIFile(rfn);
  593. for (unsigned copy=0;;) {
  594. try {
  595. if (partfile->exists())
  596. break;
  597. }
  598. catch (IException *e) {
  599. StringBuffer tmp;
  600. IERRLOG("fuse_open %s",e->errorMessage(tmp).str());
  601. partfile.clear();
  602. }
  603. copy++;
  604. if (copy>=part.numCopies()) {
  605. StringBuffer tmp;
  606. part.getFilename(rfn,0);
  607. rfn.getRemotePath(tmp);
  608. if (copy>1) {
  609. tmp.append(" or ");
  610. part.getFilename(rfn,1);
  611. rfn.getRemotePath(tmp);
  612. }
  613. OERRLOG("%s part %d not found at %s",path,pn+1,tmp.str());
  614. return -ENOENT;
  615. }
  616. part.getFilename(rfn,copy);
  617. partfile.setown(createIFile(rfn));
  618. }
  619. Owned<IFileIO> srcio = partfile->open(IFOread); // Need to cache all this! TBD
  620. if (!srcio) {
  621. StringBuffer tmp;
  622. rfn.getRemotePath(tmp);
  623. OERRLOG("could not open '%s' for read",tmp.str());
  624. return -EACCES;
  625. }
  626. bool blocked;
  627. bool compressed = file->isCompressed(&blocked);
  628. if (compressed&&blocked) {
  629. Owned<ICompressedFileIO> cmpio = createCompressedFileReader(srcio);
  630. if (cmpio.get())
  631. srcio.setown(cmpio.getClear());
  632. }
  633. size32_t szrd = srcio->read(pos-base,toread,dst);
  634. PROGLOG("Read %s offset %" I64F "d len %d returned %d",partfile->queryFilename(),pos-base,toread,szrd);
  635. sz -= szrd;
  636. dst += szrd;
  637. ret += szrd;
  638. if (sz==0)
  639. break;
  640. pn++;
  641. if (pn>=file->numParts())
  642. break;
  643. base += psz;
  644. pos += szrd;
  645. }
  646. }
  647. catch (IException *e) {
  648. EXCLOG(e,"fuse_open");
  649. return -EFAULT;
  650. }
  651. return ret;
  652. }
  653. int fuse_release (const char *path, struct fuse_file_info *info)
  654. {
  655. PROGLOG("fuse_release(%s)",path);
  656. try {
  657. unsigned h = (unsigned)info->fh;
  658. Owned<IDistributedFile> file;
  659. if ((h>=FH_SALT)&&(h<FH_SALT+openfiles.ordinality()))
  660. openfiles.replace(NULL,h-FH_SALT);
  661. }
  662. catch (IException *e) {
  663. EXCLOG(e,"fuse_release");
  664. return -EFAULT;
  665. }
  666. return 0;
  667. }
  668. void *fuse_init (struct fuse_conn_info *conn)
  669. {
  670. PROGLOG("fuse_init");
  671. try {
  672. setDaliServixSocketCaching(true);
  673. Owned<IGroup> serverGroup = createIGroup(daliServer,DALI_SERVER_PORT);
  674. initClientProcess(serverGroup, DCR_Dfu, 0, NULL, NULL, MP_WAIT_FOREVER); // so that
  675. startLogMsgParentReceiver(); // for auditing
  676. connectLogMsgManagerToDali();
  677. }
  678. catch (IException *e) {
  679. EXCLOG(e,"fuse_init");
  680. }
  681. PROGLOG("fuse_init done");
  682. return this;
  683. }
  684. void fuse_destroy (void *p)
  685. {
  686. PROGLOG("fuse_destroy");
  687. try {
  688. openfiles.kill();
  689. dircache.kill();
  690. closedownClientProcess();
  691. }
  692. catch (IException *e) {
  693. EXCLOG(e,"fuse_destroy");
  694. }
  695. PROGLOG("fuse_destroy done");
  696. }
  697. /*
  698. int fuse_readlink (const char *path, char *out, size_t sz)
  699. {
  700. // TBD
  701. return -1;
  702. }
  703. int fuse_mkdir (const char *path, mode_t mode)
  704. {
  705. // TBD
  706. return -1;
  707. }
  708. int fuse_unlink (const char *path)
  709. {
  710. // TBD
  711. return -1;
  712. }
  713. int fuse_rmdir (const char *path)
  714. {
  715. // TBD
  716. return -1;
  717. }
  718. int fuse_rename (const char *from, const char *to)
  719. {
  720. // TBD
  721. return -1;
  722. }
  723. int fuse_truncate (const char *path, off_t pos)
  724. {
  725. // TBD
  726. return -1;
  727. }
  728. int fuse_write (const char *path, const char *src, size_t sz, off_t pos, struct fuse_file_info *info)
  729. {
  730. // TBD
  731. return -1;
  732. }
  733. int fuse_statfs (const char *path, struct statvfs *stbuf)
  734. {
  735. // TBD
  736. return -1;
  737. }
  738. int fuse_flush (const char *path, struct fuse_file_info *info)
  739. {
  740. // TBD
  741. return -1;
  742. }
  743. int fuse_fsync (const char *path, int m, struct fuse_file_info *info)
  744. {
  745. // TBD
  746. return -1;
  747. }
  748. int fuse_opendir (const char *path, struct fuse_file_info *info)
  749. {
  750. // TBD
  751. return -1;
  752. }
  753. int fuse_releasedir (const char *path, struct fuse_file_info *info)
  754. {
  755. // TBD
  756. return -1;
  757. }
  758. int fuse_access (const char *path, int m)
  759. {
  760. // TBD
  761. return -1;
  762. }
  763. int fuse_create (const char *path, mode_t mode, struct fuse_file_info *info)
  764. {
  765. // TBD
  766. return -1;
  767. }
  768. int fuse_ftruncate (const char *path, off_t pos, struct fuse_file_info *info)
  769. {
  770. // TBD
  771. return -1;
  772. }
  773. int fuse_fgetattr (const char *path, struct stat *stbuf, struct fuse_file_info *info)
  774. {
  775. // TBD
  776. return -1;
  777. }
  778. int fuse_utimens (const char *path, const struct timespec tv[2])
  779. {
  780. // TBD
  781. return -1;
  782. }
  783. */
  784. public:
  785. CFuseDaliDFS(const char *_daliServer,IProperties *prop)
  786. : daliServer(_daliServer)
  787. {
  788. FUSE_USE(getattr);
  789. FUSE_USE(readdir);
  790. FUSE_USE(open);
  791. FUSE_USE(read);
  792. FUSE_USE(init);
  793. FUSE_USE(destroy);
  794. FUSE_USE(release);
  795. user = NULL; // TBD
  796. }
  797. };
  798. static void usage()
  799. {
  800. printf("Usage:\n");
  801. printf(" dafuse mount <mount-dir> <options>\n");
  802. printf(" dafuse unmount <mount-dir> \n");
  803. printf(" dafuse mapuser <mount-dir> <ldap-user> [ <ldap-password> ]\n");
  804. printf(" dafuse sprayopt <mount-dir> <dstfilemask> <cluster> <create-options>\n");
  805. printf(" dafuse list <mount-dir> -- lists spray options set and user mappings\n");
  806. printf("The following options can be passed on the command line or in ./dafuse.ini\n\n");
  807. printf(" DALISERVER=<dali-ip>\n");
  808. printf("TBD:\n");
  809. printf(" DIR=<mount-dir> -- (not needed if specified on command line)\n");
  810. printf(" DEFAULTLDAPUSER=<LDAP-user-name> -- default LDAP user\n");
  811. printf(" PASSWORD=<LDAP-password> -- if not specified will prompt for\n");
  812. printf(" LOCALUSERS=<userlist> -- allowed non-root users of share (default all)\n");
  813. printf(" READONLY=0|1 -- whether can create/delete files\n");
  814. printf(" ROOTONLY=0|1 -- only root can access mount\n");
  815. printf(" NODELETE=0|1 -- disable deletion or overwrite\n");
  816. printf(" CACHETIMEOUT=<mins> -- default 1min \n");
  817. }
  818. static bool isOpt(const char *&s,const char *name)
  819. {
  820. if (s&&name) {
  821. size32_t nl = strlen(name);
  822. if (strlen(s)>nl) {
  823. if (memicmp(s,name,nl)==0) {
  824. if (s[nl]=='=') {
  825. s += nl+1;
  826. return true;
  827. }
  828. }
  829. }
  830. }
  831. return false;
  832. }
  833. static bool parseOption(const char *s, IProperties *prop)
  834. {
  835. if (isOpt(s,"daliserver")||isOpt(s,"daliservers")) {
  836. prop->setProp("DALISERVER",s);
  837. return true;
  838. }
  839. if (isOpt(s,"user")) {
  840. prop->setProp("USER",s);
  841. return true;
  842. }
  843. if (isOpt(s,"password")) {
  844. prop->setProp("PASSWORD",s);
  845. return true;
  846. }
  847. if (isOpt(s,"logfile")) {
  848. prop->setProp("LOGFILE",s);
  849. return true;
  850. }
  851. return false;
  852. }
  853. static void removeParam(int &argc, char *argv[], int i)
  854. {
  855. while (++i<argc)
  856. argv[i-1] = argv[i];
  857. argc--;
  858. }
  859. inline bool eqs(const char *s1,const char *s2)
  860. {
  861. return strieq(s1?s1:"",s2?s2:"");
  862. }
  863. static bool parseParams(int &argc, char *argv[],IProperties *prop)
  864. {
  865. int i = 1;
  866. bool actiongot = false;
  867. bool dirgot = false;
  868. prop->removeProp("ACTION");
  869. while (i<argc) {
  870. const char *arg = argv[i];
  871. if (*arg=='-') {
  872. // ignore - all passed to fuse
  873. }
  874. else if (!actiongot) {
  875. prop->setProp("ACTION",arg);
  876. removeParam(argc,argv,i);
  877. actiongot = true;
  878. continue;
  879. }
  880. else if (!dirgot) {
  881. prop->setProp("DIR",arg);
  882. // don't remove
  883. dirgot = true;
  884. continue;
  885. }
  886. else if (parseOption(arg,prop)) {
  887. removeParam(argc,argv,i);
  888. actiongot = true;
  889. continue;
  890. }
  891. i++;
  892. }
  893. // validate props
  894. const char *action= prop->queryProp("ACTION");
  895. if (eqs(action,"mount")) {
  896. if (prop->hasProp("DIR"))
  897. return true;
  898. }
  899. if (eqs(action,"login")) {
  900. return true;
  901. }
  902. if (eqs(action,"unmount")||eqs(action,"umount")) {
  903. prop->setProp("ACTION","unmount");
  904. if (prop->hasProp("DIR"))
  905. return true;
  906. }
  907. if (eqs(action,"creatopt")) {
  908. return true;
  909. }
  910. usage();
  911. return false;
  912. }
  913. int main(int argc, char *_argv[])
  914. {
  915. InitModuleObjects();
  916. EnableSEHtoExceptionMapping();
  917. // setDefaultUser("TBD","TBD");
  918. Thread::setDefaultStackSize(0x20000);
  919. SocketEndpoint ep;
  920. ep.setLocalHost(0);
  921. char **argv = (char **)calloc(MAXPARAM,sizeof(char *));
  922. for (int i1=0;i1<argc;i1++)
  923. argv[i1] = strdup(_argv[i1]);
  924. Owned<IProperties> prop = createProperties("dafuse.ini",true);
  925. if (!parseParams(argc,argv,prop))
  926. return 1;
  927. {
  928. StringBuffer logName;
  929. if (!prop->getProp("LOGFILE", logName))
  930. logName.set(dafuse);
  931. Owned<IComponentLogFileCreator> lf = createComponentLogFileCreator(logName.str());
  932. lf->setMsgFields(MSGFIELD_STANDARD);
  933. lf->setAppend(false);
  934. ls->setMaxDetail(TopDetail);
  935. lf->beginLogging();
  936. }
  937. StringBuffer daliServer;
  938. if (!prop->getProp("DALISERVER", daliServer)) {
  939. OERRLOG("DALISERVER setting not found in dafuse.ini");
  940. return 1;
  941. }
  942. int res;
  943. try {
  944. const char *action= prop->queryProp("ACTION");
  945. if (eqs(action,"mount")) {
  946. printf("mounting %s",prop->queryProp("DIR"));
  947. CFuseDaliDFS hw(daliServer.str(),prop);
  948. res = hw.main(argc,argv);
  949. }
  950. else if (eqs(action,"unmount")) {
  951. StringBuffer s("umount ");
  952. s.append(prop->queryProp("DIR"));
  953. printf("unmounting %s",prop->queryProp("DIR"));
  954. system(s.str());
  955. }
  956. }
  957. catch (IException *e) {
  958. EXCLOG(e,"dafuse");
  959. res = 2;
  960. }
  961. /* only needed for leak checking
  962. for (unsigned i2=0;i2<MAXPARAM;i2++)
  963. free(argv[i2]);
  964. free(argv);
  965. releaseAtoms();
  966. */
  967. return res;
  968. }
  969. /* fuse opts
  970. general options:
  971. -o opt,[opt...] mount options
  972. -h --help print help
  973. -V --version print version
  974. FUSE options:
  975. -d -o debug enable debug output (implies -f)
  976. -f foreground operation
  977. -s disable multi-threaded operation
  978. -o allow_other allow access to other users
  979. -o allow_root allow access to root
  980. -o nonempty allow mounts over non-empty file/dir
  981. -o default_permissions enable permission checking by kernel
  982. -o fsname=NAME set filesystem name
  983. -o subtype=NAME set filesystem type
  984. -o large_read issue large read requests (2.4 only)
  985. -o max_read=N set maximum size of read requests
  986. -o hard_remove immediate removal (don't hide files)
  987. -o use_ino let filesystem set inode numbers
  988. -o readdir_ino try to fill in d_ino in readdir
  989. -o direct_io use direct I/O
  990. -o kernel_cache cache files in kernel
  991. -o [no]auto_cache enable caching based on modification times (off)
  992. -o umask=M set file permissions (octal)
  993. -o uid=N set file owner
  994. -o gid=N set file group
  995. -o entry_timeout=T cache timeout for names (1.0s)
  996. -o negative_timeout=T cache timeout for deleted names (0.0s)
  997. -o attr_timeout=T cache timeout for attributes (1.0s)
  998. -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)
  999. -o intr allow requests to be interrupted
  1000. -o intr_signal=NUM signal to send on interrupt (10)
  1001. -o modules=M1[:M2...] names of modules to push onto filesystem stack
  1002. -o max_write=N set maximum size of write requests
  1003. -o max_readahead=N set maximum readahead
  1004. -o async_read perform reads asynchronously (default)
  1005. -o sync_read perform reads synchronously
  1006. -o atomic_o_trunc enable atomic open+truncate support
  1007. -o big_writes enable larger than 4kB writes
  1008. -o no_remote_lock disable remote file locking
  1009. Module options:
  1010. [subdir]
  1011. -o subdir=DIR prepend this directory to all paths (mandatory)
  1012. -o [no]rellinks transform absolute symlinks to relative
  1013. [iconv]
  1014. -o from_code=CHARSET original encoding of file names (default: UTF-8)
  1015. -o to_code=CHARSET new encoding of the file names (default: UTF-8)
  1016. */