Ongoing work on watch/edit support
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java
index 7532bdb..5826d55 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/CVSTeamProvider.java
@@ -333,43 +333,6 @@
 			throw new CVSServerException(status);
 		}
 	}
-
-	/**
-	 * Checkout the provided resources so they can be modified locally and committed.
-	 */
-	public void checkout(IResource[] resources, boolean recurse, IProgressMonitor progress) throws TeamException {
-		
-		final ICVSResource[] cvsResources = getCVSArguments(resources);
-		
-		// mark the files locally as being checked out
-		for (int i = 0; i < cvsResources.length; i++) {
-			ICVSResource resource = cvsResources[i];
-			resource.accept(new ICVSResourceVisitor() {
-				public void visitFile(ICVSFile file) throws CVSException {
-					file.checkout(ICVSFile.NO_NOTIFICATION);
-				}
-				public void visitFolder(ICVSFolder folder) throws CVSException {
-					// nothing needs to be done here as the recurse will handle the traversal
-				}
-			}, recurse);
-		}
-		
-		// send the noop command to the server in order to deliver the notifications
-		final boolean[] connected = new boolean[] { false };
-		try {
-			Session.run(workspaceRoot.getRemoteLocation(), workspaceRoot.getLocalRoot(), true, new ICVSRunnable() {
-				public void run(IProgressMonitor monitor) throws CVSException {
-					connected[0] = true;
-					Command.NOOP.execute(Command.NO_GLOBAL_OPTIONS, Command.NO_LOCAL_OPTIONS, 
-					cvsResources, null, monitor);
-				}
-			}, progress);
-		} catch (CVSException e) {
-			// Only report the exception if we were able to connect.
-			// If we couldn't connect, the notification will be sent the next time we do.
-			if (connected[0]) throw e;
-		}
-	}
 		
 	/**
 	 * @see ITeamProvider#delete(IResource[], int, IProgressMonitor)
@@ -482,7 +445,7 @@
 			progress.done();
 		}
 	}
-	
+		
 	/**
 	 * Replace the local version of the provided resources with the remote using "cvs update -C ..."
 	 * 
@@ -795,14 +758,6 @@
 	}
 	
 	/**
-	 * Currently, we support only the optimistic model so uncheckout dores nothing.
-	 * 
-	 * @see ITeamProvider#uncheckout(IResource[], int, IProgressMonitor)
-	 */
-	public void uncheckout(IResource[] resources, int depth, IProgressMonitor progress) throws TeamException {
-	}
-	
-	/**
 	 * Generally useful update.
 	 * 
 	 * The tag parameter determines any stickyness after the update is run. If tag is null, any tagging on the
@@ -1200,7 +1155,9 @@
 						if (readOnlys.isEmpty()) return OK;
 						
 						// XXX We should try to create a PM using the provided context
-						checkout((IFile[]) readOnlys.toArray(new IFile[readOnlys.size()]), false /* recurse */, null);
+						edit((IFile[]) readOnlys.toArray(new IFile[readOnlys.size()]), 
+							false /* recurse */, true /* notify server */, 
+							ICVSFile.NO_NOTIFICATION, null);
 					} catch (TeamException e) {
 						return e.getStatus();
 					}
@@ -1210,7 +1167,9 @@
 					// Ignore files that are not read-only
 					if (!file.isReadOnly()) return OK;
 					try {
-						checkout(new IResource[] {file}, false /* recurse */, null);
+						edit(new IResource[] {file},
+							false /* recurse */, true /* notify server */, 
+							ICVSFile.NO_NOTIFICATION, null);
 					} catch (TeamException e) {
 						return e.getStatus();
 					}
@@ -1224,8 +1183,114 @@
 
 	/**
 	 * Answer true if watch/edit support is enabled for this provider.
+	 * @return boolean
 	 */
 	public boolean isWatchEditEnabled() {
 		return CVSProviderPlugin.getPlugin().isWatchEditEnabled();
 	}
