ticket.cc #1

  • //
  • guest/
  • perforce_software/
  • p4/
  • 2014-1/
  • support/
  • ticket.cc
  • View
  • Commits
  • Open Download .zip Download (7 KB)
/*
 * Copyright 2004 Perforce Software.  All rights reserved.
 *
 * This file is part of Perforce - the FAST SCM System.
 */

/*
 * ticket.cc - get/replace/delete stored tickets from ticketfile.
 *
 * Perforce tickets were introduced in 2003.2 (undoc).  Initially only
 * NT supported seemless setting/getting of these tickets although this
 * was limited to one server through the P4PASSWD registry variable.
 *
 * 2004.1 introduces a ticket file:
 *
 * $USERPROFILE/p4tickets.txt          --  windows(NT)
 * $HOME/.p4tickets                    --  UNIX
 * $P4TICKETS                          --  user-defined fullpath to file
 *
 * This code manipulates the users ticket file.  Tickets are issued when the
 * user runs the 'p4 login' command,  they are deleted by running 'p4 logout'
 * and they do expire after a default 12 hours or as set by group access.
 * 
 * Any operation on the file will first begin by reading the current ticket
 * file and populating an in-memory array.  Typically this will only contain
 * a few entries.  The array is modified and written back out to the file
 * using Rename() if a delete/replace/insert operation has occurred.
 *
 * Currently only one operation is allowed per object creation.
 */

# include <stdhdrs.h>
# include <strbuf.h>
# include <error.h>
# include <vararray.h>
# include <pathsys.h>
# include <filesys.h>
# include <enviro.h>
# include "ticket.h"

# ifdef OS_NT
# include <windows.h>
# endif

struct TicketItem {
	StrBuf port;
	StrBuf user;
	StrBuf ticket;
	int deleted;
};

/*
 * TicketTable -- array of available tickets
 */

class TicketTable : public VarArray {
 
    public:
			~TicketTable();
        TicketItem	*GetItem( const StrRef &port, const StrRef &user );
        void		DeleteItem( const StrRef &port, const StrRef &user );
        void      	PutItem( const StrRef &port, const StrRef &user,
			         const StrRef &ticket );
        void      	AddItem( const StrRef &port, const StrRef &user,
			         const StrRef &ticket );
};

Ticket::Ticket( const StrPtr *path )
{
        ticketTab = 0;
	ticketFile = 0;
	this->path = path;
}

Ticket::~Ticket()
{
	delete ticketTab;
	delete ticketFile;
}

int
Ticket::Init()
{
	// only one operation allowed, bail if already initialized

	if( ticketFile != 0 )
	    return 1;

	if( !ticketTab )
            ticketTab = new TicketTable;

	if( !path->Length() )
	    return 1;

	ticketFile = FileSys::Create( (FileSysType)(FST_TEXT|FST_L_LFCRLF) );
	ticketFile->Set( *path );

	// Make sure user-defined ticket is not a directory

	int stat = ticketFile->Stat();

	if( ( stat & FSF_EXISTS ) && ( stat & FSF_DIRECTORY ) )
	    return 1;

	return 0;
}

void
Ticket::List( StrBuf &b )
{
	if( Init() )
	    return;

	Error e;

	ReadTicketFile( &e );

	if( e.Test() )
	    return;

	TicketItem *t;

	for( int i = 0; i < ticketTab->Count(); i++ )
	{
	    t = (TicketItem *)ticketTab->Get( i );

	    b << t->port << " (" << t->user << ") " << t->ticket << "\n";
	}
}

void
Ticket::ListUser( const StrPtr &u, StrBuf &b )
{
	if( Init() )
	    return;

	Error e;

	ReadTicketFile( &e );

	if( e.Test() )
	    return;

	TicketItem *t;

	for( int i = 0; i < ticketTab->Count(); i++ )
	{
	    t = (TicketItem *)ticketTab->Get( i );

	    if( u == t->user )
		b << t->port << " " << t->ticket << "\n";
	}
}

char *
Ticket::GetTicket( StrPtr &port, StrPtr &user )
{
	if( Init() )
	    return( ( char *) 0 );

	Error e;

	ReadTicketFile( &e );

	if( e.Test() )
	    return( ( char * ) 0 );

	StrBuf validPort;

	// prefix local ports with localhost:

	if( !strchr( port.Text(), ':' ) )
	{
	    validPort.Set( "localhost:" );
	    validPort.Append( port.Text() );
	}
	else
	    validPort.Set( port.Text() );

	TicketItem *t = ticketTab->GetItem( validPort, user );

	if( t )
	    return( t->ticket.Text() );
	else
	    return( ( char *) 0 );
}

