aboutsummaryrefslogtreecommitdiff
path: root/src/pow_lua.c
blob: 70b32adb6e7317cb827e32282b0fb580466f2cfc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "pow_lua.h"

#include "archive.h"
#include "archive_entry.h"
#include "lauxlib.h"
#include "stdlib.h"
#include "string.h"

int pow_lua_extract(lua_State *L) {
  int r;
  ssize_t size;

  struct archive *a;
  struct archive_entry *entry;

  if (!lua_isstring(L, 1)) {
    lua_pushnil(L);
    lua_pushstring(L, "arg 1 must be string (src)");

    return 2;
  }

  if (!lua_isstring(L, 2)) {
    lua_pushnil(L);
    lua_pushstring(L, "arg 2 must be string (dest)");

    return 2;
  }

  const char *filename = lua_tostring(L, 1);
  const char *dest = lua_tostring(L, 2);

  a = archive_read_new();

  archive_read_support_filter_all(a);
  archive_read_support_format_all(a);

  if ((r = archive_read_open_filename(a, filename, 10240))) {
    return 0;
  }

  for (;;) {
    r = archive_read_next_header(a, &entry);

    if (r == ARCHIVE_EOF)
      break;
    if (r < ARCHIVE_OK)
      printf("warn while unpacking: %s\n", archive_error_string(a));
    if (r < ARCHIVE_WARN) {
      printf("error while unpacking: %s\n", archive_error_string(a));

      lua_pop(L, 1);

      char *error_msg = malloc(256);

      lua_pushnil(L);

      if (!error_msg) {
        lua_pushstring(L, "error while unpacking and failed to malloc to push "
                          "real error message");
        printf("error while unpacking and failed to push real error message\n");

        return 2;
      }

      snprintf(error_msg, 256, "error while unpacking: %s",
               archive_error_string(a));

      lua_pushstring(L, error_msg);

      free(error_msg);

      return 2;
    }

    const char *cur = archive_entry_pathname(entry);

    if (cur) {
      size_t need = strlen(dest) + strlen(cur) + 2;

      char *full = malloc(need);

      if (!full) {
        lua_pushnil(L);
        lua_pushstring(L, "failed to malloc entry path\n");

        archive_read_close(a);
        archive_read_free(a);

        return 2;
      }

      snprintf(full, need, "%s/%s", dest, cur);
      archive_entry_set_pathname(entry, full);
    }

    r = archive_read_extract(a, entry, 0);

    if (r < ARCHIVE_WARN) {
      lua_pushnil(L);
      lua_pushfstring(
          L, "failed to extract '%s': %s", archive_entry_pathname(entry),
          archive_error_string(a) ? archive_error_string(a) : "unknown");
      archive_read_close(a);
      archive_read_free(a);

      return 2;
    }
  }

  archive_read_close(a);
  archive_read_free(a);

  lua_pushboolean(L, 1);

  return 1;
}

luaL_Reg libpow[] = {{"extract", pow_lua_extract}, {NULL, NULL}};

int pow_lua_load(lua_State *L) {
  luaL_newlib(L, libpow);

  lua_setglobal(L, "pow");

  return 0;
}