+
+	/**
+	 * Checkout (cvs edit) the provided resources so they can be modified locally and committed.
+	 * This will make any read-only resources in the list writable and will notify the server
+	 * that the file is being edited. This notification may be done immediately or at some 
+	 * later point depending on whether contact with the server is possble at the time of 
+	 * invocation or the value of the notify server parameter.
+	 * 
+	 * The recurse parameter is equivalent to the cvs local options -l (<code>true</code>) and 
+	 * -R (<code>false</code>). The notifyServer parameter can be used to defer server contact
+	 * until the next command. This may be approrpiate if no shell or progress monitor is available
+	 * to the caller. The notification bit field indicates what temporary watches are to be used while
+	 * the file is being edited. The possible values that can be ORed together are ICVSFile.EDIT, 
+	 * ICVSFile.UNEDIT and ICVSFile.COMMIT. There pre-ORed convenience values ICVSFile.NO_NOTIFICATION
+	 * and ICVSFile.NOTIFY_ON_ALL are also available.
+	 * 
+	 * @param resources the resources to be edited
+	 * @param recurse indicates whether to recurse (-R) or not (-l)
+	 * @param notifyServer indicates whether to notify the server now, if possible,
+	 *     or defer until the next command.
+	 * @param notification the temporary watches.
+	 * @param progress progress monitor to provide progress indication/cancellation or <code>null</code>
+	 * @exception CVSException if this method fails.
+	 * @since 2.1
+	 * 
+	 * @see CVSTeamProvider#unedit
+	 */
+	public void edit(IResource[] resources, boolean recurse, boolean notifyServer, final int notification, IProgressMonitor progress) throws CVSException {
+		notifyEditUnedit(resources, recurse, notifyServer, new ICVSResourceVisitor() {
+			public void visitFile(ICVSFile file) throws CVSException {
+				if (file.isReadOnly())
+					file.edit(notification);
+			}
+			public void visitFolder(ICVSFolder folder) throws CVSException {
+				// nothing needs to be done here as the recurse will handle the traversal
+			}
+		}, progress);
+	}
+	
+	/**
+	 * Unedit the given resources. Any writtable resources will be reverted to their base contents
+	 * and made read-only and the server will be notified that the file is no longer being edited.
+	 * This notification may be done immediately or at some 
+	 * later point depending on whether contact with the server is possble at the time of 
+	 * invocation or the value of the notify server parameter.
+	 * 
+	 * The recurse parameter is equivalent to the cvs local options -l (<code>true</code>) and 
+	 * -R (<code>false</code>). The notifyServer parameter can be used to defer server contact
+	 * until the next command. This may be approrpiate if no shell or progress monitor is available
+	 * to the caller.
+	 * 
+	 * @param resources the resources to be unedited
+	 * @param recurse indicates whether to recurse (-R) or not (-l)
+	 * @param notifyServer indicates whether to notify the server now, if possible,
+	 *     or defer until the next command.
+	 * @param progress progress monitor to provide progress indication/cancellation or <code>null</code>
+	 * @exception CVSException if this method fails.
+	 * @since 2.1
+	 * 
+	 * @see CVSTeamProvider#edit
+	 */
+	public void unedit(IResource[] resources, boolean recurse, boolean notifyServer, IProgressMonitor progress) throws TeamException {
+		notifyEditUnedit(resources, recurse, notifyServer, new ICVSResourceVisitor() {
+			public void visitFile(ICVSFile file) throws CVSException {
+				if (!file.isReadOnly())
+					file.unedit();
+			}
+			public void visitFolder(ICVSFolder folder) throws CVSException {
+				// nothing needs to be done here as the recurse will handle the traversal
+			}
+		}, progress);
+	}
+	
+	/*
+	 * This method captures the common behavior between the edit and unedit methods.
+	 */
+	private void notifyEditUnedit(IResource[] resources, boolean recurse, boolean notifyServer, ICVSResourceVisitor editUneditVisitor, IProgressMonitor progress) throws CVSException {
+		progress = Policy.monitorFor(progress);
+		final ICVSResource[] cvsResources = getCVSArguments(resources);
+		
+		// mark the files locally as being checked out
+		for (int i = 0; i < cvsResources.length; i++) {
+			cvsResources[i].accept(editUneditVisitor, recurse);
+		}
+		
+		// send the noop command to the server in order to deliver the notifications
+		if (notifyServer) {
+			final boolean[] connected = new boolean[] { false };
+			try {
+				Session.run(workspaceRoot.getRemoteLocation(), workspaceRoot.getLocalRoot(), true, new ICVSRunnable() {
+					public void run(IProgressMonitor monitor) throws CVSException {
+						connected[0] = true;
+						Command.NOOP.execute(Command.NO_GLOBAL_OPTIONS, Command.NO_LOCAL_OPTIONS, 
+						cvsResources, null, monitor);
+					}
+				}, progress);
+			} catch (CVSException e) {
+				// Only report the exception if we were able to connect.
+				// If we couldn't connect, the notification will be sent the next time we do.
+				if (connected[0]) throw e;
+			} finally {
+				progress.done();
+			}
+		}
+	}
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFile.java
index 0ab33e4..6d9800d 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFile.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFile.java
@@ -70,16 +70,14 @@
 	 * Sets the file to read-only (<code>true</code>) or writable (<code>false</code>).
 	 * 
 	 * This method is used by the command framework and should not be used by other clients.
