;Copyright (C) 2000 Dmitry Bakhvalov ; ;$Id: cp.asm,v 1.6 2002/02/02 08:49:25 konst Exp $ ; ;hackers' cp ; ;syntax: cp [option] source dest, or ; cp [option] source... directory ; ;The only supported option by now is -r. Does anyone really use anything ;else anyway? :) ; ;If someone really feels like he needs more of the original GNU cp's ;options - just ask me or better yet add 'em yourself :) ; ;Send me any feedback,suggestions,additional code, etc. %include "system.inc" CODESEG usage_msg db "Usage: cp [-r] source dest",__n _usage_msg_len equ $-usage_msg %assign usage_msg_len _usage_msg_len %assign buf_size 0x1000 START: pop ecx ; get argc cmp ecx,byte 3 ; must have at least 3 args jae proceed invalid_args: sys_write STDOUT,usage_msg,usage_msg_len no_more_args: sys_exit eax ; exit proceed: pop eax ; skip argv[0] dec ecx ; dont count argv[0] ; let's test for "-r" option pop ebx ; cmp word [ebx],"-R" ; jz set_recursive cmp word [ebx],"-r" jnz not_recursive set_recursive: inc byte [recursive] ; set recursive flag dec ecx ; one argument has gone jmp dont_push not_recursive: push ebx ; put our arg back onto the stack dont_push: dec ecx ; last argument's index xor eax,eax ; eax=NULL xchg eax,[esp+ecx*4] ; argv[last_arg]=NULL mov [dst],eax ; dst=arv[last_arg] file_to_dir_loop: pop edi ; get nex arg test edi,edi ; no more? jz no_more_args call is_dir jnz copy_this_file ; well, we have a dir here cmp byte [recursive],1 ; did we specify -r option ? jne file_to_dir_loop ; we have a dir and no -r option ; so we simply skip this argument push dword [dst] ; push dst push edi ; push src call rcopy ; do recursive copy pop eax ; remove function's args pop eax jmp file_to_dir_loop ; go on copy_this_file: push edi ; save src filename mov edi,[dst] ; edi = destination pop esi ; esi= source call copy ; copy jmp file_to_dir_loop ; go on ; copy files ; esi - source file; edi - dest file/dir; ebp=flags ; carry = 1 if error copy: pushad sys_stat esi,stat_buf movzx edx,word [stat_buf.st_mode] test eax,eax jns .stat_ok mov edx,600q .stat_ok: call is_dir ; is our dest a dir jnz .just_copy ; it's a file. copy now push edx ; save file attr push esi ; save src filename mov edx,esi ; edx=src filename mov esi,edi ; esi=dst dir name mov edi,buf ; edi=tmp buf call full_name ; make full name: "dst_dir/filename" pop esi ; restore src filename pop edx ; restore file attr .just_copy: sys_open esi,O_RDONLY test eax,eax jns .no_error jmp .error .no_error: mov esi,eax ; esi - src handle sys_open edi,O_WRONLY|O_CREAT|O_TRUNC test eax,eax js .error mov edi,eax ; edi - dst handle .copy_loop: sys_read esi,buf,buf_size ; read source test eax,eax js .error jz .no_more_data mov ebx,edi ; ebx = dst handle mov edx,eax ; edx = num of bytes ; ecx already holds buf sys_write ; write it cmp edx,buf_size jz .copy_loop ; jmp .copy_loop .no_more_data: sys_close esi ; close src sys_close edi ; close dst clc ; clear carry bit - all ok jmp .return .error: stc ; set carry flag - error .return: popad ret ; ; recursive copying is a bitch, but what the hell! ; we do ASM here :) ; ; ; yeah, I know. These %defines look somewhat fearsome :) ; %define CALL_FRAME 8 %define SRC_DIR (CALL_FRAME+0) %define DST_DIR (CALL_FRAME+4) %define HANDLE_SIZE 4 %define HANDLE_OFFS (HANDLE_SIZE+0) %define DENTS_BUF_SIZE 266 %define DENTS_BUF_OFFS (DENTS_BUF_SIZE+HANDLE_OFFS) %define BUF_SIZE 2048 %define BUF_OFFS (DENTS_BUF_OFFS+BUF_SIZE) %define BUF1_SIZE 2048 %define BUF1_OFFS (BUF_OFFS+BUF1_SIZE) %define LOCAL_BUFSIZE (HANDLE_SIZE+DENTS_BUF_SIZE+BUF_SIZE+BUF1_SIZE) rcopy: push ebp mov ebp,esp sub esp,LOCAL_BUFSIZE mov edi,[ebp+SRC_DIR] ; src must be a dir call is_dir jnz near .error mov edi,[ebp+DST_DIR] ; dst must be a dir too call is_dir jz near .dst_ok sys_mkdir edi,755q ; create target dir test eax,eax ; if there's a file with sucha name js near .error ; or our mkdir fails we exit anyway .dst_ok: sys_open [ebp+SRC_DIR],O_RDONLY ; opendir(src) test eax,eax js near .error mov [ebp-HANDLE_OFFS],eax .next_dentry: lea ecx,[ebp-DENTS_BUF_OFFS] sys_getdents [ebp-HANDLE_OFFS],EMPTY,DENTS_BUF_SIZE test eax,eax js near .error jz near .done mov edi,ecx ; edi = buf mov ecx,eax ; ecx = rc .main_loop: lea edx,[edi+10] ; edx = filename mov ax,0x002E cmp byte [edx],al ; starts with "." ? jnz .without_dots ; nope cmp byte [edx+1],ah ; null? jz .skip ; skip "." dir cmp word [edx+1],ax ; ".." dir jz .skip ; skip it .without_dots: push edi ; save buf ptr lea edi,[ebp-BUF1_OFFS] ; tmp buffer push edi ; save for later use (.its_a_file) mov esi,[ebp+DST_DIR] ; dst dir ; edx hold filename call full_name ; create fullname lea edi,[ebp-BUF_OFFS] ; tmp buffer push edi ; save edi for later use (.its_a_file) mov esi,[ebp+SRC_DIR] ; src dir ; edx hold filename call full_name ; create fullname ; edi holds tmp buffer call is_dir jnz .its_a_file pop eax ; remove saved edi's. we dont need 'em pop eax pushad ; call ourself lea eax,[ebp-BUF1_OFFS] ; C-style calling convention push eax ; second arg first lea eax,[ebp-BUF_OFFS] push eax ; then goes the first one call rcopy pop eax ; remove function's args pop eax popad jmp .next .its_a_file: ; copy the damn file pop esi ; get saved addreses pop edi call copy .next: pop edi ; restore buf ptr .skip: xor eax,eax mov ax,[edi+8] ; eax=rec_len add edi,eax sub ecx,eax jnz .main_loop jmp .next_dentry .done: mov ebx,[ebp-HANDLE_OFFS] sys_close .error: add esp,LOCAL_BUFSIZE pop ebp ret ; ; ----------------------------- procedures ------------------------------------ ; ; edi - tmp buf, esi - dir, edx - file ; full_name: pushad call strcpy call fix_slash mov esi,edx call strcat popad ret ; edi=file name ; - fix_slash: push edx push esi mov esi,edi call strlen dec edx mov ax,0x002F cmp byte [edi+edx],al jz .ok inc edx mov word [edi+edx],ax .ok: pop esi pop edx ret ; edi = file name ; zero flag = 1 if dir; carry flag=1 if file doesnt exists is_dir: pushad sys_stat edi,stat_buf test eax,eax js .error movzx eax,word [stat_buf.st_mode] mov ebx,S_IFDIR and eax,ebx cmp eax,ebx clc ; file exists jmp .popit .error: stc ; if file doesnt exist set ; carry flag .popit: popad ret ; esi=string ; edx=strlen strlen: mov edx,esi dec edx .do_strlen: inc edx cmp [edx],byte 0 jnz .do_strlen sub edx,esi ret ; esi=source edi=dest ; - strcpy: pushad call strlen inc edx ; copy NULL too mov ecx,edx rep movsb popad ret ; esi=source edi=dest ; - strcat: pushad xchg esi,edi call strlen xchg esi,edi add edi,edx call strlen inc edx ; copy NULL byte too mov ecx,edx rep movsb ; copy popad ret UDATASEG dst resd 1 recursive resb 1 buf resb buf_size stat_buf B_STRUC Stat,.st_mode END