Пример #1
0
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;
  }
}
Пример #2
0
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 (&times, 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, &times) < 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;
}