-	 * Other clients should use <code>checkout</code> and <code>uncheckout</code> instead as they
+	 * Other clients should use <code>edit</code> and <code>unedit</code> instead as they
 	 * will report the change to the server if appropriate.
 	 */
 	void setReadOnly(boolean readOnly) throws CVSException;
 	
 	/**
-	 * Answers whether the file is read-only or not.
-	 * 
-	 * This method is used by the command framework and should not be used by other clients.
-	 * Other clients should use <code>isCheckedOut</code> instead.
+	 * Answers whether the file is read-only or not. If a file is read-only, <code>edit</code>
+	 * should be invoked to make the file editable.
 	 */
 	boolean isReadOnly() throws CVSException;
 	
@@ -118,12 +116,6 @@
 	public ILogEntry[] getLogEntries(IProgressMonitor monitor) throws TeamException;
 	
 	/**
-	 * Indicate whether a fiel has been checked out for local editing. A file is checked out
-	 * for local editing if it's read-only bit is false.
-	 */
-	public boolean isCheckedOut() throws CVSException;
-	
-	/**
 	 * Mark the file as checked out to allow local editing (analogous to "cvs edit"). 
 	 * If this method is invoked when <code>isCheckedOut()</code> returns <code>false</code>, 
 	 * a notification message that will be sent to the server on the next connection
@@ -132,7 +124,7 @@
 	 * @param notifications the set of operations for which the local user would like notification
 	 * while the local file is being edited.
 	 */
-	public void checkout(int notifications) throws CVSException;
+	public void edit(int notifications) throws CVSException;
 
 	/**
 	 * Undo a checkout of the file (analogous to "cvs unedit").
@@ -140,7 +132,7 @@
 	 * a notification message that will be sent to the server on the next connection
 	 * If <code>isCheckedOut()</code> returns <code>false</code> then nothing is done.
 	 */
-	public void uncheckout() throws CVSException;
+	public void unedit() throws CVSException;
 	
 	/**
 	 * Answer any pending notification information associated with the receiver.
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFolder.java
index c1a5d11..7a1e585 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFolder.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/ICVSFolder.java
@@ -152,12 +152,5 @@
 	 * @exception CVSException if the operation failed.
 	 */
 	public void run(ICVSRunnable job, IProgressMonitor monitor) throws CVSException;
-	
-	/**
-	 * Answer the list of pending notifications for the folder. An empty list or <code>null</code>
-	 * may be returned if there are no pending notifications.
-	 * 
-	 * This method is used by the command framework and should not be used by other clients.
-	 */
-	public NotifyInfo[] getPendingNotifications() throws CVSException;
+
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java
index fe538bc..0c9104f 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFile.java
@@ -253,8 +253,8 @@
 	/**
 	 * @see org.eclipse.team.internal.ccvs.core.ICVSFile#checkout(int)
 	 */
