/* ** Copyright (c) 2007 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the Simplified BSD License (also ** known as the "2-Clause License" or "FreeBSD License".) ** This program is distributed in the hope that it will be useful, ** but without any warranty; without even the implied warranty of ** merchantability or fitness for a particular purpose. ** ** Author contact information: ** drh@hwaci.com ** http://www.hwaci.com/drh/ ** ******************************************************************************* ** ** This file contains code used to check-out versions of the project ** from the local repository. */ #include "config.h" #include "add.h" #include #include /* ** Set to true if files whose names begin with "." should be ** included when processing a recursive "add" command. */ static int includeDotFiles = 0; /* ** Add a single file */ static void add_one_file(const char *zName, int vid, Blob *pOmit){ Blob pathname; const char *zPath; file_tree_name(zName, &pathname, 1); zPath = blob_str(&pathname); if( strcmp(zPath, "manifest")==0 || strcmp(zPath, "_FOSSIL_")==0 || strcmp(zPath, "_FOSSIL_-journal")==0 || strcmp(zPath, "_FOSSIL_-wal")==0 || strcmp(zPath, "_FOSSIL_-shm")==0 || strcmp(zPath, ".fos")==0 || strcmp(zPath, ".fos-journal")==0 || strcmp(zPath, ".fos-wal")==0 || strcmp(zPath, ".fos-shm")==0 || strcmp(zPath, "manifest.uuid")==0 || blob_compare(&pathname, pOmit)==0 ){ fossil_warning("cannot add %s", zPath); }else{ if( !file_is_simple_pathname(zPath) ){ fossil_fatal("filename contains illegal characters: %s", zPath); } #ifdef __MINGW32__ if( db_exists("SELECT 1 FROM vfile" " WHERE pathname=%Q COLLATE nocase", zPath) ){ db_multi_exec("UPDATE vfile SET deleted=0" " WHERE pathname=%Q COLLATE nocase", zPath); } #else if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){ db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath); } #endif else{ db_multi_exec( "INSERT INTO vfile(vid,deleted,rid,mrid,pathname)" "VALUES(%d,0,0,0,%Q)", vid, zPath); } printf("ADDED %s\n", zPath); } blob_reset(&pathname); } /* ** All content of the zDir directory to the SFILE table. */ void add_directory_content(const char *zDir){ DIR *d; int origSize; struct dirent *pEntry; Blob path; blob_zero(&path); blob_append(&path, zDir, -1); origSize = blob_size(&path); d = opendir(zDir); if( d ){ while( (pEntry=readdir(d))!=0 ){ char *zPath; if( pEntry->d_name[0]=='.' ){ if( !includeDotFiles ) continue; if( pEntry->d_name[1]==0 ) continue; if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; } blob_appendf(&path, "/%s", pEntry->d_name); zPath = blob_str(&path); if( file_isdir(zPath)==1 ){ add_directory_content(zPath); }else if( file_isfile(zPath) ){ db_multi_exec("INSERT INTO sfile VALUES(%Q)", zPath); } blob_resize(&path, origSize); } } closedir(d); blob_reset(&path); } /* ** Add all content of a directory. */ void add_directory(const char *zDir, int vid, Blob *pOmit){ Stmt q; add_directory_content(zDir); db_prepare(&q, "SELECT x FROM sfile ORDER BY x"); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); add_one_file(zName, vid, pOmit); } db_finalize(&q); db_multi_exec("DELETE FROM sfile"); } /* ** COMMAND: add ** ** Usage: %fossil add FILE... ** ** Make arrangements to add one or more files to the current checkout ** at the next commit. ** ** When adding files recursively, filenames that begin with "." are ** excluded by default. To include such files, add the "--dotfiles" ** option to the command-line. */ void add_cmd(void){ int i; int vid; Blob repo; includeDotFiles = find_option("dotfiles",0,0)!=0; db_must_be_within_tree(); vid = db_lget_int("checkout",0); if( vid==0 ){ fossil_panic("no checkout to add to"); } db_begin_transaction(); if( !file_tree_name(g.zRepositoryName, &repo, 0) ){ blob_zero(&repo); } db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); #ifdef __MINGW32__ db_multi_exec( "CREATE INDEX IF NOT EXISTS vfile_pathname " " ON vfile(pathname COLLATE nocase)" ); #endif for(i=2; id_name[0]=='.'){ if( !includeDotFiles ) continue; if( pEntry->d_name[1]==0 ) continue; if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; } blob_appendf(&path, "/%s", pEntry->d_name); zPath = blob_str(&path); if( file_isdir(zPath)==1 ){ del_directory_content(zPath); }else if( file_isfile(zPath) ){ char *zFilePath; Blob pathname; file_tree_name(zPath, &pathname, 1); zFilePath = blob_str(&pathname); if( !db_exists( "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zFilePath) ){ printf("SKIPPED %s\n", zPath); }else{ db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zPath); printf("DELETED %s\n", zPath); } blob_reset(&pathname); } blob_resize(&path, origSize); } } closedir(d); blob_reset(&path); } /* ** COMMAND: rm ** COMMAND: delete ** ** Usage: %fossil rm FILE... ** or: %fossil delete FILE... ** ** Remove one or more files from the tree. ** ** This command does not remove the files from disk. It just marks the ** files as no longer being part of the project. In other words, future ** changes to the named files will not be versioned. */ void delete_cmd(void){ int i; int vid; db_must_be_within_tree(); vid = db_lget_int("checkout", 0); if( vid==0 ){ fossil_panic("no checkout to remove from"); } db_begin_transaction(); for(i=2; i