COUNT dir_read(REG struct f_node FAR * fnp) { REG i; REG j; struct buffer FAR *bp; /* Directories need to point to their current offset, not for */ /* next op. Therefore, if it is anything other than the first */ /* directory entry, we will update the offset on entry rather */ /* than wait until exit. If it was new, clear the special new */ /* flag. */ if (fnp->f_flags.f_dnew) fnp->f_flags.f_dnew = FALSE; else fnp->f_diroff += DIRENT_SIZE; /* Determine if we hit the end of the directory. If we have, */ /* bump the offset back to the end and exit. If not, fill the */ /* dirent portion of the fnode, clear the f_dmod bit and leave, */ /* but only for root directories */ if (fnp->f_flags.f_droot && fnp->f_diroff >= fnp->f_dsize) { fnp->f_diroff -= DIRENT_SIZE; return 0; } else { if (fnp->f_flags.f_droot) { if ((fnp->f_diroff / fnp->f_dpb->dpb_secsize + fnp->f_dpb->dpb_dirstrt) >= fnp->f_dpb->dpb_data) { fnp->f_flags.f_dfull = TRUE; return 0; } bp = getblock((ULONG) (fnp->f_diroff / fnp->f_dpb->dpb_secsize + fnp->f_dpb->dpb_dirstrt), fnp->f_dpb->dpb_unit); bp->b_flag &= ~(BFR_DATA | BFR_FAT); bp->b_flag |= BFR_DIR; #ifdef DISPLAY_GETBLOCK printf("DIR (dir_read)\n"); #endif } else { REG UWORD secsize = fnp->f_dpb->dpb_secsize; /* Do a "seek" to the directory position */ fnp->f_offset = fnp->f_diroff; /* Search through the FAT to find the block */ /* that this entry is in. */ #ifdef DISPLAY_GETBLOCK printf("dir_read: "); #endif if (map_cluster(fnp, XFR_READ) != SUCCESS) { fnp->f_flags.f_dfull = TRUE; return 0; } /* If the returned cluster is FREE, return zero */ /* bytes read. */ if (fnp->f_cluster == FREE) return 0; /* If the returned cluster is LAST_CLUSTER or */ /* LONG_LAST_CLUSTER, return zero bytes read */ /* and set the directory as full. */ if (last_link(fnp)) { fnp->f_diroff -= DIRENT_SIZE; fnp->f_flags.f_dfull = TRUE; return 0; } /* Compute the block within the cluster and the */ /* offset within the block. */ fnp->f_sector = (fnp->f_offset / secsize) & fnp->f_dpb->dpb_clsmask; fnp->f_boff = fnp->f_offset % secsize; /* Get the block we need from cache */ bp = getblock((ULONG) clus2phys(fnp->f_cluster, (fnp->f_dpb->dpb_clsmask + 1), fnp->f_dpb->dpb_data) + fnp->f_sector, fnp->f_dpb->dpb_unit); bp->b_flag &= ~(BFR_DATA | BFR_FAT); bp->b_flag |= BFR_DIR; #ifdef DISPLAY_GETBLOCK printf("DIR (dir_read)\n"); #endif } /* Now that we have the block for our entry, get the */ /* directory entry. */ if (bp != NULL) getdirent((BYTE FAR *) & bp->b_buffer[fnp->f_diroff % fnp->f_dpb->dpb_secsize], (struct dirent FAR *)&fnp->f_dir); else { fnp->f_flags.f_dfull = TRUE; return 0; } /* Update the fnode's directory info */ fnp->f_flags.f_dfull = FALSE; fnp->f_flags.f_dmod = FALSE; /* and for efficiency, stop when we hit the first */ /* unused entry. */ if (fnp->f_dir.dir_name[0] == '\0') return 0; else return DIRENT_SIZE; } }
static void copy_out_one_file (int handle, dynamic_string *input_name, struct stat *stat_info) { struct new_cpio_header header; int input_handle; /* source file descriptor */ char *p; /* Set values in output header. */ header.c_magic = 070707; header.c_dev_maj = major (stat_info->st_dev); header.c_dev_min = minor (stat_info->st_dev); header.c_ino = stat_info->st_ino; #if DOSWIN /* DJGPP doesn't support st_rdev. Repair that. */ stat_info->st_rdev = stat_info->st_dev; #endif /* For POSIX systems that don't define the S_IF macros, we can't assume that S_ISfoo means the standard Unix S_IFfoo bit(s) are set. So do it manually, with a different name. Bleah. */ header.c_mode = (stat_info->st_mode & 07777); if (S_ISREG (stat_info->st_mode)) header.c_mode |= CP_IFREG; else if (S_ISDIR (stat_info->st_mode)) header.c_mode |= CP_IFDIR; #ifdef S_ISBLK else if (S_ISBLK (stat_info->st_mode)) header.c_mode |= CP_IFBLK; #endif #ifdef S_ISCHR else if (S_ISCHR (stat_info->st_mode)) header.c_mode |= CP_IFCHR; #endif #ifdef S_ISFIFO else if (S_ISFIFO (stat_info->st_mode)) header.c_mode |= CP_IFIFO; #endif #ifdef S_ISLNK else if (S_ISLNK (stat_info->st_mode)) header.c_mode |= CP_IFLNK; #endif #ifdef S_ISSOCK else if (S_ISSOCK (stat_info->st_mode)) header.c_mode |= CP_IFSOCK; #endif #ifdef S_ISNWK else if (S_ISNWK (stat_info->st_mode)) header.c_mode |= CP_IFNWK; #endif header.c_uid = stat_info->st_uid; header.c_gid = stat_info->st_gid; header.c_nlink = stat_info->st_nlink; header.c_rdev_maj = major (stat_info->st_rdev); header.c_rdev_min = minor (stat_info->st_rdev); header.c_mtime = (stat_info->st_mtime < 0) ? 0 :stat_info->st_mtime; header.c_filesize = stat_info->st_size; header.c_chksum = 0; header.c_tar_linkname = NULL; /* Handle HPUX CDF files. */ possibly_munge_cdf_directory_name (input_name->string, &header); if ((*name_too_long) (header.c_name)) { error (0, 0, _("%s: file name too long"), header.c_name); return; } /* FIXME: there is a memory leak here, between this and the HPUX stuff above. */ header.c_name = possibly_rename_file (header.c_name); /* Copy the named file to the output. */ switch (header.c_mode & CP_IFMT) { case CP_IFREG: #ifndef __MSDOS__ if (archive_format == V7_FORMAT || archive_format == POSIX_FORMAT || archive_format == GNUTAR_FORMAT) { char *otherfile; if ((otherfile = find_inode_file (header.c_ino, header.c_dev_maj, header.c_dev_min))) { header.c_tar_linkname = otherfile; (*header_writer) (&header, handle); break; } } if ((archive_format == NEW_ASCII_FORMAT || archive_format == CRC_ASCII_FORMAT) && header.c_nlink > 1) if (last_link (&header) ) writeout_other_defers (&header, handle); else { add_link_defer (&header); break; } #endif input_handle = open (input_name->string, O_RDONLY | O_BINARY, 0); if (input_handle < 0) { error (0, errno, "%s", input_name->string); return; } if (archive_format == CRC_ASCII_FORMAT) header.c_chksum = read_for_checksum (input_handle, header.c_filesize, input_name->string); (*header_writer) (&header, handle); copy_files_disk_to_tape (input_handle, handle, header.c_filesize, input_name->string); #ifndef __MSDOS__ if (archive_format == V7_FORMAT || archive_format == POSIX_FORMAT || archive_format == GNUTAR_FORMAT) add_inode (header.c_ino, header.c_name, header.c_dev_maj, header.c_dev_min); #endif tape_pad_output (handle, header.c_filesize); if (close (input_handle) < 0) error (0, errno, "%s", input_name->string); if (reset_access_time_option) { struct utimbuf times; /* Initialize this in case it has members we don't know to set. */ memset (×, 0, sizeof (struct utimbuf)); times.actime = stat_info->st_atime; times.modtime = stat_info->st_mtime; /* Silently ignore EROFS because reading the file won't have upset its timestamp if it's on a read-only filesystem. */ if (utime (header.c_name, ×) < 0 && errno != EROFS) error (0, errno, _("%s: error resetting file access time"), header.c_name); } break; case CP_IFDIR: header.c_filesize = 0; (*header_writer) (&header, handle); break; #ifndef __MSDOS__ case CP_IFCHR: case CP_IFBLK: #ifdef CP_IFSOCK case CP_IFSOCK: #endif #ifdef CP_IFIFO case CP_IFIFO: #endif if (archive_format == V7_FORMAT) { error (0, 0, _("%s not dumped: not a regular file"), header.c_name); return; } else if (archive_format == POSIX_FORMAT || archive_format == GNUTAR_FORMAT) { char *otherfile = find_inode_file (header.c_ino, header.c_dev_maj, header.c_dev_min); if (otherfile) { /* This file is linked to another file already in the archive, so write it out as a hard link. */ header.c_mode = (stat_info->st_mode & 07777); header.c_mode |= CP_IFREG; header.c_tar_linkname = otherfile; (*header_writer) (&header, handle); break; } add_inode (header.c_ino, header.c_name, header.c_dev_maj, header.c_dev_min); } header.c_filesize = 0; (*header_writer) (&header, handle); break; #endif #ifdef CP_IFLNK case CP_IFLNK: { char *link_name = (char *) xmalloc (stat_info->st_size + 1); int link_size = readlink (input_name->string, link_name, stat_info->st_size); if (link_size < 0) { error (0, errno, "%s", input_name->string); free (link_name); return; } header.c_filesize = link_size; if (archive_format == V7_FORMAT || archive_format == POSIX_FORMAT || archive_format == GNUTAR_FORMAT) { /* FIXME: tar can do long symlinks. */ if (link_size + 1 > 100) error (0, 0, _("%s: symbolic link too long"), header.c_name); else { link_name[link_size] = '\0'; header.c_tar_linkname = link_name; (*header_writer) (&header, handle); } } else { (*header_writer) (&header, handle); tape_buffered_write (link_name, handle, link_size); tape_pad_output (handle, link_size); } free (link_name); } break; #endif default: error (0, 0, _("%s: unknown file type"), input_name->string); } /* FIXME shouldn't do this for each file. Should maintain a dstring somewhere. */ free (header.c_name); header.c_name = NULL; }