// See RedSea File System

U0 RedSeaFreeFreeList(CDrive *drive)
{
        CFreeList       *tmpf, *tmpf1;
        Bool             unlock;
        try
        {
                unlock = DriveLock(drive);
                if (tmpf = drive->next_free)
                {
                        while (tmpf != &drive->next_free)
                        {
                                tmpf1 = tmpf->next;
                                Free(tmpf);
                                tmpf = tmpf1;
                        }
                }
                drive->next_free = NULL;
                if (unlock)
                        DriveUnlock(drive);
        }
        catch
                if (unlock)
                        DriveUnlock(drive);
}

U0 RedSeaFreeListBuild(CDrive *drive)
{
        Bool             unlock;
        CFreeList       *tmpf;
        I64                      i, first = drive->data_area, max_blk = drive->size + drive->drv_offset;

        try
        {
                unlock = DriveLock(drive);
                if (drive->next_free)
                        RedSeaFreeFreeList(drive);
                QueueInit(&drive->next_free);
                while (first < max_blk)
                {
                        i = 0;  //count free clus
                        while (first + i < max_blk)
                        {
                                DriveFATBlkSet(drive, first + i);
                                if (Bt(drive->cur_fat_blk, (first + i - drive->data_area) & (BLK_SIZE << 3 - 1)))
                                        break;
                                else
                                        i++;
                        }
                        if (i)
                        {
                                tmpf = ZMAlloc(sizeof(CFreeList));
                                tmpf->size  = i;
                                tmpf->start = first;
                                QueueInsert(tmpf, drive->last_free);
                        }
                        first += i + 1;
                }
                if (unlock)
                        DriveUnlock(drive);
        }
        catch
                if (unlock)
                        DriveUnlock(drive);
}

U0 RedSeaInit(CDrive *drive)
{
        CRedSeaBoot     br;
        Bool            unlock;

        try
        {
                unlock = DriveLock(drive);
                BlkRead(drive, &br, drive->drv_offset, 1);
                if (br.signature != MBR_PT_REDSEA || br.signature2 != 0xAA55)
                        throw('Drive');
                drive->fs_type          = FSt_REDSEA;
                RedSeaFreeFreeList(drive);
                drive->spc                      = 1;
                drive->size                     = br.sects;
                drive->data_area        = drive->drv_offset + br.bitmap_sects;
                drive->root_clus        = br.root_clus;
                drive->fat1     = drive->fat2 = drive->drv_offset + 1;
                DriveFATBlkAlloc(drive);
                if (unlock)
                        DriveUnlock(drive);
        }
        catch
                if (unlock)
                        DriveUnlock(drive);
}

Bool RedSeaValidate(U8 drv_let)
{
        CDrive          *drive;
        CRedSeaBoot      br;

        if ((drive = Letter2Drive(drv_let, FALSE)) && drive->fs_type == FSt_REDSEA &&
                        BlkRead(drive, &br, drive->drv_offset, 1) && br.signature == MBR_PT_REDSEA && br.signature2 == 0xAA55)
                return TRUE;
        else
                return FALSE;
}

