Example #1
0
File: hfs.c Project: Arvian/GRUB2
/* Read LEN bytes from the file described by DATA starting with byte
   POS.  Return the amount of read bytes in READ.  */
static grub_ssize_t
grub_hfs_read_file (struct grub_hfs_data *data,
		    void NESTED_FUNC_ATTR (*read_hook) (grub_disk_addr_t sector,
				       unsigned offset, unsigned length),
		    grub_off_t pos, grub_size_t len, char *buf)
{
  grub_off_t i;
  grub_off_t blockcnt;

  blockcnt = grub_divmod64 (((len + pos)
			     + data->blksz - 1), data->blksz, 0);

  for (i = grub_divmod64 (pos, data->blksz, 0); i < blockcnt; i++)
    {
      grub_disk_addr_t blknr;
      grub_off_t blockoff;
      grub_off_t blockend = data->blksz;

      int skipfirst = 0;

      grub_divmod64 (pos, data->blksz, &blockoff);

      blknr = grub_hfs_block (data, data->extents, data->fileid, i, 1);
      if (grub_errno)
	return -1;

      /* Last block.  */
      if (i == blockcnt - 1)
	{
	  grub_divmod64 ((len + pos), data->blksz, &blockend);

	  /* The last portion is exactly EXT2_BLOCK_SIZE (data).  */
	  if (! blockend)
	    blockend = data->blksz;
	}

      /* First block.  */
      if (i == grub_divmod64 (pos, data->blksz, 0))
	{
	  skipfirst = blockoff;
	  blockend -= skipfirst;
	}

      /* If the block number is 0 this block is not stored on disk but
	 is zero filled instead.  */
      if (blknr)
	{
	  data->disk->read_hook = read_hook;
	  grub_disk_read (data->disk, blknr, skipfirst,
			  blockend, buf);
	  data->disk->read_hook = 0;
	  if (grub_errno)
	    return -1;
	}

      buf += data->blksz - skipfirst;
    }

  return len;
}
Example #2
0
static grub_disk_addr_t
grub_affs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
{
  int links;
  grub_uint32_t pos;
  int block = node->block;
  struct grub_affs_file file;
  struct grub_affs_data *data = node->data;
  grub_uint32_t mod;

  /* Find the block that points to the fileblock we are looking up by
     following the chain until the right table is reached.  */
  for (links = grub_divmod64 (fileblock, data->htsize, &mod); links; links--)
    {
      grub_disk_read (data->disk, block + data->blocksize - 1,
		      data->blocksize * (GRUB_DISK_SECTOR_SIZE
					 - GRUB_AFFS_FILE_LOCATION),
		      sizeof (file), &file);
      if (grub_errno)
	return 0;

      block = grub_be_to_cpu32 (file.extension);
    }

  /* Translate the fileblock to the block within the right table.  */
  fileblock = mod;
  grub_disk_read (data->disk, block,
		  GRUB_AFFS_BLOCKPTR_OFFSET
		  + (data->htsize - fileblock - 1) * sizeof (pos),
		  sizeof (pos), &pos);
  if (grub_errno)
    return 0;

  return grub_be_to_cpu32 (pos);
}
Example #3
0
static grub_uint64_t
rpi_timer_ms (void)
{
  static grub_uint32_t last = 0, high = 0;
  grub_uint32_t cur = *(volatile grub_uint32_t *) 0x20003004;
  if (cur < last)
    high++;
  last = cur;
  return grub_divmod64 ((((grub_uint64_t) high) << 32) | cur, 1000, 0);
}
Example #4
0
/* Calculate the time in milliseconds since the epoch based on the RTC. */
grub_uint64_t
grub_rtc_get_time_ms (void)
{
  /* By dimensional analysis:

      1000 ms   N rtc ticks       1 s
      ------- * ----------- * ----------- = 1000*N/T ms
        1 s          1        T rtc ticks
   */
  grub_uint64_t ticks_ms_per_sec = ((grub_uint64_t) 1000) * grub_get_rtc ();
  return grub_divmod64 (ticks_ms_per_sec, GRUB_TICKS_PER_SECOND, 0);
}
Example #5
0
static grub_err_t
grub_biosdisk_open (const char *name, grub_disk_t disk)
{
  grub_uint64_t total_sectors = 0;
  int drive;
  struct grub_biosdisk_data *data;

  drive = grub_biosdisk_get_drive (name);
  if (drive < 0)
    return grub_errno;

  disk->has_partitions = ((drive & 0x80) && (drive != cd_drive));
  disk->id = drive;

  data = (struct grub_biosdisk_data *) grub_zalloc (sizeof (*data));
  if (! data)
    return grub_errno;

  data->drive = drive;

  if ((cd_drive) && (drive == cd_drive))
    {
      data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM;
      data->sectors = 32;
      total_sectors = GRUB_ULONG_MAX;  /* TODO: get the correct size.  */
    }
  else if (drive & 0x80)
    {
      /* HDD */
      int version;

      version = grub_biosdisk_check_int13_extensions (drive);
      if (version)
	{
	  struct grub_biosdisk_drp *drp
	    = (struct grub_biosdisk_drp *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;

	  /* Clear out the DRP.  */
	  grub_memset (drp, 0, sizeof (*drp));
	  drp->size = sizeof (*drp);
	  if (! grub_biosdisk_get_diskinfo_int13_extensions (drive, drp))
	    {
	      data->flags = GRUB_BIOSDISK_FLAG_LBA;

	      if (drp->total_sectors)
		total_sectors = drp->total_sectors;
	      else
                /* Some buggy BIOSes doesn't return the total sectors
                   correctly but returns zero. So if it is zero, compute
                   it by C/H/S returned by the LBA BIOS call.  */
                total_sectors = drp->cylinders * drp->heads * drp->sectors;
	    }
	}
    }

  if (! (data->flags & GRUB_BIOSDISK_FLAG_CDROM))
    {
      if (grub_biosdisk_get_diskinfo_standard (drive,
					       &data->cylinders,
					       &data->heads,
					       &data->sectors) != 0)
        {
	  if (total_sectors && (data->flags & GRUB_BIOSDISK_FLAG_LBA))
	    {
	      data->sectors = 63;
	      data->heads = 255;
	      data->cylinders
		= grub_divmod64 (total_sectors
				 + data->heads * data->sectors - 1,
				 data->heads * data->sectors, 0);
	    }
	  else
	    {
	      grub_free (data);
	      return grub_error (GRUB_ERR_BAD_DEVICE, "%s cannot get C/H/S values", disk->name);
	    }
        }

      if (! total_sectors)
        total_sectors = data->cylinders * data->heads * data->sectors;
    }

  disk->total_sectors = total_sectors;
  disk->data = data;

  return GRUB_ERR_NONE;
}
Example #6
0
File: ls.c Project: hisilicon/grub
/* Helper for grub_ls_list_files.  */
static int
print_files_long (const char *filename, const struct grub_dirhook_info *info,
		  void *data)
{
  struct grub_ls_list_files_ctx *ctx = data;

  if ((! ctx->all) && (filename[0] == '.'))
    return 0;

  if (! info->dir)
    {
      grub_file_t file;
      char *pathname;

      if (ctx->dirname[grub_strlen (ctx->dirname) - 1] == '/')
	pathname = grub_xasprintf ("%s%s", ctx->dirname, filename);
      else
	pathname = grub_xasprintf ("%s/%s", ctx->dirname, filename);

      if (!pathname)
	return 1;

      /* XXX: For ext2fs symlinks are detected as files while they
	 should be reported as directories.  */
      grub_file_filter_disable_compression ();
      file = grub_file_open (pathname);
      if (! file)
	{
	  grub_errno = 0;
	  grub_free (pathname);
	  return 0;
	}

      if (! ctx->human)
	grub_printf ("%-12llu", (unsigned long long) file->size);
      else
	{
	  grub_uint64_t fsize = file->size * 100ULL;
	  grub_uint64_t fsz = file->size;
	  int units = 0;
	  char buf[20];

	  while (fsz / 1024)
	    {
	      fsize = (fsize + 512) / 1024;
	      fsz /= 1024;
	      units++;
	    }

	  if (units)
	    {
	      grub_uint64_t whole, fraction;

	      whole = grub_divmod64 (fsize, 100, &fraction);
	      grub_snprintf (buf, sizeof (buf),
			     "%" PRIuGRUB_UINT64_T
			     ".%02" PRIuGRUB_UINT64_T "%c", whole, fraction,
			     grub_human_sizes[units]);
	      grub_printf ("%-12s", buf);
	    }
	  else
	    grub_printf ("%-12llu", (unsigned long long) file->size);

	}
      grub_file_close (file);
      grub_free (pathname);
    }
  else
    grub_printf ("%-12s", _("DIR"));

  if (info->mtimeset)
    {
      struct grub_datetime datetime;
      grub_unixtime2datetime (info->mtime, &datetime);
      if (ctx->human)
	grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ",
		     datetime.year, datetime.month, datetime.day,
		     datetime.hour, datetime.minute,
		     datetime.second,
		     grub_get_weekday_name (&datetime));
      else
	grub_printf (" %04d%02d%02d%02d%02d%02d ",
		     datetime.year, datetime.month,
		     datetime.day, datetime.hour,
		     datetime.minute, datetime.second);
    }
  grub_printf ("%s%s\n", filename, info->dir ? "/" : "");

  return 0;
}
Example #7
0
unsigned long long
grub_strtoull (const char *str, char **end, int base)
{
  unsigned long long num = 0;
  int found = 0;

  /* Skip white spaces.  */
  while (*str && grub_isspace (*str))
    str++;

  /* Guess the base, if not specified. The prefix `0x' means 16, and
     the prefix `0' means 8.  */
  if (str[0] == '0')
    {
      if (str[1] == 'x')
	{
	  if (base == 0 || base == 16)
	    {
	      base = 16;
	      str += 2;
	    }
	}
      else if (base == 0 && str[1] >= '0' && str[1] <= '7')
	base = 8;
    }

  if (base == 0)
    base = 10;

  while (*str)
    {
      unsigned long digit;

      digit = grub_tolower (*str) - '0';
      if (digit > 9)
	{
	  digit += '0' - 'a' + 10;
	  if (digit >= (unsigned long) base)
	    break;
	}

      found = 1;

      /* NUM * BASE + DIGIT > ~0ULL */
      if (num > grub_divmod64 (~0ULL - digit, base, 0))
	{
	  grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected");
	  return ~0ULL;
	}

      num = num * base + digit;
      str++;
    }

  if (! found)
    {
      grub_error (GRUB_ERR_BAD_NUMBER, "unrecognized number");
      return 0;
    }

  if (end)
    *end = (char *) str;

  return num;
}
Example #8
0
  p = str;

  if (base == 16)
    do
      {
	unsigned d = (unsigned) (n & 0xf);
	*p++ = (d > 9) ? d + 'a' - 10 : d + '0';
      }
    while (n >>= 4);
  else
    /* BASE == 10 */
    do
      {
	unsigned m;

	n = grub_divmod64 (n, 10, &m);
	*p++ = m + '0';
      }
    while (n);

  *p = 0;

  grub_reverse (str);
  return p;
}