void		
Ticket::UpdateTicket( 
	const StrPtr &port, 
	StrPtr &user, 
	StrPtr &ticket, 
	int remove,
	Error *e )
{
	if( Init() )
	    return;

	ReadTicketFile( e );

	if( e->Test() )
	    return;

	StrBuf validPort;

	// prefix local ports with localhost:

	if( !strchr( port.Text(), ':' ) )
	{
	    validPort.Set( "localhost:" );
	    validPort.Append( port.Text() );
	}
	else
	    validPort.Set( port.Text() );

	if( remove )
	    ticketTab->DeleteItem( validPort, user );
	else
	    ticketTab->PutItem( validPort, user, ticket );

	WriteTicketFile( e );
}

void
Ticket::ReadTicketFile( Error *e )
{
	if( !( ticketFile->Stat() & FSF_EXISTS ) )
	    return;

	ticketFile->Open( FOM_READ, e );

	if( e->Test() )
	    return;

	// Special markers used by trust files.
	StrRef dummy( "**++**" );
	StrRef alt( "++++++" );
	StrRef wild( "******" );

	StrBuf line, port, user;

	// read contents of ticket file into array

	while( ticketFile->ReadLine( &line, e ) )
	{
	    char *equals, *colon;

	    if( !( equals = strchr( line.Text(), '=' ) ) )
	        continue;
                                                                                
	    port.Set( line.Text(), equals++ - line.Text() );

	    int isTrust = !strncmp( equals, dummy.Text(), dummy.Length() ) ||
	                  !strncmp( equals, alt.Text(), alt.Length() )   ||
	                  !strncmp( equals, wild.Text(), wild.Length() );

	    colon = isTrust ? strchr( equals, ':' ) : strrchr( equals, ':' );
	    if( !colon )
	        continue;

	    user.Set( equals, colon - equals );

	    ticketTab->AddItem( port, user, colon + 1 );
	}

	ticketFile->Close( e );
}

void
Ticket::WriteTicketFile( Error *e )
{
	// create a temporary file

	FileSys *tmpFile = FileSys::CreateTemp( FST_TEXT );
        tmpFile->MakeLocalTemp( path->Text() );
	tmpFile->Perms( FPM_RW );
	tmpFile->Open( FOM_WRITE, e );

	if( e->Test() )
	{
	    delete tmpFile;
	    return;
	}

	TicketItem *t;
	StrBuf line;

	// write out file contents to temporary file

	for( int i = 0; i < ticketTab->Count(); i++ )
	{
	    t = (TicketItem *)ticketTab->Get( i );

	    if( t->deleted )
	        continue;
	
	    line.Clear();
	    line << t->port << "=" << t->user << ":" << t->ticket << "\n";

	    tmpFile->Write( &line, e );

	    if( e->Test() )
	        break;
	}

	// rename to the target ticket file

	tmpFile->ClearDeleteOnClose();
	tmpFile->Close( e );
	tmpFile->Rename( ticketFile, e );

	// make the file readonly by owner

	ticketFile->Chmod( FPM_ROO, e );

	delete tmpFile;
}

TicketTable::~TicketTable()
{
	for( int i = 0; i < Count(); i++ )
	    delete (TicketItem *)Get(i);
}

void
TicketTable::AddItem( 
	const StrRef &port, 
	const StrRef &user, 
	const StrRef &ticket )
{
	TicketItem *t = new TicketItem;

	t->port.Set( port );
	t->user.Set( user );
	t->ticket.Set( ticket.Text() );
	t->deleted = 0;

	VarArray::Put( t );
}

void
TicketTable::PutItem( 
	const StrRef &port, 
	const StrRef &user, 
	const StrRef &ticket )
{
	TicketItem *t = GetItem( port, user );

	if( t )
	{
	    t->ticket.Set( ticket );

	    // we need to set user just in case source or target user
	    // was a wild card.

	    t->user.Set( user );  
	}
	else
	    AddItem( port, user, ticket );
}

void
TicketTable::DeleteItem( 
	const StrRef &port, 
	const StrRef &user )
{
	TicketItem *t = GetItem( port, user );

	if( t )
	    t->deleted = 1;
}

TicketItem *
TicketTable::GetItem( 
	const StrRef &port, 
	const StrRef &user )
{
	TicketItem *t;
	StrRef userWild( "******" );

	for( int i = 0; i < Count(); ++i )
	{
	    t = (TicketItem * )Get(i);

	    if( t->port.CCompare( port ) )
	        continue;

	    if( !t->user.Compare( user ) || 
	        !t->user.Compare( userWild ) ||
	        !user.Compare( userWild ) )
	    {
	        return( t );
	    }
	}

	return( ( TicketItem * ) 0 );
}
# Change User Description Committed
#1 15902 Matt Attaway A second renaming that I will not obliterate as a badge of shame
//guest/perforce_software/p4/2014_1/support/ticket.cc
#1 15901 Matt Attaway Clean up code to fit modern Workshop naming standards
//guest/perforce_software/p4/2014.1/support/ticket.cc
#1 12188 Matt Attaway Move 'main' p4 into a release specific directory in prep for new releases
//guest/perforce_software/p4/support/ticket.cc
#1 9129 Matt Attaway Initial commit of the 2014.1 p4/p4api source code