U0 RedSeaFormat(U8 drv_let, Bool quick=TRUE)
{
        U8                      *root_dir;
        CDirEntry       *d_native;
        CRedSeaBoot     *br = CAlloc(BLK_SIZE);
        CDrive          *drive = Letter2Drive(drv_let);
        I64                      i, n, root_dir_blks;

        try
        {
                DriveLock(drive);
//                      DriveTypeSet(drv_let, FSt_REDSEA);
                DriveTypeSet(drv_let, FSt_FAT32);
                drive->fs_type          = FSt_REDSEA;
                br->signature           = MBR_PT_REDSEA;
                br->signature2          = 0xAA55;
                br->drv_offset          = drive->drv_offset; //For CD/DVD image copy.
                br->sects                       = drive->size;
                n = (br->sects + BLK_SIZE << 3 - 1) / BLK_SIZE << 3;
                br->bitmap_sects        = n;
                br->unique_id           = TSCGet^Now()(U64);
                br->root_clus           = 0;

                if (quick)
                        i = n + 1;
                else
                        i = drive->size;
                BlkWriteZero(drive, drive->drv_offset, i);

                BlkWrite(drive, br, drive->drv_offset, 1);
                RedSeaInit(drive);
                ClusAlloc(drive, 0, 1, FALSE); //Alloc #1

                root_dir_blks = MaxI64(1, drive->bd->init_root_dir_blks);
                br->root_clus = ClusAlloc(drive, 0, root_dir_blks, FALSE);
                BlkWrite(drive, br, drive->drv_offset, 1);
                root_dir = CAlloc(BLK_SIZE * root_dir_blks);

                d_native = root_dir - offset(CDirEntry.start);

                d_native->attr          = RS_ATTR_DIR | RS_ATTR_CONTIGUOUS;
                *d_native->name         = '.';
                d_native->clus          = br->root_clus;
                d_native->size          = BLK_SIZE * root_dir_blks;
                d_native->datetime      = Now;

                d_native(U8 *) += CDIR_SIZE;

                *d_native->name         = '.';
                d_native->name[1]       = '.';
                d_native->attr          = RS_ATTR_DIR | RS_ATTR_CONTIGUOUS;
                d_native->clus          = br->root_clus;
                d_native->datetime      = Now;

                BlkWrite(drive, root_dir, br->root_clus, root_dir_blks);
                RedSeaInit(drive);
                DriveUnlock(drive);
        }
        catch
                DriveUnlock(drive);
        Free(br);
        Free(root_dir);
}

Bool RedSeaFileFind(CDrive *drive, I64 cur_dir_clus, U8 *name, CDirEntry *_res, I64 fuf_flags=0)
{//FUF_JUST_DIRS, FUF_JUST_FILES
        CDirEntry       *buf, *buf2, *ptr;
        U8                       dname[CDIR_FILENAME_LEN];
        I64                      ch;
        Bool             res = FALSE, unlock;

        if (fuf_flags & ~FUG_FILE_FIND)
                throw('FUF');
        MemSet(_res, 0, sizeof(CDirEntry));
        DriveCheck(drive);
        if (drive->fs_type != FSt_REDSEA)
                PrintErr("Not RedSea Drive\n");
        else if (!CFileNameTo(dname, name))
                PrintErr("Invalid FileName: \"%s\".\n", name);
        else
                try
                {
                        unlock = DriveLock(drive);
                        buf2 = MAlloc(BLK_SIZE);
                        BlkRead(drive, buf2, cur_dir_clus, 1);

                        ptr = buf2(U8 *) - offset(CDirEntry.start);
                        buf = MAlloc(ptr->size);
                        BlkRead(drive, buf, cur_dir_clus, ptr->size >> BLK_SIZE_BITS);
                        Free(buf2);

                        ptr = buf(U8 *) - offset(CDirEntry.start);
                        *ptr->name = '.';
                        ptr->name[1] = 0;
                        while (TRUE)
                        {
                                if (!(ch = *ptr->name))
                                        break;
                                else if (!(ptr->attr & RS_ATTR_DELETED) &&
                                                 !(fuf_flags & FUF_JUST_DIRS    && !(ptr->attr & RS_ATTR_DIR)) &&
                                                 !(fuf_flags & FUF_JUST_FILES   &&   ptr->attr & RS_ATTR_DIR)  &&
                                                 !StrCompare(dname, ptr->name))
                                {
                                        MemCopy(&_res->attr, &ptr->attr, CDIR_SIZE);
                                        res = TRUE;
                                        goto rsff_done;
                                }
                                ptr(U8 *) += CDIR_SIZE;
                        }
rsff_done:
                        Free(buf);
                        if (unlock)
                                DriveUnlock(drive);
                }
                catch
                        if (unlock)
                                DriveUnlock(drive);

        return res;
}

U8 *RedSeaFileRead(CDrive *drive, U8 *cur_dir, U8 *filename, I64 *_size, I64 *_attr)
{
        U8                      *buf = NULL;
        CDirEntry        de;
        I64                      c, blk_count, cur_dir_clus;

        DriveCheck(drive);
        *_size = 0;
        *_attr = 0;
        if (drive->fs_type != FSt_REDSEA)
                PrintErr("Not RedSea Drive\n");
        else
                try
                {
                        DriveLock(drive);
                        cur_dir_clus = Name2DirClus(drive, cur_dir);
                        if (RedSeaFileFind(drive, cur_dir_clus, filename, &de, FUF_JUST_FILES))
                        {
                                blk_count = (de.size + BLK_SIZE - 1) >> BLK_SIZE_BITS;
                                buf = MAlloc(blk_count << BLK_SIZE_BITS + 1);
                                c = de.clus;
                                c = BlkRead(drive, buf, c, blk_count);
                                buf[de.size] = 0; //Terminate
                                *_size = de.size;
                                *_attr = FileAttr(de.name, de.attr);
                        }
                        DriveUnlock(drive);
                }
                catch
                        DriveUnlock(drive);

        return buf;
}

