/* * Copyright 1995, 1996 Perforce Software. All rights reserved. * * This file is part of Perforce - the FAST SCM System. */ # define NEED_FILE # define NEED_STAT # include <stdhdrs.h> # ifdef HAVE_SYMLINKS # include <error.h> # include <strbuf.h> # include <debug.h> # include <tunable.h> # include <i18napi.h> # include <charcvt.h> # include "filesys.h" # include "pathsys.h" # include "fileio.h" # ifdef OS_NT extern int nt_readlink( StrPtr *name, StrBuf &buf, int dounicode, int lfn ); # define readlink(name,buf,dounicode,lfn) nt_readlink(name,buf,dounicode,lfn) extern int nt_makelink( StrBuf &target, StrPtr *name, int dounicode, int lfn ); # define symlink(target,name,dounicode,lfn) nt_makelink(target,name,dounicode,lfn) # endif FileIOSymlink::~FileIOSymlink() { Cleanup(); } void FileIOSymlink::Open( FileOpenMode mode, Error *e ) { offset = 0; value.Clear(); this->mode = mode; // If reading, soak up the symlink now, to be passed back by Read(). // Writing is done at close. if( mode == FOM_READ ) { # ifdef OS_NT // The StrBuf allocation is done in nt_readlink(). int l = readlink( Path(), value, DOUNICODE, LFN ); # else int size = p4tunable.Get( P4TUNE_FILESYS_MAXSYMLINK ); int l = readlink( Name(), value.Alloc( size ), size ); # endif if( l < 0 ) { e->Sys( "readlink", Name() ); return; } value.SetLength( l ); // Append newline for prettiness and terminate string. value.Append( "\n" ); } } void FileIOSymlink::Write( const char *buf, int len, Error *e ) { // Just append to internal buffer. value.Append( buf, len ); } int FileIOSymlink::Read( char *buf, int len, Error *e ) { // Just read from internal buffer. // Offset tracks how much we have. int l = value.Length() - offset; if( len < l ) l = len; memcpy( buf, value.Text() + offset, l ); offset += l; return l; } void FileIOSymlink::Close( Error *e ) { if( mode == FOM_WRITE && value.Length() ) { // Strip newline added by Open(). char *p; if( p = strchr( value.Text(), '\n' ) ) { value.SetEnd( p ); value.Terminate(); } # ifdef OS_NT if( symlink( value, Path(), DOUNICODE, LFN ) < 0 ) # else if( symlink( value.Text(), Name() ) < 0 ) # endif e->Sys( "symlink", Name() ); } // Prevent duplicate closes value.Clear(); } void FileIOSymlink::Truncate( offL_t offset, Error *e ) { } void FileIOSymlink::Truncate( Error *e ) { } int FileIOSymlink::StatModTime() { # ifdef OS_NT int t = FileIO::StatModTime(); return t >= 0 ? t : 0; # else struct stat sb; if( lstat( Name(), &sb ) < 0 ) return 0; return (int)sb.st_mtime; # endif } void FileIOSymlink::Chmod( FilePerm perms, Error *e ) { } void FileIOSymlink::ChmodTime( int modTime, Error *e ) { } # endif