Module: MetakitFS

Defined in:
lib/fs/MetakitFS/MetakitFS.rb

Defined Under Namespace

Classes: MkFile

Constant Summary collapse

MK_FENTRY =
"fentry[fpath:S,ftype:I,fsize:I,ftags:B,fdata:B]"
MK_HASHVW =
"sec[_H:I,_R:I]"
TYPE_FILE =
1
TYPE_DIR =
2
3

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.supported?(dobj) ⇒ Boolean

Returns:

  • (Boolean)


13
14
15
16
17
18
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 13

def self.supported?(dobj)
  return(false) unless dobj.mkfile
  storage = Metakit::Storage.open(dobj.mkfile, 1)
  return(false) if storage.description != "#{MK_FENTRY},#{MK_HASHVW}"
  (true)
end

Instance Method Details

#fs_dirEntries(p) ⇒ Object



56
57
58
59
60
61
62
63
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 56

def fs_dirEntries(p)
  raise "Directory: #{p} does not exist" if (i = getFileIndex(p)) < 0
  raise "#{p} is not a directory" if @pType.get(@vFentry[i]) != TYPE_DIR

  data = @pData.get(@vFentry[i])
  return [] if data.size == 0
  data.contents.split("\0")
end

#fs_dirMkdir(p) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 65

def fs_dirMkdir(p)
  #
  # If the target exists, succeed if it is a directory, otherwise fail.
  #
  if (i = getFileIndex(p)) >= 0
    return if @pType.get(@vFentry[i]) == TYPE_DIR
    raise "Cannot create directory, #{p}: file exists"
  end

  #
  # Create the directory.
  #
  create(p, TYPE_DIR)

  #
  # Apply changes to database.
  #
  @storage.commit
end

#fs_dirRmdir(p) ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 85

def fs_dirRmdir(p)
  #
  # Before we can remove a directory, it must:
  # exist, be a directory and be empty.
  #
  raise "#{p}: no such directory" if (di = getFileIndex(p)) < 0
  dirRow = @vFentry[di]
  raise "#{p}: not a directory" if @pType.get(dirRow) != TYPE_DIR
  raise "#{p}: directory not empty" if @pSize.get(dirRow) != 0

  rmCommon(p, di)
end

#fs_fileAtime(p) ⇒ Object



124
125
126
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 124

def fs_fileAtime(p)
  File.atime(p)
end

#fs_fileAtime_obj(fobj) ⇒ Object



136
137
138
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 136

def fs_fileAtime_obj(fobj)
  fobj.atime
end

#fs_fileClose(_fobj) ⇒ Object



257
258
259
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 257

def fs_fileClose(_fobj)
  nil
end

#fs_fileCtime(p) ⇒ Object



128
129
130
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 128

def fs_fileCtime(p)
  File.ctime(p)
end

#fs_fileCtime_obj(fobj) ⇒ Object



140
141
142
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 140

def fs_fileCtime_obj(fobj)
  fobj.ctime
end

#fs_fileDelete(p) ⇒ Object



261
262
263
264
265
266
267
268
269
270
271
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 261

def fs_fileDelete(p)
  #
  # Before we can remove a directory, it must:
  # exist, be a directory and be empty.
  #
  raise "#{p}: no such file" if (fi = getFileIndex(p)) < 0
  dirRow = @vFentry[di]
  raise "#{p}: is a directory" if @pType.get(dirRow) == TYPE_DIR

  rmCommon(p, fi)
end

#fs_fileDirectory?(p) ⇒ Boolean

Returns:

  • (Boolean)


109
110
111
112
113
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 109

def fs_fileDirectory?(p)
  return false if (i = getFileIndex(p)) < 0
  return true  if @pType.get(@vFentry[i]) == TYPE_DIR
  false
end

#fs_fileExists?(p) ⇒ Boolean

Returns:

  • (Boolean)


98
99
100
101
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 98

def fs_fileExists?(p)
  return false if getFileIndex(p) < 0
  true
end

#fs_fileFile?(p) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
106
107
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 103

def fs_fileFile?(p)
  return false if (i = getFileIndex(p)) < 0
  return true  if @pType.get(@vFentry[i]) == TYPE_FILE
  false
