66
77static struct lock_file credential_lock ;
88
9- static void parse_credential_file (const char * fn ,
9+ static int parse_credential_file (const char * fn ,
1010 struct credential * c ,
1111 void (* match_cb )(struct credential * ),
1212 void (* other_cb )(struct strbuf * ))
1313{
1414 FILE * fh ;
1515 struct strbuf line = STRBUF_INIT ;
1616 struct credential entry = CREDENTIAL_INIT ;
17+ int found_credential = 0 ;
1718
1819 fh = fopen (fn , "r" );
1920 if (!fh ) {
20- if (errno != ENOENT )
21+ if (errno != ENOENT && errno != EACCES )
2122 die_errno ("unable to open %s" , fn );
22- return ;
23+ return found_credential ;
2324 }
2425
2526 while (strbuf_getline (& line , fh , '\n' ) != EOF ) {
2627 credential_from_url (& entry , line .buf );
2728 if (entry .username && entry .password &&
2829 credential_match (c , & entry )) {
30+ found_credential = 1 ;
2931 if (match_cb ) {
3032 match_cb (& entry );
3133 break ;
@@ -38,6 +40,7 @@ static void parse_credential_file(const char *fn,
3840 credential_clear (& entry );
3941 strbuf_release (& line );
4042 fclose (fh );
43+ return found_credential ;
4144}
4245
4346static void print_entry (struct credential * c )
@@ -64,21 +67,10 @@ static void rewrite_credential_file(const char *fn, struct credential *c,
6467 die_errno ("unable to commit credential store" );
6568}
6669
67- static void store_credential (const char * fn , struct credential * c )
70+ static void store_credential_file (const char * fn , struct credential * c )
6871{
6972 struct strbuf buf = STRBUF_INIT ;
7073
71- /*
72- * Sanity check that what we are storing is actually sensible.
73- * In particular, we can't make a URL without a protocol field.
74- * Without either a host or pathname (depending on the scheme),
75- * we have no primary key. And without a username and password,
76- * we are not actually storing a credential.
77- */
78- if (!c -> protocol || !(c -> host || c -> path ) ||
79- !c -> username || !c -> password )
80- return ;
81-
8274 strbuf_addf (& buf , "%s://" , c -> protocol );
8375 strbuf_addstr_urlencode (& buf , c -> username , 1 );
8476 strbuf_addch (& buf , ':' );
@@ -95,8 +87,37 @@ static void store_credential(const char *fn, struct credential *c)
9587 strbuf_release (& buf );
9688}
9789
98- static void remove_credential (const char * fn , struct credential * c )
90+ static void store_credential (const struct string_list * fns , struct credential * c )
91+ {
92+ struct string_list_item * fn ;
93+
94+ /*
95+ * Sanity check that what we are storing is actually sensible.
96+ * In particular, we can't make a URL without a protocol field.
97+ * Without either a host or pathname (depending on the scheme),
98+ * we have no primary key. And without a username and password,
99+ * we are not actually storing a credential.
100+ */
101+ if (!c -> protocol || !(c -> host || c -> path ) || !c -> username || !c -> password )
102+ return ;
103+
104+ for_each_string_list_item (fn , fns )
105+ if (!access (fn -> string , F_OK )) {
106+ store_credential_file (fn -> string , c );
107+ return ;
108+ }
109+ /*
110+ * Write credential to the filename specified by fns->items[0], thus
111+ * creating it
112+ */
113+ if (fns -> nr )
114+ store_credential_file (fns -> items [0 ].string , c );
115+ }
116+
117+ static void remove_credential (const struct string_list * fns , struct credential * c )
99118{
119+ struct string_list_item * fn ;
120+
100121 /*
101122 * Sanity check that we actually have something to match
102123 * against. The input we get is a restrictive pattern,
@@ -105,14 +126,20 @@ static void remove_credential(const char *fn, struct credential *c)
105126 * to empty input. So explicitly disallow it, and require that the
106127 * pattern have some actual content to match.
107128 */
108- if (c -> protocol || c -> host || c -> path || c -> username )
109- rewrite_credential_file (fn , c , NULL );
129+ if (!c -> protocol && !c -> host && !c -> path && !c -> username )
130+ return ;
131+ for_each_string_list_item (fn , fns )
132+ if (!access (fn -> string , F_OK ))
133+ rewrite_credential_file (fn -> string , c , NULL );
110134}
111135
112- static int lookup_credential (const char * fn , struct credential * c )
136+ static void lookup_credential (const struct string_list * fns , struct credential * c )
113137{
114- parse_credential_file (fn , c , print_entry , NULL );
115- return c -> username && c -> password ;
138+ struct string_list_item * fn ;
139+
140+ for_each_string_list_item (fn , fns )
141+ if (parse_credential_file (fn -> string , c , print_entry , NULL ))
142+ return ; /* Found credential */
116143}
117144
118145int main (int argc , char * * argv )
@@ -123,6 +150,7 @@ int main(int argc, char **argv)
123150 };
124151 const char * op ;
125152 struct credential c = CREDENTIAL_INIT ;
153+ struct string_list fns = STRING_LIST_INIT_DUP ;
126154 char * file = NULL ;
127155 struct option options [] = {
128156 OPT_STRING (0 , "file" , & file , "path" ,
@@ -137,22 +165,30 @@ int main(int argc, char **argv)
137165 usage_with_options (usage , options );
138166 op = argv [0 ];
139167
140- if (!file )
141- file = expand_user_path ("~/.git-credentials" );
142- if (!file )
168+ if (file ) {
169+ string_list_append (& fns , file );
170+ } else {
171+ if ((file = expand_user_path ("~/.git-credentials" )))
172+ string_list_append_nodup (& fns , file );
173+ home_config_paths (NULL , & file , "credentials" );
174+ if (file )
175+ string_list_append_nodup (& fns , file );
176+ }
177+ if (!fns .nr )
143178 die ("unable to set up default path; use --file" );
144179
145180 if (credential_read (& c , stdin ) < 0 )
146181 die ("unable to read credential" );
147182
148183 if (!strcmp (op , "get" ))
149- lookup_credential (file , & c );
184+ lookup_credential (& fns , & c );
150185 else if (!strcmp (op , "erase" ))
151- remove_credential (file , & c );
186+ remove_credential (& fns , & c );
152187 else if (!strcmp (op , "store" ))
153- store_credential (file , & c );
188+ store_credential (& fns , & c );
154189 else
155190 ; /* Ignore unknown operation. */
156191
192+ string_list_clear (& fns , 0 );
157193 return 0 ;
158194}
0 commit comments