private void NodeCacheInvalidate(NeoAssets.Mongo.NeoVirtFS node) { var key = NodeKey(node); lock (nodeCache) { nodeCache.Remove(key); } }
private void NodeCacheSet(NeoAssets.Mongo.NeoVirtFS node, int expireMins) { var key = NodeKey(node); lock (nodeCache) { var exp = DateTimeOffset.Now.AddMinutes(expireMins); nodeCache.Set(key, node, exp); } }
public override int MkDir(ReadOnlySpan <byte> path, mode_t mode) { if (verbosity > 5) { Console.WriteLine($"MkDir {path.GetString()} mode={mode}"); } int error = 0, level = 0; var procs = ProcPath(path, ref error, ref level, mustExist: false, isADir: true); if (error != 0) { return(-LibC.ENOENT); } if (procs.Count < 2) { Console.WriteLine($"Mkdir - path < 2"); return(-LibC.EPERM); } var cNode = procs.Pop(); var inNode = procs.Pop(); if (cNode.Item2 != null) { return(-LibC.EEXIST); // File (or directory) already exists } if (inNode.Item2 == null) { return(-LibC.ENOENT); // SHouldn't happen (2nd level will get error) } var createIn = inNode.Item2; if (createIn.MaintLevel) { return(-LibC.EPERM); // Nobody can create in the maintenance levels (Namespace levels) } var newRec = new NeoAssets.Mongo.NeoVirtFS() { _id = ObjectId.GenerateNewId(), Content = NeoVirtFSContent.Dir(), Stat = NeoVirtFSStat.DirDefault((uint)mode), Name = cNode.Item1, VolumeId = createIn.VolumeId, ParentId = createIn._id, MaintLevel = false, }; // It will assign it's own objectId _id NeoVirtFSCol.InsertOne(newRec); Console.WriteLine($"Create Directory {cNode.Item1.GetString()} id={newRec._id}"); return(0); }
public FileDescriptorMounted(NeoAssets.Mongo.NeoVirtFS myFile) : base(myFile) { if (!myFile.Content.MountedVolume.HasValue || !myFile.Content.AtFilePath.HasValue) { throw new ArgumentException("MountedVolume or AtFilePath not set"); } VolumeId = myFile.Content.MountedVolume.Value; MountPoint = myFile.Content.AtFilePath.Value; }
private string NodeKey(NeoAssets.Mongo.NeoVirtFS node) { var sb = new StringBuilder(); sb.Append(node.ParentId.ToString()); sb.Append('_'); sb.Append(Convert.ToHexString(node.Name)); //Console.WriteLine($"KeyN: {sb}"); return(sb.ToString()); }
public FileDescriptorAsset(NeoAssets.Mongo.NeoVirtFS myFile, MongoDB.Driver.IMongoDatabase db, MongoDB.Driver.IMongoCollection <NeoBakedVolumes.Mongo.BakedAssets> bac, MongoDB.Driver.IMongoCollection <NeoBakedVolumes.Mongo.BakedVolumes> bVol) : base(myFile) { // Just load this stuff - we become active if we get an open call asset = null; this.db = db; this.bac = bac; this.bVol = bVol; this.file = myFile; }
public static NeoVirtFS CreateDirectory(ObjectId parId, ObjectId volId, byte[] name, mode_t mode) { var newRec = new NeoVirtFS() { _id = ObjectId.GenerateNewId(), Content = NeoVirtFSContent.Dir(), Stat = NeoVirtFSStat.DirDefault((uint)mode), Name = name, VolumeId = volId, ParentId = parId, MaintLevel = false, }; return(newRec); }
private void fileDelete(NeoAssets.Mongo.NeoVirtFS rec, DeleteTypes dType) { // Remove file node from main file, move to the deleted list // Don't forget to mark the dtim rec.Stat.st_dtim = DateTimeOffset.UtcNow; rec.DeleteType = dType; // Upsert to the deleted collection - maybe this should be in a unit of work? var filter = Builders <NeoAssets.Mongo.NeoVirtFS> .Filter.Eq(x => x._id, rec._id); var insert = NeoVirtFSDeletedCol.ReplaceOneAsync(filter, rec, options: new ReplaceOptions { IsUpsert = true }); // Remove from the original collection NeoVirtFSCol.DeleteOne(filter); }
public static NeoVirtFS CreateNewFile(ObjectId parId, ObjectId volId, byte[] name, ReadOnlySpan <byte> path, mode_t mode, NeoVirtFSContent cont = null) { var id = ObjectId.GenerateNewId(); if (cont == null) { cont = NeoVirtFSContent.NewCache(path, id); } //Console.WriteLine($"Set newId for file to {id}"); var newRec = new NeoVirtFS { _id = id, Name = name, VolumeId = volId, ParentId = parId, Stat = NeoVirtFSStat.FileDefault((uint)mode), Content = cont, MaintLevel = false }; return(newRec); }
public override int Rename(ReadOnlySpan <byte> path, ReadOnlySpan <byte> newPath, int flags) { if (verbosity > 5) { Console.WriteLine($"Rename {path.GetString()} to {newPath.GetString()}"); } // Rename's a bit link link, except it's literally changing the 'Name' on the // fromPath. And the Name can also be a directory (you can rename a directory) int error = 0, level = 0; var procs = ProcPath(path, ref error, ref level, mustExist: true); if (error != 0) { return(-LibC.ENOENT); } var fromProc = procs.Pop(); var fromRec = fromProc.Item2; //Console.WriteLine($"From: {fromProc.Item1.GetString()}"); if (fromRec == null) { return(-LibC.ENOENT); // From must exist } //if (fromRec.IsDirectory) return -LibC.EISDIR; // Can't be a dir //if (!fromRec.IsFile) return -LibC.EPERM; // Must be a file if (fromRec.MaintLevel) { return(-LibC.EPERM); // Not in a maint level } int derror = 0, dlevel = 0; var dprocs = ProcPath(newPath, ref derror, ref dlevel, mustExist: false); if (derror != 0) { Console.WriteLine($" derror={derror}"); return(-LibC.ENOENT); } var toProc = dprocs.Pop(); var toRec = toProc.Item2; //Console.WriteLine($"To: {toProc.Item1.GetString()}"); Byte[] newFile = null; NeoAssets.Mongo.NeoVirtFS par = null; if (toRec != null && toRec.IsFile) // This is permitted but we obliterate the Output File { //Console.WriteLine($" -- to file - remove output {toRec.Name.GetString()}"); if (toRec.MaintLevel) { return(-LibC.EPERM); } fileDelete(toRec, DeleteTypes.RENAMEOVER); var parProc = dprocs.Pop(); var parrec = parProc.Item2; par = parrec; newFile = toRec.Name; } else if (toRec != null && toRec.IsDirectory) { //Console.WriteLine($" -- to dir - parent to new dir"); if (toRec.MaintLevel) { return(-LibC.EPERM); // Not in a maint level } par = toRec; newFile = fromRec.Name; } else { // Doesn't exist, so this is our new file (par is it's parent) var parProc = dprocs.Pop(); if (parProc.Item2 == null) { return(-LibC.ENOENT); } par = parProc.Item2; newFile = toProc.Item1; if (par.MaintLevel) { return(-LibC.EPERM); // Not in a maint level } // //Console.WriteLine($" -- nonexist - parent to new dir"); } NodeCacheInvalidate(fromRec); // Old version's going away fromRec.Rename(par, newFile); var filter = Builders <NeoAssets.Mongo.NeoVirtFS> .Filter.Eq(x => x._id, fromRec._id); var insert = NeoVirtFSCol.ReplaceOne(filter, fromRec, options: new ReplaceOptions { IsUpsert = false }); //Console.WriteLine($"Rename File: {fromRec.Name.GetString()} Match={insert.MatchedCount} Mod={insert.ModifiedCount}"); return(0); }
public override int Link(ReadOnlySpan <byte> fromPath, ReadOnlySpan <byte> toPath) { if (verbosity > 5) { Console.WriteLine($"Link {fromPath.GetString()} {toPath.GetString()} "); } // Link only creates links to files, not directories, so ultimate of fromPath must be a file // if ultimate of toPath is a directory then we create fromPath ultimate name in that directory // or we close fromPath and copy it to toPath name int error = 0, level = 0; var procs = ProcPath(fromPath, ref error, ref level, mustExist: true); if (error != 0) { return(-LibC.ENOENT); } var fromProc = procs.Pop(); var fromRec = fromProc.Item2; if (fromRec == null) { return(-LibC.ENOENT); // From must exist } if (fromRec.IsDirectory) { return(-LibC.EISDIR); // Can't be a dir } if (!fromRec.IsFile) { return(-LibC.EPERM); // Must be a file } if (fromRec.MaintLevel) { return(-LibC.EPERM); // Not in a maint level } int derror = 0, dlevel = 0; var dprocs = ProcPath(toPath, ref derror, ref dlevel, mustExist: false); if (derror != 0) { return(-LibC.ENOENT); } var toProc = dprocs.Pop(); var toRec = toProc.Item2; Byte[] newFile = null; NeoAssets.Mongo.NeoVirtFS par = null; if (toRec != null) { if (toRec.IsFile) { return(-LibC.EEXIST); // If a file it must not exist } if (!toRec.IsDirectory) { return(-LibC.EPERM); // Must be a dir otherwise } if (toRec.MaintLevel) { return(-LibC.EPERM); // Not in a maint level } par = toRec; newFile = fromRec.Name; } else { // Doesn't exist, so this is our new file (par is it's parent) var parProc = dprocs.Pop(); if (parProc.Item2 == null) { return(-LibC.ENOENT); } par = parProc.Item2; newFile = toProc.Item1; if (par.MaintLevel) { return(-LibC.EPERM); // Not in a maint level } } var newLink = fromRec.MakeLink(par, newFile); NeoVirtFSCol.InsertOne(newLink); Console.WriteLine($"Create File Link: {newLink.Name.GetString()}"); return(0); }
public FileDescriptorNotFile(NeoAssets.Mongo.NeoVirtFS myFile) : base(myFile) { }
public NodeMark(FileNode m, int level, NodeMark[] stack, ObjectId rootOfVolume, IMongoDatabase db) { NeoVirtFSCol = db.NeoVirtFS(); NeoVirtFSDeletedCol = db.NeoVirtFSDeleted(); this.m = m; this.level = level; Name = m.Name; this.rootOfVolume = rootOfVolume; var v = new NeoAssets.Mongo.NeoVirtFS { Name = Name }; if (stack == null) { v.NARPImport = v.Name.GetString(); Console.WriteLine($"NARP Import {v.NARPImport}"); var vol = NeoVirtFSVolumesCol.FindSync(x => x._id == rootOfVolume).FirstOrDefault(); if (vol == null) { throw new Exception($"Can't find volume {v.NARPImport}"); } // Make sure everything exists - this should make the filesystem nodes namespaceId = vol.NameSpace; nodeId = vol.NodeId; v.VolumeId = rootOfVolume; return; } else { v.NARPImport = stack[0].Name.GetString(); //Console.WriteLine($"NARP Import {v.NARPImport}"); v.VolumeId = rootOfVolume; } // Need potential uuid5 handle - build our raw full path var realPath = new List <byte>(Encoding.ASCII.GetBytes("/NARP")); foreach (var p in stack) { realPath.Add((byte)'/'); realPath.AddRange(p.Name); } // Work the contents Broken = true; if (m.IsLnk) { var link = m.SymbolicLink.GetString(); if (link.StartsWith(AssetTag)) { var sha1 = link.Substring(AssetTag.Length); realPath.Add((byte)'/'); realPath.AddRange(m.Name); var fileuuid = GuidUtility.Create(GuidUtility.UrlNamespace, realPath.ToArray()); AssetFiles?baRec = null; try { var theFilter = Builders <AssetFiles> .Filter.Eq("_id", fileuuid); baRec = af.FindSync(theFilter).FirstOrDefault(); } catch (Exception ex) { Console.WriteLine($"Bad assetfile {ex.Message} {Encoding.UTF8.GetString(realPath.ToArray())} - id {fileuuid}"); baRec = null; } if (baRec == null) { Console.WriteLine($"Can't find assetfile {Encoding.UTF8.GetString(realPath.ToArray())} - using file defaults"); v.Stat = NeoVirtFSStat.FileDefault(); } else { baRec.CheckStat(); // Recover old format stat //Console.WriteLine($"Found baRec {baRec._id}"); v.Stat = new NeoVirtFSStat(baRec.Stat).ToFile(); } // We've got to check the asset to see if it's actually annealed -- it could be lost // If we're a mirror we'll skip it var assFilter = Builders <BakedAssets> .Filter.Eq("_id", sha1); var ass = bac.FindSync(assFilter).FirstOrDefault(); if (ass == null) { Console.WriteLine($"Can't find the asset - {Encoding.UTF8.GetString(realPath.ToArray())} / {Encoding.UTF8.GetString(m.Name)}"); v.Stat.st_size = 0; // We could conceivably try to look on the Asset for this - restore will need to fix the stat GenerateAssetFile(m, stack, rootOfVolume, v.Stat, sha1, realPath, true); return; // Should handle as 'lost' node } v.Stat.st_size = ass.FileLength; // RealLength is the compressed size if (!ass.Annealed.Value) { //Console.WriteLine($"Asset lost -- skipping - {Encoding.UTF8.GetString(realPath.ToArray())} / {Encoding.UTF8.GetString(m.Name.ToArray())}"); GenerateAssetFile(m, stack, rootOfVolume, v.Stat, sha1, realPath, true); return; } // If we get to here, we have an annealed asset type, so we need to process Broken = false; GenerateAssetFile(m, stack, rootOfVolume, v.Stat, sha1, realPath, false); return; } else { // Let's see if we can handle the simple link to an archive directory // If the original archive exists we can just do that. var dirs = link.Split("/"); if (dirs.Length == 4 && dirs[3].StartsWith("ARC-")) { Console.WriteLine($"Archive Link: {link} dirs={dirs.Length}"); // ARC-56a6f879e8cb392b22bb7577bc5d4ba117587261-ZIP // 01234567890123456789012345678901234567890123456789 // 000000000011111111112222222222333333333344444444 var sha1 = dirs[3][4..44].ToLowerInvariant();
public FileDescriptorPhysical(NeoAssets.Mongo.NeoVirtFS myFile) : base(myFile) { }