]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/opentelemetry-cpp/third_party/prometheus-cpp/3rdparty/civetweb/src/third_party/lfs.c
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / third_party / prometheus-cpp / 3rdparty / civetweb / src / third_party / lfs.c
CommitLineData
1e59de90
TL
1/*
2** LuaFileSystem
3** Copyright Kepler Project 2003 - 2020
4** (http://keplerproject.github.io/luafilesystem)
5**
6** File system manipulation library.
7** This library offers these functions:
8** lfs.attributes (filepath [, attributename | attributetable])
9** lfs.chdir (path)
10** lfs.currentdir ()
11** lfs.dir (path)
12** lfs.link (old, new[, symlink])
13** lfs.lock (fh, mode)
14** lfs.lock_dir (path)
15** lfs.mkdir (path)
16** lfs.rmdir (path)
17** lfs.setmode (filepath, mode)
18** lfs.symlinkattributes (filepath [, attributename])
19** lfs.touch (filepath [, atime [, mtime]])
20** lfs.unlock (fh)
21*/
22
23#ifndef LFS_DO_NOT_USE_LARGE_FILE
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#endif
32
33#ifdef _WIN32
34#define _WIN32_WINNT 0x600
35#endif
36
37#ifndef LFS_DO_NOT_USE_LARGE_FILE
38#define _LARGEFILE64_SOURCE
39#endif
40
41#include <errno.h>
42#include <stdio.h>
43#include <string.h>
44#include <stdlib.h>
45#include <time.h>
46#include <sys/stat.h>
47
48#ifdef _WIN32
49
50#include <direct.h>
51#include <windows.h>
52#include <io.h>
53#include <sys/locking.h>
54
55#ifdef __BORLANDC__
56#include <utime.h>
57#else
58#include <sys/utime.h>
59#endif
60
61#include <fcntl.h>
62
63/* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
64#define LFS_MAXPATHLEN MAX_PATH
65
66#else
67
68#include <unistd.h>
69#include <dirent.h>
70#include <fcntl.h>
71#include <sys/types.h>
72#include <utime.h>
73#include <sys/param.h> /* for MAXPATHLEN */
74
75#ifdef MAXPATHLEN
76#define LFS_MAXPATHLEN MAXPATHLEN
77#else
78#include <limits.h> /* for _POSIX_PATH_MAX */
79#define LFS_MAXPATHLEN _POSIX_PATH_MAX
80#endif
81
82#endif
83
84#include <lua.h>
85#include <lauxlib.h>
86#include <lualib.h>
87
88#include "lfs.h"
89
90#define LFS_VERSION "1.8.0"
91#define LFS_LIBNAME "lfs"
92
93#if LUA_VERSION_NUM >= 503 /* Lua 5.3+ */
94
95#ifndef luaL_optlong
96#define luaL_optlong luaL_optinteger
97#endif
98
99#endif
100
101#if LUA_VERSION_NUM >= 502
102#define new_lib(L, l) (luaL_newlib(L, l))
103#else
104#define new_lib(L, l) (lua_newtable(L), luaL_register(L, NULL, l))
105#endif
106
107/* Define 'strerror' for systems that do not implement it */
108#ifdef NO_STRERROR
109#define strerror(_) "System unable to describe the error"
110#endif
111
112#define DIR_METATABLE "directory metatable"
113typedef struct dir_data {
114 int closed;
115#ifdef _WIN32
116 intptr_t hFile;
117 char pattern[MAX_PATH + 1];
118#else
119 DIR *dir;
120#endif
121} dir_data;
122
123#define LOCK_METATABLE "lock metatable"
124
125#ifdef _WIN32
126
127#ifdef __BORLANDC__
128#define lfs_setmode(file, m) (setmode(_fileno(file), m))
129#define STAT_STRUCT struct stati64
130#else
131#define lfs_setmode(file, m) (_setmode(_fileno(file), m))
132#define STAT_STRUCT struct _stati64
133#endif
134
135#ifndef _S_IFLNK
136#define _S_IFLNK 0x400
137#endif
138
139#ifndef S_ISDIR
140#define S_ISDIR(mode) (mode&_S_IFDIR)
141#endif
142#ifndef S_ISREG
143#define S_ISREG(mode) (mode&_S_IFREG)
144#endif
145#ifndef S_ISLNK
146#define S_ISLNK(mode) (mode&_S_IFLNK)
147#endif
148#ifndef S_ISSOCK
149#define S_ISSOCK(mode) (0)
150#endif
151#ifndef S_ISFIFO
152#define S_ISFIFO(mode) (0)
153#endif
154#ifndef S_ISCHR
155#define S_ISCHR(mode) (mode&_S_IFCHR)
156#endif
157#ifndef S_ISBLK
158#define S_ISBLK(mode) (0)
159#endif
160
161#define STAT_FUNC _stati64
162#define LSTAT_FUNC lfs_win32_lstat
163
164#else
165
166#define _O_TEXT 0
167#define _O_BINARY 0
168#define lfs_setmode(file, m) ((void)file, (void)m, 0)
169#define STAT_STRUCT struct stat
170#define STAT_FUNC stat
171#define LSTAT_FUNC lstat
172
173#endif
174
175#ifdef _WIN32
176#define lfs_mkdir _mkdir
177#else
178#define lfs_mkdir(path) (mkdir((path), \
179 S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH))
180#endif
181
182#ifdef _WIN32
183
184int lfs_win32_pusherror(lua_State * L)
185{
186 int en = GetLastError();
187 lua_pushnil(L);
188 if (en == ERROR_FILE_EXISTS || en == ERROR_SHARING_VIOLATION)
189 lua_pushstring(L, "File exists");
190 else
191 lua_pushstring(L, strerror(en));
192 return 2;
193}
194
195#define TICKS_PER_SECOND 10000000
196#define EPOCH_DIFFERENCE 11644473600LL
197time_t windowsToUnixTime(FILETIME ft)
198{
199 ULARGE_INTEGER uli;
200 uli.LowPart = ft.dwLowDateTime;
201 uli.HighPart = ft.dwHighDateTime;
202 return (time_t) (uli.QuadPart / TICKS_PER_SECOND - EPOCH_DIFFERENCE);
203}
204
205int lfs_win32_lstat(const char *path, STAT_STRUCT * buffer)
206{
207 WIN32_FILE_ATTRIBUTE_DATA win32buffer;
208 if (GetFileAttributesEx(path, GetFileExInfoStandard, &win32buffer)) {
209 if (!(win32buffer.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
210 return STAT_FUNC(path, buffer);
211 }
212 buffer->st_mode = _S_IFLNK;
213 buffer->st_dev = 0;
214 buffer->st_ino = 0;
215 buffer->st_nlink = 0;
216 buffer->st_uid = 0;
217 buffer->st_gid = 0;
218 buffer->st_rdev = 0;
219 buffer->st_atime = windowsToUnixTime(win32buffer.ftLastAccessTime);
220 buffer->st_mtime = windowsToUnixTime(win32buffer.ftLastWriteTime);
221 buffer->st_ctime = windowsToUnixTime(win32buffer.ftCreationTime);
222 buffer->st_size = 0;
223 return 0;
224 } else {
225 return 1;
226 }
227}
228
229#endif
230
231/*
232** Utility functions
233*/
234static int pusherror(lua_State * L, const char *info)
235{
236 lua_pushnil(L);
237 if (info == NULL)
238 lua_pushstring(L, strerror(errno));
239 else
240 lua_pushfstring(L, "%s: %s", info, strerror(errno));
241 lua_pushinteger(L, errno);
242 return 3;
243}
244
245static int pushresult(lua_State * L, int res, const char *info)
246{
247 if (res == -1) {
248 return pusherror(L, info);
249 } else {
250 lua_pushboolean(L, 1);
251 return 1;
252 }
253}
254
255
256/*
257** This function changes the working (current) directory
258*/
259static int change_dir(lua_State * L)
260{
261 const char *path = luaL_checkstring(L, 1);
262 if (chdir(path)) {
263 lua_pushnil(L);
264 lua_pushfstring(L, "Unable to change working directory to '%s'\n%s\n",
265 path, chdir_error);
266 return 2;
267 } else {
268 lua_pushboolean(L, 1);
269 return 1;
270 }
271}
272
273/*
274** This function returns the current directory
275** If unable to get the current directory, it returns nil
276** and a string describing the error
277*/
278static int get_dir(lua_State * L)
279{
280#ifdef NO_GETCWD
281 lua_pushnil(L);
282 lua_pushstring(L, "Function 'getcwd' not provided by system");
283 return 2;
284#else
285 char *path = NULL;
286 /* Passing (NULL, 0) is not guaranteed to work.
287 Use a temp buffer and size instead. */
288 size_t size = LFS_MAXPATHLEN; /* initial buffer size */
289 int result;
290 while (1) {
291 char *path2 = realloc(path, size);
292 if (!path2) { /* failed to allocate */
293 result = pusherror(L, "get_dir realloc() failed");
294 break;
295 }
296 path = path2;
297 if (getcwd(path, size) != NULL) {
298 /* success, push the path to the Lua stack */
299 lua_pushstring(L, path);
300 result = 1;
301 break;
302 }
303 if (errno != ERANGE) { /* unexpected error */
304 result = pusherror(L, "get_dir getcwd() failed");
305 break;
306 }
307 /* ERANGE = insufficient buffer capacity, double size and retry */
308 size *= 2;
309 }
310 free(path);
311 return result;
312#endif
313}
314
315/*
316** Check if the given element on the stack is a file and returns it.
317*/
318static FILE *check_file(lua_State * L, int idx, const char *funcname)
319{
320#if LUA_VERSION_NUM == 501
321 FILE **fh = (FILE **) luaL_checkudata(L, idx, "FILE*");
322 if (*fh == NULL) {
323 luaL_error(L, "%s: closed file", funcname);
324 return 0;
325 } else
326 return *fh;
327#elif LUA_VERSION_NUM >= 502 && LUA_VERSION_NUM <= 504
328 luaL_Stream *fh = (luaL_Stream *) luaL_checkudata(L, idx, "FILE*");
329 if (fh->closef == 0 || fh->f == NULL) {
330 luaL_error(L, "%s: closed file", funcname);
331 return 0;
332 } else
333 return fh->f;
334#else
335#error unsupported Lua version
336#endif
337}
338
339
340/*
341**
342*/
343static int _file_lock(lua_State * L, FILE * fh, const char *mode,
344 const long start, long len, const char *funcname)
345{
346 int code;
347#ifdef _WIN32
348 /* lkmode valid values are:
349 LK_LOCK Locks the specified bytes. If the bytes cannot be locked,
350 the program immediately tries again after 1 second.
351 If, after 10 attempts, the bytes cannot be locked,
352 the constant returns an error.
353 LK_NBLCK Locks the specified bytes. If the bytes cannot be locked,
354 the constant returns an error.
355 LK_NBRLCK Same as _LK_NBLCK.
356 LK_RLCK Same as _LK_LOCK.
357 LK_UNLCK Unlocks the specified bytes, which must have been
358 previously locked.
359
360 Regions should be locked only briefly and should be unlocked
361 before closing a file or exiting the program.
362
363 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp
364 */
365 int lkmode;
366 switch (*mode) {
367 case 'r':
368 lkmode = LK_NBLCK;
369 break;
370 case 'w':
371 lkmode = LK_NBLCK;
372 break;
373 case 'u':
374 lkmode = LK_UNLCK;
375 break;
376 default:
377 return luaL_error(L, "%s: invalid mode", funcname);
378 }
379 if (!len) {
380 fseek(fh, 0L, SEEK_END);
381 len = ftell(fh);
382 }
383 fseek(fh, start, SEEK_SET);
384#ifdef __BORLANDC__
385 code = locking(fileno(fh), lkmode, len);
386#else
387 code = _locking(fileno(fh), lkmode, len);
388#endif
389#else
390 struct flock f;
391 switch (*mode) {
392 case 'w':
393 f.l_type = F_WRLCK;
394 break;
395 case 'r':
396 f.l_type = F_RDLCK;
397 break;
398 case 'u':
399 f.l_type = F_UNLCK;
400 break;
401 default:
402 return luaL_error(L, "%s: invalid mode", funcname);
403 }
404 f.l_whence = SEEK_SET;
405 f.l_start = (off_t) start;
406 f.l_len = (off_t) len;
407 code = fcntl(fileno(fh), F_SETLK, &f);
408#endif
409 return (code != -1);
410}
411
412#ifdef _WIN32
413typedef struct lfs_Lock {
414 HANDLE fd;
415} lfs_Lock;
416static int lfs_lock_dir(lua_State * L)
417{
418 size_t pathl;
419 HANDLE fd;
420 lfs_Lock *lock;
421 char *ln;
422 const char *lockfile = "/lockfile.lfs";
423 const char *path = luaL_checklstring(L, 1, &pathl);
424 ln = (char *) malloc(pathl + strlen(lockfile) + 1);
425 if (!ln) {
426 lua_pushnil(L);
427 lua_pushstring(L, strerror(errno));
428 return 2;
429 }
430 strcpy(ln, path);
431 strcat(ln, lockfile);
432 fd = CreateFile(ln, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
433 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
434 free(ln);
435 if (fd == INVALID_HANDLE_VALUE) {
436 return lfs_win32_pusherror(L);
437 }
438 lock = (lfs_Lock *) lua_newuserdata(L, sizeof(lfs_Lock));
439 lock->fd = fd;
440 luaL_getmetatable(L, LOCK_METATABLE);
441 lua_setmetatable(L, -2);
442 return 1;
443}
444
445static int lfs_unlock_dir(lua_State * L)
446{
447 lfs_Lock *lock = (lfs_Lock *) luaL_checkudata(L, 1, LOCK_METATABLE);
448 if (lock->fd != INVALID_HANDLE_VALUE) {
449 CloseHandle(lock->fd);
450 lock->fd = INVALID_HANDLE_VALUE;
451 }
452 return 0;
453}
454#else
455typedef struct lfs_Lock {
456 char *ln;
457} lfs_Lock;
458static int lfs_lock_dir(lua_State * L)
459{
460 lfs_Lock *lock;
461 size_t pathl;
462 char *ln;
463 const char *lockfile = "/lockfile.lfs";
464 const char *path = luaL_checklstring(L, 1, &pathl);
465 lock = (lfs_Lock *) lua_newuserdata(L, sizeof(lfs_Lock));
466 ln = (char *) malloc(pathl + strlen(lockfile) + 1);
467 if (!ln) {
468 lua_pushnil(L);
469 lua_pushstring(L, strerror(errno));
470 return 2;
471 }
472 strcpy(ln, path);
473 strcat(ln, lockfile);
474 if (symlink("lock", ln) == -1) {
475 free(ln);
476 lua_pushnil(L);
477 lua_pushstring(L, strerror(errno));
478 return 2;
479 }
480 lock->ln = ln;
481 luaL_getmetatable(L, LOCK_METATABLE);
482 lua_setmetatable(L, -2);
483 return 1;
484}
485
486static int lfs_unlock_dir(lua_State * L)
487{
488 lfs_Lock *lock = (lfs_Lock *) luaL_checkudata(L, 1, LOCK_METATABLE);
489 if (lock->ln) {
490 unlink(lock->ln);
491 free(lock->ln);
492 lock->ln = NULL;
493 }
494 return 0;
495}
496#endif
497
498static int lfs_g_setmode(lua_State * L, FILE * f, int arg)
499{
500 static const int mode[] = { _O_BINARY, _O_TEXT };
501 static const char *const modenames[] = { "binary", "text", NULL };
502 int op = luaL_checkoption(L, arg, NULL, modenames);
503 int res = lfs_setmode(f, mode[op]);
504 if (res != -1) {
505 int i;
506 lua_pushboolean(L, 1);
507 for (i = 0; modenames[i] != NULL; i++) {
508 if (mode[i] == res) {
509 lua_pushstring(L, modenames[i]);
510 return 2;
511 }
512 }
513 lua_pushnil(L);
514 return 2;
515 } else {
516 return pusherror(L, NULL);
517 }
518}
519
520static int lfs_f_setmode(lua_State * L)
521{
522 return lfs_g_setmode(L, check_file(L, 1, "setmode"), 2);
523}
524
525/*
526** Locks a file.
527** @param #1 File handle.
528** @param #2 String with lock mode ('w'rite, 'r'ead).
529** @param #3 Number with start position (optional).
530** @param #4 Number with length (optional).
531*/
532static int file_lock(lua_State * L)
533{
534 FILE *fh = check_file(L, 1, "lock");
535 const char *mode = luaL_checkstring(L, 2);
536 const long start = (long) luaL_optinteger(L, 3, 0);
537 long len = (long) luaL_optinteger(L, 4, 0);
538 if (_file_lock(L, fh, mode, start, len, "lock")) {
539 lua_pushboolean(L, 1);
540 return 1;
541 } else {
542 lua_pushnil(L);
543 lua_pushfstring(L, "%s", strerror(errno));
544 return 2;
545 }
546}
547
548
549/*
550** Unlocks a file.
551** @param #1 File handle.
552** @param #2 Number with start position (optional).
553** @param #3 Number with length (optional).
554*/
555static int file_unlock(lua_State * L)
556{
557 FILE *fh = check_file(L, 1, "unlock");
558 const long start = (long) luaL_optinteger(L, 2, 0);
559 long len = (long) luaL_optinteger(L, 3, 0);
560 if (_file_lock(L, fh, "u", start, len, "unlock")) {
561 lua_pushboolean(L, 1);
562 return 1;
563 } else {
564 lua_pushnil(L);
565 lua_pushfstring(L, "%s", strerror(errno));
566 return 2;
567 }
568}
569
570
571/*
572** Creates a link.
573** @param #1 Object to link to.
574** @param #2 Name of link.
575** @param #3 True if link is symbolic (optional).
576*/
577static int make_link(lua_State * L)
578{
579 const char *oldpath = luaL_checkstring(L, 1);
580 const char *newpath = luaL_checkstring(L, 2);
581#ifndef _WIN32
582 return pushresult(L,
583 (lua_toboolean(L, 3) ? symlink : link) (oldpath,
584 newpath),
585 NULL);
586#else
587 int symbolic = lua_toboolean(L, 3);
588 STAT_STRUCT oldpathinfo;
589 int is_dir = 0;
590 if (STAT_FUNC(oldpath, &oldpathinfo) == 0) {
591 is_dir = S_ISDIR(oldpathinfo.st_mode) != 0;
592 }
593 if (!symbolic && is_dir) {
594 lua_pushnil(L);
595 lua_pushstring(L,
596 "hard links to directories are not supported on Windows");
597 return 2;
598 }
599
600 int result = symbolic ? CreateSymbolicLink(newpath, oldpath, is_dir)
601 : CreateHardLink(newpath, oldpath, NULL);
602
603 if (result) {
604 return pushresult(L, result, NULL);
605 } else {
606 lua_pushnil(L);
607 lua_pushstring(L, symbolic ? "make_link CreateSymbolicLink() failed"
608 : "make_link CreateHardLink() failed");
609 return 2;
610 }
611#endif
612}
613
614
615/*
616** Creates a directory.
617** @param #1 Directory path.
618*/
619static int make_dir(lua_State * L)
620{
621 const char *path = luaL_checkstring(L, 1);
622 return pushresult(L, lfs_mkdir(path), NULL);
623}
624
625
626/*
627** Removes a directory.
628** @param #1 Directory path.
629*/
630static int remove_dir(lua_State * L)
631{
632 const char *path = luaL_checkstring(L, 1);
633 return pushresult(L, rmdir(path), NULL);
634}
635
636
637/*
638** Directory iterator
639*/
640static int dir_iter(lua_State * L)
641{
642#ifdef _WIN32
643 struct _finddata_t c_file;
644#else
645 struct dirent *entry;
646#endif
647 dir_data *d = (dir_data *) luaL_checkudata(L, 1, DIR_METATABLE);
648 luaL_argcheck(L, d->closed == 0, 1, "closed directory");
649#ifdef _WIN32
650 if (d->hFile == 0L) { /* first entry */
651 if ((d->hFile = _findfirst(d->pattern, &c_file)) == -1L) {
652 lua_pushnil(L);
653 lua_pushstring(L, strerror(errno));
654 d->closed = 1;
655 return 2;
656 } else {
657 lua_pushstring(L, c_file.name);
658 return 1;
659 }
660 } else { /* next entry */
661 if (_findnext(d->hFile, &c_file) == -1L) {
662 /* no more entries => close directory */
663 _findclose(d->hFile);
664 d->closed = 1;
665 return 0;
666 } else {
667 lua_pushstring(L, c_file.name);
668 return 1;
669 }
670 }
671#else
672 if ((entry = readdir(d->dir)) != NULL) {
673 lua_pushstring(L, entry->d_name);
674 return 1;
675 } else {
676 /* no more entries => close directory */
677 closedir(d->dir);
678 d->closed = 1;
679 return 0;
680 }
681#endif
682}
683
684
685/*
686** Closes directory iterators
687*/
688static int dir_close(lua_State * L)
689{
690 dir_data *d = (dir_data *) lua_touserdata(L, 1);
691#ifdef _WIN32
692 if (!d->closed && d->hFile) {
693 _findclose(d->hFile);
694 }
695#else
696 if (!d->closed && d->dir) {
697 closedir(d->dir);
698 }
699#endif
700 d->closed = 1;
701 return 0;
702}
703
704
705/*
706** Factory of directory iterators
707*/
708static int dir_iter_factory(lua_State * L)
709{
710 const char *path = luaL_checkstring(L, 1);
711 dir_data *d;
712 lua_pushcfunction(L, dir_iter);
713 d = (dir_data *) lua_newuserdata(L, sizeof(dir_data));
714 luaL_getmetatable(L, DIR_METATABLE);
715 lua_setmetatable(L, -2);
716 d->closed = 0;
717#ifdef _WIN32
718 d->hFile = 0L;
719 if (strlen(path) > MAX_PATH - 2)
720 luaL_error(L, "path too long: %s", path);
721 else
722 sprintf(d->pattern, "%s/*", path);
723#else
724 d->dir = opendir(path);
725 if (d->dir == NULL)
726 luaL_error(L, "cannot open %s: %s", path, strerror(errno));
727#endif
728#if LUA_VERSION_NUM >= 504
729 lua_pushnil(L);
730 lua_pushvalue(L, -2);
731 return 4;
732#else
733 return 2;
734#endif
735}
736
737
738/*
739** Creates directory metatable.
740*/
741static int dir_create_meta(lua_State * L)
742{
743 luaL_newmetatable(L, DIR_METATABLE);
744
745 /* Method table */
746 lua_newtable(L);
747 lua_pushcfunction(L, dir_iter);
748 lua_setfield(L, -2, "next");
749 lua_pushcfunction(L, dir_close);
750 lua_setfield(L, -2, "close");
751
752 /* Metamethods */
753 lua_setfield(L, -2, "__index");
754 lua_pushcfunction(L, dir_close);
755 lua_setfield(L, -2, "__gc");
756
757#if LUA_VERSION_NUM >= 504
758 lua_pushcfunction(L, dir_close);
759 lua_setfield(L, -2, "__close");
760#endif
761 return 1;
762}
763
764
765/*
766** Creates lock metatable.
767*/
768static int lock_create_meta(lua_State * L)
769{
770 luaL_newmetatable(L, LOCK_METATABLE);
771
772 /* Method table */
773 lua_newtable(L);
774 lua_pushcfunction(L, lfs_unlock_dir);
775 lua_setfield(L, -2, "free");
776
777 /* Metamethods */
778 lua_setfield(L, -2, "__index");
779 lua_pushcfunction(L, lfs_unlock_dir);
780 lua_setfield(L, -2, "__gc");
781 return 1;
782}
783
784
785/*
786** Convert the inode protection mode to a string.
787*/
788#ifdef _WIN32
789static const char *mode2string(unsigned short mode)
790{
791#else
792static const char *mode2string(mode_t mode)
793{
794#endif
795 if (S_ISREG(mode))
796 return "file";
797 else if (S_ISDIR(mode))
798 return "directory";
799 else if (S_ISLNK(mode))
800 return "link";
801 else if (S_ISSOCK(mode))
802 return "socket";
803 else if (S_ISFIFO(mode))
804 return "named pipe";
805 else if (S_ISCHR(mode))
806 return "char device";
807 else if (S_ISBLK(mode))
808 return "block device";
809 else
810 return "other";
811}
812
813
814/*
815** Set access time and modification values for a file.
816** @param #1 File path.
817** @param #2 Access time in seconds, current time is used if missing.
818** @param #3 Modification time in seconds, access time is used if missing.
819*/
820static int file_utime(lua_State * L)
821{
822 const char *file = luaL_checkstring(L, 1);
823 struct utimbuf utb, *buf;
824
825 if (lua_gettop(L) == 1) /* set to current date/time */
826 buf = NULL;
827 else {
828 utb.actime = (time_t) luaL_optnumber(L, 2, 0);
829 utb.modtime = (time_t) luaL_optinteger(L, 3, utb.actime);
830 buf = &utb;
831 }
832
833 return pushresult(L, utime(file, buf), NULL);
834}
835
836
837/* inode protection mode */
838static void push_st_mode(lua_State * L, STAT_STRUCT * info)
839{
840 lua_pushstring(L, mode2string(info->st_mode));
841}
842
843/* device inode resides on */
844static void push_st_dev(lua_State * L, STAT_STRUCT * info)
845{
846 lua_pushinteger(L, (lua_Integer) info->st_dev);
847}
848
849/* inode's number */
850static void push_st_ino(lua_State * L, STAT_STRUCT * info)
851{
852 lua_pushinteger(L, (lua_Integer) info->st_ino);
853}
854
855/* number of hard links to the file */
856static void push_st_nlink(lua_State * L, STAT_STRUCT * info)
857{
858 lua_pushinteger(L, (lua_Integer) info->st_nlink);
859}
860
861/* user-id of owner */
862static void push_st_uid(lua_State * L, STAT_STRUCT * info)
863{
864 lua_pushinteger(L, (lua_Integer) info->st_uid);
865}
866
867/* group-id of owner */
868static void push_st_gid(lua_State * L, STAT_STRUCT * info)
869{
870 lua_pushinteger(L, (lua_Integer) info->st_gid);
871}
872
873/* device type, for special file inode */
874static void push_st_rdev(lua_State * L, STAT_STRUCT * info)
875{
876 lua_pushinteger(L, (lua_Integer) info->st_rdev);
877}
878
879/* time of last access */
880static void push_st_atime(lua_State * L, STAT_STRUCT * info)
881{
882 lua_pushinteger(L, (lua_Integer) info->st_atime);
883}
884
885/* time of last data modification */
886static void push_st_mtime(lua_State * L, STAT_STRUCT * info)
887{
888 lua_pushinteger(L, (lua_Integer) info->st_mtime);
889}
890
891/* time of last file status change */
892static void push_st_ctime(lua_State * L, STAT_STRUCT * info)
893{
894 lua_pushinteger(L, (lua_Integer) info->st_ctime);
895}
896
897/* file size, in bytes */
898static void push_st_size(lua_State * L, STAT_STRUCT * info)
899{
900 lua_pushinteger(L, (lua_Integer) info->st_size);
901}
902
903#ifndef _WIN32
904/* blocks allocated for file */
905static void push_st_blocks(lua_State * L, STAT_STRUCT * info)
906{
907 lua_pushinteger(L, (lua_Integer) info->st_blocks);
908}
909
910/* optimal file system I/O blocksize */
911static void push_st_blksize(lua_State * L, STAT_STRUCT * info)
912{
913 lua_pushinteger(L, (lua_Integer) info->st_blksize);
914}
915#endif
916
917 /*
918 ** Convert the inode protection mode to a permission list.
919 */
920
921#ifdef _WIN32
922static const char *perm2string(unsigned short mode)
923{
924 static char perms[10] = "---------";
925 int i;
926 for (i = 0; i < 9; i++)
927 perms[i] = '-';
928 if (mode & _S_IREAD) {
929 perms[0] = 'r';
930 perms[3] = 'r';
931 perms[6] = 'r';
932 }
933 if (mode & _S_IWRITE) {
934 perms[1] = 'w';
935 perms[4] = 'w';
936 perms[7] = 'w';
937 }
938 if (mode & _S_IEXEC) {
939 perms[2] = 'x';
940 perms[5] = 'x';
941 perms[8] = 'x';
942 }
943 return perms;
944}
945#else
946static const char *perm2string(mode_t mode)
947{
948 static char perms[10] = "---------";
949 int i;
950 for (i = 0; i < 9; i++)
951 perms[i] = '-';
952 if (mode & S_IRUSR)
953 perms[0] = 'r';
954 if (mode & S_IWUSR)
955 perms[1] = 'w';
956 if (mode & S_IXUSR)
957 perms[2] = 'x';
958 if (mode & S_IRGRP)
959 perms[3] = 'r';
960 if (mode & S_IWGRP)
961 perms[4] = 'w';
962 if (mode & S_IXGRP)
963 perms[5] = 'x';
964 if (mode & S_IROTH)
965 perms[6] = 'r';
966 if (mode & S_IWOTH)
967 perms[7] = 'w';
968 if (mode & S_IXOTH)
969 perms[8] = 'x';
970 return perms;
971}
972#endif
973
974/* permssions string */
975static void push_st_perm(lua_State * L, STAT_STRUCT * info)
976{
977 lua_pushstring(L, perm2string(info->st_mode));
978}
979
980typedef void (*_push_function)(lua_State * L, STAT_STRUCT * info);
981
982struct _stat_members {
983 const char *name;
984 _push_function push;
985};
986
987struct _stat_members members[] = {
988 { "mode", push_st_mode },
989 { "dev", push_st_dev },
990 { "ino", push_st_ino },
991 { "nlink", push_st_nlink },
992 { "uid", push_st_uid },
993 { "gid", push_st_gid },
994 { "rdev", push_st_rdev },
995 { "access", push_st_atime },
996 { "modification", push_st_mtime },
997 { "change", push_st_ctime },
998 { "size", push_st_size },
999 { "permissions", push_st_perm },
1000#ifndef _WIN32
1001 { "blocks", push_st_blocks },
1002 { "blksize", push_st_blksize },
1003#endif
1004 { NULL, NULL }
1005};
1006
1007/*
1008** Get file or symbolic link information
1009*/
1010static int _file_info_(lua_State * L,
1011 int (*st)(const char *, STAT_STRUCT *))
1012{
1013 STAT_STRUCT info;
1014 const char *file = luaL_checkstring(L, 1);
1015 int i;
1016
1017 if (st(file, &info)) {
1018 lua_pushnil(L);
1019 lua_pushfstring(L, "cannot obtain information from file '%s': %s",
1020 file, strerror(errno));
1021 lua_pushinteger(L, errno);
1022 return 3;
1023 }
1024 if (lua_isstring(L, 2)) {
1025 const char *member = lua_tostring(L, 2);
1026 for (i = 0; members[i].name; i++) {
1027 if (strcmp(members[i].name, member) == 0) {
1028 /* push member value and return */
1029 members[i].push(L, &info);
1030 return 1;
1031 }
1032 }
1033 /* member not found */
1034 return luaL_error(L, "invalid attribute name '%s'", member);
1035 }
1036 /* creates a table if none is given, removes extra arguments */
1037 lua_settop(L, 2);
1038 if (!lua_istable(L, 2)) {
1039 lua_newtable(L);
1040 }
1041 /* stores all members in table on top of the stack */
1042 for (i = 0; members[i].name; i++) {
1043 lua_pushstring(L, members[i].name);
1044 members[i].push(L, &info);
1045 lua_rawset(L, -3);
1046 }
1047 return 1;
1048}
1049
1050
1051/*
1052** Get file information using stat.
1053*/
1054static int file_info(lua_State * L)
1055{
1056 return _file_info_(L, STAT_FUNC);
1057}
1058
1059
1060/*
1061** Push the symlink target to the top of the stack.
1062** Assumes the file name is at position 1 of the stack.
1063** Returns 1 if successful (with the target on top of the stack),
1064** 0 on failure (with stack unchanged, and errno set).
1065*/
1066static int push_link_target(lua_State * L)
1067{
1068 const char *file = luaL_checkstring(L, 1);
1069#ifdef _WIN32
1070 HANDLE h = CreateFile(file, GENERIC_READ,
1071 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1072 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1073 if (h == INVALID_HANDLE_VALUE) {
1074 return lfs_win32_pusherror(L);
1075 }
1076#endif
1077 char *target = NULL;
1078 int tsize, size = 256; /* size = initial buffer capacity */
1079 int ok = 0;
1080 while (!ok) {
1081 char *target2 = realloc(target, size);
1082 if (!target2) { /* failed to allocate */
1083 break;
1084 }
1085 target = target2;
1086#ifdef _WIN32
1087 tsize = GetFinalPathNameByHandle(h, target, size, FILE_NAME_OPENED);
1088#else
1089 tsize = readlink(file, target, size);
1090#endif
1091 if (tsize < 0) { /* a readlink() error occurred */
1092 break;
1093 }
1094 if (tsize < size) {
1095#ifdef _WIN32
1096 if (tsize > 4 && strncmp(target, "\\\\?\\", 4) == 0) {
1097 memmove_s(target, tsize - 3, target + 4, tsize - 3);
1098 tsize -= 4;
1099 }
1100#endif
1101 ok = 1;
1102 break;
1103 }
1104 /* possibly truncated readlink() result, double size and retry */
1105 size *= 2;
1106 }
1107 if (ok) {
1108 target[tsize] = '\0';
1109 lua_pushlstring(L, target, tsize);
1110 }
1111#ifdef _WIN32
1112 CloseHandle(h);
1113#endif
1114 free(target);
1115 return ok;
1116}
1117
1118/*
1119** Get symbolic link information using lstat.
1120*/
1121static int link_info(lua_State * L)
1122{
1123 int ret;
1124 if (lua_isstring(L, 2) && (strcmp(lua_tostring(L, 2), "target") == 0)) {
1125 int ok = push_link_target(L);
1126 return ok ? 1 : pusherror(L, "could not obtain link target");
1127 }
1128 ret = _file_info_(L, LSTAT_FUNC);
1129 if (ret == 1 && lua_type(L, -1) == LUA_TTABLE) {
1130 int ok = push_link_target(L);
1131 if (ok) {
1132 lua_setfield(L, -2, "target");
1133 }
1134 }
1135 return ret;
1136}
1137
1138
1139/*
1140** Assumes the table is on top of the stack.
1141*/
1142static void set_info(lua_State * L)
1143{
1144 lua_pushliteral(L, "Copyright (C) 2003-2017 Kepler Project");
1145 lua_setfield(L, -2, "_COPYRIGHT");
1146 lua_pushliteral(L,
1147 "LuaFileSystem is a Lua library developed to complement "
1148 "the set of functions related to file systems offered by "
1149 "the standard Lua distribution");
1150 lua_setfield(L, -2, "_DESCRIPTION");
1151 lua_pushliteral(L, "LuaFileSystem " LFS_VERSION);
1152 lua_setfield(L, -2, "_VERSION");
1153}
1154
1155
1156static const struct luaL_Reg fslib[] = {
1157 { "attributes", file_info },
1158 { "chdir", change_dir },
1159 { "currentdir", get_dir },
1160 { "dir", dir_iter_factory },
1161 { "link", make_link },
1162 { "lock", file_lock },
1163 { "mkdir", make_dir },
1164 { "rmdir", remove_dir },
1165 { "symlinkattributes", link_info },
1166 { "setmode", lfs_f_setmode },
1167 { "touch", file_utime },
1168 { "unlock", file_unlock },
1169 { "lock_dir", lfs_lock_dir },
1170 { NULL, NULL },
1171};
1172
1173LFS_EXPORT int luaopen_lfs(lua_State * L)
1174{
1175 dir_create_meta(L);
1176 lock_create_meta(L);
1177 new_lib(L, fslib);
1178 lua_pushvalue(L, -1);
1179 lua_setglobal(L, LFS_LIBNAME);
1180 set_info(L);
1181 return 1;
1182}