-	public void checkout(int notifications) throws CVSException {
-		if (isCheckedOut()) return;
+	public void edit(int notifications) throws CVSException {
+		if (!isReadOnly()) return;
 		
 		// convert the notifications to internal form
 		char[] internalFormat;
@@ -287,17 +287,10 @@
 	}
 
 	/**
-	 * @see org.eclipse.team.internal.ccvs.core.ICVSFile#isCheckedOut()
-	 */
-	public boolean isCheckedOut() throws CVSException {
-		return !isReadOnly();
-	}
-
-	/**
 	 * @see org.eclipse.team.internal.ccvs.core.ICVSFile#uncheckout()
 	 */
-	public void uncheckout() throws CVSException {
-		if (!isCheckedOut()) return;
+	public void unedit() throws CVSException {
+		if (isReadOnly()) return;
 		
 		// record the notification
 		NotifyInfo info = getNotifyInfo();
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java
index 941a12c..73e3553 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseFolder.java
@@ -315,14 +315,5 @@
 	public ICVSResource[] fetchChildren(IProgressMonitor monitor) throws CVSException {
 		return members(FILE_MEMBERS | FOLDER_MEMBERS);
 	}
-	
-	/**
-	 * @see org.eclipse.team.internal.ccvs.core.ICVSFolder#getPendingNotifications()
-	 */
-	public NotifyInfo[] getPendingNotifications() throws CVSException {
-		if (isCVSFolder()) {
-			return EclipseSynchronizer.getInstance().getAllNotifyInfo((IContainer)resource);		
-		}
-		return null;
-	}
+
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
index 97b2096..6c388fe 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/EclipseSynchronizer.java
@@ -16,6 +16,7 @@
 import java.util.Set;
 
 import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
@@ -872,6 +873,7 @@
 	 */
 	public NotifyInfo getNotifyInfo(IResource resource) throws CVSException {
 		NotifyInfo[] infos = SyncFileWriter.readAllNotifyInfo(resource.getParent());
+		if (infos == null) return null;
 		for (int i = 0; i < infos.length; i++) {
 			NotifyInfo notifyInfo = infos[i];
 			if (notifyInfo.getName().equals(resource.getName())) {
@@ -880,15 +882,6 @@
 		}
 		return null;
 	}
-
-	/**
-	 * Anwser all the notification information associated with the given folder
-	 * @param parent
-	 * @return NotifyInfo[]
-	 */
-	public NotifyInfo[] getAllNotifyInfo(IContainer parent) throws CVSException {
-		return SyncFileWriter.readAllNotifyInfo(parent);
-	}
 	
 	/**
 	 * Method deleteNotifyInfo.
@@ -911,4 +904,11 @@
 		SyncFileWriter.writeAllNotifyInfo(resource.getParent(), newInfos);
 	}
 
+	public void copyFileToBaseDirectory(IFile file) throws CVSException {
+		ResourceSyncInfo info = getResourceSync(file);
+		// The file must exist remotely and must exist
+		if (info == null || info.isAdded() || info.isDeleted())
+			return;
+		SyncFileWriter.writeFileToBaseDirectory(file, info);
+	}
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
index 44dd9c7..d05d7e1 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFile.java
@@ -548,21 +548,14 @@
 	/**
 	 * @see org.eclipse.team.internal.ccvs.core.ICVSFile#checkout(int)
 	 */
-	public void checkout(int notifications) throws CVSException {
+	public void edit(int notifications) throws CVSException {
 		// do nothing
 	}
 
 	/**
-	 * @see org.eclipse.team.internal.ccvs.core.ICVSFile#isCheckedOut()
-	 */
-	public boolean isCheckedOut() {
-		return false;
-	}
-
-	/**
 	 * @see org.eclipse.team.internal.ccvs.core.ICVSFile#uncheckout()
 	 */
-	public void uncheckout() throws CVSException {
+	public void unedit() throws CVSException {
 		// do nothing
 	}
 
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolder.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolder.java
index 058d58e..2f46f46 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolder.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/resources/RemoteFolder.java
@@ -760,12 +760,5 @@
 		Assert.isTrue( ! path.isEmpty());
 		return getRelativePathFromRootRelativePath((ICVSFolder)root.getChild(path.segment(0)), path.removeFirstSegments(1));
 	}
-	
-	/**
-	 * @see org.eclipse.team.internal.ccvs.core.ICVSFolder#getPendingNotifications()
-	 */
-	public NotifyInfo[] getPendingNotifications() throws CVSException {
-		return null;
-	}
 
 }
\ No newline at end of file
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/BaseRevisionInfo.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/BaseRevisionInfo.java
new file mode 100644
index 0000000..474b67a
--- /dev/null
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/syncinfo/BaseRevisionInfo.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2002 IBM Corporation and others.
+ * All rights reserved.   This program and the accompanying materials
+ * are made available under the terms of the Common Public License v0.5
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v05.html
+ * 
+ * Contributors:
+ * IBM - Initial API and implementation
+ ******************************************************************************/
+package org.eclipse.team.internal.ccvs.core.syncinfo;
+
+import org.eclipse.team.internal.ccvs.core.CVSException;
+import org.eclipse.team.internal.ccvs.core.Policy;
+import org.eclipse.team.internal.ccvs.core.util.EmptyTokenizer;
+
+/**
+ * This class represents an entry in the CVS/Baserev file
+ */
+public class BaseRevisionInfo {
+	
+	protected static final String SEPERATOR = "/"; //$NON-NLS-1$
+	protected static final char BASE_REVISION_PREFIX = 'B';
+	
+	private String filename;
+	private String revision;
+	
+	public BaseRevisionInfo(String filename, String revision) {
+		this.filename = filename;
+		this.revision = revision;
+	}
+	
+	public BaseRevisionInfo(String line) throws CVSException {
+		if (line.charAt(0) != BASE_REVISION_PREFIX) {
+			throw new CVSException(Policy.bind("BaseRevisionInfo.MalformedLine", line)); //$NON-NLS-1$
+		};
+		EmptyTokenizer tokenizer = new EmptyTokenizer(line.substring(1), SEPERATOR);
+		if(tokenizer.countTokens() != 4) {
+			throw new CVSException(Policy.bind("BaseRevisionInfo.MalformedLine", line)); //$NON-NLS-1$
+		}
+		filename = tokenizer.nextToken();
+		revision = tokenizer.nextToken();
+	}
+
+	public String getBaserevLine() {
+		StringBuffer buffer = new StringBuffer();
+		buffer.append(BASE_REVISION_PREFIX);
+		buffer.append(getName());
+		buffer.append(SEPERATOR);
+		buffer.append(getRevision());
+		buffer.append(SEPERATOR);
+		return buffer.toString();
+	}
+
+	private Object getRevision() {
+		return revision;
+	}
+
+	private Object getName() {
+		return filename;
+	}
+
+}
diff --git a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java
index d64d8cf..3c97307 100644
--- a/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java
+++ b/bundles/org.eclipse.team.cvs.core/src/org/eclipse/team/internal/ccvs/core/util/SyncFileWriter.java
@@ -54,6 +54,8 @@
 	//private static final String PERMISSIONS = "Permissions"; //$NON-NLS-1$
 	public static final String ENTRIES_LOG="Entries.Log"; //$NON-NLS-1$
 	public static final String NOTIFY = "Notify"; //$NON-NLS-1$
+	public static final String BASE_DIRNAME = "Base"; //$NON-NLS-1$
+	public static final String BASEREV = "Baserev"; //$NON-NLS-1$
 	
 	// the local workspace file that contains pattern for ignored resources
 	public static final String IGNORE_FILE = ".cvsignore"; //$NON-NLS-1$
@@ -425,4 +427,29 @@
 			throw CVSException.wrapException(e);
 		}
 	}
+	/**
+	 * Method writeFileToBaseDirectory.
+	 * @param file
+	 * @param info
+	 */
+	public static void writeFileToBaseDirectory(IFile file, ResourceSyncInfo info) throws CVSException {
+		try {
+			IContainer cvsFolder = getCVSSubdirectory(file.getParent());
+			IFolder baseFolder = cvsFolder.getFolder(new Path(BASE_DIRNAME));
+			if (!baseFolder.exists()) {
+				baseFolder.create(false /* force */, true /* local */, null);
+			}
+			IFile target = baseFolder.getFile(new Path(file.getName()));
+			if (target.exists()) {
+				// XXX Should ensure that we haven't already copied it
+				// XXX write the revision to the CVS/Baserev file
+				target.setContents(file.getContents(), false /* force */, false /* history */, null);
+			} else {
+				target.create(file.getContents(), false /* force */, null);
+			}
+		} catch (CoreException e) {
+			throw CVSException.wrapException(e);
+		}
+	}
+
 }
\ No newline at end of file