FsysSecurity.cpp
资源名称:warftpd.zip [点击查看]
上传用户:surprise9
上传日期:2007-01-04
资源大小:426k
文件大小:21k
源码类别:
Ftp客户端
开发平台:
Visual C++
- // This is part of the WAR SOFTWARE SERIES initiated by Jarle Aase
- // Copyright 1996 by Jarle Aase. All rights reserved.
- // See the "War Software Series Licende Agreement" for details concerning
- // use and distribution.
- // ---
- // This source code, executables and programs containing source code or
- // binaries or proprietetary technology from the War Software Series are
- // NOT alloed used, viewed or tested by any governmental agencies in
- // any countries. This includes the government, departments, police,
- // military etc.
- // ---
- // This file is intended for use with Tab space = 2
- // Created and maintained in MSVC Developer Studio
- // ---
- // NAME : FsysSecurity.cpp
- // PURPOSE : File System security
- // PROGRAM :
- // DATE : Oct. 9 1996
- // AUTHOR : Jarle Aase
- // ---
- // REVISION HISTORY
- //
- /*
- The design of the security system is a combination of the UNIX security
- system and the "classic" DOS/FTP based security. The flexibility makes
- the security a little slower than other FTP servers, but it ease the
- maintainance of the sites with a uniform way of handeling the file
- system.
- Basically all files have the UNIX Perms; Read, Write and Execute.
- On directories the user must have execute permission to access the
- directory entry (if the execute permission miss, the user can not
- see the directory, or any of it's subdirs).
- Direcotories:
- Read - The user can see files in the directory
- Write - The user can create files and directories in the directory
- Execute - The user can access the directory.
- Files:
- Read - The user can read the file
- Write - The user can overwrite/delete the file
- Execute - The user can execute the file (if it is an executable)
- When the server search for permissions, it begins from the system root
- and walks down the path till the desired item is reached. If the user miss
- the execute permission on a directory along the path, the access is denied.
- The files have 3 set of permissions.
- Owner - The permissions that applies for the owner of the file
- Class - The permissions that applies for the member of the owners class
- Other - The permissions that applies for all other users.
- In order to add a little flexibility on this design, there can be defined
- several different permissions for "other".
- The rules are:
- If the current user are the owner, the "other" applies for the FTP "default" level
- (system wide or virtual server).
- If the current user not is the owner, the server checks if the current user has his
- own special permissions for this object. If he dont, the same check is performed for
- the group he belongs to (the file system itself dont distinguish between users and
- groups - they all have unique numbers. An object can therefore belong to a user or
- a group without breaking the integrety of the filesystem).
- If the current user (or his group) have special permissions, these are used as the
- "other" permissions. (If the object is owned by the users group, the user is *not*
- considered owner).
- Also: The UNIX "owner" and "class" flags are static for an object. The "other" flags
- are dynamic and can be set specially for any user or user-group. If both the user and
- his group have special rights, the uses group permissions are ignored, and the users
- personal rights used.
- The only flags that can be set on these three levels are read, write and execute.
- Other file permissions like "free file" and "dupe exception" are shared among all
- users of the object.
- In order to speed things up and avoid wasting permission files everywhere, each directory
- has a set of "default" permissions for it's directories and files. If a file or directory
- is undefined in the list, these default permissions applies. The default attributes
- are inherited by it's children, uless it has it's own attributes defined.
- This is non-standard, and allows attributes to be chained down the paths if the paths
- dont have their own permissions set. If they have their own permission set, these will
- apply and the chaining will stop.
- If no descriptos are found anywhere, the user will get "read + execute" permission on
- directories, but no permissions on the files. The users will also be able to browse, but
- not access any files.
- The security system does not check the paths against the users root-path. But the user will
- never be able to access any files below his root path, unless they apper as links to the user,
- and the link is part of the path given from the user.
- When the Find*File() functions looks for files, they first get a handle to the security
- descriptors for the Find*File() start-path. If they need to traverse directories, they
- can use this handle so that the security system dont have to perform a new scan from root.
- When the handle is closed the information is freed, and the next time the user want to
- access something, a new scan is performed.
- If the virtual file system is used this is fast, as all the information is cached. Without
- the virtual file system, the security functions have to read the information from disk.
- Each user has a UMASK for files and directories, so that files created by this user
- gets the right permissions.
- */
- #include "stdafx.h"
- #include <sys/stat.h>
- #include "WarDaemon.h"
- #include "FsysSecurity.h"
- #include "ctype.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- CLog *CFsysSecurity::m_Log = NULL;
- CCriticalSection CFsysSecurity::m_Lock;
- // Get a .Index.txt file. If we are in write mode and fail to create
- // the file in the Path, we look in .Index.ini for the path. If the
- // path dont exist, we try to create a new file in the .Index
- // directory, and when done, we add the entry to the .ini file su that
- // we can recognize the file later on...
- // In read mode we just fail if the file dont exist in the Path
- // or in the .ini file.
- FILE *CFsysSecurity::OpenSecurityGroupFile(LPCSTR Path, LPCSTR Mode)
- {
- ASSERT(AfxIsValidString(Path));
- ASSERT(AfxIsValidString(Mode));
- FILE *fp = NULL;
- LPCSTR p;
- m_Lock.Lock();
- CString cMyPath = Path;
- CString cBuf;
- CFsys::DosPath(cMyPath.GetBuffer(1));
- cMyPath.ReleaseBuffer();
- CString cMyKey;
- LPCSTR TagName = strrchr(Path, '\');
- if (!TagName || !*++TagName)
- TagName = ".suspect";
- // Check for root path
- if (!*Path)
- {
- TagName = ".Root";
- cMyKey = "@root@";
- goto ini_fallback;
- }
- // Check for disk drive X: ...
- if (cMyPath.GetLength() <= 3)
- {
- ASSERT(strlen(cMyPath) <= 3);
- ASSERT((toupper(cMyPath[0]) >= 'A') && (toupper(cMyPath[0]) <= 'Z'));
- cMyKey.Format("@drive@%c@", cMyPath[0]);
- goto ini_fallback;
- }
- cMyPath += "\.Index.txt";
- if ((fp = fopen(cMyPath,Mode)) == NULL)
- {
- LogMsg(LOGF_DEBUG,"OpenSecurityGroupFile(%s,%s) failed. %s", Path, Mode, GetLastErrorText());
- p = Path;
- cMyKey.Empty();
- while(*p)
- {
- if (!isalpha(*p) && !isdigit(*p))
- {
- char buf[8];
- sprintf(buf,"@%x@", (unsigned)*p);
- cMyKey += buf;
- }
- else
- cMyKey += *p;
- ++p;
- }
- ini_fallback:
- GetIniItem(NULL, ".\.Index\.Index.ini", "Maps", cMyKey, cMyPath, "");
- if (cMyPath.IsEmpty() && strchr(Mode,'w'))
- {
- // Make sure that we have the .Index dir available
- if (GetFileAttributes(".Index") == 0xFFFFFFFF)
- {
- CreateDirectory(".Index", NULL);
- }
- int Retries = 0;
- // Create a unique file name for this group
- for(Retries = 0; Retries < 1000; Retries ++)
- {
- struct _stat st;
- cMyPath.Format(".\.Index\%s-%lu.txt", TagName, Retries);
- if (!_stat(cMyPath,&st))
- continue; // File exist
- if ((fp = fopen(cMyPath, Mode)) != NULL)
- PutIniItem(NULL, ".\.Index\.Index.ini", "Maps", cMyKey, cMyPath);
- break;
- }
- }
- else if (!cMyPath.IsEmpty())
- {
- // The path was found in the .ini file
- fp = fopen(cMyPath, Mode);
- }
- }
- m_Lock.Unlock();
- return fp;
- }
- // Load the security descriptors for a directory
- // Path is always the directory where the permission
- // group applies
- HANDLE CFsysSecurity::LoadSecurityGroup(LPCSTR Path)
- {
- #define MYBUFSIZ (1024 * 10)
- LPSTR LineBuf = NULL;
- FILE *fp = OpenSecurityGroupFile(Path, "r");
- HANDLE Rval = INVALID_HANDLE_VALUE;
- CFsysSecurityGrp *fsg = NULL;
- CFsysSecurityNode *fsn = NULL;
- char *FileName = NULL;
- char *RealPath = NULL;
- char *Comment = NULL;
- char *UserName = NULL;
- char *ClassName = NULL;
- int Perms, Flags, DlCnt, DefaultPermDir, DefaultPermFiles;
- int FileVersion = 0;
- m_Lock.Lock();
- if (!fp)
- {
- LogMsg(LOGF_DEBUG,"LoadSecurityGroup(%s) - No security group file found.", Path);
- goto done;
- }
- LineBuf = new char[MYBUFSIZ];
- FileName = new char[MAX_PATH * 2];
- RealPath = new char[MAX_PATH * 2];
- Comment = new char[1024];
- UserName = new char[64];
- ClassName = new char[64];
- if (!fgets(LineBuf, MYBUFSIZ, fp))
- {
- LogMsg(LOGF_DEBUG,"LoadSecurityGroup(%s) - Read at 1st line.", Path);
- goto done;
- }
- sscanf(LineBuf,"%s %s %d", FileName,RealPath,&FileVersion);
- if ((FileVersion > 4) || (FileVersion < 2))
- {
- LogMsg(LOGF_WARNINGS,"LoadSecurityGroup(%s): Unknown file format (%d).", Path, FileVersion);
- goto done;
- }
- if (FileVersion == 4) // War version 2.0
- {
- if (!fgets(LineBuf, MYBUFSIZ, fp))
- {
- LogMsg(LOGF_WARNINGS,"LoadSecurityGroup(%s) - No second line.", Path);
- goto done;
- }
- MySscanf(LineBuf,"%O %O", &DefaultPermDir, &DefaultPermFiles);
- }
- else
- {
- // Fallback to War 1.* versions of the file
- DefaultPermDir = 0775; // Owner all, class all, other list + cd
- DefaultPermFiles = 0740; // Owner all, class read, other none.
- }
- // Allocate buffers for the information
- fsg = new CFsysSecurityGrp;
- fsg->DefaultPermFiles = DefaultPermFiles;
- fsg->DefaultPermDirs = DefaultPermDir;
- fsg->m_Path = Path;
- fsn = NULL;
- while(fgets(LineBuf,MYBUFSIZ,fp) != NULL)
- {
- Perms = 0; Flags = 0; *FileName = 0; *RealPath = 0; *Comment = 0; *UserName = 0; *ClassName = 0; DlCnt = 0;
- if (*LineBuf == '*')
- {
- // Link
- if (FileVersion == 2)
- MySscanf(LineBuf+1,"1%s1 %O %s %s 1%s1",
- FileName, &Perms, UserName, ClassName, RealPath);
- else
- MySscanf(LineBuf+1,"1%s1 %O 1%s1 1%s1 1%s1",
- FileName, &Perms, UserName, ClassName, RealPath);
- if (*UserName == '(') *UserName = 0;
- if (*ClassName == '(') *ClassName = 0;
- if ((Perms == 0) || !*RealPath || (*RealPath == '('))
- continue; // Bad data...
- }
- else
- {
- // Normal file info
- if (FileVersion == 2)
- MySscanf(LineBuf,"1%s1 %O %s %s %d %ld 1%s1",
- FileName, &Perms, UserName, ClassName, &Flags, &DlCnt, Comment);
- else
- MySscanf(LineBuf,"1%s1 %O 1%s1 1%s1 %d %ld 1%s1",
- FileName, &Perms, UserName, ClassName, &Flags, &DlCnt, Comment);
- if (*UserName == '(') *UserName = 0;
- if (*ClassName == '(') *ClassName = 0;
- if (!stricmp(Comment,"(null)")) *Comment = 0;
- if (!*FileName)
- continue; // Bad data...
- fsn = new CFsysSecurityNode;
- int i;
- fsn->Perms = Perms;
- fsn->DlCnt = DlCnt;
- fsn->Owner = *UserName ? (i = atoi(UserName)) ? i : CUsr::FindUser(UT_USER, UserName) : 0;
- fsn->Class = *ClassName ? (i = atoi(ClassName)) ? i : CUsr::FindUser(UT_CLASS, ClassName) : 0;
- fsn->Comment = Comment;
- fsn->FileName = FileName;
- fsg->m_Nodes.AddLast((LPVOID)fsn);
- }
- }
- Rval = (HANDLE)fsg;
- done:
- if (Rval == INVALID_HANDLE_VALUE)
- {
- if (fsg)
- delete fsg;
- }
- if (LineBuf)
- {
- delete LineBuf;
- delete FileName;
- delete RealPath;
- delete Comment;
- delete UserName;
- delete ClassName;
- }
- if (fp)
- fclose(fp);
- m_Lock.Unlock();
- return Rval;
- #undef MYBUFSIZ
- }
- HANDLE CFsysSecurity::GetSecurityDescriptor(HANDLE pGrp, LPCSTR FileName)
- {
- if (pGrp == INVALID_HANDLE_VALUE)
- return INVALID_HANDLE_VALUE;
- CFsysSecurityGrp *fsg = (CFsysSecurityGrp *)pGrp;
- CFsysSecurityNode *fsn;
- CLinkedListItem *Item;
- for(Item = fsg->m_Nodes.First(); Item; Item = fsg->m_Nodes.Next(Item))
- {
- fsn = (CFsysSecurityNode *)fsg->m_Nodes.Ptr(Item);
- ASSERT(AfxIsValidString(fsn->FileName));
- ASSERT(AfxIsValidString(fsn->Comment));
- if (!stricmp(fsn->FileName,FileName))
- return (HANDLE)fsn;
- }
- return INVALID_HANDLE_VALUE;
- }
- void CFsysSecurity::LogMsg(int flag, LPCSTR Format, ...)
- {
- CString cBuf;
- if (!ShouldLog(m_Log, flag))
- return;
- ASSERT(AfxIsValidString(Format, FALSE));
- ASSERT(m_Log != NULL);
- ASSERT(AfxIsValidAddress(m_Log,sizeof(CLog)));
- cBuf.Format("CFsysSecurity: %s", Format);
- va_list argList;
- va_start(argList, Format);
- m_Log->LogMsgV(flag, cBuf, argList);
- va_end(argList);
- }
- // Entry point when checking security. This function will
- // walk trough the path and make sure that inherited
- // permissons are taken care of.
- // If the user miss x permission to a directory down the road,
- // we return "INVALID_HANDLE_VALUE" and set the error state to
- // permission denied.
- // This function is not resolving .. or links. This must be expanded
- // prior to calling us.
- // We want the Path in internal format (cwhatever)
- HANDLE CFsysSecurity::GetSecurityGroupFromPath(int User, int Class, LPCSTR Path)
- {
- ASSERT(AfxIsValidString(Path));
- SetLastError(NO_ERROR);
- int PathLen = 0;
- LPCSTR p = Path;
- CString cMyPath = "";
- HANDLE hCurrentGrp, hPrevGrp = INVALID_HANDLE_VALUE;
- CFsysSecurityGrp *pPrevGrp = NULL;
- int Indirections;
- for(;;)
- {
- if (!*p || (*p == '\'))
- {
- if ((hCurrentGrp = LoadSecurityGroup(cMyPath)) == INVALID_HANDLE_VALUE)
- {
- ++Indirections;
- if (hPrevGrp == INVALID_HANDLE_VALUE)
- {
- // Root. Create a "dummy" group with read + execute perms on directories
- pPrevGrp = new CFsysSecurityGrp;
- pPrevGrp->DefaultPermFiles = 0;
- pPrevGrp->DefaultPermDirs = NODE_OREAD | NODE_GREAD | NODE_AREAD | NODE_OEXEC | NODE_GEXEC | NODE_AEXEC;
- hPrevGrp = (HANDLE) pPrevGrp;
- Indirections = 0;
- }
- if (Indirections == 1)
- {
- // We dont need the nodes anymore. The hPrevGrp is only neened for it's
- // default attributes.
- // In fact, if we kept the nodes we would risk to inherit file permissions
- // for files in another directory.
- pPrevGrp = (CFsysSecurityGrp *)hPrevGrp;
- pPrevGrp->DeleteAllNodes();
- }
- hCurrentGrp = hPrevGrp;
- }
- // Check execute permission
- if (!*p && (cMyPath.GetLength() > 3))
- {
- // Check if the current path is a directory.
- char *MyPath = strdup(cMyPath);
- struct _stat st;
- CFsys::DosPath(MyPath);
- if (!::_stat(MyPath,&st))
- {
- if (st.st_mode & _S_IFDIR)
- {
- free(MyPath);
- goto validiate_dir;
- }
- }
- free(MyPath);
- }
- else
- {
- // User must have execute permission
- validiate_dir:
- LPCSTR CurrentFile = strrchr(cMyPath,'\');
- if (CurrentFile)
- ++CurrentFile;
- if (CurrentFile && *CurrentFile)
- {
- if (!CheckPermission(User, Class, hPrevGrp, CurrentFile, NODE_EXEC, TRUE))
- {
- CloseSecurityGroup(hPrevGrp);
- SetLastError(ERROR_ACCESS_DENIED);
- return INVALID_HANDLE_VALUE;
- }
- }
- }
- if (hPrevGrp != hCurrentGrp)
- {
- // Close the prev group - we have a new valid one.
- if (hPrevGrp != INVALID_HANDLE_VALUE)
- CloseSecurityGroup(hPrevGrp);
- hPrevGrp = hCurrentGrp;
- Indirections = 0;
- }
- }
- if (!*p)
- break;
- cMyPath += *p++;
- }
- pPrevGrp = (CFsysSecurityGrp *)hCurrentGrp;
- pPrevGrp->m_Path = Path; // We've got to remember the correct path!
- return hCurrentGrp;
- }
- BOOL CFsysSecurity::CloseSecurityGroup(HANDLE pGrp)
- {
- CFsysSecurityGrp *pMyGrp = (CFsysSecurityGrp *)pGrp;
- ASSERT(AfxIsValidAddress(pMyGrp, sizeof(CFsysSecurityGrp)));
- delete pMyGrp;
- return TRUE;
- }
- HANDLE CFsysSecurity::CreateNode(int User, HANDLE pGrp, BOOL IsDir, LPCSTR FileName)
- {
- CFsysSecurityGrp *pMyGrp = (CFsysSecurityGrp *)pGrp;
- ASSERT(AfxIsValidAddress(pMyGrp, sizeof(CFsysSecurityGrp)));
- ASSERT(AfxIsValidString(FileName));
- HANDLE h = GetSecurityDescriptor(pGrp, FileName);
- if (h != INVALID_HANDLE_VALUE)
- return h;
- CFsysSecurityNode *fsn = new CFsysSecurityNode;
- fsn->Perms = IsDir ? pMyGrp->DefaultPermDirs : pMyGrp->DefaultPermFiles;
- fsn->Owner = 0;
- fsn->Class = 0;
- fsn->DlCnt = 0;
- fsn->Comment.Empty();
- fsn->FileName = FileName;
- pMyGrp->m_Nodes.AddLast((HANDLE) fsn);
- return (HANDLE) fsn;
- }
- // Update the .index.txt file from the data in memory. At the same time, delete
- // obsolete entries.
- BOOL CFsysSecurity::FlushGroup(HANDLE pGrp)
- {
- CFsysSecurityGrp *pMyGrp = (CFsysSecurityGrp *)pGrp;
- ASSERT(AfxIsValidAddress(pMyGrp, sizeof(CFsysSecurityGrp)));
- m_Lock.Lock();
- FILE *fp = OpenSecurityGroupFile(pMyGrp->m_Path, "w");
- if (!fp)
- {
- LogMsg(LOGF_WARNINGS,"FlushGroup(%s) - Failed to update file permissions.",
- pMyGrp->m_Path);
- m_Lock.Unlock();
- return FALSE;
- }
- fprintf(fp,"WarSoftware Series2 4n0%o 0%on",
- pMyGrp->DefaultPermDirs, pMyGrp->DefaultPermFiles);
- CFsysSecurityNode *fsn;
- CLinkedListItem *Item;
- for(Item = pMyGrp->m_Nodes.First(); Item; Item = pMyGrp->m_Nodes.Next(Item))
- {
- fsn = (CFsysSecurityNode *)pMyGrp->m_Nodes.Ptr(Item);
- ASSERT(AfxIsValidString(fsn->FileName));
- ASSERT(AfxIsValidString(fsn->Comment));
- WIN32_FIND_DATA Data;
- HANDLE h = CFsys::m_pCFsys->FindFirstFile(0, pMyGrp->m_Path, &Data);
- if (h == INVALID_HANDLE_VALUE)
- {
- // Path dont extist.
- continue;
- }
- CFsys::m_pCFsys->FindClose(h);
- // Update
- fprintf(fp,"1%s1 0%o 1%d1 1%d1 %d %ld 1%s1n",
- fsn->FileName,
- fsn->Perms,
- fsn->Owner,
- fsn->Class,
- 0, // Obsolete War 1.# inode flags...
- fsn->DlCnt,
- fsn->Comment);
- }
- fclose(fp);
- // Try to hide the file
- // If we fail, we can assume that the file is mapped into the ..Index dir and
- // then we don't care...
- CString cMyPath;
- cMyPath.Format("%s\.Index.txt", pMyGrp->m_Path);
- CFsys::DosPath(cMyPath.GetBuffer(1));
- cMyPath.ReleaseBuffer();
- CFileStatus fs;
- if (CFile::GetStatus(cMyPath,fs))
- {
- fs.m_attribute |= 0x02; // Hidden
- try
- {
- CFile::SetStatus(cMyPath, fs);
- }
- catch(CFileException *e)
- {
- LogMsg(LOGF_WARNINGS,"FlushGroup() - Caught FILE ERROR exception (%d) in file '%s' while hiding the file.",
- e->m_cause, e->m_strFileName);
- e->Delete();
- }
- }
- m_Lock.Unlock();
- return TRUE;
- }
- int CFsysSecurity::GetPermissions(int User, int Class,
- HANDLE pGrp, LPCSTR FileName, BOOL IsDir, int *Mask,
- CFsysSecurityNode **pFsn, BOOL ShowRealPerms)
- {
- CFsysSecurityGrp *pMyGrp = (CFsysSecurityGrp *)pGrp;
- ASSERT(AfxIsValidAddress(pMyGrp, sizeof(CFsysSecurityGrp)));
- ASSERT(AfxIsValidString(FileName));
- HANDLE h = GetSecurityDescriptor(pGrp, FileName);
- int Perms = 0;
- if (!ShowRealPerms && (!User || CUsr::IsAdmin(User)))
- {
- if (Mask)
- *Mask = 0777;
- return 0777; // Superuser or server call. Override security...
- }
- if (h == INVALID_HANDLE_VALUE)
- {
- if (Mask)
- *Mask = S_IRWXO;
- Perms = IsDir ? pMyGrp->DefaultPermDirs : pMyGrp->DefaultPermFiles;
- }
- else
- {
- CFsysSecurityNode *fsn = (CFsysSecurityNode *)h;
- Perms = fsn->Perms;
- if (Mask)
- {
- *Mask = S_IRWXO;
- if (fsn->Owner && (User == fsn->Owner))
- *Mask |= S_IRWXU;
- if (fsn->Class && (Class == fsn->Class))
- *Mask |= S_IRWXG;
- }
- if (pFsn)
- *pFsn = fsn;
- // TODO: Check for extra permissions for this user/class
- }
- return Perms;
- }
- BOOL CFsysSecurity::CheckPermission(int User, int Class,
- HANDLE pGrp, LPCSTR FileName, int PermsWanted, BOOL IsDir)
- {
- CFsysSecurityGrp *pMyGrp = (CFsysSecurityGrp *)pGrp;
- ASSERT(AfxIsValidAddress(pMyGrp, sizeof(CFsysSecurityGrp)));
- ASSERT(AfxIsValidString(FileName));
- int Mask;
- int Perms = GetPermissions(User, Class, pGrp, FileName, IsDir, &Mask, NULL, FALSE);
- if (PermsWanted & NODE_EXEC)
- {
- if (!((Perms & Mask) & (NODE_OEXEC | NODE_GEXEC | NODE_AEXEC)))
- return FALSE; // No permissions
- }
- if (PermsWanted & NODE_READ)
- {
- if (!((Perms & Mask) & (NODE_OREAD | NODE_GREAD | NODE_AREAD)))
- return FALSE; // No permissions
- }
- if (PermsWanted & NODE_WRITE)
- {
- if (!((Perms & Mask) & (NODE_0WRITE | NODE_GWRITE | NODE_AWRITE)))
- return FALSE; // No permissions
- }
- return TRUE;
- }
- // Handle fopen(path,"w") to hidden files
- FILE *CFsysSecurity::fopen(LPCSTR DosPath, LPCSTR Mode)
- {
- DWORD dw = GetFileAttributes(DosPath);
- if (strchr(Mode,'w') && (dw != 0xFFFFFFFF) && (dw & FILE_ATTRIBUTE_HIDDEN))
- {
- FILE *fp;
- // Turn off the readonly flag
- dw &= ~FILE_ATTRIBUTE_HIDDEN;
- SetFileAttributes(DosPath,dw);
- // open the file
- fp = ::fopen(DosPath,Mode);
- // Turn on the readonly flag
- dw |= FILE_ATTRIBUTE_HIDDEN;
- SetFileAttributes(DosPath,dw);
- return fp;
- }
- return ::fopen(DosPath,Mode);
- }
- CFsysSecurityGrp::~CFsysSecurityGrp()
- {
- ASSERT(AfxIsValidAddress(this,sizeof(CFsysSecurityGrp)));
- DeleteAllNodes();
- }
- void CFsysSecurityGrp::DeleteAllNodes()
- {
- CFsysSecurityNode *fsn;
- while(fsn = (CFsysSecurityNode *)m_Nodes.GetAndDeleteFirst())
- delete fsn;
- }
- CFsysSecurityNode::~CFsysSecurityNode()
- {
- ASSERT(AfxIsValidAddress(this,sizeof(CFsysSecurityNode)));
- }