File: compat.lua

package info (click to toggle)
lua-posix 36.3-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,720 kB
  • sloc: ansic: 5,462; makefile: 21; sh: 6
file content (286 lines) | stat: -rw-r--r-- 9,254 bytes parent folder | download | duplicates (2)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
--[[
 POSIX library for Lua 5.1, 5.2, 5.3 & 5.4.
 Copyright (C) 2014-2025 Gary V. Vaughan
]]
--[[--
 Legacy Lua POSIX bindings.

 APIs for maintaining compatibility with previous releases.

 @module posix
]]


local LOG_MASK = require 'posix.syslog'.LOG_MASK
local MODE_MAP = require 'posix._base'.MODE_MAP
local O_CREAT = require 'posix.fcntl'.O_CREAT
local O_TRUNC = require 'posix.fcntl'.O_TRUNC
local O_WRONLY = require 'posix.fcntl'.O_WRONLY
local S_IRGRP = require 'posix.sys.stat'.S_IRGRP
local S_IROTH = require 'posix.sys.stat'.S_IROTH
local S_IRUSR = require 'posix.sys.stat'.S_IRUSR
local S_IRWXG = require 'posix.sys.stat'.S_IRWXG
local S_IRWXO= require 'posix.sys.stat'.S_IRWXO
local S_IRWXU = require 'posix.sys.stat'.S_IRWXU
local S_ISGID = require 'posix.sys.stat'.S_ISGID
local S_ISUID = require 'posix.sys.stat'.S_ISUID
local S_IWGRP = require 'posix.sys.stat'.S_IWGRP
local S_IWOTH = require 'posix.sys.stat'.S_IWOTH
local S_IWUSR = require 'posix.sys.stat'.S_IWUSR
local S_IXGRP = require 'posix.sys.stat'.S_IXGRP
local S_IXOTH = require 'posix.sys.stat'.S_IXOTH
local S_IXUSR = require 'posix.sys.stat'.S_IXUSR

local argerror = require 'posix._base'.argerror
local argscheck = require 'posix._base'.argscheck
local chmod = require 'posix.sys.stat'.chmod
local band = require 'posix._base'.band
local bnot = require 'posix._base'.bnot
local bor = require 'posix._base'.bor
local concat = table.concat
local gsub = string.gsub
local match = string.match
local mkdir = require 'posix.sys.stat'.mkdir
local mkfifo = require 'posix.sys.stat'.mkfifo
local msgget = require 'posix.sys.msg'.msgget
local open = require 'posix.fcntl'.open
local pushmode = require 'posix._base'.pushmode
local setlogmask = require 'posix.syslog'.setlogmask
local stat = require 'posix.sys.stat'.stat
local sub = string.sub
local tonumber = tonumber
local umask = require 'posix.sys.stat'.umask


local RWXALL = bor(S_IRWXU, S_IRWXG, S_IRWXO)
local FCREAT = bor(O_CREAT, O_WRONLY, O_TRUNC)


local function rwxrwxrwx(modestr)
   local mode = 0
   for i = 1, 9 do
      if sub(modestr, i, i) == MODE_MAP[i].c then
         mode = bor(mode, MODE_MAP[i].b)
      elseif sub(modestr, i, i) == 's' then
         if i == 3 then
            mode = bor(mode, S_ISUID, S_IXUSR)
         elseif i == 6 then
            mode = bor(mode, S_ISGID, S_IXGRP)
         else
            return nil   -- bad mode
         end
      end
   end
   return mode
end


local function octal_mode(modestr)
   local mode = 0
   for i = 1, #modestr do
      mode = mode * 8 + tonumber(sub(modestr, i, i))
   end
   return mode
end


local function mode_munch(mode, modestr)
   if modestr == nil then
      return nil, 'string expected, got no value'
   elseif #modestr == 9 and match(modestr, '^[-rswx]+$') then
      return rwxrwxrwx(modestr)
   elseif match(modestr, '^[0-7]+$') then
      return octal_mode(modestr)
   elseif match(modestr, '^[ugoa]+%s*[-+=]%s*[rswx]+,*') then
      gsub(modestr, '%s*(%a+)%s*(.)%s*(%a+),*', function(who, op, what)
         local bits, bobs = 0, 0
         if match(who, '[ua]') then
            bits = bor(bits, S_ISUID, S_IRWXU)
         end
         if match(who, '[ga]') then
            bits = bor(bits, S_ISGID, S_IRWXG)
         end
         if match(who, '[oa]') then
            bits = bor(bits, S_IRWXO)
         end
         if match(what, 'r') then
            bobs = bor(bobs, S_IRUSR, S_IRGRP, S_IROTH)
         end
         if match(what, 'w') then
            bobs = bor(bobs, S_IWUSR, S_IWGRP, S_IWOTH)
         end
         if match(what, 'x') then
            bobs = bor(bobs, S_IXUSR, S_IXGRP, S_IXOTH)
         end
         if match(what, 's') then
            bobs = bor(bobs, S_ISUID, S_ISGID)
         end
         if op == '+' then
            -- mode |= bits & bobs
            mode = bor(mode, band(bits, bobs))
         elseif op == '-' then
            -- mode &= ~(bits & bobs)
            mode = band(mode, bnot(band(bits, bobs)))
         elseif op == '=' then
            -- mode =(mode & ~bits) |(bits & bobs)
            mode = bor(band(mode, bnot(bits)), band(bits, bobs))
         end
      end)
      return mode
   else
      return nil, 'bad mode'
   end
end


