* added compilers lcc and bcc (linux86)
[mascara-docs.git] / compilers / linux86-0.16.17 / tests / ft.c
blob7acc5575dafacac4ec02849e7f22ffaa74d63c9e
1 /* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
2 * This program is distributed under the GNU General Public License.
3 */
5 /*
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.
11 #include <stdio.h>
12 #ifdef __STDC__
13 #include <unistd.h>
14 #include <stdlib.h>
15 #endif
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <dirent.h>
22 #include <sys/param.h>
23 #include <utime.h>
24 #include <pwd.h>
25 #include <grp.h>
27 #if defined(S_IFSOCK) && !defined(__BCC__)
28 #define __HAS_SOCKETS
29 #endif
30 #ifndef S_IFLNK
31 #define lstat stat
32 #endif
34 #ifdef __HAS_SOCKETS
35 #include <sys/socket.h>
36 #endif
38 /* Ansi prototypes */
39 #ifdef __STDC__
40 #define PR(x) x
41 #else
42 #define PR(x) ()
43 #endif
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)
95 struct {
96 char * name;
97 int cmd;
98 int argpat;
99 char * opts;
100 } command_list[] =
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:" },
113 #ifdef __HAS_SOCKETS
114 { "mksock", CMD_MKSOCK, 0, "m:" },
115 #endif
116 { "mknod", CMD_MKNOD, 4, "m:" },
117 { "mv", CMD_MV, -1, "vif" },
118 { "rm", CMD_RM, 0, "vifr" },
119 { 0 }
122 int cmd_arg = 0;
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 = "";
128 char ** flist = 0;
129 int fcount = 0;
130 int add_base=0;
131 char * or_name = 0;
132 int or_offset = 0;
134 int flg_recurse = 0;
135 int flg_verbose = 1;
136 int flg_preserve= 0;
137 int flg_mkpdir = 0;
138 int flg_noderef = 0;
139 int flg_symlink = 0;
140 int flg_exestrip= 0;
142 int flg_r, flg_force;
143 char *str_o, *str_g, *str_m;
145 /* Things to set on the new file */
146 int set_user = -1;
147 int set_group = -1;
148 int set_mode = -1;
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;
160 main(argc, argv)
161 int argc; char ** argv;
163 int ar;
164 (void) select_command(argv[0]);
166 for(ar=1;
167 argv[ar] && argv[ar][0] == '-' && argv[ar][1];
168 ar++)
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;
173 while(*p)
175 char * ap=0, *av=0;
176 char ch;
177 /* Is it a valid opt for this cmd */
178 if(*p == ':' || (ap=strchr(cmd_opt, *p)) == 0) Usage();
180 /* Got an argument ? */
181 if(ap[1] == ':')
183 if(!argv[ar+1]) Usage();
184 av = argv[++ar];
187 if( (ch = *p) == '-' )
189 if( (ch=select_command(p)) < 0 ) Usage();
191 switch(ch)
193 case '\0': break;
194 case 'r':
195 case 'R': flg_recurse++; break;
196 case 'v': flg_verbose++; break;
197 case 'p': if(cmd_tok == CMD_MKDIR) flg_mkpdir++;
198 else flg_preserve++;
199 break;
200 case 'd': if(cmd_tok == CMD_INSTALL)
201 { flg_mkpdir++; cmd_arg=0; } /* Special mkdir */
202 else flg_noderef++; /* cmd_copy */
203 break;
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;
212 break;
213 case 'a': flg_recurse++; flg_preserve++; flg_noderef++;
214 break;
216 if(*p == '-') break;
217 p++;
221 switch(cmd_arg)
223 case 1:
224 if( ar >= argc ) Usage();
225 cmd_string = argv[ar++];
226 fcount = argc-ar;
227 flist = argv+ar;
228 break;
229 case 0:
230 fcount = argc-ar;
231 flist = argv+ar;
232 break;
233 case -1:
234 if( ar >= argc ) Usage();
235 cmd_string = argv[argc-1];
236 fcount = argc-ar-1;
237 flist = argv+ar;
238 break;
239 default:
240 if( ar != argc-cmd_arg ) Usage();
241 fcount = argc-ar;
242 flist = argv+ar;
243 break;
246 do_prep();
248 for(ar=0; ar<fcount; ar++)
250 done_something=1;
251 or_name = flist[ar]; or_offset = strlen(or_name)+1;
252 execute(flist[ar], (char*)0);
255 do_post();
257 if( !done_something )
259 if( cmd_tok == CMD_CAT )
260 execute("-", (char*)0);
261 else
262 Usage();
264 return 0;
267 int select_command(argv)
268 char * argv;
270 int ar;
271 char *p, *s;
272 prog_name = 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;
282 return 0;
285 return -1;
288 void do_prep()
290 char * prefix = "::";
292 u_mask = umask(077);
293 umask(u_mask);
294 u_mask = (07777&(~u_mask));
296 if(cmd_tok&DO_MCOPY) flg_preserve++;
297 if(str_m) parse_perms(prefix, str_m);
299 switch(cmd_tok)
301 /* mknod is very different */
302 case CMD_MKNOD: cmd_mknod(); exit(0); break;
304 case CMD_CP:
305 if(strcmp(cmd_string, "-") == 0)
307 cmd_tok = CMD_CAT;
308 cmd_arg = 0;
309 break;
311 if(flg_symlink)
313 cmd_tok = CMD_LN+OK_DIR+OK_NO_SOURCE;
314 flg_preserve = 0;
316 break;
318 case CMD_CHOWN: prefix++;
319 case CMD_CHGRP: prefix++;
320 case CMD_CHMOD:
321 parse_perms(prefix, cmd_string);
322 set_time = 0;
323 break;
324 case CMD_INSTALL:
325 flg_exestrip = flg_symlink;
326 flg_symlink = 0;
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;
330 else
332 cmd_tok = CMD_CP;
333 flg_preserve = 1;
335 break;
338 #ifndef S_IFLNK
339 if(flg_symlink)
341 error(0, "No support for symlinks available:", cmd_string);
342 exit(1);
344 #endif
346 /* Are we transfering many to one ? Then it must be a directory */
347 if(cmd_arg == -1)
349 if( stat(cmd_string, &dest_item) == -1)
351 if( fcount > 1 )
353 if( cmd_mkdir(cmd_string) < 0 )
354 exit(1);
355 stat(cmd_string, &dest_item);
356 add_base = 1;
359 else
361 if( !S_ISDIR(dest_item.st_mode) )
363 if( fcount > 1 )
365 error(0, "Destination must be a directory:", cmd_string);
366 exit(1);
369 else add_base = 1;
374 void do_post()
376 /* Oh! It seems there's nothing to do, ah well. */
379 void execute(dname, fname)
380 char * dname; char * fname;
382 char * buf;
383 if( strcmp(dname, "-") == 0 )
385 exec_for_item(0, dname);
386 return;
388 if( fname )
390 buf = alloca(strlen(dname) + strlen(fname) + 4);
391 if( buf == 0 )
393 error(errno, "Can't allocate memory for path beyond ", dname);
394 return ;
396 strcpy(buf, dname);
397 if(strcmp(dname, "/")) strcat(buf, "/");
398 strcat(buf, fname);
400 else buf = dname;
402 if( lstat(buf, &cur_file_stat) == -1 )
404 if( cmd_tok&(NO_SOURCE|OK_NO_SOURCE) )
405 exec_for_item(0, buf);
406 else
407 warning(errno, "", buf);
408 return;
410 if( !flg_force && ( cmd_tok&NO_SOURCE ))
412 error(EEXIST, "", buf);
413 return;
416 if( S_ISDIR(cur_file_stat.st_mode))
418 if( (cmd_tok&OK_DIR) || flg_recurse )
419 (void) exec_for_subdir(buf);
420 else
421 error(EISDIR, "", buf);
422 return;
425 #ifdef S_IFLNK
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);
434 return;
438 #endif
439 exec_for_item(0, buf);
442 int exec_for_subdir(dname)
443 char * dname;
445 DIR * dfd;
446 struct dirent * ent;
447 int old_mode = -1;
449 if( cmd_tok&DO_BDIR ) exec_for_item(-1, dname);
451 if( flg_recurse )
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 )
467 continue;
469 alloca(0); /* Free up if using fake version */
470 execute(dname, ent->d_name);
472 closedir(dfd);
473 if( old_mode != -1 )
474 chmod(dname, old_mode);
477 if( cmd_tok&DO_ADIR )
479 lstat(dname, &cur_file_stat);
480 exec_for_item(1, dname);
482 return 0;
485 void exec_for_item(when, fname)
486 int when; char * fname;
488 int rv = -1;
489 switch(cmd_tok)
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;
512 #ifdef __HAS_SOCKETS
513 case CMD_MKSOCK: rv = cmd_mksock(fname); break;
514 #endif
515 case CMD_MKNOD: break;
519 void parse_perms(prefix, ustring)
520 char * prefix; char * ustring;
522 char * userstr;
523 char * groupstr;
524 char * modestr;
525 char * cp;
526 struct passwd * pwd = 0;
527 struct group * grp;
529 userstr = alloca(strlen(prefix) + strlen(ustring) + 2);
530 strcpy(userstr, prefix);
531 strcat(userstr, ustring);
533 /* Select User */
534 cp = strchr(userstr, ':');
535 if(!cp) cp = strchr(userstr, '.');
536 if(cp) *cp = '\0';
538 /* If there's a user */
539 if( *userstr != 0 )
541 pwd = getpwnam(userstr);
542 if(pwd == NULL)
544 if(!strisdigit(userstr) )
546 error(EINVAL, "Unknown user ", userstr);
547 exit(1);
549 set_user = atoi(userstr);
551 else set_user = pwd->pw_uid;
552 endpwent();
554 if(cp)
556 groupstr = cp+1;
557 cp = strchr(groupstr, ':');
558 if(!cp) cp = strchr(groupstr, '.');
559 if(cp) *cp = '\0';
560 if( *groupstr != '\0' )
562 grp = getgrnam(groupstr);
563 if(grp == NULL)
565 if(!strisdigit(groupstr) )
567 error(EINVAL, "Unknown group ", groupstr);
568 exit(1);
570 set_group = atoi(groupstr);
572 else set_group = grp->gr_gid;
573 endgrent();
575 else if( pwd )
576 set_group = pwd->pw_gid;
578 if(cp)
580 modestr = cp+1;
581 if(strisdigit(modestr))
582 set_mode = strtol(modestr, NULL, 8);
583 else
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");
594 exit(1);
598 int edit_mode(mode, mode_str)
599 int mode; char * mode_str;
601 char * str=mode_str;
602 static mtab[] = {0, 0111, 0222, 0333, 0444, 0555, 0666, 0777 };
604 int done_change = 0;
605 int isdir = S_ISDIR(mode);
606 int change_op = 0;
607 int change_mask = u_mask;
608 int v=0, s=0, nm=0;
610 for(; *mode_str; mode_str++)
612 switch(*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; }
619 v=0; nm=0;
620 if(strchr(",=+-", mode_str[1]) == 0 ) continue;
621 break;
622 case 'a': if(change_op) goto ch_error;
623 nm |= 07777; if(0) {
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];
629 break;
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;
638 switch(change_op)
640 case 0: goto ch_error;
641 case 1: mode= ((mode&(~change_mask)) | (v&change_mask));
642 break;
643 case 2: mode= ( mode | (v&change_mask));
644 break;
645 case 3: mode= ( mode & ~(v&change_mask));
646 break;
648 done_change=1;
650 if(!done_change)
652 ch_error:
653 error(EINVAL, "Invalid mode string ", str);
654 exit(1);
656 return mode;
660 cmd_ft(fname)
661 char * fname;
663 static char oldpath[2048] = "~";
664 static int last_uid=-1, last_gid=-1, last_mode=-1;
665 struct passwd * pptr;
666 struct group * gptr;
667 int major, minor;
669 if( flg_verbose>1 )
671 char *p = 0;
672 if( fname[1] ) p = strrchr(fname, '/');
673 if( p )
675 *p = '\0';
676 if( strcmp(fname, oldpath) != 0 )
678 strcpy(oldpath, fname);
679 printf("%s/\n", oldpath);
681 *p = '/';
683 else if( *oldpath )
684 *oldpath = '\0';
685 if(p) printf("%s", p+1);
686 else printf("%s", fname);
688 #ifdef S_IFLNK
689 if( S_ISLNK(cur_file_stat.st_mode))
691 char linkbuf[1024];
692 int v;
693 *linkbuf='\0';
694 v = readlink(fname, linkbuf, sizeof(linkbuf));
695 if(v>0) linkbuf[v] = '\0';
696 printf("\t+%s", linkbuf);
698 else
699 #endif
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)
704 printf("\t");
705 if( cur_file_stat.st_uid != last_uid )
707 pptr = getpwuid(cur_file_stat.st_uid);
708 if( pptr )
709 printf("%s", pptr->pw_name);
710 else
711 printf("%d", cur_file_stat.st_uid);
713 printf(":");
714 if( cur_file_stat.st_gid != last_gid )
716 gptr = getgrgid(cur_file_stat.st_gid);
717 if( gptr )
718 printf("%s", gptr->gr_name);
719 else
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);
725 #ifdef __linux__
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);
731 #else
732 major = ((cur_file_stat.st_rdev >> 8) & 0xFF);
733 minor = (cur_file_stat.st_rdev&0xFF);
734 #endif
735 switch(cur_file_stat.st_mode & S_IFMT)
737 case S_IFDIR: printf("\td"); break;
738 case S_IFIFO: printf("\tp"); break;
739 #ifdef __HAS_SOCKETS
740 case S_IFSOCK: printf("\ts"); break;
741 #endif
742 case S_IFBLK: printf("\tb,%d,%d", major, minor);
743 break;
744 case S_IFCHR: printf("\tc,%d,%d", major, minor);
745 break;
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;
752 printf("\n");
754 else printf("%s\n", fname);
756 return 0;
760 cmd_mkfifo(fname)
761 char * fname;
763 int rv;
764 int mode=0666;
765 if( set_mode >= 0 ) mode=set_mode;
766 rv = mknod(fname, S_IFIFO|mode, 0);
767 if(rv<0)
768 warning(errno, "Cannot create fifo ", fname);
769 return rv;
772 #ifdef __HAS_SOCKETS
774 cmd_mksock(fname)
775 char * fname;
777 int rv, fd, len;
778 struct sockaddr *adr;
780 len = strlen(fname)+1 + sizeof(*adr) - sizeof(adr->sa_data);
781 if( len < sizeof(*adr) ) len = sizeof(*adr);
783 adr = alloca(len+2);
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);
793 if(rv<0)
794 warning(errno, "Cannot create socket ", fname);
795 return rv;
797 #endif
800 cmd_rm(fname)
801 char * fname;
803 struct stat dirstat;
804 int rv;
805 char * buf, * p;
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;
814 else
816 if( unlink(fname) >= 0 ) return 0;
819 if( !flg_force )
820 return error(errno, "", fname);
822 /* Try VERY hard */
823 buf = alloca(strlen(fname)+4);
824 strcpy(buf, fname);
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) )
832 rv = rmdir(fname);
833 else
834 rv = unlink(fname);
836 chmod(buf, dirstat.st_mode);
838 return rv;
841 void
842 build_dest(dest, name, newpath)
843 char * dest; char * name; char * newpath;
845 char * p;
846 strcpy(dest, newpath);
847 if( add_base )
849 strcat(dest, "/");
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);
859 strisdigit(str)
860 char * str;
862 if( str==0 || *str == 0 ) return 0;
864 for(;*str; str++)
865 if(*str>'9'|| *str<'0') return 0;
866 return 1;
870 cmd_mv(fname)
871 char * fname;
873 char * destfile;
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;
883 if( errno != EXDEV )
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);
895 cmd_ln(fname)
896 char * fname;
898 char * destfile;
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);
906 cmd_rm(destfile);
909 #ifdef S_IFLNK
910 if( flg_symlink )
912 if( symlink(fname, destfile) == 0 ) return 0;
914 else
916 #endif
917 if( link(fname, destfile) == 0 ) return 0;
918 #ifdef S_IFLNK
920 #endif
922 return error(errno, "", destfile);
926 cmd_cp(fname)
927 char * fname;
929 struct stat dest_stat;
930 char * destfile;
931 int no_dest = 0;
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);
943 return -1;
946 else no_dest = 1;
948 if( S_ISDIR(cur_file_stat.st_mode) )
950 if( !no_dest )
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) )
964 cmd_rm(destfile);
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);
973 return 0;
977 copy_modes(file)
978 char * file;
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. */
985 if(set_time)
987 struct utimbuf tv;
989 tv.actime = cur_file_stat.st_atime;
990 tv.modtime = cur_file_stat.st_mtime;
991 if( set_time != -1 )
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;
1008 else if(*mode_str)
1009 mode = edit_mode(mode, mode_str);
1011 if (chmod (file, mode & 07777))
1012 return error (errno, "", file);
1014 return 0;
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;
1025 char * buf;
1026 int sfd, dfd;
1027 struct stat st;
1028 int blksz = BUFSIZ;
1029 int cc;
1030 char * ptr;
1031 int hole_flag = 0;
1032 int retv = 0;
1033 int no_seek;
1034 int mmode = 0666;
1036 if(flg_verbose>1) printf("%s -> %s\n", source, dest);
1037 if( strcmp(source, "-") == 0 )
1038 sfd = 0;
1039 else
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 )
1047 dfd = 1;
1048 else
1050 dfd = open(dest, O_WRONLY|O_TRUNC|O_CREAT, mmode);
1051 if(dfd<0)
1053 close(sfd);
1054 return error(errno, "Cannot create ", source);
1058 if( fstat(dfd, &st) )
1060 retv = error(errno, "", dest);
1061 no_seek = 1;
1063 else
1065 #ifndef __BCC__
1066 blksz = st.st_blksize;
1067 #endif
1068 no_seek = !S_ISREG(st.st_mode);
1070 buf = alloca(blksz + sizeof(int));
1071 if( buf == 0 ) return error(0, "Out of memory", "");
1073 for(;;)
1075 cc = read(sfd, buf, blksz);
1076 if(cc<0)
1078 retv = error(errno, "", source);
1079 goto exit_now;
1081 if(cc==0) break;
1082 buf[cc] = 1;
1083 for(ptr=buf; *ptr==0 ; ptr++) ;
1084 if((hole_flag = (ptr == buf+cc)))
1085 { /* Make a hole */
1086 if( lseek(dfd, (off_t) cc, SEEK_CUR) < 0 )
1088 retv = error(errno, "", dest);
1089 goto exit_now;
1092 else
1094 if( cc != write(dfd, buf, cc))
1096 retv = error(errno, "", dest);
1097 goto exit_now;
1101 if( hole_flag )
1103 if( lseek(dfd, (off_t) -1, SEEK_CUR) < 0
1104 || write(dfd, "", 1) != 1 )
1106 retv = error(errno, "", dest);
1107 goto exit_now;
1111 exit_now:
1112 if(sfd>2) close(sfd);
1113 if(dfd>2) close(dfd);
1114 return retv;
1117 void
1118 Usage()
1120 int i;
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 )
1134 continue;
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;
1145 printf("\n");
1148 exit(99);
1152 cmd_mkdir(dirname)
1153 char * dirname;
1155 int retv;
1156 int mode = 0777;
1157 if( set_mode >= 0 ) mode = set_mode;
1159 retv = mkdir(dirname, mode);
1160 if(retv<0)
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);
1179 return retv;
1183 cmd_mknod()
1185 int device, major, minor;
1186 int rv = -1;
1187 int mode=0666;
1188 if( set_mode >= 0 ) mode=set_mode;
1190 major = atoi(flist[2]);
1191 minor = atoi(flist[3]);
1192 #ifdef __linux__
1193 /* Linux 2.6+ uses an odd arrangment. */
1194 device = (major<<8) + (minor & 0xFF) + ((minor & 0xFFF00) << 12);
1195 #else
1196 device = (major<<8) + (minor & 0xFF);
1197 #endif
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);
1203 else Usage();
1205 if(rv<0)
1207 error(errno, "", flist[0]);
1208 exit(1);
1210 return rv;
1214 warning(enumber, estr, eobj)
1215 int enumber; char * estr; char * eobj;
1217 if(flg_verbose)
1218 return error(enumber, estr, eobj);
1219 return 0;
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));
1228 return -1;