simplerfs.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. // Trivial example of RFS
  2. #ifdef _WIN32
  3. #define WIN32_LEAN_AND_MEAN
  4. #ifndef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
  5. #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
  6. #undef _CRT_SECURE_NO_WARNINGS
  7. #define _CRT_SECURE_NO_WARNINGS 1
  8. #endif
  9. #undef UNICODE
  10. #include <windows.h>
  11. #include <io.h>
  12. #include <sys/utime.h>
  13. #define S_ISDIR(m) (((m)&_S_IFDIR)!=0)
  14. #define S_ISREG(m) (((m)&_S_IFREG)!=0)
  15. #define ALLOW_WINDOWS_SERVICE
  16. #else
  17. #include <unistd.h>
  18. #include <utime.h>
  19. #include <dirent.h>
  20. #define _strdup strdup
  21. #define _O_RDONLY O_RDONLY
  22. #define _O_WRONLY O_WRONLY
  23. #define _O_RDWR O_RDWR
  24. #define _O_CREAT O_CREAT
  25. #define _O_TRUNC O_TRUNC
  26. #define _O_BINARY (0)
  27. #define _open ::open
  28. #define _read ::read
  29. #define _write ::write
  30. #define _lseek ::lseek
  31. #define _close ::close
  32. #define _unlink unlink
  33. #define _utimbuf utimbuf
  34. #define _utime utime
  35. #endif
  36. #include <stdlib.h>
  37. #include <stdio.h>
  38. #include <stdarg.h>
  39. #include <string.h>
  40. #include <errno.h>
  41. #include <assert.h>
  42. #include <time.h>
  43. #include <ctype.h>
  44. #include <fcntl.h>
  45. #include <sys/types.h>
  46. #include <sys/stat.h>
  47. #include "rfs.h"
  48. static const char * safestrcpy(char *dst,const char *src,size_t max)
  49. {
  50. const char *ret = dst;
  51. if (dst&&src&&max) {
  52. while (--max&&*src)
  53. *(dst++)=*(src++);
  54. *dst = 0;
  55. }
  56. return ret;
  57. }
  58. class CSimpleRFSconn: public RFS_ConnectionBase
  59. {
  60. // NB this class relies on single threaded nature of RFS
  61. RFS_ServerBase &base;
  62. int handle;
  63. char *filename;
  64. public:
  65. CSimpleRFSconn(RFS_ServerBase &_base)
  66. : base(_base)
  67. {
  68. handle = -1;
  69. filename = NULL;
  70. }
  71. ~CSimpleRFSconn()
  72. {
  73. close();
  74. }
  75. int open(const char *_filename,byte mode, byte share)
  76. {
  77. int openflags;
  78. switch (mode&RFS_OPEN_MODE_MASK) {
  79. case RFS_OPEN_MODE_CREATE:
  80. openflags = _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY;
  81. break;
  82. case RFS_OPEN_MODE_READ:
  83. openflags = _O_RDONLY | _O_BINARY;
  84. break;
  85. case RFS_OPEN_MODE_WRITE:
  86. openflags = _O_WRONLY | _O_CREAT | _O_BINARY;
  87. break;
  88. case RFS_OPEN_MODE_CREATERW:
  89. openflags = _O_RDWR | _O_CREAT | _O_TRUNC | _O_BINARY;
  90. break;
  91. case RFS_OPEN_MODE_READWRITE:
  92. openflags = _O_RDWR | _O_CREAT | _O_BINARY;
  93. break;
  94. default:
  95. return EACCES;
  96. }
  97. int rights = 0;
  98. #ifdef _WIN32
  99. rights = _S_IREAD|_S_IWRITE; // don't support linux style rights
  100. #else
  101. switch (share) {
  102. case RFS_SHARING_NONE:
  103. rights = S_IRUSR|S_IWUSR;
  104. case RFS_SHARING_EXEC:
  105. rights = S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
  106. break;
  107. case RFS_SHARING_ALL:
  108. rights = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; // bit excessive
  109. break;
  110. }
  111. #endif
  112. handle = _open(_filename,openflags,rights);
  113. if (handle==-1)
  114. return errno;
  115. free(filename);
  116. filename = _strdup(_filename);
  117. return 0;
  118. }
  119. void read(rfs_fpos_t pos, size_t len, size_t &outlen, void *out)
  120. {
  121. long ret = (long)_lseek(handle,(long)pos,SEEK_SET);
  122. outlen = 0;
  123. if (ret!=pos)
  124. base.throwError(errno,"read.1");
  125. int rd = _read(handle,out,len);
  126. if (rd==-1)
  127. base.throwError(errno,"read.2");
  128. outlen = (size_t)rd;
  129. }
  130. rfs_fpos_t size()
  131. {
  132. long savedPos = (long)_lseek(handle,0,SEEK_CUR);
  133. if (savedPos == -1)
  134. base.throwError(errno,"size.1");
  135. long length = (long)_lseek(handle,0,SEEK_END);
  136. if (length==-1)
  137. base.throwError(errno,"size.2");
  138. if ((long)_lseek(handle,savedPos,SEEK_SET)!=savedPos)
  139. base.throwError(errno,"size.3");
  140. return (rfs_fpos_t)length;
  141. }
  142. void close()
  143. {
  144. if (handle!=-1)
  145. _close(handle); // could check error here
  146. handle = -1;
  147. free(filename);
  148. filename = NULL;
  149. }
  150. void write(rfs_fpos_t pos, size_t len, const void *in)
  151. {
  152. long ret = (long)_lseek(handle,(long)pos,SEEK_SET);
  153. if (ret!=pos)
  154. base.throwError(errno,"write.1");
  155. int wr = _write(handle,in,len);
  156. if (wr==-1)
  157. base.throwError(errno,"write.2");
  158. if ((size_t)wr!=len) // disk full
  159. base.throwError(ENOSPC,"write.3");
  160. }
  161. };
  162. #ifdef _WIN32
  163. #define PATHSEPCHAR '\\'
  164. #else
  165. #define PATHSEPCHAR '/'
  166. #endif
  167. class cSimpleDir
  168. {
  169. RFS_SimpleString path;
  170. char *tail;
  171. size_t pathhead;
  172. int level;
  173. char *mask;
  174. bool includedirs;
  175. bool recursive;
  176. bool first;
  177. #ifdef _WIN32
  178. typedef HANDLE _Handle;
  179. time_t FileTimeToUnixTime(LPFILETIME pft)
  180. {
  181. return (time_t)((*(__int64 *)pft-116444736000000000i64)/10000000i64);
  182. }
  183. #else
  184. DIR *handle;
  185. typedef DIR * _Handle;
  186. #define INVALID_HANDLE_VALUE ((DIR *)NULL)
  187. #endif
  188. _Handle *handles;
  189. bool WildMatchN ( const char *src, size_t srclen, size_t srcidx, const char *pat, size_t patlen, size_t patidx, bool nocase)
  190. {
  191. char next_char;
  192. while (1) {
  193. if (patidx == patlen)
  194. return (srcidx == srclen);
  195. next_char = pat[patidx++];
  196. if (next_char == '?') {
  197. if (srcidx == srclen)
  198. return false;
  199. srcidx++;
  200. }
  201. else if (next_char != '*') {
  202. if (nocase) {
  203. if ((srcidx == srclen) ||
  204. (toupper(src[srcidx])!=toupper(next_char)))
  205. return false;
  206. }
  207. else
  208. if ((srcidx == srclen) || (src[srcidx]!=next_char))
  209. return false;
  210. srcidx++;
  211. }
  212. else {
  213. while (1)
  214. {
  215. if (patidx == patlen)
  216. return true;
  217. if (pat[patidx] != '*')
  218. break;
  219. patidx++;
  220. }
  221. while (srcidx < srclen) {
  222. if (WildMatchN(src,srclen,srcidx,
  223. pat, patlen, patidx,nocase))
  224. return true;
  225. srcidx++;
  226. }
  227. return false;
  228. }
  229. }
  230. return false;
  231. }
  232. bool WildMatch(const char *src, const char *pat, bool nocase)
  233. {
  234. size_t srclen = strlen(src);
  235. size_t patlen = strlen(pat);
  236. if (pat[0]=='*') {
  237. // common case optimization
  238. int i = patlen;
  239. int j = srclen;
  240. while (--i>0) {
  241. if (pat[i]=='*') goto Normal;
  242. if (j--==0) return false;
  243. if (nocase) {
  244. if ((toupper(pat[i])!=toupper(src[j]))&&(pat[i]!='?'))
  245. return false;
  246. }
  247. else
  248. if ((pat[i]!=src[j])&&(pat[i]!='?'))
  249. return false;
  250. }
  251. return true;
  252. }
  253. Normal:
  254. return WildMatchN(src,srclen,0,pat,patlen,0,nocase);
  255. }
  256. public:
  257. cSimpleDir(const char *dirname, const char *_mask, bool _recursive, bool _includedirs)
  258. {
  259. path.appends(dirname);
  260. if (path.lastChar()!='\\')
  261. path.appendc('\\');
  262. pathhead = path.length();
  263. level = 0;
  264. mask = _mask?_strdup(_mask):NULL;
  265. includedirs = _includedirs;
  266. recursive = _recursive;
  267. first = true;
  268. handles = (_Handle *)malloc(sizeof(_Handle));
  269. tail = NULL;
  270. }
  271. ~cSimpleDir()
  272. {
  273. while ((level>=0)&&(handles[level] != INVALID_HANDLE_VALUE)) {
  274. #ifdef _WIN32
  275. FindClose(handles[level--]);
  276. #else
  277. closedir(handles[level--]);
  278. #endif
  279. }
  280. free(handles);
  281. free(mask);
  282. free(tail);
  283. }
  284. void next(size_t maxfilenamesize, char *outfilename, bool &isdir, rfs_fpos_t &filesizeout, time_t &outmodifiedtime)
  285. {
  286. #ifdef _WIN32
  287. WIN32_FIND_DATA info;
  288. bool nocase = true;
  289. #else
  290. struct dirent *entry;
  291. bool nocase = false;
  292. #endif
  293. while (1) {
  294. *outfilename = 0;
  295. if (level<0)
  296. return;
  297. if (first) {
  298. first = false;
  299. handles = (_Handle *)realloc(handles,sizeof(_Handle)*(level+1));
  300. #ifdef _WIN32
  301. path.appendc('*');
  302. handles[level] = FindFirstFile(path.str(), &info);
  303. path.decLength();
  304. #else
  305. handles[level] = opendir(path.str());
  306. if (handles[level])
  307. entry = readdir(handles[level]); // don't need _r here
  308. #endif
  309. }
  310. else {
  311. #ifdef _WIN32
  312. if (!FindNextFile(handles[level], &info)) {
  313. FindClose(handles[level]);
  314. #else
  315. entry = readdir(handles[level]); // don't need _r here
  316. if (!entry) {
  317. closedir(handles[level]);
  318. #endif
  319. handles[level] = INVALID_HANDLE_VALUE;
  320. }
  321. }
  322. if (handles[level]!=INVALID_HANDLE_VALUE) {
  323. free(tail);
  324. #ifdef _WIN32
  325. tail = _strdup(info.cFileName);
  326. isdir = ((info.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)!=0);
  327. #else
  328. tail = _strdup(entry->d_name);
  329. #endif
  330. size_t hs = path.length()-pathhead;
  331. size_t ts = strlen(tail);
  332. if (hs>=maxfilenamesize)
  333. hs = maxfilenamesize-1;
  334. if (hs+ts>=maxfilenamesize)
  335. ts = maxfilenamesize-1-hs;
  336. memcpy(outfilename,path.str()+pathhead,hs);
  337. memcpy(outfilename+hs,tail,ts);
  338. outfilename[hs+ts] = 0;
  339. #ifndef _WIN32
  340. struct stat info;
  341. if (stat(outfilename, &info) != 0) // will follow link
  342. continue;
  343. isdir = S_ISDIR(info.st_mode);
  344. #endif
  345. if ((strcmp(tail,".")==0)||(strcmp(tail,"..")==0))
  346. continue;
  347. bool matched = (mask&&*mask)?WildMatch(tail,mask,nocase):false;
  348. if (!matched&&(!recursive||!isdir))
  349. continue;
  350. if (isdir&&!recursive&&!includedirs)
  351. continue;
  352. if (isdir) {
  353. if (recursive) {
  354. // add name
  355. path.appends(tail);
  356. if (path.lastChar()!='\\')
  357. path.appendc('\\');
  358. first = true;
  359. level++;
  360. }
  361. if (!includedirs||!matched)
  362. continue;
  363. filesizeout = (rfs_fpos_t)0;
  364. }
  365. else {
  366. #ifdef _WIN32
  367. LARGE_INTEGER x;
  368. x.LowPart = info.nFileSizeLow;
  369. x.HighPart = info.nFileSizeHigh;
  370. filesizeout = (rfs_fpos_t)x.QuadPart;
  371. }
  372. outmodifiedtime = FileTimeToUnixTime(&info.ftLastWriteTime);
  373. #else
  374. filesizeout = info.st_size;
  375. }
  376. outmodifiedtime = info.st_mtime;
  377. #endif
  378. break;
  379. }
  380. level--;
  381. if (level<0)
  382. return;
  383. if (path.lastChar()=='\\')
  384. path.decLength();
  385. while (path.length()) {
  386. if (path.lastChar()=='\\')
  387. break;
  388. path.decLength();
  389. }
  390. }
  391. }
  392. };
  393. class CSimpleRFS: public RFS_ServerBase
  394. {
  395. #ifdef _WIN32
  396. bool WindowsCreateDirectory(const char * path)
  397. {
  398. if (CreateDirectory(path, NULL))
  399. return true;
  400. DWORD err = GetLastError();
  401. if ((err==ERROR_FILE_NOT_FOUND) || (err==ERROR_PATH_NOT_FOUND) || (err==ERROR_FILE_EXISTS) || (err==ERROR_CANNOT_MAKE))
  402. return false;
  403. if (err==ERROR_ALREADY_EXISTS) {
  404. DWORD attr = GetFileAttributes(path);
  405. if ((attr != -1)&&( attr & FILE_ATTRIBUTE_DIRECTORY))
  406. return true;
  407. }
  408. return false;
  409. }
  410. #else
  411. bool LinuxCreateDirectory(const char * path)
  412. {
  413. if (!path)
  414. return false;
  415. if (mkdir(path,S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH)==0)
  416. return true;
  417. else
  418. {
  419. if (EEXIST == errno)
  420. {
  421. struct stat info;
  422. if (stat(path, &info) != 0)
  423. return false;
  424. return S_ISDIR(info.st_mode);
  425. }
  426. }
  427. return false;
  428. }
  429. #endif
  430. public:
  431. RFS_ConnectionBase * open(const char *name, byte mode, byte share)
  432. {
  433. CSimpleRFSconn *conn = new CSimpleRFSconn(*this);
  434. int err = conn->open(name,mode,share);
  435. if (err) {
  436. delete conn;
  437. conn = NULL;
  438. if (err==ENOENT)
  439. return false;
  440. throwError(err,"open");
  441. }
  442. return conn;
  443. }
  444. void existFile(const char *filename, bool &existsout)
  445. {
  446. struct stat info;
  447. existsout = (stat(filename, &info) == 0);
  448. }
  449. void removeFile(const char *filename)
  450. {
  451. bool isdir;
  452. isDir(filename,isdir);
  453. if (isdir) {
  454. #ifdef _WIN32
  455. // no rmdir?
  456. if (RemoveDirectory(filename)==0)
  457. return;
  458. DWORD err = GetLastError();
  459. if ( (err==ERROR_FILE_NOT_FOUND) || (err==ERROR_PATH_NOT_FOUND) )
  460. return;
  461. throwError((int)err,"removeFile"); // shouldn't really pass win error here
  462. #else
  463. if (rmdir(filename) == 0)
  464. return;
  465. #endif
  466. }
  467. else {
  468. if (_unlink(filename) == 0)
  469. return;
  470. }
  471. if (ENOENT!=errno)
  472. throwError(errno,"removeFile");
  473. }
  474. void renameFile(const char *fromname,const char *toname)
  475. {
  476. if (::rename(fromname, toname))
  477. throwError(errno,"rename");
  478. }
  479. void getFileTime(const char *filename, time_t &outaccessedtime, time_t &outcreatedtime, time_t &outmodifiedtime)
  480. {
  481. struct stat info;
  482. if (stat(filename, &info) == 0) {
  483. outaccessedtime =info.st_atime;
  484. outcreatedtime = info.st_ctime;
  485. outmodifiedtime = info.st_mtime;
  486. }
  487. }
  488. void setFileTime(const char *filename, time_t *inaccessedtime, time_t *increatedtime, time_t *inmodifiedtime) // params NULL if not to be set
  489. {
  490. // only supports accessed and modified currently
  491. struct _utimbuf am;
  492. if (!inaccessedtime||!inmodifiedtime) {
  493. struct stat info;
  494. if (stat(filename, &info) != 0)
  495. return;
  496. am.actime = info.st_atime;
  497. am.modtime = info.st_mtime;
  498. }
  499. if (inaccessedtime)
  500. am.actime = *inaccessedtime;
  501. if (inmodifiedtime)
  502. am.modtime = *inmodifiedtime;
  503. _utime(filename, &am);
  504. }
  505. void isFile(const char *filename, bool &outisfile)
  506. {
  507. outisfile = false;
  508. struct stat info;
  509. if (stat(filename, &info) == 0)
  510. outisfile = S_ISREG(info.st_mode);
  511. }
  512. void isDir(const char *filename, bool &outisdir)
  513. {
  514. outisdir = false;
  515. struct stat info;
  516. if (stat(filename, &info) == 0)
  517. outisdir = S_ISDIR(info.st_mode);
  518. }
  519. void isReadOnly(const char *filename, bool &outisreadonly)
  520. {
  521. //TBD
  522. }
  523. void setReadOnly(const char *filename, bool readonly)
  524. {
  525. // TBD
  526. }
  527. void createDir(const char *name,bool &createdout)
  528. {
  529. if (!name) {
  530. createdout = false;
  531. return;
  532. }
  533. createdout = true;
  534. size_t l = strlen(name);
  535. if (l==0)
  536. return;
  537. if ((name[0]==PATHSEPCHAR)&&((l==1)||((name[1]==PATHSEPCHAR)&&!strchr(name+2,PATHSEPCHAR))))
  538. return;
  539. #ifdef _WIN32
  540. if (name[1]==':') {
  541. if ((l==2)||((l==3)&&(name[2]=='\\')))
  542. return;
  543. }
  544. #endif
  545. bool isdir;
  546. isDir(name,isdir);
  547. if (isdir)
  548. return;
  549. #ifdef _WIN32
  550. if (WindowsCreateDirectory(name))
  551. #else
  552. if (LinuxCreateDirectory(name))
  553. #endif
  554. return;
  555. RFS_SimpleString parent(name);
  556. if (parent.lastChar()==PATHSEPCHAR)
  557. parent.decLength();
  558. while (parent.length()&&(parent.lastChar()!=PATHSEPCHAR))
  559. parent.decLength();
  560. if (parent.length()<=1)
  561. return;
  562. createDir(parent.str(),createdout);
  563. if (!createdout)
  564. return;
  565. #ifdef _WIN32
  566. createdout = WindowsCreateDirectory(name);
  567. #else
  568. createdout = LinuxCreateDirectory(name);
  569. #endif
  570. }
  571. void openDir(const char *dirname, const char *mask, bool recursive, bool includedirs, void *&outhandle)
  572. {
  573. outhandle = new cSimpleDir(dirname,mask,recursive,includedirs);
  574. }
  575. void nextDirEntry(void *handle, size_t maxfilenamesize, char *outfilename, bool &isdir, rfs_fpos_t &filesizeout, time_t &outmodifiedtime) // empty return for filename marks end
  576. {
  577. outfilename[0] = 0;
  578. if (handle)
  579. ((cSimpleDir *)handle)->next(maxfilenamesize,outfilename,isdir,filesizeout,outmodifiedtime);
  580. }
  581. void closeDir(void *handle)
  582. {
  583. delete ((cSimpleDir *)handle);
  584. }
  585. void getVersion(size_t programnamemax, char *programname, short &version)
  586. {
  587. safestrcpy(programname,"SimpleRFS",programnamemax);
  588. version = 1;
  589. }
  590. int run()
  591. {
  592. return RFS_ServerBase::run();
  593. }
  594. #ifdef ALLOW_WINDOWS_SERVICE
  595. void getServiceName(size_t maxname, char *outname, size_t maxdisplayname, char *outdisplayname)
  596. {
  597. safestrcpy(outname,"SimpleRFS",maxname);
  598. safestrcpy(outdisplayname,"RFS example",maxdisplayname);
  599. }
  600. int serviceInit(int argc, const char **argv, bool &outmulti)
  601. {
  602. // My initializtion here
  603. outmulti = false;
  604. return 0;
  605. }
  606. #endif
  607. };
  608. void usage()
  609. {
  610. printf("Usage: simplerfs { <option> }\n");
  611. printf("Options:\n");
  612. printf(" --port=<port>\n"); // --port handled by RFS_ServerBase
  613. }
  614. int main(int argc, const char **argv)
  615. {
  616. CSimpleRFS server;
  617. if (!server.init(argc,argv)) // this must be called first
  618. return 1;
  619. // my initialization here (NB Windows services won't reach here - use serviceInit for initialization code for these)
  620. return server.run();
  621. }