return {
   --- Change the mode of the path.
   -- @function chmod
   -- @string path existing file path
   -- @string mode one of the following formats:
   --
   --    * 'rwxrwxrwx' (e.g. 'rw-rw-r--')
   --    * 'ugo+-=rwx' (e.g. 'u+w')
   --    * '+-=rwx'    (e.g. '+w')
   --
   -- @return[1] int `0`, if successful
   -- @return[2] nil
   -- @treturn[2] string error message
   -- @treturn[2] int errnum
   -- @see chmod(2)
   -- @usage chmod('bin/dof', '+x')
   chmod = argscheck('chmod(string, string)', function(path, modestr)
      local mode = (stat(path) or {}).st_mode
      local bits, err = mode_munch(mode or 0, modestr)
      if bits == nil then
         argerror('chmod', 2, err, 2)
      end
      return chmod(path, band(bits, RWXALL))
   end),

   --- Create a file.
   -- This function is obsoleted by @{posix.fcntl.open} with `posix.O_CREAT`.
   -- @function creat
   -- @string path name of file to create
   -- @string mode permissions with which to create file
   -- @treturn[1] int file descriptor of file at *path*, if successful
   -- @return[2] nil
   -- @treturn[2] string error message
   -- @treturn[2] int errnum
   -- @see creat(2)
   -- @see posix.chmod
   -- @usage
   --    fd = creat('data', 'rw-r-----')
   creat = argscheck('creat(string, string)', function(path, modestr)
      local bits, err = mode_munch(0, modestr)
      if bits == nil then
         argerror('creat', 2, err, 2)
      end
      return open(path, FCREAT, band(bits, RWXALL))
   end),

   --- Make a directory.
   -- @function mkdir
   -- @string path location in file system to create directory
   -- @treturn[1] int `0`, if successful
   -- @return[2] nil
   -- @treturn[2] string error message
   -- @treturn[2] int errnum
   mkdir = argscheck('mkdir(string)', function(path)
      return mkdir(path, RWXALL)
   end),

   --- Make a FIFO pipe.
   -- @function mkfifo
   -- @string path location in file system to create fifo
   -- @treturn[1] int `0`, if successful
   -- @return[2] nil
   -- @treturn[2] string error message
   -- @treturn[2] int errnum
   mkfifo = argscheck('mkfifo(string)', function(path)
      return mkfifo(path, RWXALL)
   end),

   --- Get a message queue identifier
   -- @function msgget
   -- @int key message queue id, or `IPC_PRIVATE` for a new queue
   -- @int[opt=0] flags bitwise OR of zero or more from `IPC_CREAT` and `IPC_EXCL`
   -- @string[opt='rw-rw-rw-'] mode execute bits are ignored
   -- @treturn[1] int message queue identifier, if successful
   -- @return[2] nil
   -- @treturn[2] string error message
   -- @treturn[2] int errnum
   -- @see msgget(2)
   msgget = argscheck('msgget(int, ?int, ?string)', function(key, msgflg, modestr)
      local bits, err = mode_munch(0, modestr)
      if bits == nil then
         argerror('msgget', 3, err, 2)
      end
      return msgget(key, bor(msgflg, band(bits, RWXALL)))
   end),

   --- Open a file.
   -- @function open
   -- @string path file to act on
   -- @int oflags bitwise OR of zero or more of `O_RDONLY`, `O_WRONLY`, `O_RDWR`,
   --  `O_APPEND`, `O_CREAT`, `O_DSYNC`, `O_EXCL`, `O_NOCTTY`, `O_NONBLOCK`,
   --  `O_RSYNC`, `O_SYNC`, `O_TRUNC`
   -- @string modestr(used with `O_CREAT`; see @{chmod} for format)
   -- @treturn[1] int file descriptor for *path*, if successful
   -- @return[2] nil
   -- @treturn[2] string error message
   -- @treturn[2] int errnum
   -- @see open(2)
   -- @usage
   -- fd = posix.open('data', bit.bor(posix.O_CREAT, posix.O_RDWR), 'rw-r-----')
   open = argscheck('open(string, int, [string])', function(path, oflags, modestr)
      local bits, err
      if band(oflags, O_CREAT) ~= 0 then
         bits, err = mode_munch(0, modestr)
         if bits == nil then
            argerror('open', 3, err, 2)
         end
         bits = band(bits, RWXALL)
      end
      return open(path, oflags, bits)
   end),

   --- Set log priority mask
   -- @function setlogmask
   -- @int ... zero or more of `LOG_EMERG`, `LOG_ALERT`, `LOG_CRIT`,
   --  `LOG_WARNING`, `LOG_NOTICE`, `LOG_INFO` and `LOG_DEBUG`
   -- @treturn[1] int `0`, if successful
   -- @return[2] nil
   -- @treturn[2] string error message
   -- @treturn[2] int errnum
   setlogmask = argscheck('setlogmask(?int...)', function(...)
      local mask, i, t = 0, 1, {...}
      while t[i] do
         mask = bor(mask, LOG_MASK(t[i]))
         i = i + 1
      end
      return setlogmask(mask)
   end),

   --- Set file mode creation mask.
   -- @function umask
   -- @string[opt] mode file creation mask string
   -- @treturn string previous umask
   -- @see umask(2)
   -- @see posix.sys.stat.umask
   umask = argscheck('umask([?string])', function(modestr)
      modestr = modestr or ''
      local mode = umask(0)
      umask(mode)
      mode = band(bnot(mode), RWXALL)
      if modestr ~= '' then
         local bits, err = mode_munch(mode, modestr)
         if bits == nil then
            argerror('umask', 1, err, 2)
         end
         mode = band(bits, RWXALL)
         umask(bnot(mode))
      end
      return pushmode(mode)
   end),
}