Bool RedSeaCd(U8 *name, I64 cur_dir_clus)
{
        CDirEntry de;

        if (Fs->cur_dv->fs_type != FSt_REDSEA)
                PrintErr("Not RedSea Drive\n");
        else if (RedSeaFileFind(Fs->cur_dv, cur_dir_clus, name, &de, FUF_JUST_DIRS))
                return TRUE;
        else
                PrintErr("File not found: \"%s\".\n", name);

        return FALSE;
}

U0 RedSeaFreeClus(CDrive *drive, I64 c, I64 count)
{
        CFreeList       *tmpf;
        Bool             found = FALSE, unlock, unlock_break;

        DriveCheck(drive);
        if (!c)
                return;
        if (drive->fs_type != FSt_REDSEA)
                PrintErr("Not RedSea Drive\n");
        else
                try
                {
                        unlock_break = BreakLock;
                        unlock = DriveLock(drive);
                        if (!drive->next_free)
                                RedSeaFreeListBuild(drive);
                        tmpf = drive->next_free;
                        while (!found && tmpf != &drive->next_free)
                        {
                                if (tmpf->start + tmpf->size == c)
                                {
                                        tmpf->size += count;
                                        found = TRUE;
                                }
                                else if (c + count == tmpf->start)
                                {
                                        tmpf->size += count;
                                        tmpf->start = c;
                                        found = TRUE;
                                }
                                tmpf = tmpf->next;
                        }
                        if (!found)
                        {
                                tmpf = ZMAlloc(sizeof(CFreeList));
                                tmpf->size  = count;
                                tmpf->start = c;
                                QueueInsert(tmpf, drive->last_free);
                        }
                        while (count-- > 0)
                        {
                                DriveFATBlkSet(drive, c);
                                LBtr(drive->cur_fat_blk, (c - drive->data_area) & (BLK_SIZE << 3 - 1));
                                LBts(&drive->fat_blk_dirty, 0);
                                c++;
                        }
                        DriveFATBlkClean(drive);

                        if (unlock)
                                DriveUnlock(drive);
                        if (unlock_break)
                                BreakUnlock;
                }
                catch
                {
                        if (unlock)
                                DriveUnlock(drive);
                        if (unlock_break)
                                BreakUnlock;
                }
}

I64 RedSeaAllocClus(CDrive *drive, I64 count)
{
        CFreeList       *tmpf, *best_free = NULL;
        I64                      i, first, best_size = I64_MAX;
        Bool             unlock, unlock_break;

        if (count <= 0)
                throw('Drive');
        try
        {
                unlock_break = BreakLock;
                unlock = DriveLock(drive);
                if (!drive->next_free)
                        RedSeaFreeListBuild(drive);
                tmpf = drive->next_free;
                while (tmpf != &drive->next_free)
                {
                        if (tmpf->size >= count && tmpf->size < best_size)
                        {
                                best_free = tmpf;
                                best_size = tmpf->size;
                                if (tmpf->size == count)
                                        break;
                        }
                        tmpf = tmpf->next;
                }
                if (!best_free)
                        throw('Drive');
                first = best_free->start;
                for (i = 0; i < count; i++)
                {
                        DriveFATBlkSet(drive, first + i);
                        LBts(drive->cur_fat_blk, (first + i - drive->data_area) & (BLK_SIZE << 3 - 1));
                        LBts(&drive->fat_blk_dirty, 0);
                }
                DriveFATBlkClean(drive);
                if (best_free->size -= count)
                        best_free->start += count;
                else
                {
                        QueueRemove(best_free);
                        Free(best_free);
                }
                if (unlock)
                        DriveUnlock(drive);
                if (unlock_break)
                        BreakUnlock;
        }
        catch
        {
                if (unlock)
                        DriveUnlock(drive);
                if (unlock_break)
                        BreakUnlock;
        }

        return first;
}

