1 /* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
2 * This program is distributed under the GNU General Public License.
6 * File Tool, This program is a collection of basic file tools
7 * it includes cat, cp, ln, mkdir, mknod, chmod, chown, mv, rm
9 * Links may be used to call it under any of these names.
16 #include <sys/types.h>
22 #include <sys/param.h>
27 #if defined(S_IFSOCK) && !defined(__BCC__)
35 #include <sys/socket.h>
45 int main
PR((int argc
, char ** argv
));
46 int select_command
PR((char * argv
));
47 void do_prep
PR((void));
48 void do_post
PR((void));
49 void execute
PR((char * dname
, char * fname
));
50 int exec_for_subdir
PR((char * dname
));
51 void exec_for_item
PR((int when
, char * fname
));
52 void parse_perms
PR((char * prefix
, char * ustring
));
53 int edit_mode
PR((int mode
, char * mode_str
));
54 int cmd_ft
PR((char * fname
));
55 int cmd_mkfifo
PR((char * fname
));
56 int cmd_mksock
PR((char * fname
));
57 int cmd_rm
PR((char * fname
));
58 void build_dest
PR((char * dest
, char * name
, char * newpath
));
59 int strisdigit
PR((char * str
));
60 int cmd_mv
PR((char * fname
));
61 int cmd_ln
PR((char * fname
));
62 int cmd_cp
PR((char * fname
));
63 int copy_modes
PR((char * file
));
64 int copy_file
PR((char * source
, char * dest
));
65 void Usage
PR((void));
66 int cmd_mkdir
PR((char * dirname
));
67 int cmd_mknod
PR((void));
68 int warning
PR((int enumber
, char * estr
, char * eobj
));
69 int error
PR((int enumber
, char * estr
, char * eobj
));
71 #define DO_BDIR 0x0010 /* Do Dir before contents */
72 #define DO_ADIR 0x0020 /* Do Dir after contents */
73 #define DO_MCOPY 0x0040 /* Preserve modes flag forced */
74 #define OK_DIR 0x0080 /* Directorys OK even if no flg_recurse */
75 #define IGN_LNK 0x0100 /* Not interested in symlinks */
76 #define NO_SOURCE 0x0200 /* Named files created */
77 #define OK_NO_SOURCE 0x0400 /* Don't need the source */
79 #define CMD_FT (0+OK_DIR+DO_BDIR)
80 #define CMD_CAT (1+IGN_LNK)
81 #define CMD_CHGRP (2+OK_DIR+IGN_LNK+DO_ADIR)
82 #define CMD_CHMOD (3+OK_DIR+IGN_LNK+DO_ADIR)
83 #define CMD_CHOWN (4+OK_DIR+IGN_LNK+DO_ADIR)
84 #define CMD_CP (5+IGN_LNK)
85 #define CMD_EXTAR (6+DO_MCOPY+DO_BDIR)
86 #define CMD_INSTALL (7+DO_MCOPY)
87 #define CMD_LN (8+IGN_LNK+DO_BDIR)
88 #define CMD_MKDIR (9+NO_SOURCE)
89 #define CMD_MKFIFO (10+NO_SOURCE)
90 #define CMD_MKSOCK (11+NO_SOURCE)
91 #define CMD_MKNOD (12+NO_SOURCE)
92 #define CMD_MV (13+DO_MCOPY+OK_DIR+DO_BDIR)
93 #define CMD_RM (14+DO_ADIR)
102 { "ft", CMD_FT
, 0, "-Rv" },
103 { "cat", CMD_CAT
, 0, "uR" },
104 { "chgrp", CMD_CHGRP
, 1, "vfR" },
105 { "chmod", CMD_CHMOD
, 1, "vfR" },
106 { "chown", CMD_CHOWN
, 1, "vfR" },
107 { "cp", CMD_CP
, -1, "vifRrpsda" },
108 { "extar", CMD_EXTAR
, 1, "" },
109 { "install", CMD_INSTALL
, -1, "cdso:g:m:" },
110 { "ln", CMD_LN
, -1, "vifs" },
111 { "mkdir", CMD_MKDIR
, 0, "m:" },
112 { "mkfifo", CMD_MKFIFO
, 0, "m:" },
114 { "mksock", CMD_MKSOCK
, 0, "m:" },
116 { "mknod", CMD_MKNOD
, 4, "m:" },
117 { "mv", CMD_MV
, -1, "vif" },
118 { "rm", CMD_RM
, 0, "vifr" },
123 int cmd_tok
= CMD_FT
;
124 char * cmd_opt
= "-";
125 char * cmd_string
= 0; /* the first (or last) arg where special */
126 char * prog_name
= "";
142 int flg_r
, flg_force
;
143 char *str_o
, *str_g
, *str_m
;
145 /* Things to set on the new file */
149 time_t set_time
= -1;
150 char mode_str
[32] = "";
151 int u_mask
= 0; /* 07777 altered by umask() */
153 struct stat cur_file_stat
;
154 struct stat dest_item
;
155 struct stat access_stat
;
157 int done_something
= 0;
161 int argc
; char ** argv
;
164 (void) select_command(argv
[0]);
167 argv
[ar
] && argv
[ar
][0] == '-' && argv
[ar
][1];
170 char * p
= argv
[ar
]+1;
171 /* For symbolic changes of the form -rwx */
172 if( cmd_tok
== CMD_CHMOD
&& strchr("rwx", *p
) != 0 ) break;
177 /* Is it a valid opt for this cmd */
178 if(*p
== ':' || (ap
=strchr(cmd_opt
, *p
)) == 0) Usage();
180 /* Got an argument ? */
183 if(!argv
[ar
+1]) Usage();
187 if( (ch
= *p
) == '-' )
189 if( (ch
=select_command(p
)) < 0 ) Usage();
195 case 'R': flg_recurse
++; break;
196 case 'v': flg_verbose
++; break;
197 case 'p': if(cmd_tok
== CMD_MKDIR
) flg_mkpdir
++;
200 case 'd': if(cmd_tok
== CMD_INSTALL
)
201 { flg_mkpdir
++; cmd_arg
=0; } /* Special mkdir */
202 else flg_noderef
++; /* cmd_copy */
205 case 'f': flg_force
++; flg_verbose
=0; break;
206 case 'o': str_o
= av
; break;
207 case 'g': str_g
= av
; break;
208 case 'm': str_m
= av
; break;
210 case 's': flg_symlink
++;
211 if( cmd_tok
== CMD_LN
) cmd_tok
|= OK_DIR
+OK_NO_SOURCE
;
213 case 'a': flg_recurse
++; flg_preserve
++; flg_noderef
++;
224 if( ar
>= argc
) Usage();
225 cmd_string
= argv
[ar
++];
234 if( ar
>= argc
) Usage();
235 cmd_string
= argv
[argc
-1];
240 if( ar
!= argc
-cmd_arg
) Usage();
248 for(ar
=0; ar
<fcount
; ar
++)
251 or_name
= flist
[ar
]; or_offset
= strlen(or_name
)+1;
252 execute(flist
[ar
], (char*)0);
257 if( !done_something
)
259 if( cmd_tok
== CMD_CAT
)
260 execute("-", (char*)0);
267 int select_command(argv
)
273 for(ar
=0; command_list
[ar
].name
; ar
++)
275 p
= strrchr(argv
, '-'); if(p
) p
++; else p
=argv
;
276 s
= strrchr(p
, '/'); if(s
) s
++; else s
=p
;
277 if( strcmp(s
, command_list
[ar
].name
) == 0 )
279 cmd_arg
= command_list
[ar
].argpat
;
280 cmd_tok
= command_list
[ar
].cmd
;
281 cmd_opt
= command_list
[ar
].opts
;
290 char * prefix
= "::";
294 u_mask
= (07777&(~u_mask
));
296 if(cmd_tok
&DO_MCOPY
) flg_preserve
++;
297 if(str_m
) parse_perms(prefix
, str_m
);
301 /* mknod is very different */
302 case CMD_MKNOD
: cmd_mknod(); exit(0); break;
305 if(strcmp(cmd_string
, "-") == 0)
313 cmd_tok
= CMD_LN
+OK_DIR
+OK_NO_SOURCE
;
318 case CMD_CHOWN
: prefix
++;
319 case CMD_CHGRP
: prefix
++;
321 parse_perms(prefix
, cmd_string
);
325 flg_exestrip
= flg_symlink
;
327 if(str_o
) parse_perms(prefix
+2, str_o
);
328 if(str_g
) parse_perms(prefix
+1, str_g
);
329 if(flg_mkpdir
) cmd_tok
= CMD_MKDIR
;
341 error(0, "No support for symlinks available:", cmd_string
);
346 /* Are we transfering many to one ? Then it must be a directory */
349 if( stat(cmd_string
, &dest_item
) == -1)
353 if( cmd_mkdir(cmd_string
) < 0 )
355 stat(cmd_string
, &dest_item
);
361 if( !S_ISDIR(dest_item
.st_mode
) )
365 error(0, "Destination must be a directory:", cmd_string
);
376 /* Oh! It seems there's nothing to do, ah well. */
379 void execute(dname
, fname
)
380 char * dname
; char * fname
;
383 if( strcmp(dname
, "-") == 0 )
385 exec_for_item(0, dname
);
390 buf
= alloca(strlen(dname
) + strlen(fname
) + 4);
393 error(errno
, "Can't allocate memory for path beyond ", dname
);
397 if(strcmp(dname
, "/")) strcat(buf
, "/");
402 if( lstat(buf
, &cur_file_stat
) == -1 )
404 if( cmd_tok
&(NO_SOURCE
|OK_NO_SOURCE
) )
405 exec_for_item(0, buf
);
407 warning(errno
, "", buf
);
410 if( !flg_force
&& ( cmd_tok
&NO_SOURCE
))
412 error(EEXIST
, "", buf
);
416 if( S_ISDIR(cur_file_stat
.st_mode
))
418 if( (cmd_tok
&OK_DIR
) || flg_recurse
)
419 (void) exec_for_subdir(buf
);
421 error(EISDIR
, "", buf
);
426 if( S_ISLNK(cur_file_stat
.st_mode
))
428 /* Links are special */
429 if( cmd_tok
&IGN_LNK
)
431 if( stat(buf
, &cur_file_stat
) == -1 )
433 warning(errno
, "", buf
);
439 exec_for_item(0, buf
);
442 int exec_for_subdir(dname
)
449 if( cmd_tok
&DO_BDIR
) exec_for_item(-1, dname
);
453 dfd
= opendir(dname
);
454 if( dfd
== 0 && errno
== EACCES
&& flg_force
)
456 old_mode
= (cur_file_stat
.st_mode
& 07777);
457 if( chmod(dname
, (0700|old_mode
)) )
458 return error(errno
, "", dname
);
460 dfd
= opendir(dname
);
462 if( dfd
== 0 ) return error(errno
, "", dname
);
464 while((ent
=readdir(dfd
)))
466 if( strcmp(ent
->d_name
, ".") == 0 || strcmp(ent
->d_name
, "..") == 0 )
469 alloca(0); /* Free up if using fake version */
470 execute(dname
, ent
->d_name
);
474 chmod(dname
, old_mode
);
477 if( cmd_tok
&DO_ADIR
)
479 lstat(dname
, &cur_file_stat
);
480 exec_for_item(1, dname
);
485 void exec_for_item(when
, fname
)
486 int when
; char * fname
;
491 case CMD_FT
: rv
= cmd_ft(fname
); break;
493 case CMD_CAT
: rv
= copy_file(fname
, "-"); break;
495 case CMD_CHGRP
: /* And fall */
496 case CMD_CHMOD
: /* And fall */
497 case CMD_CHOWN
: rv
= copy_modes(fname
); break;
499 case CMD_CP
: rv
= cmd_cp(fname
); break;
500 case CMD_MV
: rv
= cmd_mv(fname
); break;
501 case CMD_RM
: rv
= cmd_rm(fname
); break;
503 case CMD_EXTAR
: error(EINVAL
, "", "No code."); exit(1);
505 case CMD_LN
+OK_DIR
+OK_NO_SOURCE
:
506 case CMD_LN
: rv
= cmd_ln(fname
); break;
508 case CMD_INSTALL
: error(EINVAL
, "", ""); exit(1);
510 case CMD_MKDIR
: rv
= cmd_mkdir(fname
); break;
511 case CMD_MKFIFO
: rv
= cmd_mkfifo(fname
); break;
513 case CMD_MKSOCK
: rv
= cmd_mksock(fname
); break;
515 case CMD_MKNOD
: break;
519 void parse_perms(prefix
, ustring
)
520 char * prefix
; char * ustring
;
526 struct passwd
* pwd
= 0;
529 userstr
= alloca(strlen(prefix
) + strlen(ustring
) + 2);
530 strcpy(userstr
, prefix
);
531 strcat(userstr
, ustring
);
534 cp
= strchr(userstr
, ':');
535 if(!cp
) cp
= strchr(userstr
, '.');
538 /* If there's a user */
541 pwd
= getpwnam(userstr
);
544 if(!strisdigit(userstr
) )
546 error(EINVAL
, "Unknown user ", userstr
);
549 set_user
= atoi(userstr
);
551 else set_user
= pwd
->pw_uid
;
557 cp
= strchr(groupstr
, ':');
558 if(!cp
) cp
= strchr(groupstr
, '.');
560 if( *groupstr
!= '\0' )
562 grp
= getgrnam(groupstr
);
565 if(!strisdigit(groupstr
) )
567 error(EINVAL
, "Unknown group ", groupstr
);
570 set_group
= atoi(groupstr
);
572 else set_group
= grp
->gr_gid
;
576 set_group
= pwd
->pw_gid
;
581 if(strisdigit(modestr
))
582 set_mode
= strtol(modestr
, NULL
, 8);
585 strncpy(mode_str
, modestr
, sizeof(mode_str
)-1);
586 /* This is the time that the mode change will fail on syn error */
587 (void) edit_mode(u_mask
, mode_str
);
591 if( set_user
== -1 && set_group
== -1 && set_mode
< 0 && *mode_str
== 0)
593 error(EINVAL
, "", "Permission string has no changes");
598 int edit_mode(mode
, mode_str
)
599 int mode
; char * mode_str
;
602 static mtab
[] = {0, 0111, 0222, 0333, 0444, 0555, 0666, 0777 };
605 int isdir
= S_ISDIR(mode
);
607 int change_mask
= u_mask
;
610 for(; *mode_str
; mode_str
++)
614 case ',': change_op
= 0;
615 change_mask
=u_mask
; continue;
616 case '=': change_op
= 1; if(0) {
617 case '+': change_op
= 2; } if(0) {
618 case '-': change_op
= 3; }
620 if(strchr(",=+-", mode_str
[1]) == 0 ) continue;
622 case 'a': if(change_op
) goto ch_error
;
624 case 'u': nm
|= 04700; s
= 6; } if(0) {
625 case 'g': nm
|= 02070; s
= 3; } if(0) {
626 case 'o': nm
|= 01007; s
= 0; }
627 if(change_op
==0) { change_mask
=nm
; continue; }
628 v
|= mtab
[(mode
>>s
)&7];
630 case 'r': v
|= 0444; break;
631 case 'w': v
|= 0222; break;
632 case 'x': v
|= 0111; break;
633 case 's': v
|=06000; break;
634 case 't': v
|=01000; break;
635 case 'X': v
|= mtab
[isdir
]; break;
636 default: goto ch_error
;
640 case 0: goto ch_error
;
641 case 1: mode
= ((mode
&(~change_mask
)) | (v
&change_mask
));
643 case 2: mode
= ( mode
| (v
&change_mask
));
645 case 3: mode
= ( mode
& ~(v
&change_mask
));
653 error(EINVAL
, "Invalid mode string ", str
);
663 static char oldpath
[2048] = "~";
664 static int last_uid
=-1, last_gid
=-1, last_mode
=-1;
665 struct passwd
* pptr
;
672 if( fname
[1] ) p
= strrchr(fname
, '/');
676 if( strcmp(fname
, oldpath
) != 0 )
678 strcpy(oldpath
, fname
);
679 printf("%s/\n", oldpath
);
685 if(p
) printf("%s", p
+1);
686 else printf("%s", fname
);
689 if( S_ISLNK(cur_file_stat
.st_mode
))
694 v
= readlink(fname
, linkbuf
, sizeof(linkbuf
));
695 if(v
>0) linkbuf
[v
] = '\0';
696 printf("\t+%s", linkbuf
);
700 if( cur_file_stat
.st_mode
!= last_mode
701 || cur_file_stat
.st_uid
!= last_uid
702 || cur_file_stat
.st_gid
!= last_gid
)
705 if( cur_file_stat
.st_uid
!= last_uid
)
707 pptr
= getpwuid(cur_file_stat
.st_uid
);
709 printf("%s", pptr
->pw_name
);
711 printf("%d", cur_file_stat
.st_uid
);
714 if( cur_file_stat
.st_gid
!= last_gid
)
716 gptr
= getgrgid(cur_file_stat
.st_gid
);
718 printf("%s", gptr
->gr_name
);
720 printf("%d", cur_file_stat
.st_gid
);
722 if( (cur_file_stat
.st_mode
&07777) != (last_mode
&07777) )
723 printf(":%03o", cur_file_stat
.st_mode
& 07777);
726 major
= ((cur_file_stat
.st_rdev
>> 8) & 0xfff);
727 if (sizeof(cur_file_stat
.st_rdev
) > 4)
728 major
|= ((cur_file_stat
.st_rdev
>> 32) & ~0xfff);
729 minor
= (cur_file_stat
.st_rdev
& 0xff) |
730 ((cur_file_stat
.st_rdev
>> 12) & ~0xff);
732 major
= ((cur_file_stat
.st_rdev
>> 8) & 0xFF);
733 minor
= (cur_file_stat
.st_rdev
&0xFF);
735 switch(cur_file_stat
.st_mode
& S_IFMT
)
737 case S_IFDIR
: printf("\td"); break;
738 case S_IFIFO
: printf("\tp"); break;
740 case S_IFSOCK
: printf("\ts"); break;
742 case S_IFBLK
: printf("\tb,%d,%d", major
, minor
);
744 case S_IFCHR
: printf("\tc,%d,%d", major
, minor
);
747 last_mode
= ((cur_file_stat
.st_mode
&07777)|S_IFREG
);
748 if( (cur_file_stat
.st_mode
&07000) ) last_mode
= -1;
749 last_uid
= cur_file_stat
.st_uid
;
750 last_gid
= cur_file_stat
.st_gid
;
754 else printf("%s\n", fname
);
765 if( set_mode
>= 0 ) mode
=set_mode
;
766 rv
= mknod(fname
, S_IFIFO
|mode
, 0);
768 warning(errno
, "Cannot create fifo ", fname
);
778 struct sockaddr
*adr
;
780 len
= strlen(fname
)+1 + sizeof(*adr
) - sizeof(adr
->sa_data
);
781 if( len
< sizeof(*adr
) ) len
= sizeof(*adr
);
784 adr
->sa_family
= AF_UNIX
;
785 strcpy(adr
->sa_data
, fname
);
787 rv
= fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
788 if( fd
>=0 ) rv
= bind(fd
, adr
, len
);
789 if( fd
>=0 ) close(fd
);
790 if(set_mode
>= 0 && chmod(fname
, set_mode
&07777) < 0 )
791 warning(errno
, "Chmod ", fname
);
794 warning(errno
, "Cannot create socket ", fname
);
807 if( S_ISDIR(cur_file_stat
.st_mode
) )
808 if( !flg_recurse
) return error(EISDIR
, "", fname
);
810 if( S_ISDIR(cur_file_stat
.st_mode
) )
812 if( rmdir(fname
) >= 0 ) return 0;
816 if( unlink(fname
) >= 0 ) return 0;
820 return error(errno
, "", fname
);
823 buf
= alloca(strlen(fname
)+4);
825 p
= strrchr(buf
, '/');
826 if( p
) strcpy(p
+1, "."); else strcpy(buf
, ".");
828 if( stat(buf
, &dirstat
) < 0 ) return -1;
829 if( chmod(buf
, dirstat
.st_mode
|0700) < 0 ) return -1;
831 if( S_ISDIR(cur_file_stat
.st_mode
) )
836 chmod(buf
, dirstat
.st_mode
);
842 build_dest(dest
, name
, newpath
)
843 char * dest
; char * name
; char * newpath
;
846 strcpy(dest
, newpath
);
850 p
= strrchr(or_name
, '/');
851 if(p
==0) strcat(dest
, or_name
);
852 else strcat(dest
, p
+1);
854 if(strlen(name
) <= or_offset
) return;
855 strcat(dest
, name
+or_offset
);
862 if( str
==0 || *str
== 0 ) return 0;
865 if(*str
>'9'|| *str
<'0') return 0;
874 destfile
= alloca(strlen(fname
)+strlen(cmd_string
)+4);
876 build_dest(destfile
, fname
, cmd_string
);
878 if( !flg_force
&& lstat(destfile
, &access_stat
) == 0 )
879 return error(EEXIST
, "", destfile
);
881 if( rename(fname
, destfile
) == 0 ) return 0;
884 return error(errno
, "", fname
);
886 if( S_ISDIR(cur_file_stat
.st_mode
) )
887 return error(EISDIR
, "Can't rename across devices ", fname
);
889 if( copy_file(fname
, destfile
) != 0 ) return -1;
890 copy_modes(destfile
);
891 return unlink(fname
);
899 destfile
= alloca(strlen(fname
)+strlen(cmd_string
)+4);
901 build_dest(destfile
, fname
, cmd_string
);
903 if( lstat(destfile
, &access_stat
) != -1 )
905 if( !flg_force
) return error(EEXIST
, "", destfile
);
912 if( symlink(fname
, destfile
) == 0 ) return 0;
917 if( link(fname
, destfile
) == 0 ) return 0;
922 return error(errno
, "", destfile
);
929 struct stat dest_stat
;
933 destfile
= alloca(strlen(fname
)+strlen(cmd_string
)+4);
935 build_dest(destfile
, fname
, cmd_string
);
937 if( stat(destfile
, &dest_stat
) >= 0 )
939 if( dest_stat
.st_ino
== cur_file_stat
.st_ino
940 && dest_stat
.st_dev
== cur_file_stat
.st_dev
)
942 warning(EPERM
, "Can't copy file to itself ", fname
);
948 if( S_ISDIR(cur_file_stat
.st_mode
) )
952 if( S_ISDIR(dest_stat
.st_mode
) ) return 0;
953 if( unlink(destfile
) < 0 )
954 return error(errno
, "Can't delete ", destfile
);
956 return cmd_mkdir(destfile
);
958 else if( S_ISDIR(dest_stat
.st_mode
) )
959 return error(EPERM
, "Can't copy non-directory to directory ", destfile
);
960 else if( S_ISREG(cur_file_stat
.st_mode
) )
962 /* Copy_ok - do we want to force a real file */;
963 if( flg_force
&& !no_dest
&& !S_ISREG(dest_stat
.st_mode
) )
966 else if( flg_recurse
) /* Don't copy other things while recursing */
968 return error(EPERM
, "Can't copy ", fname
);
971 if( copy_file(fname
, destfile
) != 0 ) return -1;
972 if( flg_preserve
) copy_modes(destfile
);
980 int user
, group
, mode
;
981 /* chown turns off set[ug]id bits for non-root,
982 so do the chmod last. */
984 /* Try to copy the old file's modtime and access time. */
989 tv
.actime
= cur_file_stat
.st_atime
;
990 tv
.modtime
= cur_file_stat
.st_mtime
;
992 tv
.modtime
= set_time
;
993 if (utime (file
, &tv
) && !flg_force
)
994 return error (errno
, "", file
);
997 /* Try to preserve ownership. For non-root it might fail, but that's ok.
998 But root probably wants to know, e.g. if NFS disallows it. */
999 user
= cur_file_stat
.st_uid
; if(set_user
!= -1) user
= set_user
;
1000 group
= cur_file_stat
.st_gid
; if(set_group
!= -1) group
= set_group
;
1002 if (chown (file
, user
, group
)
1003 && (errno
!= EPERM
|| geteuid() == 0 || (flg_preserve
==0 && flg_force
==0)))
1004 error (errno
, "Can't change perms for ", file
);
1006 mode
= cur_file_stat
.st_mode
;
1007 if(set_mode
>=0) mode
=set_mode
;
1009 mode
= edit_mode(mode
, mode_str
);
1011 if (chmod (file
, mode
& 07777))
1012 return error (errno
, "", file
);
1017 /* This copies from something to a file or stdout */
1018 /* If the source has zero blocks (possibly holes) the destination
1019 * is built with holes (assuming it's a normal file) */
1022 copy_file(source
, dest
)
1023 char * source
; char * dest
;
1036 if(flg_verbose
>1) printf("%s -> %s\n", source
, dest
);
1037 if( strcmp(source
, "-") == 0 )
1041 sfd
= open(source
, O_RDONLY
);
1042 if(sfd
<0) return error(errno
, "", source
);
1043 mmode
= (cur_file_stat
.st_mode
&0777);
1046 if( strcmp(dest
, "-") == 0 )
1050 dfd
= open(dest
, O_WRONLY
|O_TRUNC
|O_CREAT
, mmode
);
1054 return error(errno
, "Cannot create ", source
);
1058 if( fstat(dfd
, &st
) )
1060 retv
= error(errno
, "", dest
);
1066 blksz
= st
.st_blksize
;
1068 no_seek
= !S_ISREG(st
.st_mode
);
1070 buf
= alloca(blksz
+ sizeof(int));
1071 if( buf
== 0 ) return error(0, "Out of memory", "");
1075 cc
= read(sfd
, buf
, blksz
);
1078 retv
= error(errno
, "", source
);
1083 for(ptr
=buf
; *ptr
==0 ; ptr
++) ;
1084 if((hole_flag
= (ptr
== buf
+cc
)))
1086 if( lseek(dfd
, (off_t
) cc
, SEEK_CUR
) < 0 )
1088 retv
= error(errno
, "", dest
);
1094 if( cc
!= write(dfd
, buf
, cc
))
1096 retv
= error(errno
, "", dest
);
1103 if( lseek(dfd
, (off_t
) -1, SEEK_CUR
) < 0
1104 || write(dfd
, "", 1) != 1 )
1106 retv
= error(errno
, "", dest
);
1112 if(sfd
>2) close(sfd
);
1113 if(dfd
>2) close(dfd
);
1122 printf("FileTool Usage: %s%s", prog_name
[0]=='-'?"ft -":"", prog_name
);
1123 if( cmd_tok
== CMD_FT
)
1125 printf(" --[com_name] [-options] [files]\n");
1126 printf("\nAvailable commands are:\n");
1129 for(i
=1; command_list
[i
].name
; i
++)
1131 if( cmd_tok
== CMD_FT
)
1132 printf(" %s --%s", prog_name
, command_list
[i
].name
);
1133 else if( cmd_tok
!= command_list
[i
].cmd
)
1136 if( *command_list
[i
].opts
)
1137 printf(" [-%s]", command_list
[i
].opts
);
1138 switch(command_list
[i
].argpat
)
1140 case 1: printf(" <info> [files]"); break;
1141 case -1: printf(" [files] [dest]"); break;
1142 case 0: printf(" [files]"); break;
1143 default: printf(" path [bcu] major minor"); break;
1157 if( set_mode
>= 0 ) mode
= set_mode
;
1159 retv
= mkdir(dirname
, mode
);
1162 if(flg_mkpdir
&& errno
== ENOENT
)
1164 /* Create parents */
1167 if( retv
>=0 && cmd_tok
== CMD_MKDIR
)
1169 if( set_user
!= -1 || set_group
!= -1 )
1171 if( chown(dirname
, set_user
, set_group
) < 0)
1172 warning(errno
, "Cannot change directory owner ", dirname
);
1173 else if( chmod (dirname
, mode
& 07777) )
1174 warning(errno
, "", dirname
);
1178 if(retv
<0) error(errno
, "Cannot create directory ", dirname
);
1185 int device
, major
, minor
;
1188 if( set_mode
>= 0 ) mode
=set_mode
;
1190 major
= atoi(flist
[2]);
1191 minor
= atoi(flist
[3]);
1193 /* Linux 2.6+ uses an odd arrangment. */
1194 device
= (major
<<8) + (minor
& 0xFF) + ((minor
& 0xFFF00) << 12);
1196 device
= (major
<<8) + (minor
& 0xFF);
1199 if(flist
[1][0] == 'b')
1200 rv
= mknod(flist
[0], S_IFBLK
|mode
, device
);
1201 else if(flist
[1][0] == 'c' || flist
[1][0] == 'u')
1202 rv
= mknod(flist
[0], S_IFCHR
|mode
, device
);
1207 error(errno
, "", flist
[0]);
1214 warning(enumber
, estr
, eobj
)
1215 int enumber
; char * estr
; char * eobj
;
1218 return error(enumber
, estr
, eobj
);
1223 error(enumber
, estr
, eobj
)
1224 int enumber
; char * estr
; char * eobj
;
1226 fprintf(stderr
, "%s%s: ", prog_name
[0]=='-'?"ft":"", prog_name
);
1227 fprintf(stderr
, "%s%s: %s\n", estr
, eobj
, strerror(enumber
));