struct vsnprintf_closure
{
  char *str;
  grub_size_t count;
  grub_size_t max_len;
Example #9
0
File: ls.c Project: Arvian/GRUB2
static grub_err_t
grub_ls_list_files (char *dirname, int longlist, int all, int human)
{
  char *device_name;
  grub_fs_t fs;
  const char *path;
  grub_device_t dev;

  auto int print_files (const char *filename,
			const struct grub_dirhook_info *info);
  auto int print_files_long (const char *filename,
			     const struct grub_dirhook_info *info);

  int print_files (const char *filename, const struct grub_dirhook_info *info)
    {
      if (all || filename[0] != '.')
	grub_printf ("%s%s ", filename, info->dir ? "/" : "");

      return 0;
    }

  int print_files_long (const char *filename,
			const struct grub_dirhook_info *info)
    {
      if ((! all) && (filename[0] == '.'))
	return 0;

      if (! info->dir)
	{
	  grub_file_t file;
	  char *pathname;

	  if (dirname[grub_strlen (dirname) - 1] == '/')
	    pathname = grub_xasprintf ("%s%s", dirname, filename);
	  else
	    pathname = grub_xasprintf ("%s/%s", dirname, filename);

	  if (!pathname)
	    return 1;

	  /* XXX: For ext2fs symlinks are detected as files while they
	     should be reported as directories.  */
	  grub_file_filter_disable_compression ();
	  file = grub_file_open (pathname);
	  if (! file)
	    {
	      grub_errno = 0;
	      grub_free (pathname);
	      return 0;
	    }

	  if (! human)
	    grub_printf ("%-12llu", (unsigned long long) file->size);
	  else
	    {
	      grub_uint64_t fsize = file->size * 100ULL;
	      grub_uint64_t fsz = file->size;
	      int units = 0;
	      char buf[20];

	      while (fsz / 1024)
		{
		  fsize = (fsize + 512) / 1024;
		  fsz /= 1024;
		  units++;
		}

	      if (units)
		{
		  grub_uint64_t whole, fraction;

		  whole = grub_divmod64 (fsize, 100, &fraction);
		  grub_snprintf (buf, sizeof (buf),
				 "%" PRIuGRUB_UINT64_T
				 ".%02" PRIuGRUB_UINT64_T "%c", whole, fraction,
				 grub_human_sizes[units]);
		  grub_printf ("%-12s", buf);
		}
	      else
		grub_printf ("%-12llu", (unsigned long long) file->size);

	    }
	  grub_file_close (file);
	  grub_free (pathname);
	}
      else
	grub_printf ("%-12s", _("DIR"));

      if (info->mtimeset)
	{
	  struct grub_datetime datetime;
	  grub_unixtime2datetime (info->mtime, &datetime);
	  if (human)
	    grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ",
			 datetime.year, datetime.month, datetime.day,
			 datetime.hour, datetime.minute,
			 datetime.second,
			 grub_get_weekday_name (&datetime));
	  else
	    grub_printf (" %04d%02d%02d%02d%02d%02d ",
			 datetime.year, datetime.month,
			 datetime.day, datetime.hour,
			 datetime.minute, datetime.second);
	}
      grub_printf ("%s%s\n", filename, info->dir ? "/" : "");

      return 0;
    }

