Ok how about this (see the attached code snippet). _alpm_add_commit() is a BIG function, the code attached only shows the for loop for extracting the files and I've cut out the code for checking backups(). I've used the behaviour for dpkg as a bases for what we should do... * Install non-dir Install symlink Install dir * Exists not X X X * File/node/symlink LXR LXR BXR * Directory BXR - - * * X: extract file/node/link/directory * LX: atomic overwrite leaving backup * B: ordinary backup * R: later remove from other packages' lists * -: do nothing Before I try splicing this into _alpm_add_commit() does this look right? Does it cover all the bases? Andrew int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db) { // ... starting @ lib/libalpm/add.c:443 for (i = 0; archive_read_next_header(archive &entry) == ARCHIVE_OK; i++) { const char *entryname = archive_entry_pathname(entry); char filename[PATH_MAX]; int needbackup = 0; mode_t entry_type = archive_entry_filetype(entry); struct stat buf; memset(filename, 0, PATH_MAX); /* just to be sure */ if(strcmp(entryname, ".INSTALL") == 0) { /* The install script goes inside the db. */ sprintf(filename, PATH_MAX, "%s/%s-%s/install", db->path, newpkg->name, newpkg->version); } else if(strcmp(entryname, ".CHANGELOG") == 0) { /* The changelog goes inside the db. */ sprintf(filename, PATH_MAX, "%s/%s-%s/changelog", db->path, newpkg->name, newpkg->version); } else if(*entryname == '.') { /* Ignore all other files in the root directory starting with '.' * that haven't already been handled (for future posibilities). */ archive_read_data_skip(archive); continue; } else if(alpm_list_find_str(handle->noextract, entryname)) { /* If a file is in NoExtract then we never extract it. */ _alpm_log(PM_LOG_DEBUG, _("%s is in NoExtract, skipping extraction"), entryname); alpm_logaction(_("%s is in NoExtract, skipping extraction"), entryname); archive_read_data_skip(archive); continue; } else if(alpm_list_find_str(trans->skip_add, entryname)) { /* If a file is in the add skiplist we never extract it. */ _alpm_log(PM_LOG_DEBUG, _("%s is in trans->skip_add, skipping extraction"), entryname); archive_read_data_skip(archive); continue; } else { sprintf(filename, PATH_MAX, "%s%s", handle->root, entryname ); if(stat(filename, &buf) == 0) { if((S_ISDIR(entry_type) || S_ISLNK(entry_type)) && S_ISDIR(buf.st_mode)) { /* Directories and symlinks are not extracted if a directory exists * on the filesystem with the same name. */ archive_read_data_skip(archive); continue; } else if(S_ISREG(buf.st_mode)) { /* If the file already exists on the filesystem check if we need to * do a backup. */ needbackup = ...; if(needbackup) { // Do compare and backup.... } } } } unlink(filename); archive_entry_set_pathname(entry, filename); int ret = archive_read_extract(archive, entry, archive_flags | ARCHIVE_EXTRACT_NO_OVERWRITE); if(ret == ARCHIVE_WARN) { /* operation succeeded but a non-critical error was encountered */ _alpm_log(PM_LOG_DEBUG, _("warning extracting %s (%s)"), entryname, archive_error_string(archive)); } else if(ret != ARCHIVE_OK) { _alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)"), entryname, archive_error_string(archive)); alpm_logaction(_("could not extract %s (%s)"), entryname, archive_error_string(archive)); errors++; continue; } // update backup checksums } /* for archive_read_next_header(archive, &entry) == ARCHIVE_OK */ archive_read_finish(archive); // ... ending @ lib/libalpm/add.c:762 } // vim:set ts=2 sw=2 noet: