|
|
1.1 ! root 1: /* ! 2: * ln.c ! 3: * Make a link. ! 4: */ ! 5: ! 6: #include <stdio.h> ! 7: #include <sys/stat.h> ! 8: #include <errno.h> ! 9: ! 10: #define VERSION "2.2" ! 11: #define USAGE "Usage:\t%s [-f] oldfile newfile\n\t%s [-f] file ... directory\n" ! 12: ! 13: /* Externals. */ ! 14: extern int errno; ! 15: extern char * rindex(); ! 16: extern char * strcpy(); ! 17: extern int strlen(); ! 18: ! 19: /* Globals. */ ! 20: char *argv0; ! 21: int fflag; ! 22: char namebuf[200]; ! 23: ! 24: /* Functions. */ ! 25: char * basename(); ! 26: int ln(); ! 27: void usage(); ! 28: ! 29: main(argc, argv) int argc; char *argv[]; ! 30: { ! 31: register int i, estat; ! 32: struct stat sb; ! 33: char *lname, *s; ! 34: ! 35: argv0 = *argv; ! 36: if (argc > 1 && argv[1][0]=='-') { ! 37: for (s = &argv[1][1]; *s; s++) { ! 38: switch (*s) { ! 39: case 'V': ! 40: fprintf(stderr, "%s: V%s\n", argv0, VERSION); ! 41: break; ! 42: case 'f': ! 43: ++fflag; ! 44: break; ! 45: default: ! 46: usage(); ! 47: } ! 48: --argc; ! 49: ++argv; ! 50: } ! 51: } ! 52: if (argc < 3) ! 53: usage(); ! 54: ! 55: lname = argv[argc-1]; ! 56: if (stat(lname, &sb)>=0 && (sb.st_mode&S_IFMT)==S_IFDIR) { ! 57: /* The last arg is a directory. */ ! 58: strcpy(namebuf, lname); ! 59: s = &namebuf[strlen(namebuf)]; ! 60: *s++ = '/'; ! 61: for (estat = 0, i=1; i<argc-1; i++) { ! 62: strcpy(s, basename(argv[i])); ! 63: estat |= ln(argv[i], namebuf); ! 64: } ! 65: exit(estat); ! 66: } else if (argc > 3) ! 67: usage(); ! 68: else ! 69: exit(ln(argv[1], argv[2])); ! 70: } ! 71: ! 72: /* ! 73: * Do the link and check for errors. ! 74: * Try to force the link if the '-f' is specified. ! 75: * Return 0 on success, 1 on failure. ! 76: */ ! 77: int ! 78: ln(n1, n2) char *n1, *n2; ! 79: { ! 80: if (link(n1, n2) == 0) ! 81: return 0; ! 82: if (fflag && errno==EEXIST && force(n1, n2) == 0) ! 83: return 0; ! 84: perror(argv0); ! 85: return 1; ! 86: } ! 87: ! 88: /* ! 89: * The link failed, try to force it while avoiding: ! 90: * directory unlink ! 91: * unlinking source == destination ! 92: * unlinking destination when different device ! 93: * Return 0 on success, -1 on failure. ! 94: */ ! 95: int ! 96: force(n1, n2) char *n1, *n2; ! 97: { ! 98: struct stat sb1, sb2; ! 99: ! 100: if (stat(n2, &sb2) < 0) ! 101: return -1; /* e.g. n2 in nonexistent directory */ ! 102: if ((sb2.st_mode&S_IFMT) == S_IFDIR) { ! 103: errno = EISDIR; ! 104: return -1; /* n2 is a directory */ ! 105: } else if (stat(n1, &sb1) >= 0) { ! 106: if (sb1.st_dev != sb2.st_dev) { ! 107: errno = EXDEV; ! 108: return -1; /* cross device link */ ! 109: } ! 110: if (sb1.st_ino == sb2.st_ino) ! 111: return 0; /* n1 and n2 are already linked, ok */ ! 112: } ! 113: if (unlink(n2) < 0) ! 114: return -1; /* cannot unlink */ ! 115: return link(n1, n2); ! 116: } ! 117: ! 118: /* ! 119: * Find the part of a name past the last '/'. ! 120: */ ! 121: char * ! 122: basename(n) register char *n; ! 123: { ! 124: register char *s; ! 125: ! 126: if ((s = rindex(n, '/')) == NULL) ! 127: return n; ! 128: return ++s; ! 129: } ! 130: ! 131: void ! 132: usage() ! 133: { ! 134: fprintf(stderr, USAGE, argv0, argv0); ! 135: exit(1); ! 136: } ! 137: ! 138: /* end of ln.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.