end

#fs_fileHasTag?(fobj, tag) ⇒ Boolean

Returns:

  • (Boolean)


369
370
371
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 369

def fs_fileHasTag?(fobj, tag)
  fs_tagsCommon(fobj.fileRow).include?(tag)
end

#fs_fileHasTagName?(fobj, tagName) ⇒ Boolean

Returns:

  • (Boolean)


350
351
352
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 350

def fs_fileHasTagName?(fobj, tagName)
  fs_hasTagNameCommon?(fobj.fileRow, tagName)
end

#fs_fileMtime(p) ⇒ Object



132
133
134
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 132

def fs_fileMtime(p)
  File.mtime(p)
end

#fs_fileMtime_obj(fobj) ⇒ Object



144
145
146
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 144

def fs_fileMtime_obj(fobj)
  fobj.mtime
end

#fs_fileObjExtend(fo) ⇒ Object



405
406
407
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 405

def fs_fileObjExtend(fo)
  fo.extend MkFileMod
end

#fs_fileOpen(p, mode = "r") ⇒ Object



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
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 148

def fs_fileOpen(p, mode = "r")
  fread = fwrite = fcreate = ftruncate = fappend = false
  mode.delete!("b")

  case mode[0, 1]
  when "r"
    fread     = true
    fwrite    = true if mode[-1, 1] == "+"
  when "w"
    fwrite    = true
    fcreate   = true
    ftruncate = true
    fread     = true if mode[-1, 1] == "+"
  when "a"
    fwrite    = true
    fcreate   = true
    fappend   = true
    fread     = true if mode[-1, 1] == "+"
  else
    raise "Unrecognized open mode: #{mode}"
  end

  fileRow = nil
  fi = getFileIndex(p)

  if fi < 0
    #
    # Should we create the file? If not, fail.
    #
    raise "#{p}: No such file" unless fcreate

    #
    # Create the file if it doesn't exist.
    #
    fileRow = create(p, TYPE_FILE)
    fi = getFileIndex(p)
  else
    fileRow = @vFentry[fi]
  end

  fpos = 0
  fsize = @pSize.get(fileRow)
  if ftruncate && fsize != 0
    @pSize.set fileRow, 0
    @pData.set fileRow, Metakit::Bytes.new("", 0)
    @storage.commit
  elsif fappend
    fpos = fsize
  end

  (MkFile.new(p, fileRow, fpos, fread, fwrite))
end

#fs_fileRead(fobj, len) ⇒ Object



218
219
220
221
222
223
224
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 218

def fs_fileRead(fobj, len)
  dataRef = @pData.ref(fobj.fileRow)
  rb = dataRef.access(fobj.filePos, len)
  fobj.filePos += rb.size
  return(rb.contents) if rb.contents.length > 0
  (nil)
end

#fs_fileSeek(fobj, _offset, whence) ⇒ Object

def fs_fileOpen



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 201

def fs_fileSeek(fobj, _offset, whence)
  seekPos = 0
  case whence
  when IO::SEEK_CUR
    seekPos = filePos + amt
  when IO::SEEK_END
    seekPos = fs_fileSize_obj(fobj) + amt
  when IO::SEEK_SET
    seekPos = amt
  else
    raise "Invalid whence value: #{whence}"
  end
  raise "Invalid seek position: #{seekPos}" if seekPos < 0 || seekPos > fs_fileSize_obj(fobj)

  fobj.filePos = seekPos
end

#fs_fileSize(p) ⇒ Object



115
116
117
118
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 115

def fs_fileSize(p)
  raise "File: #{p} does not exist" if (i = getFileIndex(p)) < 0
  (@pSize.get(@vFentry[i]))
end

#fs_fileSize_obj(fobj) ⇒ Object



120
121
122
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 120

def fs_fileSize_obj(fobj)
  (@pSize.get(fobj.fileRow))
end

#fs_fileTagAdd(fobj, tag) ⇒ Object



283
284
285
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 283

def fs_fileTagAdd(fobj, tag)
  fs_tagAddCommon(fobj.fileRow, tag)
end

