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);
        }
Exemple #2
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);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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();
Exemple #7
0
        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);
        }
Exemple #8
0
        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);
        }