commit 0aeb8099a04ea427eff4a7b6cb52b1cba62a87b0 from: Stefan Sperling date: Thu Jul 23 14:22:37 2020 UTC set a staged file type and handle it separately from the on-disk file type commit - c631b1152565e4c18cb2123e1d3d7c08d513c02f commit + 0aeb8099a04ea427eff4a7b6cb52b1cba62a87b0 blob - 3132285fde2f86c533ea3117e76a6f577c8fcb05 blob + 55184665f7b445e704a80de758c82371bc3a475b --- lib/fileindex.c +++ lib/fileindex.c @@ -53,8 +53,8 @@ struct got_fileindex { #define GOT_FILEIDX_MAX_ENTRIES INT_MAX }; -static mode_t -fileindex_entry_perms_get(struct got_fileindex_entry *ie) +mode_t +got_fileindex_entry_perms_get(struct got_fileindex_entry *ie) { return ((ie->mode & GOT_FILEIDX_MODE_PERMS) >> GOT_FILEIDX_MODE_PERMS_SHIFT); @@ -71,7 +71,7 @@ fileindex_entry_perms_set(struct got_fileindex_entry * mode_t got_fileindex_perms_to_st(struct got_fileindex_entry *ie) { - mode_t perms = fileindex_entry_perms_get(ie); + mode_t perms = got_fileindex_entry_perms_get(ie); int type = got_fileindex_entry_filetype_get(ie); uint32_t ftype; blob - 8535201970c1361dcc48c9404c68333b0a77b2c5 blob + f10058320f24affa0531641620b65ac3641a9b6f --- lib/got_lib_fileindex.h +++ lib/got_lib_fileindex.h @@ -103,6 +103,7 @@ struct got_fileindex_hdr { uint8_t sha1[SHA1_DIGEST_LENGTH]; /* checksum of above on-disk data */ }; +mode_t got_fileindex_entry_perms_get(struct got_fileindex_entry *); uint16_t got_fileindex_perms_from_st(struct stat *); mode_t got_fileindex_perms_to_st(struct got_fileindex_entry *); blob - bde4162e571552b42ca8aea844c0fb7d81ee59e3 blob + a24230cc8594d13472a3bcf7b8a5fb461cab1138 --- lib/worktree.c +++ lib/worktree.c @@ -4459,6 +4459,7 @@ struct collect_commitables_arg { struct got_pathlist_head *commitable_paths; struct got_repository *repo; struct got_worktree *worktree; + struct got_fileindex *fileindex; int have_staged_files; }; @@ -4516,9 +4517,27 @@ collect_commitables(void *arg, unsigned char status, err = got_error_from_errno("asprintf"); goto done; } - if (status == GOT_STATUS_DELETE || staged_status == GOT_STATUS_DELETE) { - sb.st_mode = GOT_DEFAULT_FILE_MODE; - } else { + + if (staged_status == GOT_STATUS_ADD || + staged_status == GOT_STATUS_MODIFY) { + struct got_fileindex_entry *ie; + ie = got_fileindex_entry_get(a->fileindex, path, strlen(path)); + switch (got_fileindex_entry_staged_filetype_get(ie)) { + case GOT_FILEIDX_MODE_REGULAR_FILE: + case GOT_FILEIDX_MODE_BAD_SYMLINK: + ct->mode = S_IFREG; + break; + case GOT_FILEIDX_MODE_SYMLINK: + ct->mode = S_IFLNK; + break; + default: + fprintf(stderr, "got: ie mode is 0x%x\n", ie->mode); + err = got_error_path(path, GOT_ERR_BAD_FILETYPE); + goto done; + } + ct->mode |= got_fileindex_entry_perms_get(ie); + } else if (status != GOT_STATUS_DELETE && + staged_status != GOT_STATUS_DELETE) { if (dirfd != -1) { if (fstatat(dirfd, de_name, &sb, AT_SYMLINK_NOFOLLOW) == -1) { @@ -5026,7 +5045,7 @@ done: static const struct got_error * reinstall_symlink_after_commit(int *is_bad_symlink, struct got_commitable *ct, struct got_object_id *new_base_commit_id, struct got_worktree *worktree, - struct got_repository *repo) + struct got_fileindex_entry *ie, struct got_repository *repo) { const struct got_error *err = NULL; struct got_blob_object *blob = NULL; @@ -5035,6 +5054,15 @@ reinstall_symlink_after_commit(int *is_bad_symlink, st struct got_tree_object *tree = NULL; struct got_tree_entry *te; char *entry_name; + unsigned char status; + struct stat sb; + + err = get_file_status(&status, &sb, ie, ct->ondisk_path, + -1, NULL, repo); + if (err) + return err; + if (status != GOT_STATUS_NO_CHANGE) + return NULL; if (ct->staged_status == GOT_STATUS_ADD || ct->staged_status == GOT_STATUS_MODIFY) { @@ -5117,12 +5145,16 @@ reinstall_symlinks_after_commit(struct got_pathlist_he ct->status == GOT_STATUS_DELETE) continue; + ie = got_fileindex_entry_get(fileindex, ct->path, + strlen(ct->path)); + if (ie == NULL) { + err = got_error_path(ct->path, GOT_ERR_BAD_PATH); + break; + } err = reinstall_symlink_after_commit(&is_bad_symlink, - ct, new_base_commit_id, worktree, repo); + ct, new_base_commit_id, worktree, ie, repo); if (err) break; - ie = got_fileindex_entry_get(fileindex, ct->path, - strlen(ct->path)); if (ie && is_bad_symlink) { got_fileindex_entry_filetype_set(ie, GOT_FILEIDX_MODE_BAD_SYMLINK); @@ -5467,6 +5499,7 @@ got_worktree_commit(struct got_object_id **new_commit_ cc_arg.commitable_paths = &commitable_paths; cc_arg.worktree = worktree; + cc_arg.fileindex = fileindex; cc_arg.repo = repo; cc_arg.have_staged_files = have_staged_files; TAILQ_FOREACH(pe, paths, entry) { @@ -7020,6 +7053,7 @@ stage_path(void *arg, unsigned char status, char *ondisk_path = NULL, *path_content = NULL; uint32_t stage; struct got_object_id *new_staged_blob_id = NULL; + struct stat sb; if (status == GOT_STATUS_UNVERSIONED) return NULL; @@ -7035,6 +7069,11 @@ stage_path(void *arg, unsigned char status, switch (status) { case GOT_STATUS_ADD: case GOT_STATUS_MODIFY: + /* XXX could sb.st_mode be passed in by our caller? */ + if (lstat(ondisk_path, &sb) == -1) { + err = got_error_from_errno2("lstat", ondisk_path); + break; + } if (a->patch_cb) { if (status == GOT_STATUS_ADD) { int choice = GOT_PATCH_CHOICE_NONE; @@ -7064,6 +7103,13 @@ stage_path(void *arg, unsigned char status, else stage = GOT_FILEIDX_STAGE_MODIFY; got_fileindex_entry_stage_set(ie, stage); + if (S_ISLNK(sb.st_mode)) { + got_fileindex_entry_staged_filetype_set(ie, + GOT_FILEIDX_MODE_SYMLINK); + } else { + got_fileindex_entry_staged_filetype_set(ie, + GOT_FILEIDX_MODE_REGULAR_FILE); + } a->staged_something = 1; if (a->status_cb == NULL) break; blob - 199eaf6bbf1859c535e340a5c5f30777378ba090 blob + cf4a6d0c34ede0224a4b154ee7f65844ddf9f51a --- regress/cmdline/stage.sh +++ regress/cmdline/stage.sh @@ -2401,6 +2401,9 @@ EOF test_done "$testroot" "$ret" return 1 fi + + rm $testroot/wt/alpha.link + echo 'this is regular file alpha.link' > $testroot/wt/alpha.link (cd $testroot/wt && got diff -s > $testroot/stdout) @@ -2542,18 +2545,18 @@ EOF return 1 fi - if ! [ -h $testroot/wt/alpha.link ]; then - echo "alpha.link is not a symlink" + if [ -h $testroot/wt/alpha.link ]; then + echo "alpha.link is a symlink" test_done "$testroot" "1" return 1 fi - readlink $testroot/wt/alpha.link > $testroot/stdout - echo "beta" > $testroot/stdout.expected - cmp -s $testroot/stdout.expected $testroot/stdout + echo 'this is regular file alpha.link' > $testroot/content.expected + cp $testroot/wt/alpha.link $testroot/content + cmp -s $testroot/content.expected $testroot/content ret="$?" if [ "$ret" != "0" ]; then - diff -u $testroot/stdout.expected $testroot/stdout + diff -u $testroot/content.expected $testroot/content test_done "$testroot" "$ret" return 1 fi @@ -2563,7 +2566,7 @@ EOF test_done "$testroot" "1" return 1 fi - echo -n ".got/bar" >> $testroot/content.expected + echo -n ".got/bar" > $testroot/content.expected cp $testroot/wt/dotgotbar.link $testroot/content cmp -s $testroot/content.expected $testroot/content ret="$?"