#fs_fileTagDelete(fobj, tag) ⇒ Object



307
308
309
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 307

def fs_fileTagDelete(fobj, tag)
  fs_tagDeleteCommon(fobj.fileRow, tag)
end

#fs_fileTags(fobj) ⇒ Object



330
331
332
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 330

def fs_fileTags(fobj)
  fs_tagsCommon(fobj.fileRow)
end

#fs_fileTagValues(fobj, tag) ⇒ Object



387
388
389
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 387

def fs_fileTagValues(fobj, tag)
  fs_tagValuesCommon(fobj.fileRow, tag)
end

#fs_fileWrite(fobj, buf, len) ⇒ Object



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
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 226

def fs_fileWrite(fobj, buf, len)
  raise "fs_fileWrite: write length is larger than buffer" if len > buf.length
  size = fs_fileSize_obj(fobj)

  if fobj.filePos == size
    #
    # We're appending to the end of the file, so we can just use the
    # modify operation to add the data to the end of the file.
    #
    dataRef = @pData.ref(fobj.fileRow)
    data = Metakit::Bytes.new(buf, len)
    dataRef.modify(data, size, len)
    @pSize.set(fobj.fileRow, size + len)
    fobj.filePos += len
    @storage.commit
    return(len)
  end
  #
  # The Metakit modify operation inserts data. So if we need to overwrite
  # existing data, we must read the whole file, modify the data, and write
  # it out again.
  #
  dataStr = @pData.get(fobj.fileRow).contents
  dataStr[fobj.filePos, len] = buf[0, len]
  data = Metakit::Bytes.new(dataStr, dataStr.length)
  @pData.set(fobj.fileRow, data)
  @pSize.set(fobj.fileRow, dataStr.length)
  @storage.commit
  (len)
end

#fs_hasTag?(p, tag) ⇒ Boolean

Returns:

  • (Boolean)


363
364
365
366
367
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 363

def fs_hasTag?(p, tag)
  raise "Path: #{p} does not exist" if (i = getFileIndex(p)) < 0
  fileRow = @vFentry[i]
  fs_hasTagCommon?(fileRow, tag)
end

#fs_hasTagCommon?(fileRow, tag) ⇒ Boolean

Returns:

  • (Boolean)


373
374
375
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 373

def fs_hasTagCommon?(fileRow, tag)
  fs_tagsCommon(fileRow).include?(tag)
end

#fs_hasTagName?(p, tagName) ⇒ Boolean

Returns:

  • (Boolean)


344
345
346
347
348
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 344

def fs_hasTagName?(p, tagName)
  raise "Path: #{p} does not exist" if (i = getFileIndex(p)) < 0
  fileRow = @vFentry[i]
  fs_hasTagNameCommon?(fileRow, tagName)
end

#fs_hasTagNameCommon?(fileRow, tagName) ⇒ Boolean

Returns:

  • (Boolean)


354
355
356
357
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 354

