This file is indexed.

/usr/share/lua/5.1/saci.lua is in sputnik 9.03.13+1-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
-----------------------------------------------------------------------------
-- Defines a class for a document-to-table mapper on top of Versium.
--
--
-- (c) 2007, 2008  Yuri Takhteyev (yuri@freewisdom.org)
-- License: MIT/X, see http://sputnik.freewisdom.org/en/License
-----------------------------------------------------------------------------

module(..., package.seeall)

require("saci.node")
local Saci = {}
local Saci_mt = {__metatable={}, __index=Saci}

-----------------------------------------------------------------------------
-- Creates a new instance of Saci.
-- 
-- @param module_name    versium module name to use for storage.
-- @param versium_params parameters to use when creating the storage module
--                       instance.
-- @param root_prototype [optional] the id of the node to be used as the root
--                       prototype (defaults to "@Root").
-- @return               an instance of "Saci".
-----------------------------------------------------------------------------
function new(module_name, versium_params, root_prototype_id)
   local repo = setmetatable({}, Saci_mt)
   repo.root_prototype_id = root_prototype_id or "@Root"
   assert(module_name)
   module_name = module_name
   local versium_module = require(module_name)
   repo.versium = versium_module.new(versium_params)
   repo.permission_groups = {
      all_users     = function(user)   return true end,
      Authenticated = function(user)   return user ~= nil and user:len() > 0 end,
      Anonymous     = function(user)   return not user end,
      all_actions   = function(action) return true end,
   }
   repo:reset_cache()
   return repo
end


function Saci:reset_cache()
   self.cache = {}
   self.cache_stub = {}
end
-----------------------------------------------------------------------------
-- Returns true if the node exists and false otherwise.
-- 
-- @param id             an id of an node.
-- @return               true or false.
-----------------------------------------------------------------------------
function Saci:node_exists(id)
   return self.versium:node_exists(id)
end

