Print this page
5166 sendmail package should be replaceable


  43 #
  44 # Dictionary used to map action names to output format.  Each entry is
  45 # indexed by action name, and consists of a list of tuples that map
  46 # FileInfo class members to output labels.
  47 #
  48 OUTPUTMAP = {
  49     "dir": [
  50         ("group", "group="),
  51         ("mode", "mode="),
  52         ("owner", "owner="),
  53         ("path", "path=")
  54     ],
  55     "file": [
  56         ("hash", ""),
  57         ("group", "group="),
  58         ("mode", "mode="),
  59         ("owner", "owner="),
  60         ("path", "path=")
  61     ],
  62     "link": [

  63         ("path", "path="),
  64         ("target", "target=")
  65     ],
  66     "hardlink": [
  67         ("path", "path="),
  68         ("hardkey", "target=")
  69     ],
  70 }
  71 
  72 # Mode checks used to validate safe file and directory permissions
  73 ALLMODECHECKS = frozenset(("m", "w", "s", "o"))
  74 DEFAULTMODECHECKS = frozenset(("m", "w", "o"))
  75 
  76 class FileInfo(object):
  77     """Base class to represent a file.
  78 
  79     Subclassed according to whether the file represents an actual filesystem
  80     object (RealFileInfo) or an IPS manifest action (ActionInfo).
  81     """
  82 


 179         #
 180         # Because the manifest may legitimately translate a relative
 181         # path from the proto area into a different path on the installed
 182         # system, we don't compare paths here.  We only expect this comparison
 183         # to be invoked on items with identical relative paths in
 184         # first place.
 185         #
 186 
 187         #
 188         # All comparisons depend on type.  For symlink and directory, they
 189         # must be the same.  For file and hardlink, see below.
 190         #
 191         typelhs = lhs.name()
 192         typerhs = rhs.name()
 193         if typelhs in ("link", "dir"):
 194             if typelhs != typerhs:
 195                 return True
 196 
 197         #
 198         # For symlinks, all that's left is the link target.

 199         #
 200         if typelhs == "link":
 201             return lhs.target != rhs.target
 202 
 203         #
 204         # For a directory, it's important that both be directories,
 205         # the modes be identical, and the paths are identical.  We already
 206         # checked all but the modes above.
 207         #
 208         # If both objects are files, then we're in the same boat.
 209         #
 210         if typelhs == "dir" or (typelhs == "file" and typerhs == "file"):
 211             return lhs.mode != rhs.mode
 212 
 213         #
 214         # For files or hardlinks:
 215         #
 216         # Since the key space is different (inodes for real files and
 217         # actual link targets for hard links), and since the proto area will
 218         # identify all N occurrences as hardlinks, but the manifests as one
 219         # file and N-1 hardlinks, we have to compare files to hardlinks.
 220         #
 221 


 289 
 290     def __init__(self, action):
 291         FileInfo.__init__(self)
 292         #
 293         # Currently, all actions that we support have a "path"
 294         # attribute.  If that changes, then we'll need to
 295         # catch a KeyError from this assignment.
 296         #
 297         self.path = action.attrs["path"]
 298 
 299         if action.name == "file":
 300             self.owner = action.attrs["owner"]
 301             self.group = action.attrs["group"]
 302             self.mode = action.attrs["mode"]
 303             self.hash = action.hash
 304             if "preserve" in action.attrs:
 305                 self.editable = True
 306         elif action.name == "link":
 307             target = action.attrs["target"]
 308             self.target = os.path.normpath(target)




 309         elif action.name == "dir":
 310             self.owner = action.attrs["owner"]
 311             self.group = action.attrs["group"]
 312             self.mode = action.attrs["mode"]
 313             self.isdir = True
 314         elif action.name == "hardlink":
 315             target = os.path.normpath(action.get_target_path())
 316             self.hardkey = target
 317             self.hardpaths.add(target)
 318 
 319     @staticmethod
 320     def supported(action):
 321         """Indicates whether the specified IPS action time is
 322         correctly handled by the ActionInfo constructor.
 323         """
 324         return action in frozenset(("file", "dir", "link", "hardlink"))
 325 
 326 
 327 class UnsupportedFileFormatError(Exception):
 328     """This means that the stat.S_IFMT returned something we don't


 349     is no way to determine which of the hard links should be
 350     delivered as a file, and which as hardlinks.
 351     """
 352 
 353     def __init__(self, root=None, path=None):
 354         FileInfo.__init__(self)
 355         self.path = path
 356         path = os.path.join(root, path)
 357         lstat = os.lstat(path)
 358         mode = lstat.st_mode
 359 
 360         #
 361         # Per stat.py, these cases are mutually exclusive.
 362         #
 363         if stat.S_ISREG(mode):
 364             self.hash = self.path
 365         elif stat.S_ISDIR(mode):
 366             self.isdir = True
 367         elif stat.S_ISLNK(mode):
 368             self.target = os.path.normpath(os.readlink(path))

 369         else:
 370             raise UnsupportedFileFormatError(path, mode)
 371 
 372         if not stat.S_ISLNK(mode):
 373             self.mode = "%04o" % stat.S_IMODE(mode)
 374             #
 375             # Instead of reading the group and owner from the proto area after
 376             # a non-root build, just drop in dummy values.  Since we don't
 377             # compare them anywhere, this should allow at least marginally
 378             # useful comparisons of protolist-style output.
 379             #
 380             self.owner = "owner"
 381             self.group = "group"
 382 
 383         #
 384         # refcount > 1 indicates a hard link
 385         #
 386         if lstat.st_nlink > 1:
 387             #
 388             # This could get ugly if multiple proto areas reside




  43 #
  44 # Dictionary used to map action names to output format.  Each entry is
  45 # indexed by action name, and consists of a list of tuples that map
  46 # FileInfo class members to output labels.
  47 #
  48 OUTPUTMAP = {
  49     "dir": [
  50         ("group", "group="),
  51         ("mode", "mode="),
  52         ("owner", "owner="),
  53         ("path", "path=")
  54     ],
  55     "file": [
  56         ("hash", ""),
  57         ("group", "group="),
  58         ("mode", "mode="),
  59         ("owner", "owner="),
  60         ("path", "path=")
  61     ],
  62     "link": [
  63         ("mediator", "mediator="),
  64         ("path", "path="),
  65         ("target", "target=")
  66     ],
  67     "hardlink": [
  68         ("path", "path="),
  69         ("hardkey", "target=")
  70     ],
  71 }
  72 
  73 # Mode checks used to validate safe file and directory permissions
  74 ALLMODECHECKS = frozenset(("m", "w", "s", "o"))
  75 DEFAULTMODECHECKS = frozenset(("m", "w", "o"))
  76 
  77 class FileInfo(object):
  78     """Base class to represent a file.
  79 
  80     Subclassed according to whether the file represents an actual filesystem
  81     object (RealFileInfo) or an IPS manifest action (ActionInfo).
  82     """
  83 


 180         #
 181         # Because the manifest may legitimately translate a relative
 182         # path from the proto area into a different path on the installed
 183         # system, we don't compare paths here.  We only expect this comparison
 184         # to be invoked on items with identical relative paths in
 185         # first place.
 186         #
 187 
 188         #
 189         # All comparisons depend on type.  For symlink and directory, they
 190         # must be the same.  For file and hardlink, see below.
 191         #
 192         typelhs = lhs.name()
 193         typerhs = rhs.name()
 194         if typelhs in ("link", "dir"):
 195             if typelhs != typerhs:
 196                 return True
 197 
 198         #
 199         # For symlinks, all that's left is the link target.
 200         # For mediated symlinks targets can differ.
 201         #
 202         if typelhs == "link":
 203             return (lhs.mediator is None) and (lhs.target != rhs.target)
 204 
 205         #
 206         # For a directory, it's important that both be directories,
 207         # the modes be identical, and the paths are identical.  We already
 208         # checked all but the modes above.
 209         #
 210         # If both objects are files, then we're in the same boat.
 211         #
 212         if typelhs == "dir" or (typelhs == "file" and typerhs == "file"):
 213             return lhs.mode != rhs.mode
 214 
 215         #
 216         # For files or hardlinks:
 217         #
 218         # Since the key space is different (inodes for real files and
 219         # actual link targets for hard links), and since the proto area will
 220         # identify all N occurrences as hardlinks, but the manifests as one
 221         # file and N-1 hardlinks, we have to compare files to hardlinks.
 222         #
 223 


 291 
 292     def __init__(self, action):
 293         FileInfo.__init__(self)
 294         #
 295         # Currently, all actions that we support have a "path"
 296         # attribute.  If that changes, then we'll need to
 297         # catch a KeyError from this assignment.
 298         #
 299         self.path = action.attrs["path"]
 300 
 301         if action.name == "file":
 302             self.owner = action.attrs["owner"]
 303             self.group = action.attrs["group"]
 304             self.mode = action.attrs["mode"]
 305             self.hash = action.hash
 306             if "preserve" in action.attrs:
 307                 self.editable = True
 308         elif action.name == "link":
 309             target = action.attrs["target"]
 310             self.target = os.path.normpath(target)
 311             if "mediator" in action.attrs:
 312                 self.mediator = action.attrs["mediator"]
 313             else:
 314                 self.mediator = None
 315         elif action.name == "dir":
 316             self.owner = action.attrs["owner"]
 317             self.group = action.attrs["group"]
 318             self.mode = action.attrs["mode"]
 319             self.isdir = True
 320         elif action.name == "hardlink":
 321             target = os.path.normpath(action.get_target_path())
 322             self.hardkey = target
 323             self.hardpaths.add(target)
 324 
 325     @staticmethod
 326     def supported(action):
 327         """Indicates whether the specified IPS action time is
 328         correctly handled by the ActionInfo constructor.
 329         """
 330         return action in frozenset(("file", "dir", "link", "hardlink"))
 331 
 332 
 333 class UnsupportedFileFormatError(Exception):
 334     """This means that the stat.S_IFMT returned something we don't


 355     is no way to determine which of the hard links should be
 356     delivered as a file, and which as hardlinks.
 357     """
 358 
 359     def __init__(self, root=None, path=None):
 360         FileInfo.__init__(self)
 361         self.path = path
 362         path = os.path.join(root, path)
 363         lstat = os.lstat(path)
 364         mode = lstat.st_mode
 365 
 366         #
 367         # Per stat.py, these cases are mutually exclusive.
 368         #
 369         if stat.S_ISREG(mode):
 370             self.hash = self.path
 371         elif stat.S_ISDIR(mode):
 372             self.isdir = True
 373         elif stat.S_ISLNK(mode):
 374             self.target = os.path.normpath(os.readlink(path))
 375             self.mediator = None
 376         else:
 377             raise UnsupportedFileFormatError(path, mode)
 378 
 379         if not stat.S_ISLNK(mode):
 380             self.mode = "%04o" % stat.S_IMODE(mode)
 381             #
 382             # Instead of reading the group and owner from the proto area after
 383             # a non-root build, just drop in dummy values.  Since we don't
 384             # compare them anywhere, this should allow at least marginally
 385             # useful comparisons of protolist-style output.
 386             #
 387             self.owner = "owner"
 388             self.group = "group"
 389 
 390         #
 391         # refcount > 1 indicates a hard link
 392         #
 393         if lstat.st_nlink > 1:
 394             #
 395             # This could get ugly if multiple proto areas reside