  device_name = grub_file_get_device_name (dirname);
  dev = grub_device_open (device_name);
  if (! dev)
    goto fail;

  fs = grub_fs_probe (dev);
  path = grub_strchr (dirname, ')');
  if (! path)
    path = dirname;
  else
    path++;

  if (! path && ! device_name)
    {
      grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid argument");
      goto fail;
    }

  if (! *path)
    {
      if (grub_errno == GRUB_ERR_UNKNOWN_FS)
	grub_errno = GRUB_ERR_NONE;

      grub_normal_print_device_info (device_name);
    }
  else if (fs)
    {
      if (longlist)
	(fs->dir) (dev, path, print_files_long);
      else
	(fs->dir) (dev, path, print_files);

      if (grub_errno == GRUB_ERR_BAD_FILE_TYPE
	  && path[grub_strlen (path) - 1] != '/')
	{
	  /* PATH might be a regular file.  */
	  char *p;
	  grub_file_t file;
	  struct grub_dirhook_info info;
	  grub_errno = 0;

	  grub_file_filter_disable_compression ();
	  file = grub_file_open (dirname);
	  if (! file)
	    goto fail;

	  grub_file_close (file);

	  p = grub_strrchr (dirname, '/') + 1;
	  dirname = grub_strndup (dirname, p - dirname);
	  if (! dirname)
	    goto fail;

	  all = 1;
	  grub_memset (&info, 0, sizeof (info));
	  if (longlist)
	    print_files_long (p, &info);
	  else
	    print_files (p, &info);

	  grub_free (dirname);
	}

      if (grub_errno == GRUB_ERR_NONE)
	grub_xputs ("\n");

      grub_refresh ();
    }