def fs_hasTagNameCommon?(fileRow, tagName)
  fs_tagsCommon(fileRow).each { |t| return true if t =~ /#{tagName}(=.*)*$/ }
  false
end

#fs_initObject



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
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 20

def fs_init
  raise "No metakit file has been specified" unless @dobj.mkfile
  @storage = Metakit::Storage.open(@dobj.mkfile, 1)

  newFs = false
  if @storage.description != "#{MK_FENTRY},#{MK_HASHVW}"
    raise "#{@dobj.mkfile} is not a MetakitFS" unless @dobj.create
    newFs = true
  end

  self.fsType = "MetakitFS"

  vData       = @storage.get_as MK_FENTRY
  vSec        = @storage.get_as MK_HASHVW
  @vFentry    = vData.hash(vSec, 1)

  @pPath = Metakit::StringProp.new "fpath"
  @pType = Metakit::IntProp.new    "ftype"
  @pSize = Metakit::IntProp.new    "fsize"
  @pTags = Metakit::BytesProp.new  "ftags"
  @pData = Metakit::BytesProp.new  "fdata"

  @findRow = Metakit::Row.new

  #
  # If we're creating a new file system, create the root directory.
  #
  if newFs
    create("/", TYPE_DIR) if newFs
    @storage.commit
  end

  labels = fs_tagValues("/", "LABEL")
  @fsId = labels[0] unless labels.empty?
end

#fs_tagAdd(p, tag) ⇒ Object



277
278
279
280
281
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 277

def fs_tagAdd(p, tag)
  raise "Path: #{p} does not exist" if (i = getFileIndex(p)) < 0
  fileRow = @vFentry[i]
  fs_tagAddCommon(fileRow, tag)
end

#fs_tagAddCommon(fileRow, tag) ⇒ Object



287
288
289
290
291
292
293
294
295
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 287

def fs_tagAddCommon(fileRow, tag)
  tagStr = @pTags.get(fileRow).contents
  tags = tagStr.split("\0")
  return if tags.include? tag
  tags << tag
  tagStr = tags.join("\0")
  @pTags.set(fileRow, Metakit::Bytes.new(tagStr, tagStr.length))
  @storage.commit
end

#fs_tagDelete(p, tag) ⇒ Object



301
302
303
304
305
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 301

def fs_tagDelete(p, tag)
  raise "Path: #{p} does not exist" if (i = getFileIndex(p)) < 0
  fileRow = @vFentry[i]
  fs_tagDeleteCommon(fileRow, tag)
end

#fs_tagDeleteCommon(fileRow, tag) ⇒ Object



311
312
313
314
315
316
317
318
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 311

def fs_tagDeleteCommon(fileRow, tag)
  tagStr = @pTags.get(fileRow).contents
  tags = tagStr.split("\0")
  tags.delete(tag) { raise "Tag #{tag} not found" }
  tagStr = tags.join("\0")
  @pTags.set(fileRow, Metakit::Bytes.new(tagStr, tagStr.length))
  @storage.commit
end

#fs_tags(p) ⇒ Object



324
325
326
327
328
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 324

def fs_tags(p)
  raise "Path: #{p} does not exist" if (i = getFileIndex(p)) < 0
  fileRow = @vFentry[i]
  fs_tagsCommon(fileRow)
end

#fs_tagsCommon(fileRow) ⇒ Object



334
335
336
337
338
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 334

def fs_tagsCommon(fileRow)
  tags = @pTags.get(fileRow)
  return [] if tags.size == 0
  tags.contents.split("\0")
end

#fs_tagValues(p, tag) ⇒ Object



381
382
383
384
385
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 381

def fs_tagValues(p, tag)
  raise "Path: #{p} does not exist" if (i = getFileIndex(p)) < 0
  fileRow = @vFentry[i]
  fs_tagValuesCommon(fileRow, tag)
end

#fs_tagValuesCommon(fileRow, tag) ⇒ Object



391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 391

def fs_tagValuesCommon(fileRow, tag)
  values = []
  tagFound = false
  fs_tagsCommon(fileRow).each do |t|
    if t =~ /#{tag}(=(.*))*$/
      tagFound = true
      values << $2 if $2
    end
  end

  return [] unless tagFound
  values
end

#hasTag?(p, tag) ⇒ Boolean

Returns:

  • (Boolean)


359
360
361
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 359

def hasTag?(p, tag)
  fs_hasTag?(normalizePath(p), tag)
end

#hasTagName?(p, tag) ⇒ Boolean

Returns:

  • (Boolean)


340
341
342
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 340

def hasTagName?(p, tag)
  fs_hasTagName?(normalizePath(p), tag)
end

#tagAdd(p, tag) ⇒ Object



273
274
275
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 273

def tagAdd(p, tag)
  fs_tagAdd(normalizePath(p), tag)
end

#tagDelete(p, tag) ⇒ Object



297
298
299
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 297

def tagDelete(p, tag)
  fs_tagDelete(normalizePath(p), tag)
end

#tags(p) ⇒ Object



320
321
322
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 320

def tags(p)
  fs_tags(normalizePath(p))
end

#tagValues(p, tag) ⇒ Object



377
378
379
# File 'lib/fs/MetakitFS/MetakitFS.rb', line 377

def tagValues(p, tag)
  fs_tagValues(normalizePath(p), tag)
end