Хрестоматия по программированию на Си в Unix
* программа должна обладать правами суперпользователя.
*/
return FAILED;
}
unlink( src );
return OK;
default: /* dst - не существует или обычный файл */
printf( "move %s --> %s\n", src, dst );
unlinkd( dst, typeto );
/* зачищаем место, т.к. link()
* отказывается выполняться, если
* файл dst уже существует (errno==EEXIST).
*/
if( link( src, dst ) < 0 ) return FAILED;
unlinkd( src, typefrom ); /* удаляем старый файл */
return OK;
}
}
/* Если не получилось связать файл при помощи link() - следует
* скопировать файл в указанное место, а затем уничтожить старый файл.
*/
int mcopy(char *src, char *dst, unsigned typefrom, unsigned typeto)
{
if( typefrom == S_IFDIR )
return FAILED;
/* каталог не копируем, поскольку непосредственная запись
* в каталог (как целевой файл) разрешена только ядру ОС.
*/
return docopy( src, dst, typefrom, typeto );
}
/* Переименование файла */
int domove(char *src, char *dst, unsigned typefrom, unsigned typeto)
{
switch( typefrom ){
default:
if( ! mlink( src, dst, typefrom, typeto)){
if( ! mcopy( src, dst, typefrom, typeto)){
printf( "Can't move %s\n", src );
return FAILED;
} else unlinkd( src, typefrom ); /* стереть старый */
}
break;
case S_IFDIR: /* каталог переименовываем в каталог */
if( ! strcmp( ".", basename(src))){
printf( "impossible to move directory \".\"\n" );
return FAILED;
}
if( ! mlink( src, dst, typefrom, typeto )){
if( errno == EXDEV )
printf( "No cross device directory links\n" );
return FAILED;
}
break;
case ECANTSTAT:
printf( "%s does not exist\n", src );
return FAILED;
}
return OK; /* okay */
}
int docpmv( char *src, /* файл-источник */
char *dst, /* файл-получатель */
struct ftype typeto, /* тип файла-получателя */
int cp, /* 0 - переименование, 1 - копирование */
int *confirm /* запрашивать подтверждение на перезапись ? */
){
struct ftype typefrom; /* тип источника */
char namebuf[BUFSIZ]; /* новое имя получателя (если надо) */
typefrom = filetype(src);
if(typefrom.type == ECANTSTAT){ /* не существует */
printf("%s does not exist.\n", src);
return FAILED;
}
if( typefrom.type != S_IFDIR && typeto.type == S_IFDIR ){
/* файл в каталоге dst */
sprintf(namebuf, "%s/%s", dst, basename(src));
typeto = filetype(dst = namebuf);
}
if(typefrom.dev == typeto.dev && typefrom.ino == typeto.ino){
/* Нельзя копировать файл сам в себя */
printf("%s and %s are identical.\n", src, dst);
return OK; /* так как файл уже есть - считаем это удачей */
}
/* если получатель уже существует, то
* запросить подтверждение на перезапись */
if(*confirm && typeto.type == S_IFREG){
char answer[40];
printf("%s already exists. Overwrite (y/n/all) ? ", dst);
fflush(stdout);
switch( *gets(answer)){
case 'n': default: return OK; /* ничего не делать */
case 'y': break;
case 'a': *confirm = NO; /* дальше - без запросов */
break;
}
}
return cp ? docopy(src, dst, typefrom.type, typeto.type) :
domove(src, dst, typefrom.type, typeto.type) ;
}
void main(int argc, char *argv[]) {
char *cmd; int cp, i, err, confirm = YES;
struct ftype typeto; /* тип файла-получателя */
if( argc < 3 ) {
printf( "Usage: %s source... destination\n", argv[0] );
exit(1);
/* ненулевой код возврата сигнализирует об ошибке */
}
/* выделяем базовое имя программы. */
cmd = basename( argv[0] );
if ( !strcmp( cmd, CP )) cp = 1;
else if( !strcmp( cmd, MV )) cp = 0;
else{
printf( "%s - wrong program name.\n", cmd );
exit(2);
}
typeto = filetype( argv[argc-1] );
if(cp && typeto.type != S_IFDIR && typeto.type != S_IFBLK
&& typeto.type != S_IFCHR && argc > 3){
printf("Group of files can be copied "
"to the directory or device only.\n"); exit(3);
}
if(!cp && typeto.type != S_IFDIR && argc > 3){
printf("Group of files can be moved "
"to the directory only.\n"); exit(4);
}
for(err=0, i=1; i < argc-1; i++)
err += ! docpmv(argv[i], argv[argc-1], typeto,
cp, &confirm);
exit(err); /* 0, если не было ошибок */
}
/* Пример 13 */
/* Обход дерева каталогов в MS DOS при помощи смены текущего каталога.
* Аналог ls -R в UNIX. По аналогичному алгоритму работает программа
* find . -print (напишите команду find, используя match())
*/
#define STYLE2
#include
#include
#include
#include
#include /* для malloc() */
#include /* strchr(), strrchr(), strcpy(), ... */
/* прототипы */
char *strend(char *s); char *strdup(const char *s);
void action(int, char **); void main(int, char **);
int listdir(char *); void printdir(int n);
#ifdef STYLE2
void lookdir(char *s, int ac, char **av, register int level);
#else
void lookdir(char *s, int ac, char **av);
#endif
char root[256]; /* имя стартового каталога */
char cwd[256]; /* полное имя текущего каталога */
char *strend(register char *s){ while(*s)s++; return s; }
char *strdup(const char *s){ /* прототип malloc в */
char *p = (char *) malloc(strlen(s) + 1);
if(p) strcpy(p, s); return p;
}
stop(){ /* Реакция на control/break */
chdir( root );
/* Это необходимо потому, что MS DOS имеет (в отличие от UNIX)
понятие "текущий каталог" как глобальное для всей системы.
Если мы прервем программу, то окажемся не в том каталоге,
откуда начинали. */
printf( "\nInterrupted by ctrl-break\n");
return 0; /* exit */
}
void main(int argc, char **argv){
/* получить имя текущего каталога */
(void) getcwd(root, sizeof root);
ctrlbrk( stop ); /* установить реакцию на ctrl/break */
#ifndef STYLE2
lookdir( "." /* корень дерева */, argc, argv );
#else
/* для примера: дерево от "\\" а не от "." */
lookdir( "\\", argc, argv, 0 /* начальный уровень */ );
#endif /*STYLE2*/
chdir(root); /* вернуться в исх. каталог */
}
# ifndef STYLE2
void lookdir(char *s, int ac, char **av){
static int level = 0; /* уровень рекурсии */
# else
void lookdir(char *s, int ac, char **av, register int level){
# endif /*STYLE2*/
struct ffblk dblk, *psd = &dblk;
register done;
if( chdir(s) < 0 ){ /* войти в каталог */
printf( "Cannot cd %s\n", s ); return;
} else if (level == 0){ /* верхний уровень */
(void) getcwd(cwd, sizeof cwd);
/* получить полное имя корня поддерева */
}
action(ac, av);
/* искать имена каталогов, удовлетворяющие шаблону "*" */
/* (не в алфавитном порядке !) */
done = findfirst("*.", psd, FA_DIREC);
while( !done ){
if((psd->ff_attrib & FA_DIREC) && psd->ff_name[0] != '.' ){
/* Видим каталог: войти в него! */
char *tail = strend(cwd); char *addplace;
if( tail[-1] == '\\' ){
addplace = tail;
}else{
*tail = '\\'; addplace = tail+1;
}
strcpy(addplace, psd->ff_name);
#ifndef STYLE2
level++; lookdir( psd->ff_name, ac, av ); level--;
#else
lookdir( psd->ff_name, ac, av, level+1 );
#endif
*tail = '\0';
}
/* Искать следующее имя. Информация о точке, где был
* прерван поиск, хранится в dblk */
done = findnext(psd);
}
if( level ) chdir( ".." ); /* выйти вверх */
}
/* Выполнить действия в каталоге */
void action(int ac, char **av){
extern int busy;
busy = 0;
if( ac == 1 ) listdir( "*.*" );
else{
av++;
while( *av ) listdir( *av++ );
}
printdir( busy );
}
#define MAXF 400
struct fst{
char *name; long size; short attr;
} files[MAXF];
int busy; /* сколько имен собрано */
/* Собрать имена, удовлетворяющие шаблону. */
int listdir( char *picture ){
int done, n; struct ffblk dentry;
for(n=0, done=findfirst(picture, &dentry,0xFF /* все типы */);
busy < MAXF && !done ;
done = findnext( &dentry )){
files[busy].name = strdup(dentry.ff_name);
files[busy].size = dentry.ff_fsize;
files[busy].attr = dentry.ff_attrib;
n++; busy++;
}
return n;
}
/* int cmp(struct fst *a, struct fst *b) */
/* новые веяния в Си требуют такого прототипа: */
int cmp(const void *a, const void *b){
return strcmp(((struct fst *) a) -> name,
((struct fst *) b) -> name );
}
/* отсортировать и напечатать */
void printdir(int n){
register i;
struct fst *f;
qsort( files, n, sizeof files[0], cmp );
printf( "Directory %s\n", cwd );
for( i=0, f = files; i < n; i++, f++ )
printf("\t%-16s\t%10ld\t%c%c%c%c%c%c\n",
f->name, f->size,
f->attr & FA_DIREC ? 'd':'-', /* directory */
f->attr & FA_RDONLY ? 'r':'-', /* read only */
f->attr & FA_HIDDEN ? 'h':'-', /* hidden */
f->attr & FA_SYSTEM ? 's':'-', /* system */
f->attr & FA_LABEL ? 'l':'-', /* volume label */
f->attr & FA_ARCH ? 'a':'-' /* archive */
), free(f->name);
putchar('\n');
}
/* Пример 14 */
/* Демонстрация работы с longjmp/setjmp и сигналами */
/* По мотивам книги М.Дансмура и Г.Дейвиса. */
#include
#include
#include
#include
/*#define IGN*/ /* потом откомментируйте эту строку */
jmp_buf cs_stack; /* control point */
int in_cs; /* флаг, что мы в критической секции */
int sig_recd; /* флаг signal received */
/* активная задержка */
Delay(){
int i; for( i=0; i < 10000; i++ ){ i += 200; i -= 200; }
}
interrupt( code ){
fprintf( stderr, "\n\n***\n" );
fprintf( stderr, "*** Обрабатываем сигнал (%s)\n",
code == 1 ? "разрешенный" : "отложенный" );
fprintf( stderr, "***\n\n" );
}
/* аргумент реакции на сигнал - номер сигнала (подставляется системой) */
void mexit( nsig ){
fprintf( stderr, "\nУбили сигналом #%d...\n\n", nsig ); exit(0);
}
void main(){
extern void sig_vec(); int code; int killable = 1;
signal( SIGINT, mexit );
signal( SIGQUIT, mexit );
fprintf( stderr, "Данная программа перезапускается по сигналу INTR\n" );
fprintf( stderr, "Выход из программы по сигналу QUIT\n\n\n" );
fprintf( stderr, "Сейчас вы еще можете успеть убить эту программу...\n\n" );
Delay(); Delay(); Delay();
for(;;){
if( code = setjmp( cs_stack )){
/* Возвращает не 0, если возврат в эту точку произошел