 fail:
  if (dev)
    grub_device_close (dev);

  grub_free (device_name);

  return 0;
}
Example #10
0
static grub_err_t
grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector,
		grub_size_t size, char *buf)
{
  grub_err_t err = 0;
  struct grub_lvm_lv *lv = disk->data;
  struct grub_lvm_vg *vg = lv->vg;
  struct grub_lvm_segment *seg = lv->segments;
  struct grub_lvm_pv *pv;
  grub_uint64_t offset;
  grub_uint64_t extent;
  unsigned int i;

  extent = grub_divmod64 (sector, vg->extent_size, NULL);

  /* Find the right segment.  */
  for (i = 0; i < lv->segment_count; i++)
    {
      if ((seg->start_extent <= extent)
	  && ((seg->start_extent + seg->extent_count) > extent))
	{
	  break;
	}

      seg++;
    }

  if (seg->stripe_count == 1)
    {
      /* This segment is linear, so that's easy.  We just need to find
	 out the offset in the physical volume and read SIZE bytes
	 from that.  */
      struct grub_lvm_stripe *stripe = seg->stripes;
      grub_uint64_t seg_offset; /* Offset of the segment in PV device.  */

      pv = stripe->pv;
      seg_offset = ((grub_uint64_t) stripe->start
		    * (grub_uint64_t) vg->extent_size) + pv->start;

      offset = sector - ((grub_uint64_t) seg->start_extent
			 * (grub_uint64_t) vg->extent_size) + seg_offset;
    }
  else
    {
      /* This is a striped segment. We have to find the right PV
	 similar to RAID0. */
      struct grub_lvm_stripe *stripe = seg->stripes;
      grub_uint32_t a, b;
      grub_uint64_t seg_offset; /* Offset of the segment in PV device.  */
      unsigned int stripenr;

      offset = sector - ((grub_uint64_t) seg->start_extent
			 * (grub_uint64_t) vg->extent_size);

      a = grub_divmod64 (offset, seg->stripe_size, NULL);
      grub_divmod64 (a, seg->stripe_count, &stripenr);

      a = grub_divmod64 (offset, seg->stripe_size * seg->stripe_count, NULL);
      grub_divmod64 (offset, seg->stripe_size, &b);
      offset = a * seg->stripe_size + b;

      stripe += stripenr;
      pv = stripe->pv;

      seg_offset = ((grub_uint64_t) stripe->start
		    * (grub_uint64_t) vg->extent_size) + pv->start;

      offset += seg_offset;
    }

  /* Check whether we actually know the physical volume we want to
     read from.  */
  if (pv->disk)
    err = grub_disk_read (pv->disk, offset, 0,
			  size << GRUB_DISK_SECTOR_BITS, buf);
  else
    err = grub_error (GRUB_ERR_UNKNOWN_DEVICE,
		      "physical volume %s not found", pv->name);

  return err;
}
Example #11
0
static grub_ssize_t
grub_bufio_read (grub_file_t file, char *buf, grub_size_t len)
{
  grub_size_t res = len;
  grub_bufio_t bufio = file->data;
  grub_uint32_t pos;

  if ((file->offset >= bufio->file->offset) &&
      (file->offset < bufio->file->offset + bufio->buffer_len))
    {
      grub_size_t n;

      pos = file->offset - bufio->file->offset;
      n = bufio->buffer_len - pos;
      if (n > len)
        n = len;

      grub_memcpy (buf, &bufio->buffer[pos], n);
      len -= n;
      if (! len)
        return res;

      buf += n;
      bufio->file->offset += bufio->buffer_len;
      pos = 0;
    }
  else
    {
      bufio->file->offset = grub_divmod64 (file->offset, bufio->block_size,
                                           &pos);
      bufio->file->offset *= bufio->block_size;
    }

  if (pos + len >= bufio->block_size)
    {
      if (pos)
        {
          grub_size_t n;

          bufio->file->fs->read (bufio->file, bufio->buffer,
                                 bufio->block_size);
          if (grub_errno)
            return -1;

          n = bufio->block_size - pos;
          grub_memcpy (buf, &bufio->buffer[pos], n);
          len -= n;
          buf += n;
          bufio->file->offset += bufio->block_size;
          pos = 0;
        }

      while (len >= bufio->block_size)
        {
          bufio->file->fs->read (bufio->file, buf, bufio->block_size);
          if (grub_errno)
            return -1;

          len -= bufio->block_size;
          buf += bufio->block_size;
          bufio->file->offset += bufio->block_size;
        }

      if (! len)
        {
          bufio->buffer_len = 0;
          return res;
        }
    }

  bufio->buffer_len = bufio->file->size - bufio->file->offset;
  if (bufio->buffer_len > bufio->block_size)
    bufio->buffer_len = bufio->block_size;

  bufio->file->fs->read (bufio->file, bufio->buffer, bufio->buffer_len);
  if (grub_errno)
    return -1;

  grub_memcpy (buf, &bufio->buffer[pos], len);

  return res;
}