Bool RedSeaDirNew(CDrive *drive, U8 *cur_dir, CDirEntry *tmpde, Bool free_old_chain)
{
        CDirEntry       *buf, *buf2, *ptr, de2;
        CRedSeaBoot     *br;
        I64                      c, ch, i = 1, j = 0, n = BLK_SIZE / CDIR_SIZE, dir_size, cur_dir_clus;
        Bool             written = FALSE, unlock, unlock_break;
        U8                      *tmp, *parent_dir;

        try
        {
                unlock_break = BreakLock;
                tmpde->attr |= RS_ATTR_CONTIGUOUS;
                unlock = DriveLock(drive);
                cur_dir_clus = Name2DirClus(drive, cur_dir);
                buf2 = MAlloc(BLK_SIZE);
                BlkRead(drive, buf2, cur_dir_clus, 1);

                ptr = buf2(U8 *) - offset(CDirEntry.start);
                buf = MAlloc(ptr->size);
                BlkRead(drive, buf, cur_dir_clus, ptr->size >> BLK_SIZE_BITS);

                dir_size = ptr->size;
                ptr = buf(U8 *) - offset(CDirEntry.start) + CDIR_SIZE;
                Free(buf2);
                while (TRUE)
                {
                        if (!(ch = *ptr->name))
                        {
                                if (!written)
                                        MemCopy(&ptr->start, &tmpde->start, CDIR_SIZE);
                                if ((i + 1) * CDIR_SIZE + j << BLK_SIZE_BITS < dir_size)
                                        BlkWrite(drive, buf(U8 *) + j << BLK_SIZE_BITS, cur_dir_clus + j, 1);
                                else
                                {
                                        buf2 = CAlloc(dir_size + BLK_SIZE);
                                        MemCopy(buf2, buf, dir_size);
                                        RedSeaFreeClus(drive, cur_dir_clus, dir_size >> BLK_SIZE_BITS);
                                        dir_size += BLK_SIZE;
                                        c = ClusAlloc(drive, 0, dir_size >> BLK_SIZE_BITS, TRUE);
                                        Free(buf);
                                        buf = buf2;
                                        ptr = buf(U8 *) - offset(CDirEntry.start);
                                        ptr->size = dir_size;
                                        ptr->clus = c;
                                        BlkWrite(drive, buf, c, dir_size >> BLK_SIZE_BITS);
                                        if (cur_dir_clus == drive->root_clus)
                                        {
                                                br = CAlloc(BLK_SIZE);
                                                BlkRead(drive, br, drive->drv_offset, 1);
                                                br->root_clus = c;
                                                BlkWrite(drive, br, drive->drv_offset, 1);
                                                Free(br);
                                                drive->root_clus = c;
                                        }
                                        else
                                        {
                                                tmp = StrNew(cur_dir);
                                                parent_dir = StrNew(cur_dir);
                                                StrLastRemove(parent_dir, "/", tmp);
                                                if (!*parent_dir)
                                                {
                                                        Free(parent_dir);
                                                        parent_dir = StrNew("/");
                                                }
                                                if (RedSeaFileFind(drive, Name2DirClus(drive, parent_dir), tmp, &de2, FUF_JUST_DIRS))
                                                {
                                                        de2.clus = c;
                                                        de2.size = dir_size;
                                                        RedSeaDirNew(drive, parent_dir, &de2, FALSE);
                                                }
                                                else
                                                        throw('Drive');
                                                Free(tmp);
                                                Free(parent_dir);
                                        }
                                }
                                break;
                        }
                        else if (ptr->attr & RS_ATTR_DELETED)
                        {
                                if (!written)
                                {
                                        MemCopy(&ptr->start, &tmpde->start, CDIR_SIZE);
                                        BlkWrite(drive, buf(U8 *) + j << BLK_SIZE_BITS, cur_dir_clus + j, 1);
                                        written = TRUE;
                                }
                        }
                        else
                        {
                                if (!StrCompare(tmpde->name, ptr->name))
                                {
                                        if (free_old_chain)
                                                RedSeaFreeClus(drive, ptr->clus, (ptr->size + BLK_SIZE - 1) >> BLK_SIZE_BITS);
                                        if (!written)
                                                MemCopy(&ptr->start, &tmpde->start, CDIR_SIZE);
                                        else
                                                ptr->attr |= RS_ATTR_DELETED;
                                        BlkWrite(drive, buf(U8 *) + j << BLK_SIZE_BITS, cur_dir_clus + j, 1);
                                        break;
                                }
                        }
                        ptr(U8 *) += CDIR_SIZE;
                        if (++i >= n)
                        {
                                j++;
                                i = 0;
                        }
                }
                Free(buf);
                if (unlock)
                        DriveUnlock(drive);
                if (unlock_break)
                        BreakUnlock;
        }
        catch
        {
                if (unlock)
                        DriveUnlock(drive);
                if (unlock_break)
                        BreakUnlock;
        }

        return FALSE;
}

