sqfs.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. /*
  2. ** LuaFileSystem
  3. ** Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem)
  4. **
  5. ** File system manipulation library.
  6. ** This library offers these functions:
  7. ** lfs.attributes (filepath [, attributename])
  8. ** lfs.chdir (path)
  9. ** lfs.currentdir ()
  10. ** lfs.dir (path)
  11. ** lfs.lock (fh, mode)
  12. ** lfs.lock_dir (path)
  13. ** lfs.mkdir (path)
  14. ** lfs.rmdir (path)
  15. ** lfs.setmode (filepath, mode)
  16. ** lfs.symlinkattributes (filepath [, attributename]) -- thanks to Sam Roberts
  17. ** lfs.touch (filepath [, atime [, mtime]])
  18. ** lfs.unlock (fh)
  19. **
  20. ** $Id: lfs.c,v 1.61 2009/07/04 02:10:16 mascarenhas Exp $
  21. *
  22. * Ported to Squirrel by Domingo Alvarez Duarte
  23. */
  24. #ifndef _WIN32
  25. #ifndef _AIX
  26. #define _FILE_OFFSET_BITS 64 /* Linux, Solaris and HP-UX */
  27. #else
  28. #define _LARGE_FILES 1 /* AIX */
  29. #endif
  30. #endif
  31. #define _LARGEFILE64_SOURCE
  32. #include <errno.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <stdlib.h>
  36. #include <time.h>
  37. #include <sys/stat.h>
  38. #ifdef _WIN32
  39. #include <direct.h>
  40. #include <windows.h>
  41. #include <io.h>
  42. #include <sys/locking.h>
  43. #ifdef __BORLANDC__
  44. #include <utime.h>
  45. #else
  46. #include <sys/utime.h>
  47. #endif
  48. #include <fcntl.h>
  49. #else
  50. #include <unistd.h>
  51. #include <dirent.h>
  52. #include <fcntl.h>
  53. #include <sys/types.h>
  54. #include <utime.h>
  55. #endif
  56. #include "squirrel.h"
  57. SQ_OPT_STRING_STRLEN();
  58. #include "sqfs.h"
  59. /* Define 'strerror' for systems that do not implement it */
  60. #ifdef NO_STRERROR
  61. #define strerror(_) "System unable to describe the error"
  62. #endif
  63. /* Define 'getcwd' for systems that do not implement it */
  64. #ifdef NO_GETCWD
  65. #define getcwd(p,s) NULL
  66. #define getcwd_error "Function 'getcwd' not provided by system"
  67. #else
  68. #define getcwd_error strerror(errno)
  69. #ifdef _WIN32
  70. /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
  71. #define LFS_MAXPATHLEN MAX_PATH
  72. #else
  73. /* For MAXPATHLEN: */
  74. #include <sys/param.h>
  75. #define LFS_MAXPATHLEN MAXPATHLEN
  76. #endif
  77. #endif
  78. #define DIR_METATABLE "directory metatable"
  79. typedef struct dir_data {
  80. int closed;
  81. #ifdef _WIN32
  82. long hFile;
  83. char pattern[MAX_PATH+1];
  84. #else
  85. DIR *dir;
  86. #endif
  87. } dir_data;
  88. #define LOCK_METATABLE "lock metatable"
  89. #ifdef _WIN32
  90. #ifdef __BORLANDC__
  91. #define lfs_setmode(L,file,m) ((void)L, setmode(_fileno(file), m))
  92. #define STAT_STRUCT struct stati64
  93. #else
  94. #define lfs_setmode(L,file,m) ((void)L, _setmode(_fileno(file), m))
  95. #define STAT_STRUCT struct _stati64
  96. #endif
  97. #define STAT_FUNC _stati64
  98. #define LSTAT_FUNC STAT_FUNC
  99. #else
  100. #define _O_TEXT 0
  101. #define _O_BINARY 0
  102. #define lfs_setmode(L,file,m) ((void)L, (void)file, (void)m, 0)
  103. #define STAT_STRUCT struct stat
  104. #define STAT_FUNC stat
  105. #define LSTAT_FUNC lstat
  106. #endif
  107. /*
  108. ** This function changes the working (current) directory
  109. */
  110. static int sqfs_chdir (HSQUIRRELVM v) {
  111. SQ_FUNC_VARS_NO_TOP(v);
  112. SQ_GET_STRING(v, 2, path);
  113. if (chdir(path)) {
  114. return sq_throwerror(v, "Unable to change working directory to '%s'\n%s\n",
  115. path, chdir_error);
  116. } else {
  117. sq_pushbool (v, SQTrue);
  118. return 1;
  119. }
  120. }
  121. /*
  122. ** This function returns the current directory
  123. ** If unable to get the current directory, it returns nil
  124. ** and a string describing the error
  125. */
  126. static int sqfs_currentdir (HSQUIRRELVM v) {
  127. SQChar *path;
  128. /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
  129. char buf[LFS_MAXPATHLEN];
  130. if ((path = getcwd(buf, LFS_MAXPATHLEN)) == NULL) {
  131. return sq_throwerror(v, getcwd_error);
  132. }
  133. else {
  134. sq_pushstring(v, buf, -1);
  135. return 1;
  136. }
  137. }
  138. #if 0
  139. /*
  140. ** Check if the given element on the stack is a file and returns it.
  141. */
  142. static FILE *check_file (HSQUIRRELVM v, int idx, const SQChar *funcname) {
  143. FILE **fh = (FILE **)luaL_checkudata (L, idx, "FILE*");
  144. if (fh == NULL) {
  145. return sq_throwerror(v, "%s: not a file", funcname);
  146. } else if (*fh == NULL) {
  147. return sq_throwerror(v, "%s: closed file", funcname);
  148. return 0;
  149. } else
  150. return *fh;
  151. }
  152. /*
  153. **
  154. */
  155. static int _file_lock (HSQUIRRELVM v, FILE *fh, const char *mode, const long start, long len, const char *funcname) {
  156. int code;
  157. #ifdef _WIN32
  158. /* lkmode valid values are:
  159. LK_LOCK Locks the specified bytes. If the bytes cannot be locked, the program immediately tries again after 1 second. If, after 10 attempts, the bytes cannot be locked, the constant returns an error.
  160. LK_NBLCK Locks the specified bytes. If the bytes cannot be locked, the constant returns an error.
  161. LK_NBRLCK Same as _LK_NBLCK.
  162. LK_RLCK Same as _LK_LOCK.
  163. LK_UNLCK Unlocks the specified bytes, which must have been previously locked.
  164. Regions should be locked only briefly and should be unlocked before closing a file or exiting the program.
  165. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp
  166. */
  167. int lkmode;
  168. switch (*mode) {
  169. case 'r': lkmode = LK_NBLCK; break;
  170. case 'w': lkmode = LK_NBLCK; break;
  171. case 'u': lkmode = LK_UNLCK; break;
  172. default : return sq_throwerror (v, "%s: invalid mode", funcname);
  173. }
  174. if (!len) {
  175. fseek (fh, 0L, SEEK_END);
  176. len = ftell (fh);
  177. }
  178. fseek (fh, start, SEEK_SET);
  179. code = _locking (fileno(fh), lkmode, len);
  180. #else
  181. struct flock f;
  182. switch (*mode) {
  183. case 'w': f.l_type = F_WRLCK; break;
  184. case 'r': f.l_type = F_RDLCK; break;
  185. case 'u': f.l_type = F_UNLCK; break;
  186. default : return sq_throwerror(v, "%s: invalid mode", funcname);
  187. }
  188. f.l_whence = SEEK_SET;
  189. f.l_start = (off_t)start;
  190. f.l_len = (off_t)len;
  191. code = fcntl (fileno(fh), F_SETLK, &f);
  192. #endif
  193. return (code != -1);
  194. }
  195. #ifdef _WIN32
  196. typedef struct sqfs_Lock {
  197. HANDLE fd;
  198. } lfs_Lock;
  199. static int sqfs_lock_dir(HSQUIRRELVM v) {
  200. SQ_FUNC_VARS_NO_TOP(v);
  201. SQ_GET_STRING(v, 2, path);
  202. HANDLE fd;
  203. lfs_Lock *lock;
  204. char *ln;
  205. const char *lockfile = "/lockfile.sqfs";
  206. ln = (char*)sq_malloc(path_size + strlen(lockfile) + 1);
  207. if(!ln) return sq_throwerror(v, strerror(errno));
  208. strcpy(ln, path); strcat(ln, lockfile);
  209. if((fd = CreateFile(ln, GENERIC_WRITE, 0, NULL, CREATE_NEW,
  210. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)) == INVALID_HANDLE_VALUE) {
  211. int en = GetLastError();
  212. free(ln);
  213. if(en == ERROR_FILE_EXISTS || en == ERROR_SHARING_VIOLATION)
  214. sq_pushliteral(v, "File exists");
  215. else
  216. sq_pushstring(v, strerror(en), -1);
  217. return 1;
  218. }
  219. free(ln);
  220. lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
  221. lock->fd = fd;
  222. luaL_getmetatable (L, LOCK_METATABLE);
  223. lua_setmetatable (L, -2);
  224. return 1;
  225. }
  226. static int sqfs_unlock_dir(HSQUIRRELVM v) {
  227. lfs_Lock *lock = luaL_checkudata(L, 1, LOCK_METATABLE);
  228. CloseHandle(lock->fd);
  229. return 0;
  230. }
  231. #else
  232. typedef struct sqfs_Lock {
  233. char *ln;
  234. } lfs_Lock;
  235. static int sqfs_lock_dir(HSQUIRRELVM v) {
  236. SQ_FUNC_VARS_NO_TOP(v);
  237. SQ_GET_STRING(v, 2, path);
  238. lfs_Lock *lock;
  239. char *ln;
  240. const char *lockfile = "/lockfile.sqfs";
  241. lock = (lfs_Lock*)lua_newuserdata(L, sizeof(sqfs_Lock));
  242. ln = (char*)sq_malloc(path_size + strlen(lockfile) + 1);
  243. if(!ln) return sq_throwerror(v, strerror(errno));
  244. strcpy(ln, path); strcat(ln, lockfile);
  245. if(symlink("lock", ln) == -1) {
  246. free(ln);
  247. return sq_throwerror(v, strerror(errno));
  248. }
  249. lock->ln = ln;
  250. luaL_getmetatable (L, LOCK_METATABLE);
  251. lua_setmetatable (L, -2);
  252. return 1;
  253. }
  254. static int lfs_unlock_dir(HSQUIRRELVM v) {
  255. lfs_Lock *lock = luaL_checkudata(L, 1, LOCK_METATABLE);
  256. if(lock->ln) {
  257. unlink(lock->ln);
  258. free(lock->ln);
  259. lock->ln = NULL;
  260. }
  261. return 0;
  262. }
  263. #endif
  264. #ifdef _WIN32
  265. static int lfs_g_setmode (HSQUIRRELVM v, FILE *f, int arg) {
  266. static const int mode[] = {_O_TEXT, _O_BINARY};
  267. static const char *const modenames[] = {"text", "binary", NULL};
  268. int op = luaL_checkoption(L, arg, NULL, modenames);
  269. int res = lfs_setmode(L, f, mode[op]);
  270. if (res != -1) {
  271. int i;
  272. lua_pushboolean(L, 1);
  273. for (i = 0; modenames[i] != NULL; i++) {
  274. if (mode[i] == res) {
  275. lua_pushstring(L, modenames[i]);
  276. goto exit;
  277. }
  278. }
  279. lua_pushnil(L);
  280. exit:
  281. return 2;
  282. } else {
  283. int en = errno;
  284. lua_pushnil(L);
  285. lua_pushfstring(L, "%s", strerror(en));
  286. lua_pushinteger(L, en);
  287. return 3;
  288. }
  289. }
  290. #else
  291. static int lfs_g_setmode (HSQUIRRELVM v, FILE *f, int arg) {
  292. return sq_throwerror(v, "setmode not supported on this platform");
  293. }
  294. #endif
  295. static int sqfs_setmode(HSQUIRRELVM v) {
  296. return lfs_g_setmode(v, check_file(v, 1, "setmode"), 2);
  297. }
  298. /*
  299. ** Locks a file.
  300. ** @param #1 File handle.
  301. ** @param #2 String with lock mode ('w'rite, 'r'ead).
  302. ** @param #3 Number with start position (optional).
  303. ** @param #4 Number with length (optional).
  304. */
  305. static int sqfs_lock (HSQUIRRELVM v) {
  306. SQ_FUNC_VARS(v);
  307. SQ_GET_STRING(v, 3, mode);
  308. SQ_OPT_INTEGER(v, 4, start, 0);
  309. SQ_OPT_INTEGER(v, 5, len, 0);
  310. FILE *fh = check_file (L, 1, SC("lock");
  311. if (_file_lock (v, fh, mode, start, len, _SC("lock")) {
  312. sq_pushbool (v, SQTrue);
  313. return 1;
  314. } else {
  315. return sq_throwerror(v, "%s", strerror(errno));
  316. }
  317. }
  318. /*
  319. ** Unlocks a file.
  320. ** @param #1 File handle.
  321. ** @param #2 Number with start position (optional).
  322. ** @param #3 Number with length (optional).
  323. */
  324. static int sqfs_unlock (HSQUIRRELVM v) {
  325. SQ_FUNC_VARS(v);
  326. SQ_OPT_INTEGER(v, 3, start, 0);
  327. SQ_OPT_INTEGER(v, 4, len, 0);
  328. FILE *fh = check_file (L, 1, "unlock");
  329. if (_file_lock (v, fh, "u", start, len, "unlock")) {
  330. sq_pushbool (v, SQTrue);
  331. return 1;
  332. } else {
  333. return sq_throwerror (v, "%s", strerror(errno));
  334. }
  335. }
  336. #endif
  337. /*
  338. ** Creates a link.
  339. ** @param #1 Object to link to.
  340. ** @param #2 Name of link.
  341. ** @param #3 True if link is symbolic (optional).
  342. */
  343. static int sqfs_link(HSQUIRRELVM v)
  344. {
  345. #ifndef _WIN32
  346. SQ_FUNC_VARS(v);
  347. SQ_GET_STRING(v, 2, oldpath);
  348. SQ_GET_STRING(v, 3, newpath);
  349. SQ_OPT_BOOL(v, 4, bsym, SQFalse);
  350. sq_pushinteger(v, (bsym ? symlink : link)(oldpath, newpath));
  351. return 1;
  352. #else
  353. return sq_throwerror(v, "make_link is not supported on Windows");
  354. #endif
  355. }
  356. static int sqfs_mkdir (HSQUIRRELVM v) {
  357. SQ_FUNC_VARS_NO_TOP(v);
  358. SQ_GET_STRING(v, 2, path);
  359. int fail;
  360. #ifdef _WIN32
  361. int oldmask = umask (0);
  362. fail = _mkdir (path);
  363. #else
  364. mode_t oldmask = umask( (mode_t)0 );
  365. fail = mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
  366. S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH );
  367. #endif
  368. if (fail) {
  369. return sq_throwerror (v, "%s", strerror(errno));
  370. }
  371. umask (oldmask);
  372. sq_pushbool (v, SQTrue);
  373. return 1;
  374. }
  375. /*
  376. ** Removes a directory.
  377. ** @param #1 Directory path.
  378. */
  379. static int sqfs_rmdir (HSQUIRRELVM v) {
  380. SQ_FUNC_VARS_NO_TOP(v);
  381. SQ_GET_STRING(v, 2, path);
  382. int fail;
  383. fail = rmdir (path);
  384. if (fail) {
  385. return sq_throwerror (v, "%s", strerror(errno));
  386. }
  387. sq_pushbool (v, SQTrue);
  388. return 1;
  389. }
  390. static const SQChar SQFS_DIR_TAG[] = _SC("sqfs_dir_tag");
  391. #define GET_dir_INSTANCE() SQ_GET_INSTANCE(v, 1, dir_data, SQFS_DIR_TAG)
  392. static void _dir_close_dir(dir_data *dir)
  393. {
  394. #ifdef _WIN32
  395. if (!dir->closed && dir->hFile) {
  396. _findclose (dir->hFile);
  397. }
  398. #else
  399. if (!dir->closed && dir->dir) {
  400. closedir (dir->dir);
  401. }
  402. #endif
  403. dir->closed = 1;
  404. }
  405. static SQRESULT _dir_releasehook(SQUserPointer p, SQInteger size)
  406. {
  407. dir_data *dir = ((dir_data *)p);
  408. _dir_close_dir(dir);
  409. sq_free(dir, sizeof(dir_data));
  410. return 0;
  411. }
  412. static SQRESULT _dir_constructor(HSQUIRRELVM v)
  413. {
  414. SQ_FUNC_VARS_NO_TOP(v);
  415. SQ_GET_STRING(v, 2, path);
  416. dir_data *dir = (dir_data*)sq_malloc(sizeof(dir_data));
  417. dir->closed = 0;
  418. #ifdef _WIN32
  419. dir->hFile = 0L;
  420. if (strlen(path) > MAX_PATH-2)
  421. return sq_throwerror(v, "path too long: %s", path);
  422. else
  423. scsnprintf (dir->pattern, sizeof(dir->pattern), "%s/*", path);
  424. #else
  425. dir->dir = opendir (path);
  426. if (dir->dir == NULL)
  427. return sq_throwerror(v, "cannot open %s: %s", path, strerror (errno));
  428. #endif
  429. sq_setinstanceup(v, 1, dir); //replace self for this instance with this new sqlite3_stmt
  430. sq_setreleasehook(v,1, _dir_releasehook);
  431. return 1;
  432. }
  433. static SQRESULT _dir_close(HSQUIRRELVM v)
  434. {
  435. SQ_FUNC_VARS_NO_TOP(v);
  436. GET_dir_INSTANCE();
  437. _dir_close_dir(self);
  438. return 0;
  439. }
  440. static SQRESULT _dir__get(HSQUIRRELVM v)
  441. {
  442. SQ_FUNC_VARS_NO_TOP(v);
  443. GET_dir_INSTANCE();
  444. sq_pushuserpointer(v, self);
  445. if(sq_getonregistrytable(v) != SQ_OK) sq_pushnull(v);
  446. //do not worry about registry table it will be removed anyway when restoring the stack
  447. return 1;
  448. }
  449. static SQRESULT _dir__nexti(HSQUIRRELVM v)
  450. {
  451. SQ_FUNC_VARS_NO_TOP(v);
  452. GET_dir_INSTANCE();
  453. SQInteger idx;
  454. if(sq_gettype(v,2) == OT_NULL) idx = 0;
  455. else
  456. {
  457. if(!SQ_SUCCEEDED(sq_getinteger(v, 2, &idx)))
  458. return sq_throwerror(v,_SC("internal error (_nexti) wrong argument type"));
  459. ++idx;
  460. }
  461. #ifdef _WIN32
  462. struct _finddata_t c_file;
  463. #else
  464. struct dirent *entry;
  465. #endif
  466. const char *fname;
  467. if(self->closed) return sq_throwerror(v, "closed directory");
  468. #ifdef _WIN32
  469. if (self->hFile == 0L) { /* first entry */
  470. if ((self->hFile = _findfirst (self->pattern, &c_file)) == -1L) {
  471. self->closed = 1;
  472. return sq_throwerror(v, strerror (errno));
  473. }
  474. } else { /* next entry */
  475. if (_findnext (self->hFile, &c_file) == -1L) {
  476. /* no more entries => close directory */
  477. _findclose (self->hFile);
  478. self->closed = 1;
  479. sq_pushnull(v);
  480. return 1;
  481. }
  482. }
  483. fname = c_file.name;
  484. #else
  485. if ((entry = readdir (self->dir)) == NULL) {
  486. /* no more entries => close directory */
  487. closedir (self->dir);
  488. self->closed = 1;
  489. sq_pushnull(v);
  490. return 1;
  491. }
  492. fname = entry->d_name;
  493. #endif
  494. sq_pushuserpointer(v, self);
  495. sq_pushstring(v, fname, -1);
  496. sq_setonregistrytable(v);
  497. sq_pushinteger(v, idx);
  498. return 1;
  499. }
  500. #define _DECL_DIR_FUNC(name,nparams,typecheck) {_SC(#name),_dir_##name,nparams,typecheck}
  501. static SQRegFunction _dir_methods[] = {
  502. _DECL_DIR_FUNC(constructor,-1,_SC("xs")),
  503. _DECL_DIR_FUNC(close,1,_SC("x")),
  504. _DECL_DIR_FUNC(_nexti,2,_SC("x.")),
  505. _DECL_DIR_FUNC(_get,2,_SC("xn")),
  506. {0,0,0,0}
  507. };
  508. #ifdef _WIN32
  509. #ifndef S_ISDIR
  510. #define S_ISDIR(mode) (mode&_S_IFDIR)
  511. #endif
  512. #ifndef S_ISREG
  513. #define S_ISREG(mode) (mode&_S_IFREG)
  514. #endif
  515. #ifndef S_ISLNK
  516. #define S_ISLNK(mode) (0)
  517. #endif
  518. #ifndef S_ISSOCK
  519. #define S_ISSOCK(mode) (0)
  520. #endif
  521. #ifndef S_ISFIFO
  522. #define S_ISFIFO(mode) (0)
  523. #endif
  524. #ifndef S_ISCHR
  525. #define S_ISCHR(mode) (mode&_S_IFCHR)
  526. #endif
  527. #ifndef S_ISBLK
  528. #define S_ISBLK(mode) (0)
  529. #endif
  530. #endif
  531. /*
  532. ** Convert the inode protection mode to a string.
  533. */
  534. #ifdef _WIN32
  535. static const SQChar *mode2string (unsigned short mode) {
  536. #else
  537. static const SQChar *mode2string (mode_t mode) {
  538. #endif
  539. if ( S_ISREG(mode) )
  540. return _SC("file");
  541. else if ( S_ISDIR(mode) )
  542. return _SC("directory");
  543. else if ( S_ISLNK(mode) )
  544. return _SC("link");
  545. else if ( S_ISSOCK(mode) )
  546. return _SC("socket");
  547. else if ( S_ISFIFO(mode) )
  548. return _SC("named pipe");
  549. else if ( S_ISCHR(mode) )
  550. return _SC("char device");
  551. else if ( S_ISBLK(mode) )
  552. return _SC("block device");
  553. else
  554. return _SC("other");
  555. }
  556. /*
  557. ** Set access time and modification values for file
  558. */
  559. static int sqfs_touch (HSQUIRRELVM v) {
  560. SQ_FUNC_VARS(v);
  561. SQ_GET_STRING(v, 2, file);
  562. struct utimbuf utb, *buf;
  563. if (_top_ == 2) /* set to current date/time */
  564. buf = NULL;
  565. else {
  566. SQ_OPT_INTEGER(v, 3, actime, 0);
  567. SQ_OPT_INTEGER(v, 4, modtime, actime);
  568. utb.actime = (time_t)actime;
  569. utb.modtime = (time_t)modtime;
  570. buf = &utb;
  571. }
  572. if (utime (file, buf)) {
  573. return sq_throwerror(v, "%s", strerror (errno));
  574. }
  575. sq_pushbool (v, SQTrue);
  576. return 1;
  577. }
  578. /* inode protection mode */
  579. static void push_st_mode (HSQUIRRELVM v, STAT_STRUCT *info) {
  580. sq_pushstring (v, mode2string (info->st_mode), -1);
  581. }
  582. /* device inode resides on */
  583. static void push_st_dev (HSQUIRRELVM v, STAT_STRUCT *info) {
  584. sq_pushinteger (v, (SQInteger)info->st_dev);
  585. }
  586. /* inode's number */
  587. static void push_st_ino (HSQUIRRELVM v, STAT_STRUCT *info) {
  588. sq_pushinteger (v, (SQInteger)info->st_ino);
  589. }
  590. /* number of hard links to the file */
  591. static void push_st_nlink (HSQUIRRELVM v, STAT_STRUCT *info) {
  592. sq_pushinteger (v, (SQInteger)info->st_nlink);
  593. }
  594. /* user-id of owner */
  595. static void push_st_uid (HSQUIRRELVM v, STAT_STRUCT *info) {
  596. sq_pushinteger (v, (SQInteger)info->st_uid);
  597. }
  598. /* group-id of owner */
  599. static void push_st_gid (HSQUIRRELVM v, STAT_STRUCT *info) {
  600. sq_pushinteger (v, (SQInteger)info->st_gid);
  601. }
  602. /* device type, for special file inode */
  603. static void push_st_rdev (HSQUIRRELVM v, STAT_STRUCT *info) {
  604. sq_pushinteger (v, (SQInteger)info->st_rdev);
  605. }
  606. /* time of last access */
  607. static void push_st_atime (HSQUIRRELVM v, STAT_STRUCT *info) {
  608. sq_pushinteger (v, info->st_atime);
  609. }
  610. /* time of last data modification */
  611. static void push_st_mtime (HSQUIRRELVM v, STAT_STRUCT *info) {
  612. sq_pushinteger (v, info->st_mtime);
  613. }
  614. /* time of last file status change */
  615. static void push_st_ctime (HSQUIRRELVM v, STAT_STRUCT *info) {
  616. sq_pushinteger (v, info->st_ctime);
  617. }
  618. /* file size, in bytes */
  619. static void push_st_size (HSQUIRRELVM v, STAT_STRUCT *info) {
  620. sq_pushinteger (v, (SQInteger)info->st_size);
  621. }
  622. #ifndef _WIN32
  623. /* blocks allocated for file */
  624. static void push_st_blocks (HSQUIRRELVM v, STAT_STRUCT *info) {
  625. sq_pushinteger (v, (SQInteger)info->st_blocks);
  626. }
  627. /* optimal file system I/O blocksize */
  628. static void push_st_blksize (HSQUIRRELVM v, STAT_STRUCT *info) {
  629. sq_pushinteger (v, (SQInteger)info->st_blksize);
  630. }
  631. #endif
  632. static void push_invalid (HSQUIRRELVM v, STAT_STRUCT *info) {
  633. sq_throwerror(v, "invalid attribute name");
  634. #ifndef _WIN32
  635. info->st_blksize = 0; /* never reached */
  636. #endif
  637. }
  638. typedef void (*_push_function) (HSQUIRRELVM v, STAT_STRUCT *info);
  639. struct _stat_members {
  640. const char *name;
  641. _push_function push;
  642. };
  643. struct _stat_members members[] = {
  644. { "mode", push_st_mode },
  645. { "dev", push_st_dev },
  646. { "ino", push_st_ino },
  647. { "nlink", push_st_nlink },
  648. { "uid", push_st_uid },
  649. { "gid", push_st_gid },
  650. { "rdev", push_st_rdev },
  651. { "access", push_st_atime },
  652. { "modification", push_st_mtime },
  653. { "change", push_st_ctime },
  654. { "size", push_st_size },
  655. #ifndef _WIN32
  656. { "blocks", push_st_blocks },
  657. { "blksize", push_st_blksize },
  658. #endif
  659. { NULL, push_invalid }
  660. };
  661. /*
  662. ** Get file or symbolic link information
  663. */
  664. static int _file_info_ (HSQUIRRELVM v, int (*st)(const SQChar*, STAT_STRUCT*)) {
  665. SQ_FUNC_VARS(v);
  666. SQ_GET_STRING(v, 2, file);
  667. int i;
  668. STAT_STRUCT info;
  669. if (st(file, &info)) {
  670. return sq_throwerror(v, "cannot obtain information from file `%s'", file);
  671. }
  672. if(_top_ > 2){
  673. int ptype = sq_gettype(v, 3);
  674. if (ptype == OT_STRING) {
  675. int iv;
  676. SQ_GET_STRING(v, 3, member);
  677. if (strcmp (member, "mode") == 0) iv = 0;
  678. #ifndef _WIN32
  679. else if (strcmp (member, "blocks") == 0) iv = 11;
  680. else if (strcmp (member, "blksize") == 0) iv = 12;
  681. #endif
  682. else /* look for member */
  683. for (iv = 1; members[iv].name; iv++)
  684. if (*members[iv].name == *member)
  685. break;
  686. /* push member value and return */
  687. members[iv].push (v, &info);
  688. return 1;
  689. } else if (ptype != OT_TABLE)
  690. /* creates a table if none is given */
  691. sq_newtable (v);
  692. }
  693. else sq_newtable (v);
  694. /* stores all members in table on top of the stack */
  695. for (i = 0; members[i].name; i++) {
  696. sq_pushstring (v, members[i].name, -1);
  697. members[i].push (v, &info);
  698. sq_rawset (v, -3);
  699. }
  700. return 1;
  701. }
  702. /*
  703. ** Get file information using stat.
  704. */
  705. static int sqfs_attributes (HSQUIRRELVM v) {
  706. return _file_info_ (v, STAT_FUNC);
  707. }
  708. /*
  709. ** Get symbolic link information using lstat.
  710. */
  711. #ifndef _WIN32
  712. static int sqfs_symlinkattributes (HSQUIRRELVM v) {
  713. return _file_info_ (v, LSTAT_FUNC);
  714. }
  715. #else
  716. static int sqfs_symlinkattributes (HSQUIRRELVM v) {
  717. sq_pushliteral(v, "symlinkattributes not supported on this platform");
  718. return 1;
  719. }
  720. #endif
  721. /*
  722. ** Assumes the table is on top of the stack.
  723. */
  724. static void set_info (HSQUIRRELVM v) {
  725. sq_pushliteral (v, "_COPYRIGHT");
  726. sq_pushliteral (v, "Copyright (C) Copyright (C) 2003-2012 Kepler Project, Domingo Alvarez Duarte");
  727. sq_rawset (v, -3);
  728. sq_pushliteral (v, "_DESCRIPTION");
  729. sq_pushliteral (v, "LuaFileSystem is a Lua library developed to complement the set of"
  730. " functions related to file systems offered by the standard Lua distribution"
  731. ", adapted to Squirrel by Domingo Alvarez Duarte");
  732. sq_rawset (v, -3);
  733. sq_pushliteral (v, "_VERSION");
  734. sq_pushliteral (v, "LuaFileSystem 1.61");
  735. sq_rawset (v, -3);
  736. }
  737. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sqfs_##name,nparams,tycheck}
  738. static SQRegFunction sqfs_methods[] =
  739. {
  740. _DECL_FUNC(attributes, -2, _SC(".ss")),
  741. _DECL_FUNC(chdir, 2, _SC(".s")),
  742. _DECL_FUNC(currentdir, 1, _SC(".")),
  743. /*
  744. _DECL_FUNC(lock, -3, _SC("xsii")),
  745. */
  746. _DECL_FUNC(link, -3, _SC(".ssb")),
  747. _DECL_FUNC(mkdir, 2, _SC(".s")),
  748. _DECL_FUNC(rmdir, 2, _SC(".s")),
  749. _DECL_FUNC(symlinkattributes, -2, _SC(".ss")),
  750. // _DECL_FUNC(setmode, 3, _SC(".ss")),
  751. _DECL_FUNC(touch, -2, _SC(".sii")),
  752. /*
  753. _DECL_FUNC(unlock, -2, _SC(".sii")),
  754. _DECL_FUNC(lock_dir, -2, _SC(".si")),
  755. */
  756. {0,0}
  757. };
  758. #ifdef __cplusplus
  759. extern "C" {
  760. #endif
  761. SQRESULT sqstd_register_sqfs(HSQUIRRELVM v)
  762. {
  763. sq_pushstring(v,_SC("sqfs"),-1);
  764. sq_newtable(v);
  765. set_info(v);
  766. sq_insert_reg_funcs(v, sqfs_methods);
  767. sq_pushliteral(v, _SC("dir"));
  768. sq_newclass(v, SQFalse);
  769. sq_settypetag(v,-1,(void*)SQFS_DIR_TAG);
  770. sq_insert_reg_funcs(v, _dir_methods);
  771. sq_newslot(v,-3,SQTrue);
  772. sq_newslot(v,-3,SQTrue);
  773. return 1;
  774. }
  775. #ifdef __cplusplus
  776. }
  777. #endif