--[--------------------------------------------------------------------------
-- Prepares a Lua value for serialization into a stored saci node.  This
-- function will only output boolean, numeric, and number values.
--
-- @param data           The data to be serialized
-- @return               The string representation of the data
-----------------------------------------------------------------------------
local function serialize(data)
	local data_type = type(data)
	if data_type == "boolean" or data_type == "number" then
		return tostring(data)
	elseif data_type ~= "string" then
      return string.format("nil -- Could not serialize '%s'", tostring(data))
	end

	-- if the string contains any newlines, find a version of long quotes that will work
	if data:find("\n") then
		local count = 0
		local open = string.format("[%s[", string.rep("=", count))
		local close = string.format("]%s]", string.rep("=", count))

		while data:find(open, nil, true) or data:find(close, nil, true) do
			open = string.format("[%s[", string.rep("=", count))
			close = string.format("]%s]", string.rep("=", count))
			count = count + 1
		end

		return string.format("%s%s%s", open, data, close)
	else
		return string.format("%q", data)
	end
end

-----------------------------------------------------------------------------
-- Turns a node represented as a Lua table into a string representation which
-- could later be inflated again.
--
-- @param node           A versium node as a table.
-- @return               The string representation of the versium node.
-----------------------------------------------------------------------------
function Saci:deflate(node, fields)
   local buffer = ""
   local keysort = {}

   -- Sort the keys of the node so output is consistent
   for k,v in pairs(node) do
      if k ~= "__index" then
         table.insert(keysort, k)
      end
   end
   table.sort(keysort, function(x, y)
                          if fields and fields[x] and fields[y] then
                             return (fields[x][1] or 1000) < (fields[y][1] or 1000)
                          else
                             return x < y
                          end
                       end)

   for idx,key in ipairs(keysort) do
      local value = serialize(node[key])
      local padded_key = key
      if key:len() < 15 then
         padded_key = (key.."               "):sub(1,15)
      end
      buffer = string.format("%s\n%s= %s", buffer, padded_key, value)
   end

   return buffer
end

-----------------------------------------------------------------------------
-- Retrieves data from Versium and creates a Saci node from it.  If Versium
-- returns nil then Saci will check if it has a method get_fallback_node()
-- (which must be set by the client) and will use it to retrieve a fallback
-- node if it is defined.  If not, it will just return nil.
--
-- @param id             the id of the desired node.
-- @param version        the desired version of the node (defaults to latest).
-- @return               (1) a newly created instance of saci.node.Node,
--                       (2) 'true' if the node returned is a stub (nil
--                           otherwise).
-----------------------------------------------------------------------------
function Saci:get_node(id, version)
   --assert(id)
   --assert(type(id)=="string")

   -- first, check if we have this node in cache
   local cache_key = id
   if version then
      cache_key = cache_key.."."..version
   end
   if self.cache[cache_key] then
      return self.cache[cache_key], self.cache_stub[cache_key]
   end

   -- second, check if we have it in versium
   local data = self.versium:get_node(id, version)
   if data then
      local node = self:make_node(data, id)
      self.cache[cache_key] = node
      return node
   end

   -- third, check with the node's parent
   local parent_id, rest = string.match(id, "^(.+)/(.-)$")
   if parent_id then
      local parent = self:get_node(parent_id)
      if parent then
         local node = parent:get_child(rest)
         if node then
            self.cache[cache_key] = node
            return node
         end
      end
   end

   -- no luck, check if we have a fallback function
   if self.get_fallback_node then
      local prototype = nil
      local node, stub = self:get_fallback_node(id, version)
      self.cache[cache_key] = node
      self.cache_stub[cache_key] = stub
      return node, stub
   end
end

-----------------------------------------------------------------------------
-- Returns revision information for the specified version of the node with a
-- given id, or for the latest version.
--
-- @param id             the id of the desired node
-- @param version        [optional] the id of the revision that we want to
--                       know about (defaults to latest version).
-- @return               a table with revision metadata, just like versium's
--                       get_node_info()
-----------------------------------------------------------------------------
function Saci:get_node_info(id, version)
   return self.versium:get_node_info(id, version)
end

-----------------------------------------------------------------------------
-- Creates a node from a data string.
--
-- @param data           data for the node
-- @param id             the id of the desired node
-- @return               the version tag for the latest version of the node
-----------------------------------------------------------------------------
function Saci:make_node(data, id)
   return saci.node.new{data=data, id=id, repository=self}
end

-----------------------------------------------------------------------------
-- Saves a node.
--
-- @param node           the node to be saved.
-- @param author         the .user name associated with the change (required).
-- @param comment        a comment associated with this change (optional).
-- @param extra          extra params (optional).
-- @return               nothing
-----------------------------------------------------------------------------
function Saci:save_node(node, author, comment, extra, timestamp)
   assert(node.id)
   self.versium:save_version(node.id, self:deflate(node.raw_values, node.fields),
                             author, comment, extra, timestamp)
end

-----------------------------------------------------------------------------
-- Returns the history of edits to the node, optionally filtered by time
-- prefix (e.g., "2007-12") and/or capped at a certain number.
--
-- @param id             the id of the node.
-- @param date_prefix    [optional] a date prefix (e.g., "2007-12").
-- @param limit          [optional] a maxium number of records to return.
-- @return               history as a table.
-----------------------------------------------------------------------------
function Saci:get_node_history(id, date_prefix, limit)
   assert(id)
   return self.versium:get_node_history(id, date_prefix, limit) or {}
end

function Saci:get_complete_history(id_prefix, date_prefix, limit)
   local id_prefix = id_prefix or ""
   if self.versium.get_complete_history then
      return self.versium:get_complete_history(id_prefix, date_prefix, limit)
   end

   local edits = {}
   local preflen = id_prefix:len()
   local ids = self.versium:get_node_ids(id_prefix or nil, limit or nil)
   for i, id in ipairs(ids) do
      if id:sub(1, preflen) == id_prefix then
         for i, edit in ipairs(self:get_node_history(id, date_prefix, limit)) do
            edit.id = id
            table.insert(edits, edit)
         end
      end
   end
   table.sort(edits, function(e1, e2) return e1.timestamp > e2.timestamp end)
   if limit then
      local another_table = {}
      for i=1,limit do
         table.insert(another_table, edits[i])
      end
      edits = another_table
   end   
   return edits
end



-----------------------------------------------------------------------------
-- Retrieves multiple data nodes from Versium and returns Saci nodes created
-- from them.  If Versium returns an empty table, then Saci will also return
-- an empty table.  This function always returns the most recent version of 
-- each node
--
-- @param prefix         the desired node prefix
-- @return               a table containing the returned Saci nodes, indexed
--                       by node name.
-----------------------------------------------------------------------------
function Saci:get_nodes_by_prefix(prefix, limit, visible, id_filter)
   local versium_nodes = self:get_versium_nodes_by_prefix(prefix, limit)
   local nodes = {}
   local ids = {}
   local cache = self.cache
   local num_hidden = 0
   for id, vnode in pairs(versium_nodes) do
      if (not id_filter) or id_filter(id) then
         local node
         if cache[id] then
            node = cache[id]
         else
            node = self:make_node(vnode, id) 
            cache[id] = node
         end
         if visible then
            if node:check_permissions(user, "show") then
               nodes[id] = node
               ids[#ids+1] = id
            else
               num_hidden = num_hidden + 1
            end
         else
            nodes[id] = node
            ids[#ids+1] = id            
         end
      end
   end
   table.sort(ids)
   return nodes, ids, num_hidden
end

-----------------------------------------------------------------------------
-- Retrieves multiple data nodes from Versium, and returns them _without_
-- creating Saci nodes from them.
--
-- @param prefix         the desired node prefix
-- @return               a table containing the returned versium nodes,
--                       indexed by node name.
-----------------------------------------------------------------------------
function Saci:get_versium_nodes_by_prefix(prefix, limit)
   -- Get the nodes, either all at once, of one by one   
   if self.versium.get_nodes_by_prefix then
      return self.versium:get_nodes_by_prefix(prefix, limit)
   else
      local versium_nodes = {}
      for i, id in ipairs(self.versium:get_node_ids(prefix, limit)) do
         versium_nodes[id] = self.versium:get_node(id)
      end
      return versium_nodes
   end
end


-----------------------------------------------------------------------------
-- Returns a list of Saci nodes with fields matching the query.
--
-- @param query          a query as a string, with implicit "or" and with
--                       negatable terms, e.g., "lua git -storage"
-- @param fields         a list of fields to search.
-- @param prefix         a prefix within which to search.
-----------------------------------------------------------------------------
function Saci:find_nodes(fields, patterns, prefix)
   assert(fields)
   assert(patterns)
   if type(fields) == "string" then fields = {fields} end
   if type(patterns) == "string" then patterns = {patterns} end
   local nodes = {}
   -- find nodes matching the patterns
   local basic_match, matched, node, value

   local function basic_match(vnode) -- check if the pattern matches raw node
      for _, pattern in ipairs(patterns) do
         if vnode:lower():match(pattern) then return true end
      end
      return false
   end

   for id, vnode in pairs(self:get_versium_nodes_by_prefix(prefix)) do
      if basic_match(vnode) then -- ok, the pattern is somewhere there, let's look
         node = self:make_node(vnode, id)
         if node:multimatch(fields, patterns) then
            table.insert(nodes, node)
         end
      end
   end

   return nodes
end      

function Saci:query_nodes(fields, query, prefix)   
   query = " "..query.." "
   fields = fields or {"content"}
   local positive_terms = {}
   local negative_terms = {}
   for term in query:gmatch("%S+") do
      if term:match("%:") then
         local key, value = term:match("^(%w+):(.+)")
         if key == "prefix" then
            prefix=value
         end
      elseif term:sub(1,1)=="-" then
         table.insert(negative_terms, "%W("..term:sub(2)..")%W")
      else
         table.insert(positive_terms, "%W("..term..")%W")
      end
   end

   local nodes = self:find_nodes(fields, positive_terms, prefix)
   local nodes_without_negatives = {}
   for i, node in ipairs(nodes) do
      if not node:multimatch(fields, negative_terms) then
         table.insert(nodes_without_negatives, node)
      end
   end
   return nodes_without_negatives
end


-- vim:ts=3 ss=3 sw=3 expandtab