@@ -828,8 +828,9 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo)
828828 case 'F' :
829829 if (diri ) apk_db_dir_apply_diri_permissions (diri );
830830 if (pkg -> name == NULL ) goto bad_entry ;
831- diri = apk_db_diri_new (db , pkg , l , & diri_node );
832- file_diri_node = & diri -> owned_files .first ;
831+ diri = find_diri (ipkg , l , NULL , & diri_node );
832+ if (!diri ) diri = apk_db_diri_new (db , pkg , l , & diri_node );
833+ file_diri_node = hlist_tail_ptr (& diri -> owned_files );
833834 break ;
834835 case 'a' :
835836 if (file == NULL ) goto bad_entry ;
@@ -2358,6 +2359,31 @@ static struct apk_db_dir_instance *apk_db_install_directory_entry(struct install
23582359 return diri ;
23592360}
23602361
2362+ #define TMPNAME_MAX (PATH_MAX + 64)
2363+
2364+ static const char * format_tmpname (struct apk_package * pkg , struct apk_db_file * f , char tmpname [static TMPNAME_MAX ])
2365+ {
2366+ EVP_MD_CTX mdctx ;
2367+ unsigned char md [EVP_MAX_MD_SIZE ];
2368+ apk_blob_t b = APK_BLOB_PTR_LEN (tmpname , TMPNAME_MAX );
2369+
2370+ if (!f ) return NULL ;
2371+
2372+ EVP_DigestInit (& mdctx , EVP_sha256 ());
2373+ EVP_DigestUpdate (& mdctx , pkg -> name -> name , strlen (pkg -> name -> name ) + 1 );
2374+ EVP_DigestUpdate (& mdctx , f -> diri -> dir -> name , f -> diri -> dir -> namelen );
2375+ EVP_DigestUpdate (& mdctx , "/" , 1 );
2376+ EVP_DigestUpdate (& mdctx , f -> name , f -> namelen );
2377+ EVP_DigestFinal (& mdctx , md , NULL );
2378+
2379+ apk_blob_push_blob (& b , APK_BLOB_PTR_LEN (f -> diri -> dir -> name , f -> diri -> dir -> namelen ));
2380+ apk_blob_push_blob (& b , APK_BLOB_STR ("/.apk." ));
2381+ apk_blob_push_hexdump (& b , APK_BLOB_PTR_LEN ((char * )md , 24 ));
2382+ apk_blob_push_blob (& b , APK_BLOB_PTR_LEN ("" , 1 ));
2383+
2384+ return tmpname ;
2385+ }
2386+
23612387static int apk_db_install_archive_entry (void * _ctx ,
23622388 const struct apk_file_info * ae ,
23632389 struct apk_istream * is )
@@ -2369,8 +2395,9 @@ static int apk_db_install_archive_entry(void *_ctx,
23692395 struct apk_installed_package * ipkg = pkg -> ipkg ;
23702396 apk_blob_t name = APK_BLOB_STR (ae -> name ), bdir , bfile ;
23712397 struct apk_db_dir_instance * diri = ctx -> diri ;
2372- struct apk_db_file * file ;
2398+ struct apk_db_file * file , * link_target_file = NULL ;
23732399 int ret = 0 , r , type = APK_SCRIPT_INVALID ;
2400+ char tmpname_file [TMPNAME_MAX ], tmpname_link_target [TMPNAME_MAX ];
23742401
23752402 r = apk_sign_ctx_process_file (& ctx -> sctx , ae , is );
23762403 if (r <= 0 )
@@ -2437,6 +2464,40 @@ static int apk_db_install_archive_entry(void *_ctx,
24372464 diri = apk_db_install_directory_entry (ctx , bdir );
24382465 }
24392466
2467+ /* Check hard link target to exist in this package */
2468+ if (S_ISREG (ae -> mode ) && ae -> link_target ) {
2469+ do {
2470+ struct apk_db_file * lfile ;
2471+ struct apk_db_dir_instance * ldiri ;
2472+ struct hlist_node * n ;
2473+ apk_blob_t hldir , hlfile ;
2474+
2475+ if (!apk_blob_rsplit (APK_BLOB_STR (ae -> link_target ),
2476+ '/' , & hldir , & hlfile ))
2477+ break ;
2478+
2479+ ldiri = find_diri (ipkg , hldir , diri , NULL );
2480+ if (ldiri == NULL )
2481+ break ;
2482+
2483+ hlist_for_each_entry (lfile , n , & ldiri -> owned_files ,
2484+ diri_files_list ) {
2485+ if (apk_blob_compare (APK_BLOB_PTR_LEN (lfile -> name , lfile -> namelen ),
2486+ hlfile ) == 0 ) {
2487+ link_target_file = lfile ;
2488+ break ;
2489+ }
2490+ }
2491+ } while (0 );
2492+
2493+ if (!link_target_file ) {
2494+ apk_error (PKG_VER_FMT ": " BLOB_FMT ": no hard link target (%s) in archive" ,
2495+ PKG_VER_PRINTF (pkg ), BLOB_PRINTF (name ), ae -> link_target );
2496+ ipkg -> broken_files = 1 ;
2497+ return 0 ;
2498+ }
2499+ }
2500+
24402501 opkg = NULL ;
24412502 file = apk_db_file_query (db , bdir , bfile );
24422503 if (file != NULL ) {
@@ -2495,41 +2556,21 @@ static int apk_db_install_archive_entry(void *_ctx,
24952556 if (apk_verbosity >= 3 )
24962557 apk_message ("%s" , ae -> name );
24972558
2498- /* Extract the file as name.apk-new */
2559+ /* Extract the file with temporary name */
24992560 file -> acl = apk_db_acl_atomize (ae -> mode , ae -> uid , ae -> gid , & ae -> xattr_csum );
2500- r = apk_archive_entry_extract (db -> root_fd , ae , ".apk-new" , is ,
2501- extract_cb , ctx );
2561+ r = apk_archive_entry_extract (
2562+ db -> root_fd , ae ,
2563+ format_tmpname (pkg , file , tmpname_file ),
2564+ format_tmpname (pkg , link_target_file , tmpname_link_target ),
2565+ is , extract_cb , ctx );
25022566
25032567 switch (r ) {
25042568 case 0 :
25052569 /* Hardlinks need special care for checksum */
2506- if (ae -> csum .type == APK_CHECKSUM_NONE &&
2507- ae -> link_target != NULL ) {
2508- do {
2509- struct apk_db_file * lfile ;
2510- struct apk_db_dir_instance * ldiri ;
2511- struct hlist_node * n ;
2512-
2513- if (!apk_blob_rsplit (APK_BLOB_STR (ae -> link_target ),
2514- '/' , & bdir , & bfile ))
2515- break ;
2516-
2517- ldiri = find_diri (ipkg , bdir , diri , NULL );
2518- if (ldiri == NULL )
2519- break ;
2520-
2521- hlist_for_each_entry (lfile , n , & ldiri -> owned_files ,
2522- diri_files_list ) {
2523- if (apk_blob_compare (APK_BLOB_PTR_LEN (lfile -> name , lfile -> namelen ),
2524- bfile ) == 0 ) {
2525- memcpy (& file -> csum , & lfile -> csum ,
2526- sizeof (file -> csum ));
2527- break ;
2528- }
2529- }
2530- } while (0 );
2531- } else
2532- memcpy (& file -> csum , & ae -> csum , sizeof (file -> csum ));
2570+ if (link_target_file )
2571+ memcpy (& file -> csum , & link_target_file -> csum , sizeof file -> csum );
2572+ else
2573+ memcpy (& file -> csum , & ae -> csum , sizeof file -> csum );
25332574 break ;
25342575 case - ENOTSUP :
25352576 ipkg -> broken_xattr = 1 ;
@@ -2547,8 +2588,11 @@ static int apk_db_install_archive_entry(void *_ctx,
25472588 if (name .ptr [name .len - 1 ] == '/' )
25482589 name .len -- ;
25492590
2550- diri = apk_db_install_directory_entry (ctx , name );
2551- apk_db_dir_prepare (db , diri -> dir , ae -> mode );
2591+ diri = ctx -> diri = find_diri (ipkg , name , NULL , & ctx -> file_diri_node );
2592+ if (!diri ) {
2593+ diri = apk_db_install_directory_entry (ctx , name );
2594+ apk_db_dir_prepare (db , diri -> dir , ae -> mode );
2595+ }
25522596 apk_db_diri_set (diri , apk_db_acl_atomize (ae -> mode , ae -> uid , ae -> gid , & ae -> xattr_csum ));
25532597 }
25542598 ctx -> installed_size += ctx -> current_file_size ;
@@ -2558,25 +2602,24 @@ static int apk_db_install_archive_entry(void *_ctx,
25582602
25592603static void apk_db_purge_pkg (struct apk_database * db ,
25602604 struct apk_installed_package * ipkg ,
2561- const char * exten )
2605+ int is_installed )
25622606{
25632607 struct apk_db_dir_instance * diri ;
25642608 struct apk_db_file * file ;
25652609 struct apk_db_file_hash_key key ;
25662610 struct apk_file_info fi ;
25672611 struct hlist_node * dc , * dn , * fc , * fn ;
25682612 unsigned long hash ;
2569- char name [PATH_MAX ];
2613+ char name [TMPNAME_MAX ];
25702614
25712615 hlist_for_each_entry_safe (diri , dc , dn , & ipkg -> owned_dirs , pkg_dirs_list ) {
2572- if (exten == NULL )
2573- diri -> dir -> modified = 1 ;
2616+ if (is_installed ) diri -> dir -> modified = 1 ;
25742617
25752618 hlist_for_each_entry_safe (file , fc , fn , & diri -> owned_files , diri_files_list ) {
2576- snprintf ( name , sizeof ( name ),
2577- DIR_FILE_FMT "%s" ,
2578- DIR_FILE_PRINTF ( diri -> dir , file ),
2579- exten ?: "" );
2619+ if ( is_installed )
2620+ snprintf ( name , sizeof name , DIR_FILE_FMT , DIR_FILE_PRINTF ( diri -> dir , file ));
2621+ else
2622+ format_tmpname ( ipkg -> pkg , file , name );
25802623
25812624 key = (struct apk_db_file_hash_key ) {
25822625 .dirname = APK_BLOB_PTR_LEN (diri -> dir -> name , diri -> dir -> namelen ),
@@ -2592,7 +2635,7 @@ static void apk_db_purge_pkg(struct apk_database *db,
25922635 if (apk_verbosity >= 3 )
25932636 apk_message ("%s" , name );
25942637 __hlist_del (fc , & diri -> owned_files .first );
2595- if (exten == NULL ) {
2638+ if (is_installed ) {
25962639 apk_hash_delete_hashed (& db -> installed .files , APK_BLOB_BUF (& key ), hash );
25972640 db -> installed .stats .files -- ;
25982641 }
@@ -2613,18 +2656,16 @@ static void apk_db_migrate_files(struct apk_database *db,
26132656 struct apk_file_info fi ;
26142657 struct hlist_node * dc , * dn , * fc , * fn ;
26152658 unsigned long hash ;
2616- char name [PATH_MAX ], tmpname [PATH_MAX ];
2659+ char name [PATH_MAX ], tmpname [TMPNAME_MAX ];
26172660 int cstype , r ;
26182661
26192662 hlist_for_each_entry_safe (diri , dc , dn , & ipkg -> owned_dirs , pkg_dirs_list ) {
26202663 dir = diri -> dir ;
26212664 dir -> modified = 1 ;
26222665
26232666 hlist_for_each_entry_safe (file , fc , fn , & diri -> owned_files , diri_files_list ) {
2624- snprintf (name , sizeof (name ), DIR_FILE_FMT ,
2625- DIR_FILE_PRINTF (diri -> dir , file ));
2626- snprintf (tmpname , sizeof (tmpname ), DIR_FILE_FMT ".apk-new" ,
2627- DIR_FILE_PRINTF (diri -> dir , file ));
2667+ snprintf (name , sizeof (name ), DIR_FILE_FMT , DIR_FILE_PRINTF (diri -> dir , file ));
2668+ format_tmpname (ipkg -> pkg , file , tmpname );
26282669
26292670 key = (struct apk_db_file_hash_key ) {
26302671 .dirname = APK_BLOB_PTR_LEN (dir -> name , dir -> namelen ),
@@ -2665,8 +2706,21 @@ static void apk_db_migrate_files(struct apk_database *db,
26652706 APK_FI_NOFOLLOW | file -> csum .type , & fi );
26662707 if ((apk_flags & APK_CLEAN_PROTECTED ) ||
26672708 (file -> csum .type != APK_CHECKSUM_NONE &&
2668- apk_checksum_compare (& file -> csum , & fi .csum ) == 0 ))
2709+ apk_checksum_compare (& file -> csum , & fi .csum ) == 0 )) {
26692710 unlinkat (db -> root_fd , tmpname , 0 );
2711+ } else {
2712+ snprintf (name , sizeof name ,
2713+ DIR_FILE_FMT ".apk-new" ,
2714+ DIR_FILE_PRINTF (diri -> dir , file ));
2715+ if (renameat (db -> root_fd , tmpname ,
2716+ db -> root_fd , name ) != 0 ) {
2717+ apk_error (PKG_VER_FMT ": failed to rename %s to %s." ,
2718+ PKG_VER_PRINTF (ipkg -> pkg ),
2719+ tmpname , name );
2720+ ipkg -> broken_files = 1 ;
2721+ }
2722+ }
2723+
26702724 } else {
26712725 /* Overwrite the old file */
26722726 if (renameat (db -> root_fd , tmpname ,
@@ -2799,7 +2853,7 @@ int apk_db_install_pkg(struct apk_database *db, struct apk_package *oldpkg,
27992853 if (ipkg == NULL )
28002854 goto ret_r ;
28012855 apk_ipkg_run_script (ipkg , db , APK_SCRIPT_PRE_DEINSTALL , script_args );
2802- apk_db_purge_pkg (db , ipkg , NULL );
2856+ apk_db_purge_pkg (db , ipkg , TRUE );
28032857 apk_ipkg_run_script (ipkg , db , APK_SCRIPT_POST_DEINSTALL , script_args );
28042858 apk_pkg_uninstall (db , oldpkg );
28052859 goto ret_r ;
@@ -2822,15 +2876,15 @@ int apk_db_install_pkg(struct apk_database *db, struct apk_package *oldpkg,
28222876 cb , cb_ctx , script_args );
28232877 if (r != 0 ) {
28242878 if (oldpkg != newpkg )
2825- apk_db_purge_pkg (db , ipkg , ".apk-new" );
2879+ apk_db_purge_pkg (db , ipkg , FALSE );
28262880 apk_pkg_uninstall (db , newpkg );
28272881 goto ret_r ;
28282882 }
28292883 apk_db_migrate_files (db , ipkg );
28302884 }
28312885
28322886 if (oldpkg != NULL && oldpkg != newpkg && oldpkg -> ipkg != NULL ) {
2833- apk_db_purge_pkg (db , oldpkg -> ipkg , NULL );
2887+ apk_db_purge_pkg (db , oldpkg -> ipkg , TRUE );
28342888 apk_pkg_uninstall (db , oldpkg );
28352889 }
28362890
0 commit comments