public IFile SaveFile(IEnumerable <char> name, Stream data)
        {
            lock (this.FileManager.SyncRoot)
            {
                var realName = name.AsString();
                if (realName == null)
                {
                    throw new ArgumentNullException("realName");
                }

                realName = realName.Trim();
                if (realName == string.Empty)
                {
                    throw new ArgumentException("realName");
                }

                if (data == null)
                {
                    throw new ArgumentNullException("data");
                }

                if (data.CanRead == false)
                {
                    throw new ArgumentException("data");
                }

                var deleteMaskFileOnFailure = false;
                var maskedFile = this.GetNextMaskedFile();
                try
                {
                    var meta = this.TryGetMetaData();
                    if (meta == null)
                    {
                        // current meta data could not be read or was not found
                        meta = new XDocument(new XDeclaration("1.0", Encoding.UTF8.WebName, "yes"));
                    }

                    var directoryElement = meta.Root;
                    if (directoryElement == null)
                    {
                        // root element does not exist

                        directoryElement = new XElement(_XML_TAG_METAFILE_ROOT);
                        meta.Add(directoryElement);
                    }

                    var fileListElement = directoryElement.Elements(_XML_TAG_METAFILE_FILELIST).SingleOrDefault();
                    if (fileListElement == null)
                    {
                        // file list element does not exist

                        fileListElement = new XElement(_XML_TAG_METAFILE_FILELIST);
                        directoryElement.Add(fileListElement);
                    }

                    // try find existing entry
                    var fileElement = CollectionHelper.SingleOrDefault(fileListElement.Elements(_XML_TAG_METAFILE_FILE),
                                                                       e =>
                    {
                        var realNameNameAttrib = e.Attribute(_XML_ATTRIB_METAFILE_REALNAME);
                        if (realNameNameAttrib != null)
                        {
                            return((realNameNameAttrib.Value ?? string.Empty).ToLower().Trim() ==
                                   realName.ToLower().Trim());
                        }

                        return(false);
                    });

                    if (fileElement == null)
                    {
                        // no entry found => create new one

                        using (var s = new FileStream(maskedFile.FullName,
                                                      FileMode.CreateNew,
                                                      FileAccess.ReadWrite))
                        { /* create 0 byte file */ }

                        deleteMaskFileOnFailure = true;

                        fileElement = new XElement(_XML_TAG_METAFILE_FILE);
                        fileElement.SetAttributeValue(_XML_ATTRIB_METAFILE_REALNAME, realName);
                        fileElement.SetAttributeValue(_XML_ATTRIB_METAFILE_MASKEDNAME, maskedFile.Name);

                        fileListElement.Add(fileElement);
                    }
                    else
                    {
                        var maskedNameAttrib = fileElement.Attribute(_XML_ATTRIB_METAFILE_MASKEDNAME);
                        if (maskedNameAttrib != null &&
                            string.IsNullOrWhiteSpace(maskedNameAttrib.Value) == false)
                        {
                            maskedFile = new FileInfo(Path.Combine(this.LocalPath,
                                                                   maskedNameAttrib.Value.Trim()));
                        }
                    }

                    Rijndael           alg;
                    Rfc2898DeriveBytes pdb;
                    var pwd = new byte[48];
                    try
                    {
                        // create encrypted file
                        using (var fs = new FileStream(maskedFile.FullName,
                                                       FileMode.OpenOrCreate,
                                                       FileAccess.ReadWrite))
                        {
                            // make file empty
                            fs.SetLength(0);

                            // generate password
                            {
                                var rng = new RNGCryptoServiceProvider();
                                rng.GetBytes(pwd);

                                fileElement.SetAttributeValue(_XML_ATTRIB_METAFILE_PASSWORD,
                                                              Convert.ToBase64String(pwd));

                                pdb = new Rfc2898DeriveBytes(pwd,
                                                             CryptoHelper.DEFAULT_CRYTO_SALT,
                                                             CryptoHelper.DEFAULT_ITERATIONS);
                            }

                            alg     = Rijndael.Create();
                            alg.Key = pdb.GetBytes(32);
                            alg.IV  = pdb.GetBytes(16);

                            using (var cs = new CryptoStream(fs,
                                                             alg.CreateEncryptor(),
                                                             CryptoStreamMode.Write))
                            {
                                data.CopyTo(cs);

                                cs.Flush();
                                cs.Close();
                            }
                        }

                        // file size
                        try
                        {
                            fileElement.SetAttributeValue(_XML_ATTRIB_METAFILE_SIZE,
                                                          data.Length);
                        }
                        catch
                        {
                            // ignore
                        }

                        // update meta file
                        this.UpdateMetaData(meta);

                        var secPwd = CryptoHelper.ToSecureString(fileElement.Attribute(_XML_ATTRIB_METAFILE_PASSWORD).Value);
                        if (secPwd != null)
                        {
                            secPwd.MakeReadOnly();
                        }

                        var result = new CloudPrincipalFile();
                        result.Directory   = this;
                        result.FileManager = this.FileManager;
                        result.LocalPath   = maskedFile.FullName;
                        result.Password    = secPwd;
                        result.Xml         = fileElement;
                        result.SetName(realName);

                        // store file size
                        var sizeAttrib = fileElement.Attribute(_XML_ATTRIB_METAFILE_SIZE);
                        if (sizeAttrib != null &&
                            string.IsNullOrWhiteSpace(sizeAttrib.Value) == false)
                        {
                            result.Size = GlobalConverter.Current.ChangeType <long>(sizeAttrib.Value.Trim(),
                                                                                    CultureInfo.InvariantCulture);
                        }

                        // try update timestamps
                        try
                        {
                            maskedFile.Refresh();

                            var actions = new Action <CloudPrincipalFile, FileInfo>[]
                            {
                                (cloudFile, localFile) => cloudFile.CreationTime = localFile.CreationTimeUtc,
                                (cloudFile, localFile) => cloudFile.WriteTime    = localFile.LastWriteTimeUtc,
                            };
                            actions.ForAll(ctx => ctx.Item(result, maskedFile),
                                           throwExceptions: false);
                        }
                        catch
                        {
                            // ignore errors here
                        }

                        return(result);
                    }
                    finally
                    {
                        alg = null;
                        pwd = null;
                        pdb = null;
                    }
                }
                catch
                {
                    if (deleteMaskFileOnFailure)
                    {
                        if (maskedFile != null)
                        {
                            maskedFile.Refresh();
                            if (maskedFile.Exists)
                            {
                                maskedFile.Delete();
                                maskedFile.Refresh();
                            }
                        }
                    }

                    throw;
                }
            }
        }
        public IEnumerable <IFile> GetFiles()
        {
            var meta = this.TryGetMetaData();

            if (meta == null)
            {
                yield break;
            }

            var dir = new DirectoryInfo(this.LocalPath);

            foreach (var grp in meta.XPathSelectElements("//" + _XML_TAG_METAFILE_ROOT + "/" + _XML_TAG_METAFILE_FILELIST + "/" + _XML_TAG_METAFILE_FILE)
                     .Select(fe =>
            {
                string maskedName = null;
                string realName;

                var maskedNameAttrib = fe.Attribute(_XML_ATTRIB_METAFILE_MASKEDNAME);
                if (maskedNameAttrib != null)
                {
                    maskedName = maskedNameAttrib.Value;
                }

                var realNameAttrib = fe.Attribute(_XML_ATTRIB_METAFILE_REALNAME);
                if (realNameAttrib == null ||
                    string.IsNullOrWhiteSpace(realNameAttrib.Value))
                {
                    realName = maskedName;
                }
                else
                {
                    realName = realNameAttrib.Value.Trim();
                }

                return(new
                {
                    MaskedName = maskedName,
                    RealName = realName,
                    XmlElement = fe,
                });
            }).Where(i => string.IsNullOrWhiteSpace(i.MaskedName) == false &&
                     string.IsNullOrWhiteSpace(i.RealName) == false)
                     .GroupBy(i => i.MaskedName.ToLower().Trim()))
            {
                var item = grp.Last();

                var maskedFile = new FileInfo(Path.Combine(dir.FullName, item.MaskedName));
                if (maskedFile.Exists == false)
                {
                    continue;
                }

                SecureString pwd = null;

                var passwordAttrib = item.XmlElement.Attribute(_XML_ATTRIB_METAFILE_PASSWORD);
                if (passwordAttrib != null &&
                    string.IsNullOrWhiteSpace(passwordAttrib.Value) == false)
                {
                    pwd = CryptoHelper.ToSecureString(passwordAttrib.Value);
                    if (pwd != null)
                    {
                        pwd.MakeReadOnly();
                    }
                }

                var newFile = new CloudPrincipalFile()
                {
                    Directory   = this,
                    FileManager = this.FileManager,
                    LocalPath   = maskedFile.FullName,
                    Password    = pwd,
                    Xml         = item.XmlElement,
                };
                newFile.SetName(item.RealName);

                // try get file size
                var sizeAttrib = item.XmlElement.Attribute(_XML_ATTRIB_METAFILE_SIZE);
                if (sizeAttrib != null &&
                    string.IsNullOrWhiteSpace(sizeAttrib.Value) == false)
                {
                    newFile.Size = GlobalConverter.Current
                                   .ChangeType <long>(sizeAttrib.Value.Trim(),
                                                      CultureInfo.InvariantCulture);
                }

                newFile.RefreshTimestamps();

                yield return(newFile);
            }
        }