/* * Copyright 1995, 1996 Perforce Software. All rights reserved. * * This file is part of Perforce - the FAST SCM System. */ # define NEED_FILE # define NEED_CHDIR # include <stdhdrs.h> # include <charman.h> # include <i18napi.h> # include <charcvt.h> # include <charset.h> # include <error.h> # include <debug.h> # include <tunable.h> # include <strbuf.h> # include <strops.h> # include <md5.h> # include "pathsys.h" # include "filesys.h" # include "macfile.h" # include "fileio.h" # include "signaler.h" # include "enviro.h" # include "errno.h" # include "hostenv.h" # define USE_ERRNO # include <msgos.h> void FileSysCleanup( FileSys *f ) { if( f->IsDeleteOnClose() ) f->Cleanup(); } FileSys * FileSys::Create( FileSysType t ) { FileSys *f; LineType lt; // Pull the LineType out of the FileSysType. switch( t & FST_L_MASK ) { case FST_L_LOCAL: lt = LineTypeLocal; break; case FST_L_LF: lt = LineTypeRaw; break; case FST_L_CR: lt = LineTypeCr; break; case FST_L_CRLF: lt = LineTypeCrLf; break; case FST_L_LFCRLF: lt = LineTypeLfcrlf; break; default: lt = LineTypeLocal; } // Apple's an odd mod: it's a mod, but totally supplants // the text/binary type. So include it in the switch. // The other mods don't affect the base type. switch( t & ( FST_MASK | FST_M_APPLE | FST_M_APPEND ) ) { case FST_TEXT: f = new FileIOBuffer( lt ); break; case FST_UNICODE: f = new FileIOUnicode( lt ); break; case FST_BINARY: if( t & FST_C_MASK ) f = new FileIOCompress; else f = new FileIOBinary; break; case FST_RESOURCE: f = new FileIOResource; break; case FST_APPLETEXT: case FST_APPLEFILE: f = new FileIOApple; break; case FST_SYMLINK: if( SymlinksSupported() ) f = new FileIOSymlink; else f = new FileIOBinary; break; case FST_ATEXT: f = new FileIOAppend; break; case FST_UTF16: f = new FileIOUTF16( lt ); break; case FST_EMPTY: f = new FileIOEmpty; break; default: return NULL; } // Replace the type. f->type = t; // Arrange for temps to blow on exit. signaler.OnIntr( (SignalFunc)FileSysCleanup, f ); return f; } FileSys::FileSys() { // start off with permission bits as the umask; mode = FOM_READ; perms = FPM_RO; modTime = 0; sizeHint = 0; checksum = 0; cacheHint = 0; charSet = GlobalCharSet::Get(); content_charSet = GlobalCharSet::Get(); type = FST_TEXT; # ifdef OS_NT LFN = 0; # endif isTemp = 0; } FileSys::~FileSys() { // Once gone, we don't need to delete it // on interrupt anymore. signaler.DeleteOnIntr( this ); } int FileSys::BufferSize() { return p4tunable.Get( P4TUNE_FILESYS_BUFSIZE ); } void FileSys::Cleanup() { Error e; Close( &e ); if( IsDeleteOnClose() ) Unlink(); } # ifdef OS_NT void FileSys::SetLFN( const StrPtr &name ) { int lfn_val = p4tunable.Get( P4TUNE_FILESYS_WINDOWS_LFN ); if( lfn_val ) { // For LFN we need an absolute path with a drive spec. // CWD is still limited by MAX_PATH if( IsRelative( name ) ) { StrBuf cwd; cwd.Alloc( _MAX_PATH ); _getcwd( cwd.Text(), cwd.Length() ); cwd.SetLength(); // If the absolute path is over 255, use LFN support. // If the tunable is 10, LFN is always on for QA. if( lfn_val == 10 || ( cwd.Length() + name.Length() > 255 ) ) LFN = 1; } else { // Here the path is already absolute, assume a drive spec. if( lfn_val == 10 || ( name.Length() > 255 ) ) LFN = 1; } // If UNC, set LFN=2, later we use "\\?\UNC" instead of "\\?\" if( IsUNC( name ) ) LFN = 2; } } # endif void FileSys::Set( const StrPtr &name ) { # if defined(OS_NT) && (_MSC_VER >= 1800) if( name.Text()[0] != '-' ) SetLFN( name ); # endif path.Set( name ); } void FileSys::Set( const StrPtr &name, Error *e ) { # ifdef OS_NT # if (_MSC_VER >= 1800) if( name.Text()[0] != '-' ) SetLFN( name ); # endif if( !LFN ) { // For a relative path, this does not take into account p4root. int maxLen = 260; // MAX_PATH from <windows.h> if( e && name.Text() && name.Length() > maxLen ) e->Set( MsgOs::NameTooLong ) << name << StrNum( (int)name.Length() ) << StrNum( maxLen ); } # endif path.Set( name ); } void FileSys::SetDigest( MD5 *m ) { checksum = m; } int FileSys::DoIndirectWrites() { # if defined( OS_MACOSX ) return ( ( type & FST_MASK ) == FST_SYMLINK ); # else return 1; # endif } void FileSys::Translator( CharSetCvt * ) { } void FileSys::LowerCasePath() { if( CharSetApi::isUnicode( (CharSetApi::CharSet)GetCharSetPriv()) ) { StrBuf res; if( CharSetCvt::Utf8Fold( &path, &res ) == 0 ) { path = res; return; } // if Utf8 fold failed... fall through... } StrOps::Lower( path ); } /* * FileSys::GetFd() * FileSys::GetSize() * FileSys::Seek() * * Non-functional stubs. */ int FileSys::GetFd() { return -1; } int FileSys::GetOwner() { return 0; } bool FileSys::HasOnlyPerm( FilePerm perms ) { return true; } offL_t FileSys::GetSize() { return 0; } void FileSys::Seek( offL_t offset, Error * ) { } offL_t FileSys::Tell() { return 0; } /* * FileSys::Perms() - translate permission */ FilePerm FileSys::Perm( const char *perms ) { return strcmp( perms, "rw" ) ? FPM_RO : FPM_RW; } static int ContainsTraversal( const char *p ) { while( p && *p ) { if( p[0] == '.' && p[1] == '.' && ( p[2] == '\0' || p[2] == '/' # ifdef OS_NT || p[2] == '\\' # endif ) ) return 1; do { if( *++p == '/' # ifdef OS_NT || *p == '\\' # endif ) { ++p; break; } } while( *p != '\0' ); } return 0; } bool FileSys::IsRelative( const StrPtr &path ) { const char *p = path.Text(); if( *p == '/' ) return false; #ifdef OS_NT if( *p == '\\' ) return false; if( p[0] && p[1] == ':' ) return false; #endif return true; } #ifdef OS_NT bool FileSys::IsUNC( const StrPtr &path ) { const char *p = path.Text(); // At a minimum we are looking for "\\host\share". if( (p[0] == '/' || p[0] == '\\') && (p[1] == '/' || p[1] == '\\') ) { if( strchr( &(p[2]), '/' ) || strchr( &(p[2]), '\\' ) ) return true; } return false; } #endif static int UnderRootCheck( const char *name, const char *root, int rootLen ) { int result; PathSys *p = PathSys::Create(); p->Set( name ); StrBuf r; if( *root == '.' ) { HostEnv h; Enviro e; StrBuf b; h.GetCwd( b, &e ); r << b << StrRef( root + 1, rootLen - 1 ); } else r.Set( root, rootLen ); result = p->IsUnderRoot( r ); delete p; return result; } /** * FileExists * * @brief Verify that the file exists * * @param filepath * @return boolean true if exists false otherwise * @throws */ bool FileSys::FileExists( const char *filepath ) { if( !filepath ) return false; FileSys *f = FileSys::Create( FST_BINARY ); f->Set( filepath ); if( f->Stat() & FSF_EXISTS ) { delete f; return true; } delete f; return false; } // Enforces P4CLIENTPATH restrictions int FileSys::IsUnderPath( const StrPtr &roots ) { if( roots.Length() == 0 ) return 1; HostEnv h; Enviro e; StrBuf b; const char *n = Name(); if( ContainsTraversal( n ) ) return 0; if( IsRelative( StrRef( n ) ) ) { h.GetCwd( b, &e ); n = b.Text(); } char listSep = ';'; const char *p = roots.Text(); const char *s = p; while( *p ) { if( *p == listSep ) { if( p != s ) { if( UnderRootCheck( n, s, p - s ) ) return 1; } s = p + 1; } p++; } if( p != s ) return UnderRootCheck( n, s, p - s ); return 0; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 18760 | rlranft |
Populate -o //guest/perforce_software/p4/... //guest/rlranft/p4/.... |
||
//guest/perforce_software/p4/2015-1/sys/filesys.cc | |||||
#1 | 15903 | Matt Attaway | Everything should be happy now between the Workshop and the depot paths | ||
//guest/perforce_software/p4/2015_1/sys/filesys.cc | |||||
#1 | 15901 | Matt Attaway | Clean up code to fit modern Workshop naming standards | ||
//guest/perforce_software/p4/2015.1/sys/filesys.cc | |||||
#1 | 12190 | Matt Attaway | Initial drop of 2015.1 p4/p4api source |