void stage_updated_gitmodules(void) { struct strbuf buf = STRBUF_INIT; struct stat st; int pos; struct cache_entry *ce; int namelen = strlen(".gitmodules"); pos = cache_name_pos(".gitmodules", namelen); if (pos < 0) { warning(_("could not find .gitmodules in index")); return; } ce = active_cache[pos]; ce->ce_flags = namelen; if (strbuf_read_file(&buf, ".gitmodules", 0) < 0) die(_("reading updated .gitmodules failed")); if (lstat(".gitmodules", &st) < 0) die_errno(_("unable to stat updated .gitmodules")); fill_stat_cache_info(ce, &st); ce->ce_mode = ce_mode_from_stat(ce, st.st_mode); if (remove_cache_entry_at(pos) < 0) die(_("unable to remove .gitmodules from index")); if (write_sha1_file(buf.buf, buf.len, blob_type, ce->sha1)) die(_("adding updated .gitmodules failed")); if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE)) die(_("staging updated .gitmodules failed")); }
static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st) { int option, size; struct cache_entry *ce; /* Was the old index entry already up-to-date? */ if (old && !ce_stage(old) && !ce_match_stat(old, st, 0)) return 0; size = cache_entry_size(len); ce = xcalloc(1, size); memcpy(ce->name, path, len); ce->ce_flags = create_ce_flags(0); ce->ce_namelen = len; fill_stat_cache_info(ce, st); ce->ce_mode = ce_mode_from_stat(old, st->st_mode); if (index_path(ce->sha1, path, st, info_only ? 0 : HASH_WRITE_OBJECT)) { free(ce); return -1; } option = allow_add ? ADD_CACHE_OK_TO_ADD : 0; option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0; if (add_cache_entry(ce, option)) return error("%s: cannot add to the index - missing --add option?", path); return 0; }
static int checkout_entry (struct cache_entry *ce, struct unpack_trees_options *o, gboolean recover_merge, const char *conflict_suffix) { int base_len = strlen(o->base); int len = ce_namelen(ce); int full_len; char path[PATH_MAX]; int offset; struct stat st; char file_id[41]; if (!len) { g_warning ("entry name should not be empty.\n"); return -1; } snprintf (path, PATH_MAX, "%s/", o->base); /* first create all leading directories. */ full_len = base_len + len + 1; offset = base_len + 1; while (offset < full_len) { do { path[offset] = ce->name[offset-base_len-1]; offset++; } while (offset < full_len && ce->name[offset-base_len-1] != '/'); if (offset >= full_len) break; path[offset] = 0; if (g_lstat (path, &st) == 0 && S_ISDIR(st.st_mode)) continue; if (ccnet_mkdir (path, 0777) < 0) { g_warning ("Failed to create directory %s.\n", path); return -1; } } path[offset] = 0; if (!S_ISDIR(ce->ce_mode)) { /* In case that we're replacing an empty dir with a file, * we need first to remove the empty dir. */ if (g_lstat (path, &st) == 0 && S_ISDIR(st.st_mode)) { if (g_rmdir (path) < 0) { g_warning ("Failed to remove dir %s: %s\n", path, strerror(errno)); /* Don't quit since we can handle conflict later. */ } } } else { /* For simplicity, we just don't checkout the empty dir if there is * already a file with the same name in the worktree. * This implies, you can't remove a file then create an empty directory * with the same name. But it's a rare requirement. */ if (g_mkdir (path, 0777) < 0) { g_warning ("Failed to create empty dir %s.\n", path); } return 0; } if (!o->reset && g_lstat (path, &st) == 0 && S_ISREG(st.st_mode) && (ce->ce_ctime.sec != st.st_ctime || ce->ce_mtime.sec != st.st_mtime)) { /* If we're recovering an interrupted merge, we don't know whether * the file was changed by checkout or by the user. So we have to * calculate the sha1 for that file and compare it with the one in * cache entry. */ if (!recover_merge || compare_file_content (path, &st, ce->sha1, o->crypt) != 0) { g_warning ("File %s is changed. Skip checking out.\n", path); return -1; } /* Recover merge and file content matches index entry. * We were interrupted before updating the index, update index * entry timestamp now. */ goto update_cache; } /* then checkout the file. */ rawdata_to_hex (ce->sha1, file_id, 20); if (seaf_fs_manager_checkout_file (seaf->fs_mgr, file_id, path, ce->ce_mode, o->crypt, conflict_suffix) < 0) { g_warning ("Failed to checkout file %s.\n", path); return -1; } update_cache: /* finally fill cache_entry info */ g_lstat (path, &st); fill_stat_cache_info (ce, &st); return 0; }
static int checkout_entry (struct cache_entry *ce, struct unpack_trees_options *o, gboolean recover_merge, const char *conflict_head_id, GHashTable *conflict_hash, GHashTable *no_conflict_hash) { char *path_in, *path; SeafStat st; char file_id[41]; gboolean case_conflict = FALSE; gboolean force_conflict = FALSE; path_in = g_build_path ("/", o->base, ce->name, NULL); #ifndef __linux__ path = build_case_conflict_free_path (o->base, ce->name, conflict_hash, no_conflict_hash, &case_conflict, FALSE); #else path = build_checkout_path (o->base, ce->name, ce_namelen(ce)); #endif g_free (path_in); if (!path) return -1; if (!S_ISDIR(ce->ce_mode)) { /* In case that we're replacing an empty dir with a file, * we need first to remove the empty dir. */ if (seaf_stat (path, &st) == 0 && S_ISDIR(st.st_mode)) { if (g_rmdir (path) < 0) { g_warning ("Failed to remove dir %s: %s\n", path, strerror(errno)); /* Don't quit since we can handle conflict later. */ } } } else { if (g_mkdir (path, 0777) < 0) { g_warning ("Failed to create empty dir %s in checkout.\n", path); g_free (path); return -1; } if (ce->ce_mtime.sec != 0 && seaf_set_file_time (path, ce->ce_mtime.sec) < 0) { g_warning ("Failed to set mtime for %s.\n", path); } goto update_cache; } if (!o->reset && seaf_stat (path, &st) == 0 && S_ISREG(st.st_mode) && (ce->current_mtime != st.st_mtime)) { /* If we're recovering an interrupted merge, we don't know whether * the file was changed by checkout or by the user. So we have to * calculate the sha1 for that file and compare it with the one in * cache entry. */ if (!recover_merge || compare_file_content (path, &st, ce->sha1, o->crypt, o->version) != 0) { g_warning ("File %s is changed. Checkout to conflict file.\n", path); force_conflict = TRUE; } else { /* Recover merge and file content matches index entry. * We were interrupted before updating the index, update index * entry timestamp now. */ goto update_cache; } } /* then checkout the file. */ gboolean conflicted = FALSE; rawdata_to_hex (ce->sha1, file_id, 20); if (seaf_fs_manager_checkout_file (seaf->fs_mgr, o->repo_id, o->version, file_id, path, ce->ce_mode, ce->ce_mtime.sec, o->crypt, ce->name, conflict_head_id, force_conflict, &conflicted) < 0) { g_warning ("Failed to checkout file %s.\n", path); g_free (path); return -1; } /* If case conflict, this file has been checked out to another path. * Remove the current entry, otherwise it won't be removed later * since it's timestamp is 0. */ if (case_conflict) { ce->ce_flags |= CE_REMOVE; g_free (path); return 0; } if (conflicted) { g_free (path); return 0; } update_cache: /* finally fill cache_entry info */ /* Only update index if we checked out the file without any error * or conflicts. The timestamp of the entry will remain 0 if error * or conflicted. */ seaf_stat (path, &st); fill_stat_cache_info (ce, &st); g_free (path); return 0; }