// gcc -Wall -o stca stca.c #include #include #include #include // strerror() #include #include #include // lstat() #include /* A file that has been deleted, but is still "held open" by an entry in the open file table (i.e. the file is referred by an open file descriptor), can be opened again read-write in Linux, but not in Cygwin ... */ // NOTE: my text uses "fd 2" for a file descriptor that equals 2; and fd2 for variable fd2 static int errExit(const char *str) { printf("id = %s, errno = %d, errstr = %s\n", str, errno, strerror(errno)); fflush(stdout); exit(EXIT_FAILURE); } static void Usage(const char *const arg) { fprintf(stderr, "Usage: %s /dev/fd/N\n", arg); exit(EXIT_FAILURE); } #if 0 #define DISPLAYSTATINFO static void displayStatInfo(const struct stat *sb); #endif // invoke as follows: ./stca /dev/fd/0 < 9) || ( (argv[1][8] - 0x30 < 0) || (argv[1][8] - 0x30 > 9) ) ) { fprintf(stderr, "N must be a single digit, please!\n"); Usage(argv[0]); } // end kludge int fd1; fd1 = argv[1][8] - 0x30; printf("fd1 = %d\n", fd1); // using bash, /dev/fd/N refers to a file which been unlink'ed printf("argv[1] = %s\n", argv[1]); errno = 0; int fd2; #if 0 if ( (fd2 = open(argv[1], O_RDONLY)) == -1) errExit("openfd2"); // what 'cat' does #else #define WRITE if ( (fd2 = open(argv[1], O_RDWR)) == -1) errExit("openfd2"); //if ( (fd2 = open(argv[1], O_RDWR | O_APPEND)) == -1) errExit("openfd2"); #endif printf("fd2 = %d\n", fd2); #if defined(DISPLAYSTATINFO) struct stat sb; if (fstat(fd2, &sb) == -1) errExit("fstatfd2"); displayStatInfo(&sb); #endif /* if file has been opened read-write, write() will succeed in Linux, but fail in Cygwin */ #if defined(WRITE) if (write(fd2, "Hello, world!\n", 14) == -1) errExit("writefd2"); #endif // how about an lseek() first? (write() modifies the file offset) if (lseek(fd2, 0, SEEK_SET) == -1) errExit("lseekfd2"); char buf[80] = { 0 }; // another kludge if (read(fd2, buf, sizeof(buf) ) == -1) errExit("readfd2"); printf("buf = \\\n%s", buf); if (close(fd2) == -1) printf("closefd2 failed\n"); } #if defined(DISPLAYSTATINFO) #if 1 static void displayStatInfo(const struct stat *sb) { printf("Link count: %ld\n", (long)sb->st_nlink); } #else static char *filePermStr(mode_t perm, int flags); static void displayStatInfo(const struct stat *sb) { printf("File type: "); // deprecated by S_ISREG(m) and c.s. ...? /usr/include/linux/stat.h switch (sb->st_mode & S_IFMT) { case S_IFBLK: printf("block device\n"); break; case S_IFCHR: printf("character device\n"); break; case S_IFDIR: printf("directory\n"); break; case S_IFIFO: printf("FIFO/pipe\n"); break; case S_IFLNK: printf("symlink\n"); break; case S_IFREG: printf("regular file\n"); break; case S_IFSOCK: printf("socket\n"); break; default: printf("unknown?\n"); break; } printf("I-node number: %ld\n", (long)sb->st_ino); #if 0 printf("Mode: %lo (octal)\n", (unsigned long)sb->st_mode); #else printf("Mode: %lo (octal), ls(1)-style: %s\n", (unsigned long)sb->st_mode, filePermStr(sb->st_mode, 0)); #endif printf("Link count: %ld\n", (long)sb->st_nlink); printf("Ownership: UID=%ld GID=%ld\n", (long)sb->st_uid, (long)sb->st_gid); printf("Preferred I/O block size: %ld bytes\n", (long)sb->st_blksize); printf("File size: %lld bytes\n", (long long)sb->st_size); printf("Blocks allocated: %lld\n", (long long)sb->st_blocks); printf("Last status change: %s", ctime(&sb->st_ctime)); printf("Last file access: %s", ctime(&sb->st_atime)); printf("Last file modification: %s", ctime(&sb->st_mtime)); } /* Return ls(1)-style string for file permissions mask */ /* Include set-user-ID, set-group-ID, and sticky bit information in returned string */ #define FP_SPECIAL 1 #define STR_SIZE sizeof("rwxrwxrwx") static char * filePermStr(mode_t perm, int flags) { static char str[STR_SIZE]; /* If FP_SPECIAL was specified, we emulate the trickery of ls(1) in returning set-user-ID, set-group-ID, and sticky bit information in the user/group/other execute fields. This is made more complex by the fact that the case of the character displayed for this bits depends on whether the corresponding execute bit is on or off. */ snprintf(str, STR_SIZE, "%c%c%c%c%c%c%c%c%c", (perm & S_IRUSR) ? 'r' : '-', (perm & S_IWUSR) ? 'w' : '-', (perm & S_IXUSR) ? (((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 's' : 'x') : (((perm & S_ISUID) && (flags & FP_SPECIAL)) ? 'S' : '-'), (perm & S_IRGRP) ? 'r' : '-', (perm & S_IWGRP) ? 'w' : '-', (perm & S_IXGRP) ? (((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 's' : 'x') : (((perm & S_ISGID) && (flags & FP_SPECIAL)) ? 'S' : '-'), (perm & S_IROTH) ? 'r' : '-', (perm & S_IWOTH) ? 'w' : '-', (perm & S_IXOTH) ? (((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 't' : 'x') : (((perm & S_ISVTX) && (flags & FP_SPECIAL)) ? 'T' : '-')); return str; } #endif #endif //=====