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 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); }
public static NeoVirtFSStat FileDefault(uint mode = 0b110_100_100) { var stt = DateTimeOffset.UtcNow; var st = new NeoVirtFSStat() { st_size = 0, st_mode = NeoMode_T.S_IFREG | (NeoMode_T)mode, // 644 st_uid = 10010, st_gid = 10010, st_atim = stt, st_ctim = stt, st_mtim = stt, st_dtim = DateTimeOffset.MinValue, }; return(st); }
public static NeoVirtFSStat DirDefault(uint mode = 0b111_101_101) { var stt = DateTimeOffset.UtcNow; var st = new NeoVirtFSStat() { st_size = 0, st_mode = NeoMode_T.S_IFDIR | (NeoMode_T)mode, // 755 st_uid = 10010, st_gid = 10010, st_atim = stt, st_ctim = stt, st_mtim = stt, st_dtim = DateTimeOffset.MinValue, }; return(st); }
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 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 static ObjectId EnsureVolumeSetUpProperly(IMongoDatabase db, string volumeNamePath) { var HaveRoot = false; var NamespaceNames = new Dictionary <string, NeoVirtFSNamespaces>(); var Namespaces = new Dictionary <ObjectId, NeoVirtFSNamespaces>(); NeoVirtFSNamespaces RootNameSpace = null; var NeoVirtFSCol = db.NeoVirtFS(); var NeoVirtFSDeletedCol = db.NeoVirtFSDeleted(); var NeoVirtFSNamespacesCol = db.NeoVirtFSNamespaces(); var NeoVirtFSVolumesCol = db.NeoVirtFSVolumes(); var NeoVirtFSSecPrincipalsCol = db.NeoVirtFSSecPrincipals(); var NeoVirtFSSecACLsCol = db.NeoVirtFSSecACLs(); // Prepare for bulk update var updates = new List <WriteModel <NeoVirtFS> >(); // Load up the namespaces -- there just shouldn't be too many of these ProcessNamespaces(db, NamespaceNames, Namespaces, ref RootNameSpace, ref HaveRoot, updates); if (!HaveRoot) { throw new ApplicationException("Volume Namespaces don't define a Root - Setup Issue"); } // Now do volumes var(parentPath, VolumeName) = FindVolumeNameWithPath(volumeNamePath, Namespaces, RootNameSpace); if (parentPath == null) // We won't really get here - the above will throw { throw new ArgumentException($"Volume Path Not Valid: {volumeNamePath}"); } // So we actually need to create this volume into NeoVirtFSVolumes, which unfortunately needs business logic // We need some sort of policy for this. Maybe we're overthinking. Maybe we just need to be passed the path so we // don't need to decide? We have the Namespaces above so we can decode var volume = NeoVirtFSVolumesCol.FindSync(Builders <NeoVirtFSVolumes> .Filter.Eq(x => x.Name, VolumeName)).FirstOrDefault(); if (volume == null) { Console.WriteLine($"[Create Volume {VolumeName} into Namespace {parentPath.NameSpace}]"); var newNode = ObjectId.GenerateNewId(); // If the namespace moved then this isn't going to change it, though we may assert below NeoVirtFSVolumesCol.InsertOne(new NeoVirtFSVolumes() { _id = newNode, Name = VolumeName, NameSpace = parentPath._id, NodeId = newNode, // These are intentionally the same VolumeDefaultACL = null, ImportLocked = false, VolumeLocked = false, }); } // This is only going to return our one volume (which we may have just created) var volFilter = Builders <NeoVirtFSVolumes> .Filter.Eq(x => x.Name, VolumeName); var v = NeoVirtFSVolumesCol.FindSync(volFilter).FirstOrDefault(); // This is making sure that the NeoVirtFS elements match the Volume setup (they use the same keys for clarity) Console.WriteLine($"Volume: {v.Name}, NameSpace: {Namespaces[v.NameSpace].NameSpace}"); // Assert if the namespace has moved - We can just move it if (v.NameSpace != parentPath._id) { Console.WriteLine($"Volume Namespace {Namespaces[v.NameSpace].NameSpace} is not same as current Namespace {Namespaces[parentPath._id].NameSpace}"); v.NameSpace = parentPath._id; // Just move the node to the correct place within namespaces // And do it in the table (not bulk) var fixPar = new UpdateDefinitionBuilder <NeoVirtFSVolumes>() .Set("NameSpace", parentPath._id); NeoVirtFSVolumesCol.UpdateOne(volFilter, fixPar); } // Ensure that the filesystem nodes exist at the top level FilterDefinition <NeoVirtFS> filter = Builders <NeoAssets.Mongo.NeoVirtFS> .Filter.Eq(x => x._id, v._id); var upd = new UpdateDefinitionBuilder <NeoAssets.Mongo.NeoVirtFS>() .Set("_id", v._id) .SetOnInsert("Content", NeoVirtFSContent.Dir()) .SetOnInsert("Stat", NeoVirtFSStat.DirDefault()) .Set("VolumeId", v.NameSpace) .Set("ParentId", Namespaces[v.NameSpace]._id) // Set's see what root does - this will also move the Node to match the Volume .Set("Name", Encoding.UTF8.GetBytes(v.Name)) .Set("MaintLevel", false); // This is the volume level - users can do stuff here (by their policy) UpdateOneModel <NeoVirtFS> update = new UpdateOneModel <NeoAssets.Mongo.NeoVirtFS>(filter, upd) { IsUpsert = true }; updates.Add(update); // Persist NeoVirtFSCol.BulkWrite(updates); return(v._id); }
public static bool PullNamespacesAndVolumes(IMongoDatabase db, ref Dictionary <string, NeoVirtFSNamespaces> NamespaceNames, ref Dictionary <ObjectId, NeoVirtFSNamespaces> Namespaces, ref NeoVirtFSNamespaces RootNameSpace) { bool HaveRoot = false; var NeoVirtFSCol = db.NeoVirtFS(); var NeoVirtFSDeletedCol = db.NeoVirtFSDeleted(); var NeoVirtFSNamespacesCol = db.NeoVirtFSNamespaces(); var NeoVirtFSVolumesCol = db.NeoVirtFSVolumes(); var NeoVirtFSSecPrincipalsCol = db.NeoVirtFSSecPrincipals(); var NeoVirtFSSecACLsCol = db.NeoVirtFSSecACLs(); // Prepare for bulk update var updates = new List <WriteModel <NeoAssets.Mongo.NeoVirtFS> >(); // Load up the namespaces -- there just shouldn't be too many of these var nCount = ProcessNamespaces(db, NamespaceNames, Namespaces, ref RootNameSpace, ref HaveRoot, updates); if (!HaveRoot) { throw new ApplicationException("Volume Namespaces don't define a Root - Setup Issue"); } // Now do volumes int vCount = 0; var volumes = NeoVirtFSVolumesCol.FindSync(Builders <NeoVirtFSVolumes> .Filter.Empty).ToList(); foreach (var v in volumes) { //Console.WriteLine($"Volume: {v.Name}"); vCount++; // Ensure that the filesystem nodes exist at the top level FilterDefinition <NeoVirtFS> filter = Builders <NeoAssets.Mongo.NeoVirtFS> .Filter.Eq(x => x._id, v._id); var upd = new UpdateDefinitionBuilder <NeoAssets.Mongo.NeoVirtFS>() .Set("_id", v._id) .SetOnInsert("Content", NeoVirtFSContent.Dir()) .SetOnInsert("Stat", NeoVirtFSStat.DirDefault()) .Set("VolumeId", v.NameSpace) .Set("ParentId", Namespaces[v.NameSpace]._id) // Set's see what root does .Set("Name", Encoding.UTF8.GetBytes(v.Name)) .Set("MaintLevel", false); // This is the volume level - users can do stuff here (by their policy) UpdateOneModel <NeoVirtFS> update = new UpdateOneModel <NeoAssets.Mongo.NeoVirtFS>(filter, upd) { IsUpsert = true }; updates.Add(update); } Console.WriteLine($"[Loaded {nCount} Namespaces and {vCount} Volumes]"); // Persist NeoVirtFSCol.BulkWrite(updates); return(HaveRoot); }