Panu Matilainen 459c2d
diff --git a/lib/transaction.c b/lib/transaction.c
Panu Matilainen 459c2d
index 1860dfb..d913258 100644
Panu Matilainen 459c2d
--- a/lib/transaction.c
Panu Matilainen 459c2d
+++ b/lib/transaction.c
Panu Matilainen 459c2d
@@ -45,6 +45,7 @@
Panu Matilainen 459c2d
 #include "debug.h"
Panu Matilainen 459c2d
 
Panu Matilainen 459c2d
 struct diskspaceInfo_s {
Panu Matilainen 459c2d
+    char * mntPoint;	/*!< File system mount point */
Panu Matilainen 459c2d
     dev_t dev;		/*!< File system device number. */
Panu Matilainen 459c2d
     int64_t bneeded;	/*!< No. of blocks needed. */
Panu Matilainen 459c2d
     int64_t ineeded;	/*!< No. of inodes needed. */
Panu Matilainen 459c2d
@@ -61,83 +62,114 @@ struct diskspaceInfo_s {
Panu Matilainen 459c2d
 
Panu Matilainen 459c2d
 static int rpmtsInitDSI(const rpmts ts)
Panu Matilainen 459c2d
 {
Panu Matilainen 459c2d
-    rpmDiskSpaceInfo dsi;
Panu Matilainen 459c2d
-    struct stat sb;
Panu Matilainen 459c2d
-    int rc;
Panu Matilainen 459c2d
-    int i;
Panu Matilainen 459c2d
-
Panu Matilainen 459c2d
     if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE)
Panu Matilainen 459c2d
 	return 0;
Panu Matilainen 459c2d
-
Panu Matilainen 459c2d
-    rpmlog(RPMLOG_DEBUG, "mounted filesystems:\n");
Panu Matilainen 459c2d
-    rpmlog(RPMLOG_DEBUG,
Panu Matilainen 459c2d
-	"    i        dev    bsize       bavail       iavail mount point\n");
Panu Matilainen 459c2d
-
Panu Matilainen 459c2d
-    rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
Panu Matilainen 459c2d
-    if (rc || ts->filesystems == NULL || ts->filesystemCount <= 0)
Panu Matilainen 459c2d
-	return rc;
Panu Matilainen 459c2d
-
Panu Matilainen 459c2d
-    /* Get available space on mounted file systems. */
Panu Matilainen 459c2d
-
Panu Matilainen 459c2d
     ts->dsi = _free(ts->dsi);
Panu Matilainen 459c2d
-    ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
Panu Matilainen 459c2d
+    ts->filesystemCount = 0;
Panu Matilainen 459c2d
+    ts->dsi = xcalloc(1, sizeof(*ts->dsi));
Panu Matilainen 459c2d
+    return 0;
Panu Matilainen 459c2d
+}
Panu Matilainen 459c2d
 
Panu Matilainen 459c2d
-    dsi = ts->dsi;
Panu Matilainen 459c2d
+static rpmDiskSpaceInfo rpmtsCreateDSI(const rpmts ts, dev_t dev,
Panu Matilainen 459c2d
+				       const char * dirName, int count)
Panu Matilainen 459c2d
+{
Panu Matilainen 459c2d
+    rpmDiskSpaceInfo dsi;
Panu Matilainen 459c2d
+    struct stat sb;
Panu Matilainen 459c2d
+    char * resolved_path;
Panu Matilainen 459c2d
+    char mntPoint[PATH_MAX];
Panu Matilainen 459c2d
+    int rc;
Panu Matilainen 459c2d
 
Panu Matilainen 459c2d
-    if (dsi != NULL)
Panu Matilainen 459c2d
-    for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
Panu Matilainen 459c2d
 #if STATFS_IN_SYS_STATVFS
Panu Matilainen 459c2d
-	struct statvfs sfb;
Panu Matilainen 459c2d
-	memset(&sfb, 0, sizeof(sfb));
Panu Matilainen 459c2d
-	rc = statvfs(ts->filesystems[i], &sfb;;
Panu Matilainen 459c2d
+    struct statvfs sfb;
Panu Matilainen 459c2d
+    memset(&sfb, 0, sizeof(sfb));
Panu Matilainen 459c2d
+    rc = statvfs(dirName, &sfb;;
Panu Matilainen 459c2d
 #else
Panu Matilainen 459c2d
-	struct statfs sfb;
Panu Matilainen 459c2d
-	memset(&sfb, 0, sizeof(sfb));
Panu Matilainen 459c2d
+    struct statfs sfb;
Panu Matilainen 459c2d
+    memset(&sfb, 0, sizeof(sfb));
Panu Matilainen 459c2d
 #  if STAT_STATFS4
Panu Matilainen 459c2d
 /* This platform has the 4-argument version of the statfs call.  The last two
Panu Matilainen 459c2d
  * should be the size of struct statfs and 0, respectively.  The 0 is the
Panu Matilainen 459c2d
  * filesystem type, and is always 0 when statfs is called on a mounted
Panu Matilainen 459c2d
  * filesystem, as we're doing.
Panu Matilainen 459c2d
  */
Panu Matilainen 459c2d
-	rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
Panu Matilainen 459c2d
+    rc = statfs(dirName, &sfb, sizeof(sfb), 0);
Panu Matilainen 459c2d
 #  else
Panu Matilainen 459c2d
-	rc = statfs(ts->filesystems[i], &sfb;;
Panu Matilainen 459c2d
+    rc = statfs(dirName, &sfb;;
Panu Matilainen 459c2d
 #  endif
Panu Matilainen 459c2d
 #endif
Panu Matilainen 459c2d
-	if (rc)
Panu Matilainen 459c2d
-	    break;
Panu Matilainen 459c2d
-
Panu Matilainen 459c2d
-	rc = stat(ts->filesystems[i], &sb);
Panu Matilainen 459c2d
-	if (rc)
Panu Matilainen 459c2d
-	    break;
Panu Matilainen 459c2d
-	dsi->dev = sb.st_dev;
Panu Matilainen 459c2d
-
Panu Matilainen 459c2d
-	dsi->bsize = sfb.f_bsize;
Panu Matilainen 459c2d
-	dsi->bneeded = 0;
Panu Matilainen 459c2d
-	dsi->ineeded = 0;
Panu Matilainen 459c2d
+    if (rc)
Panu Matilainen 459c2d
+	return NULL;
Panu Matilainen 459c2d
+
Panu Matilainen 459c2d
+    rc = stat(dirName, &sb);
Panu Matilainen 459c2d
+    if (rc)
Panu Matilainen 459c2d
+	return NULL;
Panu Matilainen 459c2d
+    if (sb.st_dev != dev) // XXX WHY?
Panu Matilainen 459c2d
+	return NULL;
Panu Matilainen 459c2d
+
Panu Matilainen 459c2d
+    ts->dsi = xrealloc(ts->dsi, (count + 2) * sizeof(*ts->dsi));
Panu Matilainen 459c2d
+    dsi = ts->dsi + count;
Panu Matilainen 459c2d
+    memset(dsi, 0, 2 * sizeof(*dsi));
Panu Matilainen 459c2d
+
Panu Matilainen 459c2d
+    dsi->dev = sb.st_dev;
Panu Matilainen 459c2d
+    dsi->bsize = sfb.f_bsize;
Panu Matilainen 459c2d
+    if (!dsi->bsize)
Panu Matilainen 459c2d
+	dsi->bsize = 512;       /* we need a bsize */
Panu Matilainen 459c2d
+    dsi->bneeded = 0;
Panu Matilainen 459c2d
+    dsi->ineeded = 0;
Panu Matilainen 459c2d
 #ifdef STATFS_HAS_F_BAVAIL
Panu Matilainen 459c2d
-	dsi->bavail = (sfb.f_flag & ST_RDONLY) ? 0 : sfb.f_bavail;
Panu Matilainen 459c2d
+    dsi->bavail = (sfb.f_flag & ST_RDONLY) ? 0 : sfb.f_bavail;
Panu Matilainen 459c2d
 #else
Panu Matilainen 459c2d
 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
Panu Matilainen 459c2d
  * available for non-superusers.  f_blocks - f_bfree is probably too big, but
Panu Matilainen 459c2d
  * it's about all we can do.
Panu Matilainen 459c2d
  */
Panu Matilainen 459c2d
-	dsi->bavail = sfb.f_blocks - sfb.f_bfree;
Panu Matilainen 459c2d
+    dsi->bavail = sfb.f_blocks - sfb.f_bfree;
Panu Matilainen 459c2d
 #endif
Panu Matilainen 459c2d
-	/* XXX Avoid FAT and other file systems that have not inodes. */
Panu Matilainen 459c2d
-	/* XXX assigning negative value to unsigned type */
Panu Matilainen 459c2d
-	dsi->iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
Panu Matilainen 459c2d
-				? sfb.f_ffree : -1;
Panu Matilainen 459c2d
-	rpmlog(RPMLOG_DEBUG, 
Panu Matilainen 459c2d
-		"%5d 0x%08x %8" PRId64 " %12" PRId64 " %12" PRId64" %s\n",
Panu Matilainen 459c2d
-		i, (unsigned) dsi->dev, dsi->bsize,
Panu Matilainen 459c2d
-		dsi->bavail, dsi->iavail,
Panu Matilainen 459c2d
-		ts->filesystems[i]);
Panu Matilainen 459c2d
+    /* XXX Avoid FAT and other file systems that have not inodes. */
Panu Matilainen 459c2d
+    /* XXX assigning negative value to unsigned type */
Panu Matilainen 459c2d
+    dsi->iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
Panu Matilainen 459c2d
+	? sfb.f_ffree : -1;
Panu Matilainen 459c2d
+
Panu Matilainen 459c2d
+    /* Find mount point belonging to this device number */
Panu Matilainen 459c2d
+    resolved_path = realpath(dirName, mntPoint);
Panu Matilainen 459c2d
+    if (!resolved_path) {
Panu Matilainen 459c2d
+	strncpy(mntPoint, dirName, PATH_MAX);
Panu Matilainen 459c2d
+	mntPoint[PATH_MAX-1] = '\0';
Panu Matilainen 459c2d
     }
Panu Matilainen 459c2d
-    return rc;
Panu Matilainen 459c2d
+    char * end = NULL;
Panu Matilainen 459c2d
+    while (end != mntPoint) {
Panu Matilainen 459c2d
+	end = strrchr(mntPoint, '/');
Panu Matilainen 459c2d
+	if (end == mntPoint) { // reached "/"
Panu Matilainen 459c2d
+	    stat("/", &sb);
Panu Matilainen 459c2d
+	    if (dsi->dev != sb.st_dev) {
Panu Matilainen 459c2d
+		dsi->mntPoint = xstrdup(mntPoint);
Panu Matilainen 459c2d
+	    } else {
Panu Matilainen 459c2d
+		dsi->mntPoint = xstrdup("/");
Panu Matilainen 459c2d
+	    }
Panu Matilainen 459c2d
+	    break;
Panu Matilainen 459c2d
+	} else if (end) {
Panu Matilainen 459c2d
+	    *end = '\0';
Panu Matilainen 459c2d
+	} else { // dirName doesn't start with / - should not happen
Panu Matilainen 459c2d
+	    dsi->mntPoint = xstrdup(dirName);
Panu Matilainen 459c2d
+	    break;
Panu Matilainen 459c2d
+	}
Panu Matilainen 459c2d
+	stat(mntPoint, &sb);
Panu Matilainen 459c2d
+	if (dsi->dev != sb.st_dev) {
Panu Matilainen 459c2d
+	    *end = '/';
Panu Matilainen 459c2d
+	    dsi->mntPoint = xstrdup(mntPoint);
Panu Matilainen 459c2d
+	    break;
Panu Matilainen 459c2d
+	}
Panu Matilainen 459c2d
+    }
Panu Matilainen 459c2d
+
Panu Matilainen 459c2d
+    rpmlog(RPMLOG_DEBUG,
Panu Matilainen 459c2d
+	   "0x%08x %8" PRId64 " %12" PRId64 " %12" PRId64" %s\n",
Panu Matilainen 459c2d
+	   (unsigned) dsi->dev, dsi->bsize,
Panu Matilainen 459c2d
+	   dsi->bavail, dsi->iavail,
Panu Matilainen 459c2d
+	   dsi->mntPoint);
Panu Matilainen 459c2d
+    return dsi;
Panu Matilainen 459c2d
 }
Panu Matilainen 459c2d
 
Panu Matilainen 459c2d
-static void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
Panu Matilainen 459c2d
+static void rpmtsUpdateDSI(const rpmts ts, dev_t dev, const char *dirName,
Panu Matilainen 459c2d
 		rpm_loff_t fileSize, rpm_loff_t prevSize, rpm_loff_t fixupSize,
Panu Matilainen 459c2d
 		rpmFileAction action)
Panu Matilainen 459c2d
 {
Panu Matilainen 459c2d
@@ -148,8 +180,10 @@ static void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
Panu Matilainen 459c2d
     if (dsi) {
Panu Matilainen 459c2d
 	while (dsi->bsize && dsi->dev != dev)
Panu Matilainen 459c2d
 	    dsi++;
Panu Matilainen 459c2d
-	if (dsi->bsize == 0)
Panu Matilainen 459c2d
-	    dsi = NULL;
Panu Matilainen 459c2d
+	if (dsi->bsize == 0) {
Panu Matilainen 459c2d
+	    /* create new entry */
Panu Matilainen 459c2d
+	    dsi = rpmtsCreateDSI(ts, dev, dirName, dsi - ts->dsi);
Panu Matilainen 459c2d
+	}
Panu Matilainen 459c2d
     }
Panu Matilainen 459c2d
     if (dsi == NULL)
Panu Matilainen 459c2d
 	return;
Panu Matilainen 459c2d
@@ -192,26 +226,22 @@ static void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
Panu Matilainen 459c2d
     rpmDiskSpaceInfo dsi;
Panu Matilainen 459c2d
     rpmps ps;
Panu Matilainen 459c2d
     int fc;
Panu Matilainen 459c2d
-    int i;
Panu Matilainen 459c2d
-
Panu Matilainen 459c2d
-    if (ts->filesystems == NULL || ts->filesystemCount <= 0)
Panu Matilainen 459c2d
-	return;
Panu Matilainen 459c2d
 
Panu Matilainen 459c2d
     dsi = ts->dsi;
Panu Matilainen 459c2d
-    if (dsi == NULL)
Panu Matilainen 459c2d
+    if (dsi == NULL || !dsi->bsize)
Panu Matilainen 459c2d
 	return;
Panu Matilainen 459c2d
     fc = rpmfiFC(rpmteFI(te));
Panu Matilainen 459c2d
     if (fc <= 0)
Panu Matilainen 459c2d
 	return;
Panu Matilainen 459c2d
 
Panu Matilainen 459c2d
     ps = rpmtsProblems(ts);
Panu Matilainen 459c2d
-    for (i = 0; i < ts->filesystemCount; i++, dsi++) {
Panu Matilainen 459c2d
+    for (; dsi->bsize; dsi++) {
Panu Matilainen 459c2d
 
Panu Matilainen 459c2d
 	if (dsi->bavail >= 0 && adj_fs_blocks(dsi->bneeded) > dsi->bavail) {
Panu Matilainen 459c2d
 	    if (dsi->bneeded != dsi->obneeded) {
Panu Matilainen 459c2d
 		rpmpsAppend(ps, RPMPROB_DISKSPACE,
Panu Matilainen 459c2d
 			rpmteNEVRA(te), rpmteKey(te),
Panu Matilainen 459c2d
-			ts->filesystems[i], NULL, NULL,
Panu Matilainen 459c2d
+			dsi->mntPoint, NULL, NULL,
Panu Matilainen 459c2d
 		   (adj_fs_blocks(dsi->bneeded) - dsi->bavail) * dsi->bsize);
Panu Matilainen 459c2d
 		dsi->obneeded = dsi->bneeded;
Panu Matilainen 459c2d
 	    }
Panu Matilainen 459c2d
@@ -221,7 +251,7 @@ static void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
Panu Matilainen 459c2d
 	    if (dsi->ineeded != dsi->oineeded) {
Panu Matilainen 459c2d
 		rpmpsAppend(ps, RPMPROB_DISKNODES,
Panu Matilainen 459c2d
 			rpmteNEVRA(te), rpmteKey(te),
Panu Matilainen 459c2d
-			ts->filesystems[i], NULL, NULL,
Panu Matilainen 459c2d
+			dsi->mntPoint, NULL, NULL,
Panu Matilainen 459c2d
 			(adj_fs_blocks(dsi->ineeded) - dsi->iavail));
Panu Matilainen 459c2d
 		dsi->oineeded = dsi->ineeded;
Panu Matilainen 459c2d
 	    }
Panu Matilainen 459c2d
@@ -230,6 +260,20 @@ static void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
Panu Matilainen 459c2d
     ps = rpmpsFree(ps);
Panu Matilainen 459c2d
 }
Panu Matilainen 459c2d
 
Panu Matilainen 459c2d
+static void rpmtsFreeDSI(rpmts ts){
Panu Matilainen 459c2d
+    rpmDiskSpaceInfo dsi;
Panu Matilainen 459c2d
+    if (ts == NULL)
Panu Matilainen 459c2d
+	return;
Panu Matilainen 459c2d
+    dsi = ts->dsi;
Panu Matilainen 459c2d
+    while (dsi && dsi->bsize != 0) {
Panu Matilainen 459c2d
+	dsi->mntPoint = _free(dsi->mntPoint);
Panu Matilainen 459c2d
+	dsi++;
Panu Matilainen 459c2d
+    }
Panu Matilainen 459c2d
+
Panu Matilainen 459c2d
+    ts->dsi = _free(ts->dsi);
Panu Matilainen 459c2d
+}
Panu Matilainen 459c2d
+
Panu Matilainen 459c2d
+
Panu Matilainen 459c2d
 /**
Panu Matilainen 459c2d
  */
Panu Matilainen 459c2d
 static int archOkay(const char * pkgArch)
Panu Matilainen 459c2d
@@ -543,8 +587,9 @@ assert(otherFi != NULL);
Panu Matilainen 459c2d
 	}
Panu Matilainen 459c2d
 
Panu Matilainen 459c2d
 	/* Update disk space info for a file. */
Panu Matilainen 459c2d
-	rpmtsUpdateDSI(ts, fiFps->entry->dev, rpmfiFSize(fi),
Panu Matilainen 459c2d
-		       rpmfiFReplacedSize(fi), fixupSize, rpmfsGetAction(fs, i));
Panu Matilainen 459c2d
+	rpmtsUpdateDSI(ts, fiFps->entry->dev, fiFps->entry->dirName,
Panu Matilainen 459c2d
+		       rpmfiFSize(fi), rpmfiFReplacedSize(fi),
Panu Matilainen 459c2d
+		       fixupSize, rpmfsGetAction(fs, i));
Panu Matilainen 459c2d
 
Panu Matilainen 459c2d
     }
Panu Matilainen 459c2d
     ps = rpmpsFree(ps);
Panu Matilainen 459c2d
@@ -1338,6 +1383,7 @@ static int rpmtsPrepare(rpmts ts)
Panu Matilainen 459c2d
 exit:
Panu Matilainen 459c2d
     ht = rpmFpHashFree(ht);
Panu Matilainen 459c2d
     fpc = fpCacheFree(fpc);
Panu Matilainen 459c2d
+    rpmtsFreeDSI(ts);
Panu Matilainen 459c2d
     return rc;
Panu Matilainen 459c2d
 }
Panu Matilainen 459c2d