(root)/
util-linux-2.39/
libfdisk/
src/
table.c
       1  
       2  #include "fdiskP.h"
       3  
       4  /**
       5   * SECTION: table
       6   * @title: Table
       7   * @short_description: container for fdisk partitions
       8   *
       9   * The fdisk_table is simple container for fdisk_partitions. The table is no
      10   * directly connected to label data (partition table), and table changes don't
      11   * affect in-memory or on-disk data.
      12   */
      13  
      14  /**
      15   * fdisk_new_table:
      16   *
      17   * The table is a container for struct fdisk_partition entries. The container
      18   * does not have any real connection with label (partition table) and with
      19   * real on-disk data.
      20   *
      21   * Returns: newly allocated table struct.
      22   */
      23  struct fdisk_table *fdisk_new_table(void)
      24  {
      25  	struct fdisk_table *tb = NULL;
      26  
      27  	tb = calloc(1, sizeof(*tb));
      28  	if (!tb)
      29  		return NULL;
      30  
      31  	DBG(TAB, ul_debugobj(tb, "alloc"));
      32  	tb->refcount = 1;
      33  	INIT_LIST_HEAD(&tb->parts);
      34  	return tb;
      35  }
      36  
      37  /**
      38   * fdisk_reset_table:
      39   * @tb: tab pointer
      40   *
      41   * Removes all entries (partitions) from the table. The partitions with zero
      42   * reference count will be deallocated. This function does not modify partition
      43   * table.
      44   *
      45   * Returns: 0 on success or negative number in case of error.
      46   */
      47  int fdisk_reset_table(struct fdisk_table *tb)
      48  {
      49  	if (!tb)
      50  		return -EINVAL;
      51  
      52  	DBG(TAB, ul_debugobj(tb, "reset"));
      53  
      54  	while (!list_empty(&tb->parts)) {
      55  		struct fdisk_partition *pa = list_entry(tb->parts.next,
      56  				                  struct fdisk_partition, parts);
      57  		fdisk_table_remove_partition(tb, pa);
      58  	}
      59  
      60  	tb->nents = 0;
      61  	return 0;
      62  }
      63  
      64  /**
      65   * fdisk_ref_table:
      66   * @tb: table pointer
      67   *
      68   * Increments reference counter.
      69   */
      70  void fdisk_ref_table(struct fdisk_table *tb)
      71  {
      72  	if (tb)
      73  		tb->refcount++;
      74  }
      75  
      76  /**
      77   * fdisk_unref_table:
      78   * @tb: table pointer
      79   *
      80   * Descrements reference counter, on zero the @tb is automatically
      81   * deallocated.
      82   */
      83  void fdisk_unref_table(struct fdisk_table *tb)
      84  {
      85  	if (!tb)
      86  		return;
      87  
      88  	tb->refcount--;
      89  	if (tb->refcount <= 0) {
      90  		fdisk_reset_table(tb);
      91  
      92  		DBG(TAB, ul_debugobj(tb, "free"));
      93  		free(tb);
      94  	}
      95  }
      96  
      97  /**
      98   * fdisk_table_is_empty:
      99   * @tb: pointer to tab
     100   *
     101   * Returns: 1 if the table is without filesystems, or 0.
     102   */
     103  int fdisk_table_is_empty(struct fdisk_table *tb)
     104  {
     105  	return tb == NULL || list_empty(&tb->parts) ? 1 : 0;
     106  }
     107  
     108  /**
     109   * fdisk_table_get_nents:
     110   * @tb: pointer to tab
     111   *
     112   * Returns: number of entries in table.
     113   */
     114  size_t fdisk_table_get_nents(struct fdisk_table *tb)
     115  {
     116  	return tb ? tb->nents : 0;
     117  }
     118  
     119  /**
     120   * fdisk_table_next_partition:
     121   * @tb: tab pointer
     122   * @itr: iterator
     123   * @pa: returns the next tab entry
     124   *
     125   * Returns: 0 on success, negative number in case of error or 1 at the end of list.
     126   *
     127   * Example:
     128   * <informalexample>
     129   *   <programlisting>
     130   *	while(fdisk_table_next_partition(tb, itr, &pa) == 0) {
     131   *		...
     132   *	}
     133   *   </programlisting>
     134   * </informalexample>
     135   */
     136  int fdisk_table_next_partition(
     137  			struct fdisk_table *tb,
     138  			struct fdisk_iter *itr,
     139  			struct fdisk_partition **pa)
     140  {
     141  	int rc = 1;
     142  
     143  	if (!tb || !itr || !pa)
     144  		return -EINVAL;
     145  	*pa = NULL;
     146  
     147  	if (!itr->head)
     148  		FDISK_ITER_INIT(itr, &tb->parts);
     149  	if (itr->p != itr->head) {
     150  		FDISK_ITER_ITERATE(itr, *pa, struct fdisk_partition, parts);
     151  		rc = 0;
     152  	}
     153  
     154  	return rc;
     155  }
     156  
     157  /**
     158   * fdisk_table_get_partition:
     159   * @tb: tab pointer
     160   * @n: number of entry in table
     161   *
     162   * Returns: n-th entry from table or NULL
     163   */
     164  struct fdisk_partition *fdisk_table_get_partition(
     165  			struct fdisk_table *tb,
     166  			size_t n)
     167  {
     168  	struct fdisk_partition *pa = NULL;
     169  	struct fdisk_iter itr;
     170  
     171  	if (!tb)
     172  		return NULL;
     173  
     174  	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
     175  
     176  	while (fdisk_table_next_partition(tb, &itr, &pa) == 0) {
     177  		if (n == 0)
     178  			return pa;
     179  		n--;
     180  	}
     181  
     182  	return NULL;
     183  }
     184  
     185  /**
     186   * fdisk_table_get_partition_by_partno:
     187   * @tb: tab pointer
     188   * @partno: partition number
     189   *
     190   * Returns: partition with @partno or NULL.
     191   */
     192  struct fdisk_partition *fdisk_table_get_partition_by_partno(
     193  			struct fdisk_table *tb,
     194  			size_t partno)
     195  {
     196  	struct fdisk_partition *pa = NULL;
     197  	struct fdisk_iter itr;
     198  
     199  	if (!tb)
     200  		return NULL;
     201  
     202  	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
     203  
     204  	while (fdisk_table_next_partition(tb, &itr, &pa) == 0) {
     205  		if (pa->partno == partno)
     206  			return pa;
     207  	}
     208  
     209  	return NULL;
     210  }
     211  
     212  /**
     213   * fdisk_table_add_partition
     214   * @tb: tab pointer
     215   * @pa: new entry
     216   *
     217   * Adds a new entry to table and increment @pa reference counter. Don't forget to
     218   * use fdisk_unref_partition() after fdisk_table_add_partition() if you want to keep
     219   * the @pa referenced by the table only.
     220   *
     221   * Returns: 0 on success or negative number in case of error.
     222   */
     223  int fdisk_table_add_partition(struct fdisk_table *tb, struct fdisk_partition *pa)
     224  {
     225  	if (!tb || !pa)
     226  		return -EINVAL;
     227  
     228  	if (!list_empty(&pa->parts))
     229  		return -EBUSY;
     230  
     231  	fdisk_ref_partition(pa);
     232  	list_add_tail(&pa->parts, &tb->parts);
     233  	tb->nents++;
     234  
     235  	DBG(TAB, ul_debugobj(tb, "add entry %p [start=%ju, end=%ju, size=%ju, %s %s %s]",
     236  			pa,
     237  			(uintmax_t) fdisk_partition_get_start(pa),
     238  			fdisk_partition_has_end(pa) ? (uintmax_t) fdisk_partition_get_end(pa) : 0,
     239  			fdisk_partition_has_size(pa) ? (uintmax_t) fdisk_partition_get_size(pa) : 0,
     240  			fdisk_partition_is_freespace(pa) ? "freespace" : "",
     241  			fdisk_partition_is_nested(pa)    ? "nested"    : "",
     242  			fdisk_partition_is_container(pa) ? "container" : "primary"));
     243  	return 0;
     244  }
     245  
     246  /* inserts @pa after @poz */
     247  static int table_insert_partition(
     248  			struct fdisk_table *tb,
     249  			struct fdisk_partition *poz,
     250  			struct fdisk_partition *pa)
     251  {
     252  	assert(tb);
     253  	assert(pa);
     254  
     255  	fdisk_ref_partition(pa);
     256  	if (poz)
     257  		list_add(&pa->parts, &poz->parts);
     258  	else
     259  		list_add(&pa->parts, &tb->parts);
     260  	tb->nents++;
     261  
     262  	DBG(TAB, ul_debugobj(tb, "insert entry %p pre=%p [start=%ju, end=%ju, size=%ju, %s %s %s]",
     263  			pa, poz ? poz : NULL,
     264  			(uintmax_t) fdisk_partition_get_start(pa),
     265  			(uintmax_t) fdisk_partition_get_end(pa),
     266  			(uintmax_t) fdisk_partition_get_size(pa),
     267  			fdisk_partition_is_freespace(pa) ? "freespace" : "",
     268  			fdisk_partition_is_nested(pa)    ? "nested"    : "",
     269  			fdisk_partition_is_container(pa) ? "container" : ""));
     270  	return 0;
     271  }
     272  
     273  /**
     274   * fdisk_table_remove_partition
     275   * @tb: tab pointer
     276   * @pa: new entry
     277   *
     278   * Removes the @pa from the table and de-increment reference counter of the @pa. The
     279   * partition with zero reference counter will be deallocated. Don't forget to use
     280   * fdisk_ref_partition() before call fdisk_table_remove_partition() if you want
     281   * to use @pa later.
     282   *
     283   * Returns: 0 on success or negative number in case of error.
     284   */
     285  int fdisk_table_remove_partition(struct fdisk_table *tb, struct fdisk_partition *pa)
     286  {
     287  	if (!tb || !pa)
     288  		return -EINVAL;
     289  
     290  	DBG(TAB, ul_debugobj(tb, "remove entry %p", pa));
     291  	list_del(&pa->parts);
     292  	INIT_LIST_HEAD(&pa->parts);
     293  
     294  	fdisk_unref_partition(pa);
     295  	tb->nents--;
     296  
     297  	return 0;
     298  }
     299  
     300  /**
     301   * fdisk_get_partitions
     302   * @cxt: fdisk context
     303   * @tb: returns table
     304   *
     305   * This function adds partitions from disklabel to @table, it allocates a new
     306   * table if @table points to NULL.
     307   *
     308   * Returns: 0 on success, otherwise, a corresponding error.
     309   */
     310  int fdisk_get_partitions(struct fdisk_context *cxt, struct fdisk_table **tb)
     311  {
     312  	size_t i;
     313  
     314  	if (!cxt || !cxt->label || !tb)
     315  		return -EINVAL;
     316  	if (!cxt->label->op->get_part)
     317  		return -ENOSYS;
     318  
     319  	DBG(CXT, ul_debugobj(cxt, " -- get table --"));
     320  
     321  	if (!*tb && !(*tb = fdisk_new_table()))
     322  		return -ENOMEM;
     323  
     324  	for (i = 0; i < cxt->label->nparts_max; i++) {
     325  		struct fdisk_partition *pa = NULL;
     326  
     327  		if (fdisk_get_partition(cxt, i, &pa) != 0)
     328  			continue;
     329  		if (fdisk_partition_is_used(pa))
     330  			fdisk_table_add_partition(*tb, pa);
     331  		fdisk_unref_partition(pa);
     332  	}
     333  
     334  	return 0;
     335  }
     336  
     337  void fdisk_debug_print_table(struct fdisk_table *tb)
     338  {
     339  	struct fdisk_iter itr;
     340  	struct fdisk_partition *pa;
     341  
     342  	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
     343  	while (fdisk_table_next_partition(tb, &itr, &pa) == 0)
     344  		ul_debugobj(tb, "partition %p [partno=%zu, start=%ju, end=%ju, size=%ju%s%s%s] ",
     345  			    pa, pa->partno,
     346  			    (uintmax_t) fdisk_partition_get_start(pa),
     347  			    (uintmax_t) fdisk_partition_get_end(pa),
     348  			    (uintmax_t) fdisk_partition_get_size(pa),
     349  			    fdisk_partition_is_nested(pa) ? " nested" : "",
     350  			    fdisk_partition_is_freespace(pa) ? " freespace" : "",
     351  			    fdisk_partition_is_container(pa) ? " container" : "");
     352  
     353  }
     354  
     355  
     356  typedef	int (*fdisk_partcmp_t)(struct fdisk_partition *, struct fdisk_partition *);
     357  
     358  static int cmp_parts_wrapper(struct list_head *a, struct list_head *b, void *data)
     359  {
     360  	struct fdisk_partition *pa = list_entry(a, struct fdisk_partition, parts),
     361  			       *pb = list_entry(b, struct fdisk_partition, parts);
     362  
     363  	fdisk_partcmp_t cmp = (fdisk_partcmp_t) data;
     364  
     365  	return cmp(pa, pb);
     366  }
     367  
     368  
     369  /**
     370   * fdisk_table_sort_partitions:
     371   * @tb: table
     372   * @cmp: compare function
     373   *
     374   * Sort partition in the table.
     375   *
     376   * Returns: 0 on success, <0 on error.
     377   */
     378  int fdisk_table_sort_partitions(struct fdisk_table *tb,
     379  			int (*cmp)(struct fdisk_partition *,
     380  				   struct fdisk_partition *))
     381  {
     382  	if (!tb)
     383  		return -EINVAL;
     384  
     385  	/*
     386  	DBG(TAB, ul_debugobj(tb, "Before sort:"));
     387  	ON_DBG(TAB, fdisk_debug_print_table(tb));
     388  	*/
     389  
     390  	list_sort(&tb->parts, cmp_parts_wrapper, (void *) cmp);
     391  
     392  	/*
     393  	DBG(TAB, ul_debugobj(tb, "After sort:"));
     394  	ON_DBG(TAB, fdisk_debug_print_table(tb));
     395  	*/
     396  
     397  	return 0;
     398  }
     399  
     400  /* allocates a new freespace description */
     401  static int new_freespace(struct fdisk_context *cxt,
     402  			 fdisk_sector_t start,
     403  			 fdisk_sector_t end,
     404  			 struct fdisk_partition *parent,
     405  			 struct fdisk_partition **pa)
     406  {
     407  	fdisk_sector_t aligned_start, size;
     408  
     409  	assert(cxt);
     410  	assert(pa);
     411  
     412  	*pa = NULL;
     413  
     414  	if (start == end)
     415  		return 0;
     416  
     417  	assert(start >= cxt->first_lba);
     418  	assert(end);
     419  	assert(end > start);
     420  
     421  	aligned_start = fdisk_align_lba_in_range(cxt, start, start, end);
     422  	size = end - aligned_start + 1ULL;
     423  
     424  	if (size == 0) {
     425  		DBG(TAB, ul_debug("ignore freespace (aligned size is zero)"));
     426  		return 0;
     427  	}
     428  
     429  	*pa = fdisk_new_partition();
     430  	if (!*pa)
     431  		return -ENOMEM;
     432  
     433  	(*pa)->freespace = 1;
     434  	(*pa)->start = aligned_start;
     435  	(*pa)->size = size;
     436  
     437  	if (parent)
     438  		(*pa)->parent_partno = parent->partno;
     439  	return 0;
     440  }
     441  
     442  /* add freespace description to the right place within @tb */
     443  static int table_add_freespace(
     444  			struct fdisk_context *cxt,
     445  			struct fdisk_table *tb,
     446  			fdisk_sector_t start,
     447  			fdisk_sector_t end,
     448  			struct fdisk_partition *parent)
     449  {
     450  	struct fdisk_partition *pa, *x, *real_parent = NULL, *best = NULL;
     451  	struct fdisk_iter itr;
     452  	int rc = 0;
     453  
     454  	assert(tb);
     455  
     456  	rc = new_freespace(cxt, start, end, parent, &pa);
     457  	if (rc)
     458  		return -ENOMEM;
     459  	if (!pa)
     460  		return 0;
     461  
     462  	assert(fdisk_partition_has_start(pa));
     463  	assert(fdisk_partition_has_end(pa));
     464  
     465  	DBG(TAB, ul_debugobj(tb, "adding freespace"));
     466  
     467  	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
     468  	if (parent && fdisk_partition_has_partno(parent)) {
     469  		while (fdisk_table_next_partition(tb, &itr, &x) == 0) {
     470  			if (!fdisk_partition_has_partno(x))
     471  				continue;
     472  			if (x->partno == parent->partno) {
     473  				real_parent = x;
     474  				break;
     475  			}
     476  		}
     477  		if (!real_parent) {
     478  			DBG(TAB, ul_debugobj(tb, "not found freespace parent (partno=%zu)",
     479  					parent->partno));
     480  			fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
     481  		}
     482  	}
     483  
     484  	while (fdisk_table_next_partition(tb, &itr, &x) == 0) {
     485  		fdisk_sector_t the_end, best_end = 0;
     486  
     487  		if (!fdisk_partition_has_end(x))
     488  			continue;
     489  
     490  		the_end = fdisk_partition_get_end(x);
     491  		if (best)
     492  			best_end = fdisk_partition_get_end(best);
     493  
     494  		if (the_end < pa->start && (!best || best_end < the_end))
     495  			best = x;
     496  	}
     497  
     498  	if (!best && real_parent)
     499  		best = real_parent;
     500  	rc = table_insert_partition(tb, best, pa);
     501  
     502  	fdisk_unref_partition(pa);
     503  
     504  	DBG(TAB, ul_debugobj(tb, "adding freespace DONE [rc=%d]", rc));
     505  	return rc;
     506  }
     507  
     508  /* analyze @cont(ainer) in @parts and add all detected freespace into @tb, note
     509   * that @parts has to be sorted by partition starts */
     510  static int check_container_freespace(struct fdisk_context *cxt,
     511  				     struct fdisk_table *parts,
     512  				     struct fdisk_table *tb,
     513  				     struct fdisk_partition *cont)
     514  {
     515  	struct fdisk_iter itr;
     516  	struct fdisk_partition *pa;
     517  	fdisk_sector_t x, last, grain, lastplusoff;
     518  	int rc = 0;
     519  
     520  	assert(cxt);
     521  	assert(parts);
     522  	assert(tb);
     523  	assert(cont);
     524  	assert(fdisk_partition_has_start(cont));
     525  
     526  	DBG(TAB, ul_debugobj(tb, "analyze container 0x%p", cont));
     527  
     528  	last = fdisk_partition_get_start(cont);
     529  	grain = cxt->grain > cxt->sector_size ?	cxt->grain / cxt->sector_size : 1;
     530  	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
     531  
     532  	DBG(CXT, ul_debugobj(cxt, "initialized:  last=%ju, grain=%ju",
     533  	                     (uintmax_t)last,  (uintmax_t)grain));
     534  
     535  	while (fdisk_table_next_partition(parts, &itr, &pa) == 0) {
     536  
     537  		DBG(CXT, ul_debugobj(cxt, "partno=%zu, start=%ju",
     538  		                     pa->partno, (uintmax_t)pa->start));
     539  
     540  		if (!pa->used || !fdisk_partition_is_nested(pa)
     541  			      || !fdisk_partition_has_start(pa))
     542  			continue;
     543  
     544  		DBG(CXT, ul_debugobj(cxt, "freespace container analyze: partno=%zu, start=%ju, end=%ju",
     545  					pa->partno,
     546  					(uintmax_t) fdisk_partition_get_start(pa),
     547  					(uintmax_t) fdisk_partition_get_end(pa)));
     548  
     549  		lastplusoff = last + cxt->first_lba;
     550  		if (pa->start > lastplusoff && pa->start - lastplusoff > grain)
     551  			rc = table_add_freespace(cxt, tb, lastplusoff, pa->start, cont);
     552  		if (rc)
     553  			goto done;
     554  		last = fdisk_partition_get_end(pa);
     555  	}
     556  
     557  	/* free-space remaining in extended partition */
     558  	x = fdisk_partition_get_start(cont) + fdisk_partition_get_size(cont) - 1;
     559  	lastplusoff = last + cxt->first_lba;
     560  	if (lastplusoff < x && x - lastplusoff > grain) {
     561  		DBG(TAB, ul_debugobj(tb, "add remaining space in container 0x%p", cont));
     562  		rc = table_add_freespace(cxt, tb, lastplusoff, x, cont);
     563  	}
     564  
     565  done:
     566  	DBG(TAB, ul_debugobj(tb, "analyze container 0x%p DONE [rc=%d]", cont, rc));
     567  	return rc;
     568  }
     569  
     570  
     571  /**
     572   * fdisk_get_freespaces
     573   * @cxt: fdisk context
     574   * @tb: returns table
     575   *
     576   * This function adds freespace (described by fdisk_partition) to @table, it
     577   * allocates a new table if the @table points to NULL.
     578   *
     579   * Note that free space smaller than grain (see fdisk_get_grain_size()) is
     580   * ignored.
     581   *
     582   * Returns: 0 on success, otherwise, a corresponding error.
     583   */
     584  int fdisk_get_freespaces(struct fdisk_context *cxt, struct fdisk_table **tb)
     585  {
     586  	int rc = 0;
     587  	size_t nparts = 0;
     588  	fdisk_sector_t last, grain;
     589  	struct fdisk_table *parts = NULL;
     590  	struct fdisk_partition *pa;
     591  	struct fdisk_iter itr;
     592  
     593  	DBG(CXT, ul_debugobj(cxt, "-- get freespace --"));
     594  
     595  	if (!cxt || !cxt->label || !tb)
     596  		return -EINVAL;
     597  	if (!*tb && !(*tb = fdisk_new_table()))
     598  		return -ENOMEM;
     599  
     600  	rc = fdisk_get_partitions(cxt, &parts);
     601  	if (rc)
     602  		goto done;
     603  
     604  	fdisk_table_sort_partitions(parts, fdisk_partition_cmp_start);
     605  	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
     606  	last = cxt->first_lba;
     607  	grain = cxt->grain > cxt->sector_size ?	cxt->grain / cxt->sector_size : 1;
     608  
     609  	DBG(CXT, ul_debugobj(cxt, "initialized:  last=%ju, grain=%ju",
     610  	                     (uintmax_t)last,  (uintmax_t)grain));
     611  
     612  	/* analyze gaps between partitions */
     613  	while (rc == 0 && fdisk_table_next_partition(parts, &itr, &pa) == 0) {
     614  
     615  		DBG(CXT, ul_debugobj(cxt, "partno=%zu, start=%ju",
     616  		                     pa->partno, (uintmax_t)pa->start));
     617  
     618  		if (!pa->used || pa->wholedisk || fdisk_partition_is_nested(pa)
     619  			      || !fdisk_partition_has_start(pa))
     620  			continue;
     621  		DBG(CXT, ul_debugobj(cxt, "freespace analyze: partno=%zu, start=%ju, end=%ju",
     622  					pa->partno,
     623  					(uintmax_t) fdisk_partition_get_start(pa),
     624  					(uintmax_t) fdisk_partition_get_end(pa)));
     625  
     626  		/* We ignore small free spaces (smaller than grain) to keep partitions
     627  		 * aligned, the exception is space before the first partition when
     628  		 * cxt->first_lba is aligned. */
     629  		if (last + grain < pa->start
     630  		    || (nparts == 0 &&
     631  		        (fdisk_align_lba(cxt, last, FDISK_ALIGN_UP) <
     632  			 pa->start))) {
     633  			rc = table_add_freespace(cxt, *tb,
     634  				last + (nparts == 0 ? 0 : 1),
     635  				pa->start - 1, NULL);
     636  		}
     637  		/* add gaps between logical partitions */
     638  		if (fdisk_partition_is_container(pa))
     639  			rc = check_container_freespace(cxt, parts, *tb, pa);
     640  
     641  		if (fdisk_partition_has_end(pa)) {
     642  			fdisk_sector_t pa_end = fdisk_partition_get_end(pa);
     643  			if (pa_end > last)
     644  				last = fdisk_partition_get_end(pa);
     645  		}
     646  		nparts++;
     647  	}
     648  
     649  	/* add free-space behind last partition to the end of the table (so
     650  	 * don't use table_add_freespace()) */
     651  	if (rc == 0 && last + grain < cxt->last_lba - 1) {
     652  		DBG(CXT, ul_debugobj(cxt, "freespace behind last partition detected"));
     653  		rc = new_freespace(cxt,
     654  			last + (last > cxt->first_lba || nparts ? 1 : 0),
     655  			cxt->last_lba, NULL, &pa);
     656  		if (pa) {
     657  			fdisk_table_add_partition(*tb, pa);
     658  			fdisk_unref_partition(pa);
     659  		}
     660  	}
     661  
     662  done:
     663  	fdisk_unref_table(parts);
     664  
     665  	DBG(CXT, ul_debugobj(cxt, "get freespace DONE [rc=%d]", rc));
     666  	return rc;
     667  }
     668  
     669  /**
     670   * fdisk_table_wrong_order:
     671   * @tb: table
     672   *
     673   * Returns: 1 of the table is not in disk order
     674   */
     675  int fdisk_table_wrong_order(struct fdisk_table *tb)
     676  {
     677  	struct fdisk_partition *pa;
     678  	struct fdisk_iter itr;
     679  	fdisk_sector_t last = 0;
     680  
     681  	DBG(TAB, ul_debugobj(tb, "wrong older check"));
     682  
     683  	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
     684  	while (tb && fdisk_table_next_partition(tb, &itr, &pa) == 0) {
     685  		if (!fdisk_partition_has_start(pa) || fdisk_partition_is_wholedisk(pa))
     686  			continue;
     687  		if (pa->start < last)
     688  			return 1;
     689  		last = pa->start;
     690  	}
     691  	return 0;
     692  }
     693  
     694  /**
     695   * fdisk_apply_table:
     696   * @cxt: context
     697   * @tb: table
     698   *
     699   * Add partitions from table @tb to the in-memory disk label. See
     700   * fdisk_add_partition(), fdisk_delete_all_partitions(). The partitions
     701   * that does not define start (or does not follow the default start)
     702   * are ignored.
     703   *
     704   * Returns: 0 on success, <0 on error.
     705   */
     706  int fdisk_apply_table(struct fdisk_context *cxt, struct fdisk_table *tb)
     707  {
     708  	struct fdisk_partition *pa;
     709  	struct fdisk_iter itr;
     710  	int rc = 0;
     711  
     712  	assert(cxt);
     713  	assert(tb);
     714  
     715  	DBG(TAB, ul_debugobj(tb, "applying to context %p", cxt));
     716  
     717  	fdisk_reset_iter(&itr, FDISK_ITER_FORWARD);
     718  	while (tb && fdisk_table_next_partition(tb, &itr, &pa) == 0) {
     719  		if (!fdisk_partition_has_start(pa) && !pa->start_follow_default)
     720  			continue;
     721  		rc = fdisk_add_partition(cxt, pa, NULL);
     722  		if (rc)
     723  			break;
     724  	}
     725  
     726  	return rc;
     727  }
     728  
     729  int fdisk_diff_tables(struct fdisk_table *a, struct fdisk_table *b,
     730  		      struct fdisk_iter *itr,
     731  		      struct fdisk_partition **res, int *change)
     732  {
     733  	struct fdisk_partition *pa = NULL, *pb;
     734  	int rc = 1;
     735  
     736  	assert(itr);
     737  	assert(res);
     738  	assert(change);
     739  
     740  	DBG(TAB, ul_debugobj(a, "table diff [new table=%p]", b));
     741  
     742  	if (a && (itr->head == NULL || itr->head == &a->parts)) {
     743  		DBG(TAB, ul_debugobj(a, " scanning old table"));
     744  		do {
     745  			rc = fdisk_table_next_partition(a, itr, &pa);
     746  			if (rc != 0)
     747  				break;
     748  		} while (!fdisk_partition_has_partno(pa));
     749  	}
     750  
     751  	if (rc == 1 && b) {
     752  		DBG(TAB, ul_debugobj(a, " scanning new table"));
     753  		if (itr->head != &b->parts) {
     754  			DBG(TAB, ul_debugobj(a, "  initialize to TAB=%p", b));
     755  			fdisk_reset_iter(itr, FDISK_ITER_FORWARD);
     756  		}
     757  
     758  		while (fdisk_table_next_partition(b, itr, &pb) == 0) {
     759  			if (!fdisk_partition_has_partno(pb))
     760  				continue;
     761  			if (a == NULL ||
     762  			    fdisk_table_get_partition_by_partno(a, pb->partno) == NULL) {
     763  				DBG(TAB, ul_debugobj(a, " #%zu ADDED", pb->partno));
     764  				*change = FDISK_DIFF_ADDED;
     765  				*res = pb;
     766  				return 0;
     767  			}
     768  		}
     769  	}
     770  
     771  	if (rc) {
     772  		DBG(TAB, ul_debugobj(a, "table diff done [rc=%d]", rc));
     773  		return rc;	/* error or done */
     774  	}
     775  
     776  	pb = fdisk_table_get_partition_by_partno(b, pa->partno);
     777  
     778  	if (!pb) {
     779  		DBG(TAB, ul_debugobj(a, " #%zu REMOVED", pa->partno));
     780  		*change = FDISK_DIFF_REMOVED;
     781  		*res = pa;
     782  	} else if (pb->start != pa->start) {
     783  		DBG(TAB, ul_debugobj(a, " #%zu MOVED", pb->partno));
     784  		*change = FDISK_DIFF_MOVED;
     785  		*res = pb;
     786  	} else if (pb->size != pa->size) {
     787  		DBG(TAB, ul_debugobj(a, " #%zu RESIZED", pb->partno));
     788  		*change = FDISK_DIFF_RESIZED;
     789  		*res = pb;
     790  	} else {
     791  		DBG(TAB, ul_debugobj(a, " #%zu UNCHANGED", pb->partno));
     792  		*change = FDISK_DIFF_UNCHANGED;
     793  		*res = pa;
     794  	}
     795  	return 0;
     796  }
     797