1
37
38# include "../lua/lmtinterface.h"
39# include "../utilities/auxmemory.h"
40# include "../utilities/auxfile.h"
41
42# ifndef R_OK
43# define F_OK 0x0
44# define W_OK 0x2
45# define R_OK 0x4
46# endif
47
48# define DIR_METATABLE "file.directory"
49
50# ifndef _WIN32
51 # ifndef _FILE_OFFSET_BITS
52 # define _FILE_OFFSET_BITS 64
53 # endif
54# endif
55
56# ifdef _WIN32
57 # ifndef WINVER
58 # define WINVER 0x0601
59 # undef _WIN32_WINNT
60 # define _WIN32_WINNT 0x0601
61 # endif
62# endif
63
64
65 # define _LARGEFILE64_SOURCE 1
66
67
68# include <errno.h>
69# include <stdio.h>
70# include <string.h>
71# include <stdlib.h>
72# include <time.h>
73# include <sys/stat.h>
74
75
76
77
78
79
80
81# ifdef _WIN32
82
83 # include <direct.h>
84 # include <windows.h>
85 # include <io.h>
86 # include <fileapi.h>
87 # include <sys/locking.h>
88 # include <sys/utime.h>
89 # include <fcntl.h>
90
91
96
97 # ifdef MAX_PATH
98 # define MY_MAXPATHLEN MAX_PATH
99 # else
100 # define MY_MAXPATHLEN 255
101 # endif
102
103# else
104
105
106
107 # include <unistd.h>
108 # include <dirent.h>
109 # include <fcntl.h>
110 # include <sys/types.h>
111 # include <utime.h>
112 # include <sys/param.h>
113
114 # ifdef MAXPATHLEN
115 # define MY_MAXPATHLEN MAXPATHLEN
116 # else
117 # define MY_MAXPATHLEN 255
118 # endif
119
120# endif
121
122
123
124# ifdef _WIN32
125
126 # ifndef S_ISDIR
127 # define S_ISDIR(mode) (mode & _S_IFDIR)
128 # endif
129
130 # ifndef S_ISREG
131 # define S_ISREG(mode) (mode & _S_IFREG)
132 # endif
133
134 # ifndef S_ISLNK
135 # define S_ISLNK(mode) (0)
136 # endif
137
138 # ifndef S_ISSUB
139 # define S_ISSUB(mode) (file_data.attrib & _A_SUBDIR)
140 # endif
141
142 # define info_struct struct _stati64
143 # define utime_struct struct __utimbuf64
144
145 # define exec_mode_flag _S_IEXEC
146
147
151
152
161
162 typedef struct dir_data {
163 intptr_t handle;
164 int closed;
165 char pattern[MY_MAXPATHLEN+1];
166 } dir_data;
167
168 static int get_stat(const char *s, info_struct *i)
169 {
170 LPWSTR w = aux_utf8_to_wide(s);
171 int r = _wstati64(w, i);
172 lmt_memory_free(w);
173 return r;
174 }
175
176 static int mk_dir(const char *s)
177 {
178 LPWSTR w = aux_utf8_to_wide(s);
179 int r = _wmkdir(w);
180 lmt_memory_free(w);
181 return r;
182 }
183
184 static int ch_dir(const char *s)
185 {
186 LPWSTR w = aux_utf8_to_wide(s);
187 int r = _wchdir(w);
188 lmt_memory_free(w);
189 return r;
190 }
191
192 static int rm_dir(const char *s)
193 {
194 LPWSTR w = aux_utf8_to_wide(s);
195 int r = _wrmdir(w);
196 lmt_memory_free(w);
197 return r;
198 }
199
200
201
202
203
204 static int mk_symlink(const char *t, const char *f)
205 {
206 LPWSTR wt = aux_utf8_to_wide(t);
207 LPWSTR wf = aux_utf8_to_wide(f);
208 int r = CreateSymbolicLinkW((LPCWSTR) t, (LPCWSTR) f, 0x2) != 0;
209 lmt_memory_free(wt);
210 lmt_memory_free(wf);
211 return r;
212 }
213
214 static int mk_link(const char *t, const char *f)
215 {
216 LPWSTR wt = aux_utf8_to_wide(t);
217 LPWSTR wf = aux_utf8_to_wide(f);
218 int r = CreateSymbolicLinkW((LPCWSTR) t, (LPCWSTR) f, 0x3) != 0;
219 lmt_memory_free(wt);
220 lmt_memory_free(wf);
221 return r;
222 }
223
224 static int ch_to_exec(const char *s, int n)
225 {
226 LPWSTR w = aux_utf8_to_wide(s);
227 int r = _wchmod(w, n);
228 lmt_memory_free(w);
229 return r;
230 }
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249 static int set_utime(const char *s, utime_struct *b)
250 {
251 LPWSTR w = aux_utf8_to_wide(s);
252 int r = _wutime64(w, b);
253 lmt_memory_free(w);
254 return r;
255 }
256
257
258
259# else
260
261 # define info_struct struct stat
262 # define utime_struct struct utimbuf
263
264 typedef struct dir_data {
265 DIR *handle;
266 int closed;
267 char pattern[MY_MAXPATHLEN+1];
268 } dir_data;
269
270 # define get_stat stat
271 # define mk_dir(p) (mkdir((p), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH))
272 # define ch_dir chdir
273 # define get_cwd getcwd
274 # define rm_dir rmdir
275 # define mk_symlink(f,t) (symlink(f,t) != -1)
276 # define mk_link(f,t) (link(f,t) != -1)
277 # define ch_to_exec(f,n) (chmod(f,n))
278 # define exec_mode_flag S_IXUSR | S_IXGRP | S_IXOTH
279 # define set_utime(f,b) utime(f,b)
280
281# endif
282
283# include <lua.h>
284# include <lauxlib.h>
285# include <lualib.h>
286
287
292
293static int filelib_chdir(lua_State *L) {
294 if (lua_type(L, 1) == LUA_TSTRING) {
295 lua_pushboolean(L, ! ch_dir(luaL_checkstring(L, 1)));
296 } else {
297 lua_pushboolean(L, 0);
298 }
299 return 1;
300}
301
302
307
308# ifdef _WIN32
309
310 static int filelib_currentdir(lua_State *L)
311 {
312 LPWSTR wpath = NULL;
313 int size = 256;
314 while (1) {
315 LPWSTR temp = lmt_memory_realloc(wpath, size * sizeof(WCHAR));
316 wpath = temp;
317 if (! wpath) {
318 lua_pushboolean(L, 0);
319 break;
320 } else if (_wgetcwd(wpath, size)) {
321 char *path = aux_utf8_from_wide(wpath);
322 lua_pushstring(L, path);
323 lmt_memory_free(path);
324 break;
325 } else if (errno != ERANGE) {
326 lua_pushboolean(L, 0);
327 break;
328 } else {
329 size *= 2;
330 }
331 }
332 lmt_memory_free(wpath);
333 return 1;
334 }
335
336# else
337
338 static int filelib_currentdir(lua_State *L)
339 {
340 char *path = NULL;
341 size_t size = MY_MAXPATHLEN;
342 while (1) {
343 path = lmt_memory_realloc(path, size);
344 if (! path) {
345 lua_pushboolean(L,0);
346 break;
347 }
348 if (get_cwd(path, size)) {
349 lua_pushstring(L, path);
350 break;
351 }
352 if (errno != ERANGE) {
353 lua_pushboolean(L,0);
354 break;
355 }
356 size *= 2;
357 }
358 lmt_memory_free(path);
359 return 1;
360 }
361
362# endif
363
364
370
371static int filelib_link(lua_State *L)
372{
373 if (lua_type(L, 1) == LUA_TSTRING && lua_type(L, 2) == LUA_TSTRING) {
374 const char *oldpath = lua_tostring(L, 1);
375 const char *newpath = lua_tostring(L, 2);
376 lua_pushboolean(L, lua_toboolean(L, 3) ? mk_symlink(oldpath, newpath) : mk_link(oldpath, newpath));
377 } else {
378 lua_pushboolean(L, 0);
379 }
380 return 1;
381}
382
383static int filelib_symlink(lua_State *L)
384{
385 if (lua_type(L, 1) == LUA_TSTRING && lua_type(L, 2) == LUA_TSTRING) {
386 const char *oldpath = lua_tostring(L, 1);
387 const char *newpath = lua_tostring(L, 2);
388 lua_pushboolean(L, mk_symlink(oldpath, newpath));
389 } else {
390 lua_pushboolean(L, 0);
391 }
392 return 1;
393}
394
395
400
401static int filelib_mkdir(lua_State *L)
402{
403 if (lua_type(L, 1) == LUA_TSTRING) {
404 lua_pushboolean(L, mk_dir(lua_tostring(L, 1)) != -1);
405 } else {
406 lua_pushboolean(L, 0);
407 }
408 return 1;
409}
410
411
416
417static int filelib_rmdir(lua_State *L)
418{
419 if (lua_type(L, 1) == LUA_TSTRING) {
420 lua_pushboolean(L, rm_dir(luaL_checkstring(L, 1)) != -1);
421 } else {
422 lua_pushboolean(L, 0);
423 }
424 return 1;
425}
426
427
435
436# ifdef _WIN32
437
438 inline static int push_entry(lua_State *L, struct _wfinddata_t file_data, int details)
439 {
440 char *s = aux_utf8_from_wide(file_data.name);
441 lua_pushstring(L, s);
442 lmt_memory_free(s);
443 if (S_ISSUB(file_data.attrib)) {
444 lua_push_key(directory);
445 } else {
446 lua_push_key(file);
447 }
448 if (details) {
449 lua_pushinteger(L, file_data.size);
450 lua_pushinteger(L, file_data.time_write);
451 return 4;
452 } else {
453 return 2;
454 }
455 }
456
457 static int filelib_aux_dir_iterator(lua_State *L)
458 {
459 struct _wfinddata_t file_data;
460 int details = 1;
461 dir_data *d = (dir_data *) luaL_checkudata(L, 1, DIR_METATABLE);
462 lua_getiuservalue(L, 1, 1);
463 details = lua_toboolean(L, -1);
464 lua_pop(L, 1);
465 luaL_argcheck(L, d->closed == 0, 1, "closed directory");
466 if (d->handle == 0L) {
467
468 LPWSTR s = aux_utf8_to_wide(d->pattern);
469 if ((d->handle = _wfindfirst(s, &file_data)) == -1L) {
470 d->closed = 1;
471 lmt_memory_free(s);
472 return 0;
473 } else {
474 lmt_memory_free(s);
475 return push_entry(L, file_data, details);
476 }
477 } else if (_wfindnext(d->handle, &file_data) == -1L) {
478
479
480 _findclose(d->handle);
481 d->closed = 1;
482 return 0;
483 } else {
484
485 return push_entry(L, file_data, details);
486 }
487 }
488
489 static int filelib_aux_dir_close(lua_State *L)
490 {
491 dir_data *d = (dir_data *) lua_touserdata(L, 1);
492 if (!d->closed && d->handle) {
493 _findclose(d->handle);
494 }
495 d->closed = 1;
496 return 0;
497 }
498
499 static int filelib_dir(lua_State *L)
500 {
501 const char *path = luaL_checkstring(L, 1);
502 int detail = lua_type(L, 2) == LUA_TBOOLEAN ? lua_toboolean(L, 2) : 1;
503 dir_data *d ;
504 lua_pushcfunction(L, filelib_aux_dir_iterator);
505 d = (dir_data *) lua_newuserdatauv(L, sizeof(dir_data), 1);
506 lua_pushboolean(L, detail);
507 lua_setiuservalue(L, -2, 1);
508 luaL_getmetatable(L, DIR_METATABLE);
509 lua_setmetatable(L, -2);
510 d->closed = 0;
511 d->handle = 0L;
512 if (path && strlen(path) > MY_MAXPATHLEN-2) {
513 luaL_error(L, "path too long: %s", path);
514 } else {
515 sprintf(d->pattern, "%s/*", path ? path : ".");
516 }
517 return 2;
518 }
519
520# else
521
522
532
533 static int filelib_aux_dir_iterator(lua_State *L)
534 {
535 struct dirent *entry;
536 dir_data *d;
537 int details = 1;
538 lua_pushcfunction(L, filelib_aux_dir_iterator);
539 d = (dir_data *) luaL_checkudata(L, 1, DIR_METATABLE);
540 lua_getiuservalue(L, 1, 1);
541 details = lua_toboolean(L, -1);
542 lua_pop(L, 1);
543 luaL_argcheck(L, d->closed == 0, 1, "closed directory");
544 entry = readdir (d->handle);
545 if (entry) {
546 lua_pushstring(L, entry->d_name);
547# ifdef _DIRENT_HAVE_D_TYPE
548 if (! details) {
549 if (entry->d_type == DT_DIR) {
550 lua_push_key(directory);
551 return 2;
552 } else if (entry->d_type == DT_REG) {
553 lua_push_key(file);
554 return 2;
555 }
556 }
557# endif
558
559 {
560 info_struct info;
561 char file_path[2*MY_MAXPATHLEN];
562 snprintf(file_path, 2*MY_MAXPATHLEN, "%s/%s", d->pattern, entry->d_name);
563 if (! get_stat(file_path, &info)) {
564 if (S_ISDIR(info.st_mode)) {
565 lua_push_key(directory);
566 } else if (S_ISREG(info.st_mode) || S_ISLNK(info.st_mode)) {
567 lua_push_key(file);
568 } else {
569 lua_pushnil(L);
570 return 2;
571 }
572 if (details) {
573 lua_pushinteger(L, info.st_size);
574 lua_pushinteger(L, info.st_mtime);
575 return 4;
576 }
577 } else {
578 lua_pushnil(L);
579 }
580 return 2;
581 }
582 } else {
583 closedir(d->handle);
584 d->closed = 1;
585 return 0;
586 }
587 }
588
589 static int filelib_aux_dir_close(lua_State *L)
590 {
591 dir_data *d = (dir_data *) lua_touserdata(L, 1);
592 if (!d->closed && d->handle) {
593 closedir(d->handle);
594 }
595 d->closed = 1;
596 return 0;
597 }
598
599 static int filelib_dir(lua_State *L)
600 {
601 const char *path = luaL_checkstring(L, 1);
602 dir_data *d;
603 lua_pushcfunction(L, filelib_aux_dir_iterator);
604 d = (dir_data *) lua_newuserdatauv(L, sizeof(dir_data), 1);
605 lua_pushboolean(L, lua_type(L, 2) == LUA_TBOOLEAN ? lua_toboolean(L, 2) : 1);
606 lua_setiuservalue(L, -2, 1);
607 luaL_getmetatable(L, DIR_METATABLE);
608 lua_setmetatable(L, -2);
609 d->closed = 0;
610 d->handle = opendir(path ? path : ".");
611 if (! d->handle) {
612 luaL_error(L, "cannot open %s: %s", path, strerror(errno));
613 }
614 snprintf(d->pattern, MY_MAXPATHLEN, "%s", path ? path : ".");
615 return 2;
616 }
617
618# endif
619
620static int dir_create_meta(lua_State *L)
621{
622 luaL_newmetatable(L, DIR_METATABLE);
623 lua_newtable(L);
624 lua_pushcfunction(L, filelib_aux_dir_iterator);
625 lua_setfield(L, -2, "next");
626 lua_pushcfunction(L, filelib_aux_dir_close);
627 lua_setfield(L, -2, "close");
628 lua_setfield(L, -2, "__index");
629 lua_pushcfunction(L, filelib_aux_dir_close);
630 lua_setfield(L, -2, "__gc");
631 return 1;
632}
633
634# define mode2string(mode) \
635 ((S_ISREG(mode)) ? "file" : ((S_ISDIR(mode)) ? "directory" : ((S_ISLNK(mode)) ? "link" : "other")))
636
637
638
639# ifdef _WIN32
640
641 static const char *perm2string(unsigned short mode)
642 {
643 static char perms[10] = "---------";
644
645 for (int i = 0; i < 9; i++) {
646 perms[i]='-';
647 }
648 if (mode & _S_IREAD) { perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; }
649 if (mode & _S_IWRITE) { perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; }
650 if (mode & _S_IEXEC) { perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; }
651 return perms;
652 }
653
654# else
655
656 static const char *perm2string(mode_t mode)
657 {
658 static char perms[10] = "---------";
659
660 for (int i = 0; i < 9; i++) {
661 perms[i]='-';
662 }
663 if (mode & S_IRUSR) perms[0] = 'r';
664 if (mode & S_IWUSR) perms[1] = 'w';
665 if (mode & S_IXUSR) perms[2] = 'x';
666 if (mode & S_IRGRP) perms[3] = 'r';
667 if (mode & S_IWGRP) perms[4] = 'w';
668 if (mode & S_IXGRP) perms[5] = 'x';
669 if (mode & S_IROTH) perms[6] = 'r';
670 if (mode & S_IWOTH) perms[7] = 'w';
671 if (mode & S_IXOTH) perms[8] = 'x';
672 return perms;
673 }
674
675# endif
676
677
684
685static int filelib_touch(lua_State *L)
686{
687 if (lua_type(L, 1) == LUA_TSTRING) {
688 const char *file = luaL_checkstring(L, 1);
689 utime_struct utb, *buf;
690 if (lua_gettop(L) == 1) {
691 buf = NULL;
692 } else {
693 utb.actime = (time_t) luaL_optinteger(L, 2, 0);
694 utb.modtime = (time_t) luaL_optinteger(L, 3, utb.actime);
695 buf = &utb;
696 }
697 lua_pushboolean(L, set_utime(file, buf) != -1);
698 } else {
699 lua_pushboolean(L, 0);
700 }
701 return 1;
702}
703
704static void push_st_mode (lua_State *L, info_struct *info) { lua_pushstring (L, mode2string (info->st_mode)); }
705static void push_st_size (lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_size); }
706static void push_st_mtime(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_mtime); }
707static void push_st_atime(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_atime); }
708static void push_st_ctime(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_ctime); }
709static void push_st_perm (lua_State *L, info_struct *info) { lua_pushstring (L, perm2string (info->st_mode)); }
710static void push_st_nlink(lua_State *L, info_struct *info) { lua_pushinteger(L, (lua_Integer) info->st_nlink); }
711
712typedef void (*push_info_struct_function) (lua_State *L, info_struct *info);
713
714struct file_stat_members {
715 const char *name;
716 push_info_struct_function push;
717};
718
719static struct file_stat_members members[] = {
720 { "mode", push_st_mode },
721 { "size", push_st_size },
722 { "modification", push_st_mtime },
723 { "access", push_st_atime },
724 { "change", push_st_ctime },
725 { "permissions", push_st_perm },
726 { "nlink", push_st_nlink },
727 { NULL, NULL },
728};
729
730
733
734static int filelib_attributes(lua_State *L)
735{
736 if (lua_type(L, 1) == LUA_TSTRING) {
737 info_struct info;
738 const char *file = luaL_checkstring(L, 1);
739 if (get_stat(file, &info)) {
740
741 } else if (lua_isstring(L, 2)) {
742 const char *member = lua_tostring(L, 2);
743 for (int i = 0; members[i].name; i++) {
744 if (strcmp(members[i].name, member) == 0) {
745 members[i].push(L, &info);
746 return 1;
747 }
748 }
749 } else {
750 lua_settop(L, 2);
751 if (! lua_istable(L, 2)) {
752 lua_createtable(L, 0, 6);
753 }
754 for (int i = 0; members[i].name; i++) {
755 lua_pushstring(L, members[i].name);
756 members[i].push(L, &info);
757 lua_rawset(L, -3);
758 }
759 return 1;
760 }
761 }
762 lua_pushnil(L);
763 return 1;
764}
765
766# define is_whatever(L,IS_OK,okay) do { \
767 if (lua_type(L, 1) == LUA_TSTRING) { \
768 info_struct info; \
769 const char *name = lua_tostring(L, 1); \
770 if (get_stat(name, &info)) { \
771 lua_pushboolean(L, 0); \
772 } else { \
773 lua_pushboolean(L, okay && ! access(name, IS_OK)); \
774 } \
775 } else { \
776 lua_pushboolean(L, 0); \
777 } \
778 return 1; \
779} while(1)
780
781static int filelib_isdir (lua_State *L) { is_whatever(L, F_OK,(S_ISDIR(info.st_mode))); }
782static int filelib_isreadabledir (lua_State *L) { is_whatever(L, R_OK,(S_ISDIR(info.st_mode))); }
783static int filelib_iswriteabledir (lua_State *L) { is_whatever(L, W_OK,(S_ISDIR(info.st_mode))); }
784
785static int filelib_isfile (lua_State *L) { is_whatever(L, F_OK,(S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))); }
786static int filelib_isreadablefile (lua_State *L) { is_whatever(L, R_OK,(S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))); }
787static int filelib_iswriteablefile(lua_State *L) { is_whatever(L, W_OK,(S_ISREG(info.st_mode) || S_ISLNK(info.st_mode))); }
788
789static int filelib_setexecutable(lua_State *L)
790{
791 int ok = 0;
792 if (lua_type(L, 1) == LUA_TSTRING) {
793 info_struct info;
794 const char *name = lua_tostring(L, 1);
795 if (! get_stat(name, &info) && S_ISREG(info.st_mode)) {
796 if (ch_to_exec(name, info.st_mode | exec_mode_flag)) {
797
798 } else {
799 ok = 1;
800 }
801 } else {
802
803 }
804 }
805 lua_pushboolean(L, ok);
806 return 1;
807}
808
809
817
818static int filelib_symlinktarget(lua_State *L)
819{
820 const char *file = aux_utf8_readlink(luaL_checkstring(L, 1));
821 if (file) {
822 lua_pushstring(L, file);
823 } else {
824 lua_pushnil(L);
825 }
826 return 1;
827}
828
829static const struct luaL_Reg filelib_function_list[] = {
830 { "attributes", filelib_attributes },
831 { "chdir", filelib_chdir },
832 { "currentdir", filelib_currentdir },
833 { "dir", filelib_dir },
834 { "mkdir", filelib_mkdir },
835 { "rmdir", filelib_rmdir },
836 { "touch", filelib_touch },
837
838 { "link", filelib_link },
839 { "symlink", filelib_symlink },
840 { "setexecutable", filelib_setexecutable },
841 { "symlinktarget", filelib_symlinktarget },
842
843 { "isdir", filelib_isdir },
844 { "isfile", filelib_isfile },
845 { "iswriteabledir", filelib_iswriteabledir },
846 { "iswriteablefile", filelib_iswriteablefile },
847 { "isreadabledir", filelib_isreadabledir },
848 { "isreadablefile", filelib_isreadablefile },
849
850 { NULL, NULL },
851};
852
853int luaopen_filelib(lua_State *L) {
854 dir_create_meta(L);
855 luaL_newlib(L,filelib_function_list);
856 return 1;
857}
858 |