sqfs.c 22 KB

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