I64 RedSeaFilesDel(CDrive *drive, U8 *cur_dir, U8 *files_find_mask, I64 fuf_flags, Bool del_dir, Bool print_message)
{
        CDirEntry       *buf, *buf2, *ptr;
        I64                      i = 0, res = 0, ch, j = 0, n = BLK_SIZE / CDIR_SIZE, cur_dir_clus;
        Bool             unlock_break;

        try
        {
                unlock_break = BreakLock;
                DriveLock(drive);
                cur_dir_clus = Name2DirClus(drive, cur_dir);
                buf2 = MAlloc(BLK_SIZE);
                BlkRead(drive, buf2, cur_dir_clus, 1);

                ptr = buf2(U8 *) - offset(CDirEntry.start);
                buf = MAlloc(ptr->size);
                BlkRead(drive, buf, cur_dir_clus, ptr->size >> BLK_SIZE_BITS);
                Free(buf2);

                ptr = buf(U8 *) - offset(CDirEntry.start);
                *ptr->name   = '.';
                ptr->name[1] = 0;
                while (TRUE)
                {
                        if (!(ch = *ptr->name))
                                break;
                        else if (!(ptr->attr & RS_ATTR_DELETED) && ch != '.' &&
                                        (del_dir || !(ptr->attr & RS_ATTR_DIR)) && FilesFindMatch(ptr->name, files_find_mask, fuf_flags))
                        {
                                if (!(ptr->attr & RS_ATTR_DIR))
                                        res++;
                                if (print_message)
                                        "Del %s\n", ptr->name;
                                ptr->attr |= RS_ATTR_DELETED;
                                BlkWrite(drive, buf(U8 *) + j << BLK_SIZE_BITS, cur_dir_clus + j, 1);
                                RedSeaFreeClus(drive, ptr->clus, (ptr->size + BLK_SIZE - 1) >> BLK_SIZE_BITS);
                        }
                        ptr(U8 *) += CDIR_SIZE;
                        if (++i >= n)
                        {
                                j++;
                                i = 0;
                        }
                }
                Free(buf);
                DriveUnlock(drive);
                if (unlock_break)
                        BreakUnlock;
        }
        catch
        {
                DriveUnlock(drive);
                if (unlock_break)
                        BreakUnlock;
        }

        return res;
}

I64 RedSeaFileWrite(CDrive *drive, U8 *cur_dir, U8 *name, U8 *buf, I64 size, CDate cdt, I64 attr)
{
        CDirEntry       de;
        I64                     c = 0, blk_count;

        MemSet(&de, 0, sizeof(CDirEntry));
        if (size < 0)
                size = 0;
        if (drive->fs_type != FSt_REDSEA)
                PrintErr("Not RedSea Drive\n");
        else if (!CFileNameTo(de.name, name))
                PrintErr("Invalid FileName: \"%s\".\n", name);
        else
        {
                RedSeaFilesDel(drive, cur_dir, de.name, 0, FALSE, FALSE);
                de.size = size;
                if (blk_count = (size + BLK_SIZE - 1) >> BLK_SIZE_BITS)
                        c = ClusAlloc(drive, 0, blk_count, TRUE); //Always contiguous
                else
                        c = INVALID_CLUS;
                de.clus         = c;
                de.attr         = attr|RS_ATTR_CONTIGUOUS;
                de.datetime     = cdt;
                if (blk_count)
                        BlkWrite(drive, buf, c, blk_count);
                RedSeaDirNew(drive, cur_dir, &de, TRUE);
        }
        return c;
}

CDirEntry *RedSeaFilesFind(U8 *files_find_mask, I64 fuf_flags, CDirEntry *parent=NULL)
{
        CDrive          *drive = Fs->cur_dv;
        CDirEntry       *buf, *buf2, *ptr, *res = NULL, *tmpde;
        I64                      ch, cur_dir_clus;

        if (fuf_flags & ~FUG_FILES_FIND)
                throw('FUF');
        try
        {
                DriveLock(drive);
                cur_dir_clus = Name2DirClus(drive, Fs->cur_dir);
                buf2 = MAlloc(BLK_SIZE);
                BlkRead(drive, buf2, cur_dir_clus, 1);

                ptr = buf2(U8 *) - offset(CDirEntry.start);
                buf = MAlloc(ptr->size);
                BlkRead(drive, buf, cur_dir_clus, ptr->size >> BLK_SIZE_BITS);
                Free(buf2);

                ptr = buf(U8 *) - offset(CDirEntry.start);
                *ptr->name   = '.';
                ptr->name[1] = 0;
                ptr(U8 *) += CDIR_SIZE;
                ptr->clus = Name2ParentDirClus(drive, Fs->cur_dir);
                ptr(U8 *) -= CDIR_SIZE;
                while (TRUE)
                {
                        if (!(ch = *ptr->name))
                                break;
                        else if (!(ptr->attr & RS_ATTR_DELETED))
                        {
                                tmpde = CAlloc(sizeof(CDirEntry));
                                MemCopy(&tmpde->start, &ptr->start, CDIR_SIZE);
                                tmpde->parent = parent;
                                if (Bt(&fuf_flags, FUf_RECURSE) && tmpde->attr & RS_ATTR_DIR && *tmpde->name != '.')
                                {
                                        tmpde->next = res;
                                        res = tmpde;
                                        tmpde->full_name = DirNameAbs(tmpde->name);
                                        DriveUnlock(drive);
                                        if (Cd(tmpde->name))
                                        {
                                                tmpde->sub = RedSeaFilesFind(files_find_mask, fuf_flags, tmpde);
                                                Cd("..");
                                        }
                                        DriveLock(drive);
                                }
                                else
                                {
                                        tmpde->full_name = FileNameAbs(tmpde->name);
                                        if ((tmpde->attr & RS_ATTR_DIR || !Bt(&fuf_flags, FUf_JUST_DIRS)) &&
                                                !(Bt(&fuf_flags, FUf_RECURSE) && *tmpde->name == '.' && tmpde->attr & RS_ATTR_DIR) &&
                                                FilesFindMatch(tmpde->full_name, files_find_mask, fuf_flags))
                                        {
                                                tmpde->next = res;
                                                res = tmpde;
                                        }
                                        else
                                                DirEntryDel(tmpde);
                                }
                        }
                        ptr(U8 *) += CDIR_SIZE;
                }
                Free(buf);
                DriveUnlock(drive);
        }
        catch
                DriveUnlock(drive);

        return res;
}

Bool RedSeaMkDir(CDrive *drive, U8 *cur_dir, U8 *name, I64 entry_count)
{//entry_count is for preallocating dir blks.
        I64                      c, cur_dir_clus = Name2DirClus(drive, cur_dir), size = CeilU64((entry_count + 3) << 6, BLK_SIZE);
#assert CDIR_SIZE == 64
        U8                      *buf = CAlloc(size);
        CDirEntry       *d_native = buf - offset(CDirEntry.start);
        Bool             unlock_break;

        try
        {
                unlock_break = BreakLock;
                c = FileWrite(name, buf, size, 0, RS_ATTR_DIR);
                d_native->attr          = RS_ATTR_DIR | RS_ATTR_CONTIGUOUS;
                StrCopy(d_native->name, name);
                d_native->clus          = c;
                d_native->size          = size;
                d_native->datetime      = Now;
                d_native(U8 *) += CDIR_SIZE;

                d_native->attr          = RS_ATTR_DIR | RS_ATTR_CONTIGUOUS;
                *d_native->name         = '.';
                d_native->name[1]       = '.';
                d_native->name[2]       = 0;
                d_native->clus          = cur_dir_clus;
                d_native->size          = 0;
                d_native->datetime      = Now;
                BlkWrite(drive, buf, c, 1);
                Free(buf);
                if (unlock_break)
                        BreakUnlock;
        }
        catch
                if (unlock_break)
                        BreakUnlock;

        return TRUE;
}