|
dbda8d6…
|
drh
|
1 |
/* |
|
c19f34c…
|
drh
|
2 |
** Copyright (c) 2007 D. Richard Hipp |
|
dbda8d6…
|
drh
|
3 |
** |
|
dbda8d6…
|
drh
|
4 |
** This program is free software; you can redistribute it and/or |
|
c06edd2…
|
drh
|
5 |
** modify it under the terms of the Simplified BSD License (also |
|
c06edd2…
|
drh
|
6 |
** known as the "2-Clause License" or "FreeBSD License".) |
|
c06edd2…
|
drh
|
7 |
|
|
dbda8d6…
|
drh
|
8 |
** This program is distributed in the hope that it will be useful, |
|
c06edd2…
|
drh
|
9 |
** but without any warranty; without even the implied warranty of |
|
c06edd2…
|
drh
|
10 |
** merchantability or fitness for a particular purpose. |
|
dbda8d6…
|
drh
|
11 |
** |
|
dbda8d6…
|
drh
|
12 |
** Author contact information: |
|
dbda8d6…
|
drh
|
13 |
** [email protected] |
|
dbda8d6…
|
drh
|
14 |
** http://www.hwaci.com/drh/ |
|
dbda8d6…
|
drh
|
15 |
** |
|
dbda8d6…
|
drh
|
16 |
******************************************************************************* |
|
dbda8d6…
|
drh
|
17 |
** |
|
dbda8d6…
|
drh
|
18 |
** This file contains code used to check-out versions of the project |
|
dbda8d6…
|
drh
|
19 |
** from the local repository. |
|
dbda8d6…
|
drh
|
20 |
*/ |
|
dbda8d6…
|
drh
|
21 |
#include "config.h" |
|
dbda8d6…
|
drh
|
22 |
#include "checkout.h" |
|
dbda8d6…
|
drh
|
23 |
#include <assert.h> |
|
2f9920a…
|
drh
|
24 |
#include <zlib.h> |
|
dbda8d6…
|
drh
|
25 |
|
|
dbda8d6…
|
drh
|
26 |
/* |
|
bc36fdc…
|
danield
|
27 |
** Check to see if there is an existing check-out that has been |
|
dbda8d6…
|
drh
|
28 |
** modified. Return values: |
|
dbda8d6…
|
drh
|
29 |
** |
|
bc36fdc…
|
danield
|
30 |
** 0: There is an existing check-out but it is unmodified |
|
bc36fdc…
|
danield
|
31 |
** 1: There is a modified check-out - there are unsaved changes |
|
dbda8d6…
|
drh
|
32 |
*/ |
|
a9ad53b…
|
joel
|
33 |
int unsaved_changes(unsigned int cksigFlags){ |
|
dbda8d6…
|
drh
|
34 |
int vid; |
|
dbda8d6…
|
drh
|
35 |
db_must_be_within_tree(); |
|
dbda8d6…
|
drh
|
36 |
vid = db_lget_int("checkout",0); |
|
a9ad53b…
|
joel
|
37 |
vfile_check_signature(vid, cksigFlags|CKSIG_ENOTFILE); |
|
e146d80…
|
drh
|
38 |
return db_exists("SELECT 1 FROM vfile WHERE chnged" |
|
e146d80…
|
drh
|
39 |
" OR coalesce(origname!=pathname,0)"); |
|
dbda8d6…
|
drh
|
40 |
} |
|
dbda8d6…
|
drh
|
41 |
|
|
dbda8d6…
|
drh
|
42 |
/* |
|
dbda8d6…
|
drh
|
43 |
** Undo the current check-out. Unlink all files from the disk. |
|
dbda8d6…
|
drh
|
44 |
** Clear the VFILE table. |
|
f132f86…
|
drh
|
45 |
** |
|
f132f86…
|
drh
|
46 |
** Also delete any directory that becomes empty as a result of deleting |
|
f132f86…
|
drh
|
47 |
** files due to this operation, as long as that directory is not the |
|
f132f86…
|
drh
|
48 |
** current working directory and is not on the empty-dirs list. |
|
dbda8d6…
|
drh
|
49 |
*/ |
|
dbda8d6…
|
drh
|
50 |
void uncheckout(int vid){ |
|
f132f86…
|
drh
|
51 |
char *zPwd; |
|
f132f86…
|
drh
|
52 |
if( vid<=0 ) return; |
|
f132f86…
|
drh
|
53 |
sqlite3_create_function(g.db, "dirname",1,SQLITE_UTF8,0, |
|
f132f86…
|
drh
|
54 |
file_dirname_sql_function, 0, 0); |
|
994a7c7…
|
drh
|
55 |
sqlite3_create_function(g.db, "unlink",1,SQLITE_UTF8|SQLITE_DIRECTONLY,0, |
|
f132f86…
|
drh
|
56 |
file_delete_sql_function, 0, 0); |
|
994a7c7…
|
drh
|
57 |
sqlite3_create_function(g.db, "rmdir", 1, SQLITE_UTF8|SQLITE_DIRECTONLY, 0, |
|
f132f86…
|
drh
|
58 |
file_rmdir_sql_function, 0, 0); |
|
f132f86…
|
drh
|
59 |
db_multi_exec( |
|
f132f86…
|
drh
|
60 |
"CREATE TEMP TABLE dir_to_delete(name TEXT %s PRIMARY KEY)WITHOUT ROWID", |
|
f132f86…
|
drh
|
61 |
filename_collation() |
|
f132f86…
|
drh
|
62 |
); |
|
f132f86…
|
drh
|
63 |
db_multi_exec( |
|
f132f86…
|
drh
|
64 |
"INSERT OR IGNORE INTO dir_to_delete(name)" |
|
f132f86…
|
drh
|
65 |
" SELECT dirname(pathname) FROM vfile" |
|
f132f86…
|
drh
|
66 |
" WHERE vid=%d AND mrid>0", |
|
f132f86…
|
drh
|
67 |
vid |
|
f132f86…
|
drh
|
68 |
); |
|
f132f86…
|
drh
|
69 |
do{ |
|
f132f86…
|
drh
|
70 |
db_multi_exec( |
|
f132f86…
|
drh
|
71 |
"INSERT OR IGNORE INTO dir_to_delete(name)" |
|
f132f86…
|
drh
|
72 |
" SELECT dirname(name) FROM dir_to_delete;" |
|
f132f86…
|
drh
|
73 |
); |
|
f132f86…
|
drh
|
74 |
}while( db_changes() ); |
|
f132f86…
|
drh
|
75 |
db_multi_exec( |
|
f132f86…
|
drh
|
76 |
"SELECT unlink(%Q||pathname) FROM vfile" |
|
f132f86…
|
drh
|
77 |
" WHERE vid=%d AND mrid>0;", |
|
f132f86…
|
drh
|
78 |
g.zLocalRoot, vid |
|
f132f86…
|
drh
|
79 |
); |
|
f132f86…
|
drh
|
80 |
ensure_empty_dirs_created(1); |
|
f132f86…
|
drh
|
81 |
zPwd = file_getcwd(0,0); |
|
f132f86…
|
drh
|
82 |
db_multi_exec( |
|
f132f86…
|
drh
|
83 |
"SELECT rmdir(%Q||name) FROM dir_to_delete" |
|
f132f86…
|
drh
|
84 |
" WHERE (%Q||name)<>%Q ORDER BY name DESC", |
|
f132f86…
|
drh
|
85 |
g.zLocalRoot, g.zLocalRoot, zPwd |
|
f132f86…
|
drh
|
86 |
); |
|
f132f86…
|
drh
|
87 |
fossil_free(zPwd); |
|
dbda8d6…
|
drh
|
88 |
db_multi_exec("DELETE FROM vfile WHERE vid=%d", vid); |
|
dbda8d6…
|
drh
|
89 |
} |
|
dbda8d6…
|
drh
|
90 |
|
|
dbda8d6…
|
drh
|
91 |
|
|
dbda8d6…
|
drh
|
92 |
/* |
|
8ad5e46…
|
wyoung
|
93 |
** Given the abbreviated hash of a version, load the content of that |
|
dbda8d6…
|
drh
|
94 |
** version in the VFILE table. Return the VID for the version. |
|
dbda8d6…
|
drh
|
95 |
** |
|
dbda8d6…
|
drh
|
96 |
** If anything goes wrong, panic. |
|
dbda8d6…
|
drh
|
97 |
*/ |
|
941ead2…
|
andybradford
|
98 |
int load_vfile(const char *zName, int forceMissingFlag){ |
|
dbda8d6…
|
drh
|
99 |
Blob uuid; |
|
dbda8d6…
|
drh
|
100 |
int vid; |
|
dbda8d6…
|
drh
|
101 |
|
|
dbda8d6…
|
drh
|
102 |
blob_init(&uuid, zName, -1); |
|
2a013f0…
|
drh
|
103 |
if( name_to_uuid(&uuid, 1, "ci") ){ |
|
49b0ff1…
|
drh
|
104 |
fossil_fatal("%s", g.zErrMsg); |
|
dbda8d6…
|
drh
|
105 |
} |
|
dbda8d6…
|
drh
|
106 |
vid = db_int(0, "SELECT rid FROM blob WHERE uuid=%B", &uuid); |
|
dbda8d6…
|
drh
|
107 |
if( vid==0 ){ |
|
c774e29…
|
drh
|
108 |
fossil_fatal("no such check-in: %s", g.argv[2]); |
|
c774e29…
|
drh
|
109 |
} |
|
999b177…
|
drh
|
110 |
if( !is_a_version(vid) ){ |
|
fe6d393…
|
jan.nijtmans
|
111 |
fossil_fatal("object [%S] is not a check-in", blob_str(&uuid)); |
|
1298918…
|
drh
|
112 |
} |
|
941ead2…
|
andybradford
|
113 |
if( load_vfile_from_rid(vid) && !forceMissingFlag ){ |
|
bc36fdc…
|
danield
|
114 |
fossil_fatal("missing content, unable to check out"); |
|
941ead2…
|
andybradford
|
115 |
}; |
|
1298918…
|
drh
|
116 |
return vid; |
|
dbda8d6…
|
drh
|
117 |
} |
|
dbda8d6…
|
drh
|
118 |
|
|
dbda8d6…
|
drh
|
119 |
/* |
|
7c2577b…
|
drh
|
120 |
** Set or clear the vfile.isexe flag for a file. |
|
588bb7c…
|
aku
|
121 |
*/ |
|
7c2577b…
|
drh
|
122 |
static void set_or_clear_isexe(const char *zFilename, int vid, int onoff){ |
|
d13054c…
|
drh
|
123 |
static Stmt s; |
|
d13054c…
|
drh
|
124 |
db_static_prepare(&s, |
|
d13054c…
|
drh
|
125 |
"UPDATE vfile SET isexe=:isexe" |
|
d13054c…
|
drh
|
126 |
" WHERE vid=:vid AND pathname=:path AND isexe!=:isexe" |
|
d13054c…
|
drh
|
127 |
); |
|
d13054c…
|
drh
|
128 |
db_bind_int(&s, ":isexe", onoff); |
|
d13054c…
|
drh
|
129 |
db_bind_int(&s, ":vid", vid); |
|
d13054c…
|
drh
|
130 |
db_bind_text(&s, ":path", zFilename); |
|
d13054c…
|
drh
|
131 |
db_step(&s); |
|
d13054c…
|
drh
|
132 |
db_reset(&s); |
|
588bb7c…
|
aku
|
133 |
} |
|
588bb7c…
|
aku
|
134 |
|
|
588bb7c…
|
aku
|
135 |
/* |
|
5a48a9b…
|
drh
|
136 |
** Set or clear the execute permission bit (as appropriate) for all |
|
e4f1c1f…
|
drh
|
137 |
** files in the current check-out, and replace files that have |
|
e4f1c1f…
|
drh
|
138 |
** symlink bit with actual symlinks. |
|
588bb7c…
|
aku
|
139 |
*/ |
|
d13054c…
|
drh
|
140 |
void checkout_set_all_exe(int vid){ |
|
588bb7c…
|
aku
|
141 |
Blob filename; |
|
588bb7c…
|
aku
|
142 |
int baseLen; |
|
d13054c…
|
drh
|
143 |
Manifest *pManifest; |
|
d13054c…
|
drh
|
144 |
ManifestFile *pFile; |
|
5a48a9b…
|
drh
|
145 |
|
|
5a48a9b…
|
drh
|
146 |
/* Check the EXE permission status of all files |
|
5a48a9b…
|
drh
|
147 |
*/ |
|
ec81aee…
|
jan.nijtmans
|
148 |
pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0); |
|
d13054c…
|
drh
|
149 |
if( pManifest==0 ) return; |
|
588bb7c…
|
aku
|
150 |
blob_zero(&filename); |
|
897dfa4…
|
drh
|
151 |
blob_appendf(&filename, "%s", g.zLocalRoot); |
|
588bb7c…
|
aku
|
152 |
baseLen = blob_size(&filename); |
|
d13054c…
|
drh
|
153 |
manifest_file_rewind(pManifest); |
|
d13054c…
|
drh
|
154 |
while( (pFile = manifest_file_next(pManifest, 0))!=0 ){ |
|
588bb7c…
|
aku
|
155 |
int isExe; |
|
d13054c…
|
drh
|
156 |
blob_append(&filename, pFile->zName, -1); |
|
d13054c…
|
drh
|
157 |
isExe = pFile->zPerm && strstr(pFile->zPerm, "x"); |
|
1772357…
|
drh
|
158 |
file_setexe(blob_str(&filename), isExe); |
|
d13054c…
|
drh
|
159 |
set_or_clear_isexe(pFile->zName, vid, isExe); |
|
588bb7c…
|
aku
|
160 |
blob_resize(&filename, baseLen); |
|
588bb7c…
|
aku
|
161 |
} |
|
588bb7c…
|
aku
|
162 |
blob_reset(&filename); |
|
d13054c…
|
drh
|
163 |
manifest_destroy(pManifest); |
|
d13054c…
|
drh
|
164 |
} |
|
d13054c…
|
drh
|
165 |
|
|
d13054c…
|
drh
|
166 |
|
|
d13054c…
|
drh
|
167 |
/* |
|
d13054c…
|
drh
|
168 |
** If the "manifest" setting is true, then automatically generate |
|
d13054c…
|
drh
|
169 |
** files named "manifest" and "manifest.uuid" containing, respectively, |
|
d13054c…
|
drh
|
170 |
** the text of the manifest and the artifact ID of the manifest. |
|
189bfc2…
|
jan
|
171 |
** If the manifest setting is set, but is not a boolean value, then treat |
|
189bfc2…
|
jan
|
172 |
** each character as a flag to enable writing "manifest", "manifest.uuid" or |
|
189bfc2…
|
jan
|
173 |
** "manifest.tags". |
|
d13054c…
|
drh
|
174 |
*/ |
|
d13054c…
|
drh
|
175 |
void manifest_to_disk(int vid){ |
|
d13054c…
|
drh
|
176 |
char *zManFile; |
|
189bfc2…
|
jan
|
177 |
int flg; |
|
189bfc2…
|
jan
|
178 |
|
|
dfc0f1b…
|
drh
|
179 |
flg = db_get_manifest_setting(0); |
|
5a48a9b…
|
drh
|
180 |
|
|
41af304…
|
drh
|
181 |
if( flg & MFESTFLG_RAW ){ |
|
d564056…
|
drh
|
182 |
Blob manifest = BLOB_INITIALIZER; |
|
d13054c…
|
drh
|
183 |
content_get(vid, &manifest); |
|
2777682…
|
drh
|
184 |
sterilize_manifest(&manifest, CFTYPE_MANIFEST); |
|
5a48a9b…
|
drh
|
185 |
zManFile = mprintf("%smanifest", g.zLocalRoot); |
|
5a48a9b…
|
drh
|
186 |
blob_write_to_file(&manifest, zManFile); |
|
5a48a9b…
|
drh
|
187 |
free(zManFile); |
|
d564056…
|
drh
|
188 |
blob_reset(&manifest); |
|
d8ec765…
|
drh
|
189 |
}else{ |
|
d8ec765…
|
drh
|
190 |
if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest'") ){ |
|
d8ec765…
|
drh
|
191 |
zManFile = mprintf("%smanifest", g.zLocalRoot); |
|
d8ec765…
|
drh
|
192 |
file_delete(zManFile); |
|
d8ec765…
|
drh
|
193 |
free(zManFile); |
|
d8ec765…
|
drh
|
194 |
} |
|
189bfc2…
|
jan
|
195 |
} |
|
189bfc2…
|
jan
|
196 |
if( flg & MFESTFLG_UUID ){ |
|
41af304…
|
drh
|
197 |
Blob hash; |
|
189bfc2…
|
jan
|
198 |
zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
|
41af304…
|
drh
|
199 |
blob_set_dynamic(&hash, rid_to_uuid(vid)); |
|
189bfc2…
|
jan
|
200 |
blob_append(&hash, "\n", 1); |
|
189bfc2…
|
jan
|
201 |
blob_write_to_file(&hash, zManFile); |
|
189bfc2…
|
jan
|
202 |
free(zManFile); |
|
189bfc2…
|
jan
|
203 |
blob_reset(&hash); |
|
189bfc2…
|
jan
|
204 |
}else{ |
|
d8ec765…
|
drh
|
205 |
if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest.uuid'") ){ |
|
d8ec765…
|
drh
|
206 |
zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
|
d8ec765…
|
drh
|
207 |
file_delete(zManFile); |
|
d8ec765…
|
drh
|
208 |
free(zManFile); |
|
d8ec765…
|
drh
|
209 |
} |
|
d8ec765…
|
drh
|
210 |
} |
|
189bfc2…
|
jan
|
211 |
if( flg & MFESTFLG_TAGS ){ |
|
d564056…
|
drh
|
212 |
Blob taglist = BLOB_INITIALIZER; |
|
189bfc2…
|
jan
|
213 |
zManFile = mprintf("%smanifest.tags", g.zLocalRoot); |
|
189bfc2…
|
jan
|
214 |
get_checkin_taglist(vid, &taglist); |
|
189bfc2…
|
jan
|
215 |
blob_write_to_file(&taglist, zManFile); |
|
189bfc2…
|
jan
|
216 |
free(zManFile); |
|
189bfc2…
|
jan
|
217 |
blob_reset(&taglist); |
|
189bfc2…
|
jan
|
218 |
}else{ |
|
189bfc2…
|
jan
|
219 |
if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest.tags'") ){ |
|
189bfc2…
|
jan
|
220 |
zManFile = mprintf("%smanifest.tags", g.zLocalRoot); |
|
189bfc2…
|
jan
|
221 |
file_delete(zManFile); |
|
189bfc2…
|
jan
|
222 |
free(zManFile); |
|
189bfc2…
|
jan
|
223 |
} |
|
189bfc2…
|
jan
|
224 |
} |
|
189bfc2…
|
jan
|
225 |
} |
|
3df526c…
|
jan.nijtmans
|
226 |
|
|
189bfc2…
|
jan
|
227 |
/* |
|
189bfc2…
|
jan
|
228 |
** Find the branch name and all symbolic tags for a particular check-in |
|
189bfc2…
|
jan
|
229 |
** identified by "rid". |
|
189bfc2…
|
jan
|
230 |
** |
|
189bfc2…
|
jan
|
231 |
** The branch name is actually only extracted if this procedure is run |
|
189bfc2…
|
jan
|
232 |
** from within a local check-out. And the branch name is not the branch |
|
189bfc2…
|
jan
|
233 |
** name for "rid" but rather the branch name for the current check-out. |
|
189bfc2…
|
jan
|
234 |
** It is unclear if the rid parameter is always the same as the current |
|
189bfc2…
|
jan
|
235 |
** check-out. |
|
189bfc2…
|
jan
|
236 |
*/ |
|
189bfc2…
|
jan
|
237 |
void get_checkin_taglist(int rid, Blob *pOut){ |
|
189bfc2…
|
jan
|
238 |
Stmt stmt; |
|
189bfc2…
|
jan
|
239 |
char *zCurrent; |
|
189bfc2…
|
jan
|
240 |
blob_reset(pOut); |
|
189bfc2…
|
jan
|
241 |
zCurrent = db_text(0, "SELECT value FROM tagxref" |
|
189bfc2…
|
jan
|
242 |
" WHERE rid=%d AND tagid=%d", rid, TAG_BRANCH); |
|
189bfc2…
|
jan
|
243 |
blob_appendf(pOut, "branch %s\n", zCurrent); |
|
189bfc2…
|
jan
|
244 |
db_prepare(&stmt, "SELECT substr(tagname, 5)" |
|
189bfc2…
|
jan
|
245 |
" FROM tagxref, tag" |
|
189bfc2…
|
jan
|
246 |
" WHERE tagxref.rid=%d" |
|
189bfc2…
|
jan
|
247 |
" AND tagxref.tagtype>0" |
|
189bfc2…
|
jan
|
248 |
" AND tag.tagid=tagxref.tagid" |
|
189bfc2…
|
jan
|
249 |
" AND tag.tagname GLOB 'sym-*'", rid); |
|
189bfc2…
|
jan
|
250 |
while( db_step(&stmt)==SQLITE_ROW ){ |
|
189bfc2…
|
jan
|
251 |
const char *zName; |
|
189bfc2…
|
jan
|
252 |
zName = db_column_text(&stmt, 0); |
|
189bfc2…
|
jan
|
253 |
blob_appendf(pOut, "tag %s\n", zName); |
|
189bfc2…
|
jan
|
254 |
} |
|
189bfc2…
|
jan
|
255 |
db_reset(&stmt); |
|
189bfc2…
|
jan
|
256 |
db_finalize(&stmt); |
|
d8ec765…
|
drh
|
257 |
} |
|
189bfc2…
|
jan
|
258 |
|
|
841772c…
|
drh
|
259 |
|
|
d8ec765…
|
drh
|
260 |
/* |
|
841772c…
|
drh
|
261 |
** COMMAND: checkout* |
|
db70849…
|
danield
|
262 |
** COMMAND: co# |
|
2210be1…
|
drh
|
263 |
** |
|
2210be1…
|
drh
|
264 |
** Usage: %fossil checkout ?VERSION | --latest? ?OPTIONS? |
|
2210be1…
|
drh
|
265 |
** or: %fossil co ?VERSION | --latest? ?OPTIONS? |
|
2210be1…
|
drh
|
266 |
** |
|
1bdd485…
|
drh
|
267 |
** NOTE: Most people use "fossil update" instead of "fossil checkout" for |
|
1bdd485…
|
drh
|
268 |
** day-to-day operations. If you are new to Fossil and trying to learn your |
|
1bdd485…
|
drh
|
269 |
** way around, it is recommended that you become familiar with the |
|
1bdd485…
|
drh
|
270 |
** "fossil update" command first. |
|
1bdd485…
|
drh
|
271 |
** |
|
1bdd485…
|
drh
|
272 |
** This command changes the current check-out to the version specified |
|
1bdd485…
|
drh
|
273 |
** as an argument. The command aborts if there are edited files in the |
|
bc36fdc…
|
danield
|
274 |
** current check-out unless the --force option is used. The --keep option |
|
d8ec765…
|
drh
|
275 |
** leaves files on disk unchanged, except the manifest and manifest.uuid |
|
d8ec765…
|
drh
|
276 |
** files. |
|
d8ec765…
|
drh
|
277 |
** |
|
bc36fdc…
|
danield
|
278 |
** The --latest flag can be used in place of VERSION to check-out the |
|
d8ec765…
|
drh
|
279 |
** latest version in the repository. |
|
3df526c…
|
jan.nijtmans
|
280 |
** |
|
2210be1…
|
drh
|
281 |
** Options: |
|
5bc31db…
|
mgagnon
|
282 |
** -f|--force Ignore edited files in the current check-out |
|
5bc31db…
|
mgagnon
|
283 |
** -k|--keep Only update the manifest file(s) |
|
bc36fdc…
|
danield
|
284 |
** --force-missing Force check-out even if content is missing |
|
e194398…
|
danield
|
285 |
** --prompt Prompt before overwriting when --force is used |
|
a7e86f5…
|
drh
|
286 |
** --setmtime Set timestamps of all files to match their SCM-side |
|
bc36fdc…
|
danield
|
287 |
** times (the timestamp of the last check-in which modified |
|
4cb50c4…
|
stephan
|
288 |
** them) |
|
2210be1…
|
drh
|
289 |
** |
|
c965636…
|
drh
|
290 |
** See also: [[update]] |
|
d8ec765…
|
drh
|
291 |
*/ |
|
d8ec765…
|
drh
|
292 |
void checkout_cmd(void){ |
|
bc36fdc…
|
danield
|
293 |
int forceFlag; /* Force check-out even if edits exist */ |
|
bc36fdc…
|
danield
|
294 |
int forceMissingFlag; /* Force check-out even if missing content */ |
|
d8ec765…
|
drh
|
295 |
int keepFlag; /* Do not change any files on disk */ |
|
bc36fdc…
|
danield
|
296 |
int latestFlag; /* Check out the latest version */ |
|
bc36fdc…
|
danield
|
297 |
char *zVers; /* Version to check out */ |
|
d8ec765…
|
drh
|
298 |
int promptFlag; /* True to prompt before overwriting */ |
|
d8ec765…
|
drh
|
299 |
int vid, prior; |
|
a7e86f5…
|
drh
|
300 |
int setmtimeFlag; /* --setmtime. Set mtimes on files */ |
|
d8ec765…
|
drh
|
301 |
Blob cksum1, cksum1b, cksum2; |
|
3df526c…
|
jan.nijtmans
|
302 |
|
|
d8ec765…
|
drh
|
303 |
db_must_be_within_tree(); |
|
e1962ef…
|
drh
|
304 |
db_begin_transaction(); |
|
941ead2…
|
andybradford
|
305 |
forceMissingFlag = find_option("force-missing",0,0)!=0; |
|
5bc31db…
|
mgagnon
|
306 |
keepFlag = find_option("keep","k",0)!=0; |
|
5bc31db…
|
mgagnon
|
307 |
forceFlag = find_option("force","f",0)!=0; |
|
d8ec765…
|
drh
|
308 |
latestFlag = find_option("latest",0,0)!=0; |
|
d8ec765…
|
drh
|
309 |
promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0; |
|
a7e86f5…
|
drh
|
310 |
setmtimeFlag = find_option("setmtime",0,0)!=0; |
|
5bc31db…
|
mgagnon
|
311 |
|
|
5bc31db…
|
mgagnon
|
312 |
if( keepFlag != 0 ){ |
|
e194398…
|
danield
|
313 |
/* After flag collection, in order not to affect promptFlag */ |
|
5bc31db…
|
mgagnon
|
314 |
forceFlag=1; |
|
5bc31db…
|
mgagnon
|
315 |
} |
|
74ac0c9…
|
drh
|
316 |
|
|
74ac0c9…
|
drh
|
317 |
/* We should be done with options.. */ |
|
74ac0c9…
|
drh
|
318 |
verify_all_options(); |
|
74ac0c9…
|
drh
|
319 |
|
|
d8ec765…
|
drh
|
320 |
if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
|
d8ec765…
|
drh
|
321 |
usage("VERSION|--latest ?--force? ?--keep?"); |
|
d8ec765…
|
drh
|
322 |
} |
|
f7d9413…
|
jan.nijtmans
|
323 |
if( !forceFlag && unsaved_changes(0) ){ |
|
bc36fdc…
|
danield
|
324 |
fossil_fatal("there are unsaved changes in the current check-out"); |
|
dbda8d6…
|
drh
|
325 |
} |
|
dbda8d6…
|
drh
|
326 |
if( forceFlag ){ |
|
dbda8d6…
|
drh
|
327 |
db_multi_exec("DELETE FROM vfile"); |
|
dbda8d6…
|
drh
|
328 |
prior = 0; |
|
dbda8d6…
|
drh
|
329 |
}else{ |
|
dbda8d6…
|
drh
|
330 |
prior = db_lget_int("checkout",0); |
|
dbda8d6…
|
drh
|
331 |
} |
|
915bfd9…
|
drh
|
332 |
if( latestFlag ){ |
|
915bfd9…
|
drh
|
333 |
compute_leaves(db_lget_int("checkout",0), 1); |
|
915bfd9…
|
drh
|
334 |
zVers = db_text(0, "SELECT uuid FROM leaves, event, blob" |
|
915bfd9…
|
drh
|
335 |
" WHERE event.objid=leaves.rid AND blob.rid=leaves.rid" |
|
915bfd9…
|
drh
|
336 |
" ORDER BY event.mtime DESC"); |
|
915bfd9…
|
drh
|
337 |
if( zVers==0 ){ |
|
16e703b…
|
drh
|
338 |
zVers = db_text(0, "SELECT uuid FROM event, blob" |
|
16e703b…
|
drh
|
339 |
" WHERE event.objid=blob.rid AND event.type='ci'" |
|
16e703b…
|
drh
|
340 |
" ORDER BY event.mtime DESC"); |
|
16e703b…
|
drh
|
341 |
} |
|
16e703b…
|
drh
|
342 |
if( zVers==0 ){ |
|
b0db865…
|
jan.nijtmans
|
343 |
db_end_transaction(0); |
|
b725c1c…
|
jan.nijtmans
|
344 |
return; |
|
915bfd9…
|
drh
|
345 |
} |
|
915bfd9…
|
drh
|
346 |
}else{ |
|
915bfd9…
|
drh
|
347 |
zVers = g.argv[2]; |
|
915bfd9…
|
drh
|
348 |
} |
|
941ead2…
|
andybradford
|
349 |
vid = load_vfile(zVers, forceMissingFlag); |
|
dbda8d6…
|
drh
|
350 |
if( prior==vid ){ |
|
a7e86f5…
|
drh
|
351 |
if( setmtimeFlag ) vfile_check_signature(vid, CKSIG_SETMTIME); |
|
b31aa7d…
|
drh
|
352 |
db_end_transaction(0); |
|
dbda8d6…
|
drh
|
353 |
return; |
|
dbda8d6…
|
drh
|
354 |
} |
|
915bfd9…
|
drh
|
355 |
if( !keepFlag ){ |
|
dbda8d6…
|
drh
|
356 |
uncheckout(prior); |
|
dbda8d6…
|
drh
|
357 |
} |
|
dbda8d6…
|
drh
|
358 |
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
|
915bfd9…
|
drh
|
359 |
if( !keepFlag ){ |
|
f3e8e3e…
|
drh
|
360 |
vfile_to_disk(vid, 0, !g.fQuiet, promptFlag); |
|
a040ae6…
|
drh
|
361 |
} |
|
d13054c…
|
drh
|
362 |
checkout_set_all_exe(vid); |
|
f132f86…
|
drh
|
363 |
ensure_empty_dirs_created(0); |
|
f72ef85…
|
andybradford
|
364 |
db_set_checkout(vid, 1); |
|
915bfd9…
|
drh
|
365 |
undo_reset(); |
|
dbda8d6…
|
drh
|
366 |
db_multi_exec("DELETE FROM vmerge"); |
|
46ef289…
|
drh
|
367 |
if( !keepFlag && db_get_boolean("repo-cksum",1) ){ |
|
915bfd9…
|
drh
|
368 |
vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); |
|
915bfd9…
|
drh
|
369 |
vfile_aggregate_checksum_disk(vid, &cksum2); |
|
915bfd9…
|
drh
|
370 |
if( blob_compare(&cksum1, &cksum2) ){ |
|
d8ec765…
|
drh
|
371 |
fossil_print("WARNING: manifest checksum does not agree with disk\n"); |
|
915bfd9…
|
drh
|
372 |
} |
|
aab38ef…
|
drh
|
373 |
if( blob_size(&cksum1b) && blob_compare(&cksum1, &cksum1b) ){ |
|
d8ec765…
|
drh
|
374 |
fossil_print("WARNING: manifest checksum does not agree with manifest\n"); |
|
915bfd9…
|
drh
|
375 |
} |
|
915bfd9…
|
drh
|
376 |
} |
|
a7e86f5…
|
drh
|
377 |
if( setmtimeFlag ) vfile_check_signature(vid, CKSIG_SETMTIME); |
|
dbda8d6…
|
drh
|
378 |
db_end_transaction(0); |
|
4452576…
|
drh
|
379 |
} |
|
4452576…
|
drh
|
380 |
|
|
4452576…
|
drh
|
381 |
/* |
|
915bfd9…
|
drh
|
382 |
** Unlink the local database file |
|
915bfd9…
|
drh
|
383 |
*/ |
|
56d69db…
|
drh
|
384 |
static void unlink_local_database(int manifestOnly){ |
|
56d69db…
|
drh
|
385 |
const char *zReserved; |
|
915bfd9…
|
drh
|
386 |
int i; |
|
fcdeaa2…
|
drh
|
387 |
for(i=0; (zReserved = fossil_reserved_name(i, 1))!=0; i++){ |
|
56d69db…
|
drh
|
388 |
if( manifestOnly==0 || zReserved[0]=='m' ){ |
|
56d69db…
|
drh
|
389 |
char *z; |
|
56d69db…
|
drh
|
390 |
z = mprintf("%s%s", g.zLocalRoot, zReserved); |
|
d8ec765…
|
drh
|
391 |
file_delete(z); |
|
56d69db…
|
drh
|
392 |
free(z); |
|
56d69db…
|
drh
|
393 |
} |
|
915bfd9…
|
drh
|
394 |
} |
|
915bfd9…
|
drh
|
395 |
} |
|
915bfd9…
|
drh
|
396 |
|
|
915bfd9…
|
drh
|
397 |
/* |
|
841772c…
|
drh
|
398 |
** COMMAND: close* |
|
2210be1…
|
drh
|
399 |
** |
|
2210be1…
|
drh
|
400 |
** Usage: %fossil close ?OPTIONS? |
|
2210be1…
|
drh
|
401 |
** |
|
c965636…
|
drh
|
402 |
** The opposite of "[[open]]". Close the current database connection. |
|
b6b50b1…
|
mistachkin
|
403 |
** Require a -f or --force flag if there are unsaved changes in the |
|
c6aedbd…
|
drh
|
404 |
** current check-out or if there is non-empty stash. |
|
6b85fd1…
|
drh
|
405 |
** |
|
2210be1…
|
drh
|
406 |
** Options: |
|
2512d2d…
|
km
|
407 |
** -f|--force Necessary to close a check-out with uncommitted changes |
|
4452576…
|
drh
|
408 |
** |
|
c965636…
|
drh
|
409 |
** See also: [[open]] |
|
4452576…
|
drh
|
410 |
*/ |
|
4452576…
|
drh
|
411 |
void close_cmd(void){ |
|
4452576…
|
drh
|
412 |
int forceFlag = find_option("force","f",0)!=0; |
|
4452576…
|
drh
|
413 |
db_must_be_within_tree(); |
|
4e18dba…
|
jan.nijtmans
|
414 |
|
|
74ac0c9…
|
drh
|
415 |
/* We should be done with options.. */ |
|
74ac0c9…
|
drh
|
416 |
verify_all_options(); |
|
74ac0c9…
|
drh
|
417 |
|
|
f7d9413…
|
jan.nijtmans
|
418 |
if( !forceFlag && unsaved_changes(0) ){ |
|
bc36fdc…
|
danield
|
419 |
fossil_fatal("there are unsaved changes in the current check-out"); |
|
c6aedbd…
|
drh
|
420 |
} |
|
c6aedbd…
|
drh
|
421 |
if( !forceFlag |
|
1aa8067…
|
drh
|
422 |
&& db_table_exists("localdb","stash") |
|
06aec61…
|
drh
|
423 |
&& db_exists("SELECT 1 FROM localdb.stash") |
|
c6aedbd…
|
drh
|
424 |
){ |
|
bc36fdc…
|
danield
|
425 |
fossil_fatal("closing the check-out will delete your stash"); |
|
0205148…
|
drh
|
426 |
} |
|
0205148…
|
drh
|
427 |
if( db_is_writeable("repository") ){ |
|
0a5d0e1…
|
drh
|
428 |
db_unset_mprintf(1, "ckout:%q", g.zLocalRoot); |
|
56d69db…
|
drh
|
429 |
} |
|
56d69db…
|
drh
|
430 |
unlink_local_database(1); |
|
c2f5dbe…
|
drh
|
431 |
db_close(1); |
|
56d69db…
|
drh
|
432 |
unlink_local_database(0); |
|
2f9920a…
|
drh
|
433 |
} |
|
2f9920a…
|
drh
|
434 |
|
|
2f9920a…
|
drh
|
435 |
|
|
2f9920a…
|
drh
|
436 |
/* |
|
2f9920a…
|
drh
|
437 |
** COMMAND: get |
|
2f9920a…
|
drh
|
438 |
** |
|
2f9920a…
|
drh
|
439 |
** Usage: %fossil get URL ?VERSION? ?OPTIONS? |
|
2f9920a…
|
drh
|
440 |
** |
|
2f9920a…
|
drh
|
441 |
** Download a single check-in from a remote repository named URL and |
|
692140d…
|
drh
|
442 |
** unpack all of the files into a subdirectory. The specific check-in |
|
692140d…
|
drh
|
443 |
** to download is identified by VERSION. If VERSION is omitted, the |
|
692140d…
|
drh
|
444 |
** latest trunk check-in is used. The URL can be a traditional "https:", |
|
692140d…
|
drh
|
445 |
** "ssh:", or "file:" URL similar to the examples shown below, or it can |
|
692140d…
|
drh
|
446 |
** be the name of a local repository/ |
|
2f9920a…
|
drh
|
447 |
** |
|
2f9920a…
|
drh
|
448 |
** * https://domain.com/project |
|
2f9920a…
|
drh
|
449 |
** * ssh://my-server/project.fossil |
|
2f9920a…
|
drh
|
450 |
** * file:/home/user/Fossils/project.fossil |
|
2f9920a…
|
drh
|
451 |
** |
|
2f9920a…
|
drh
|
452 |
** This command works by downloading an SQL archive of the requested |
|
2f9920a…
|
drh
|
453 |
** check-in and then extracting all the files from the archive. |
|
2f9920a…
|
drh
|
454 |
** |
|
2f9920a…
|
drh
|
455 |
** Options: |
|
692140d…
|
drh
|
456 |
** --dest DIRECTORY Extract files into DIRECTORY. Use "--dest ." to |
|
692140d…
|
drh
|
457 |
** extract into the local directory. If this option is |
|
692140d…
|
drh
|
458 |
** omitted, Fossil invents a subdirectory name derived |
|
692140d…
|
drh
|
459 |
** from base filename in the URL and from the VERSION. |
|
692140d…
|
drh
|
460 |
** -f|--force Overwrite existing files |
|
692140d…
|
drh
|
461 |
** --list List all the files that would have been checked |
|
692140d…
|
drh
|
462 |
** out but do not actually write anything to the |
|
692140d…
|
drh
|
463 |
** filesystem. |
|
692140d…
|
drh
|
464 |
** --sqlar ARCHIVE Leave the check-out in an SQL-archive named ARCHIVE |
|
692140d…
|
drh
|
465 |
** rather than unpacking into separate files. |
|
692140d…
|
drh
|
466 |
** -v|--verbose Show all files as they are extracted |
|
2f9920a…
|
drh
|
467 |
*/ |
|
2f9920a…
|
drh
|
468 |
void get_cmd(void){ |
|
2f9920a…
|
drh
|
469 |
int forceFlag = find_option("force","f",0)!=0; |
|
2f9920a…
|
drh
|
470 |
int bVerbose = find_option("verbose","v",0)!=0; |
|
74d5ce3…
|
florian
|
471 |
int bQuiet = g.fQuiet; |
|
2f9920a…
|
drh
|
472 |
int bDebug = find_option("debug",0,0)!=0; |
|
2f9920a…
|
drh
|
473 |
int bList = find_option("list",0,0)!=0; |
|
2f9920a…
|
drh
|
474 |
const char *zSqlArchive = find_option("sqlar",0,1); |
|
2f9920a…
|
drh
|
475 |
const char *z; |
|
2f9920a…
|
drh
|
476 |
char *zDest = 0; /* Where to store results */ |
|
2f9920a…
|
drh
|
477 |
char *zSql; /* SQL used to query the results */ |
|
2f9920a…
|
drh
|
478 |
const char *zUrl; /* Url to get */ |
|
2f9920a…
|
drh
|
479 |
const char *zVers; /* Version name to get */ |
|
2f9920a…
|
drh
|
480 |
unsigned int mHttpFlags = HTTP_GENERIC|HTTP_NOCOMPRESS; |
|
2f9920a…
|
drh
|
481 |
Blob in, out; /* I/O for the HTTP request */ |
|
2f9920a…
|
drh
|
482 |
Blob file; /* A file to extract */ |
|
2f9920a…
|
drh
|
483 |
sqlite3 *db; /* Database containing downloaded sqlar */ |
|
2f9920a…
|
drh
|
484 |
sqlite3_stmt *pStmt; /* Statement for querying the database */ |
|
2f9920a…
|
drh
|
485 |
int rc; /* Result of subroutine calls */ |
|
2f9920a…
|
drh
|
486 |
int nFile = 0; /* Number of files written */ |
|
2f9920a…
|
drh
|
487 |
int nDir = 0; /* Number of directories written */ |
|
2f9920a…
|
drh
|
488 |
i64 nByte = 0; /* Number of bytes written */ |
|
2f9920a…
|
drh
|
489 |
|
|
2f9920a…
|
drh
|
490 |
z = find_option("dest",0,1); |
|
2f9920a…
|
drh
|
491 |
if( z ) zDest = fossil_strdup(z); |
|
2f9920a…
|
drh
|
492 |
verify_all_options(); |
|
2f9920a…
|
drh
|
493 |
if( g.argc<3 || g.argc>4 ){ |
|
788e68b…
|
andybradford
|
494 |
usage("URL ?VERSION? ?OPTIONS?"); |
|
2f9920a…
|
drh
|
495 |
} |
|
2f9920a…
|
drh
|
496 |
zUrl = g.argv[2]; |
|
ca0d66b…
|
danield
|
497 |
zVers = g.argc==4 ? g.argv[3] : db_main_branch(); |
|
2f9920a…
|
drh
|
498 |
|
|
2f9920a…
|
drh
|
499 |
/* Parse the URL of the repository */ |
|
2f9920a…
|
drh
|
500 |
url_parse(zUrl, 0); |
|
2f9920a…
|
drh
|
501 |
|
|
2f9920a…
|
drh
|
502 |
/* Construct an appropriate name for the destination directory */ |
|
2f9920a…
|
drh
|
503 |
if( zDest==0 ){ |
|
2f9920a…
|
drh
|
504 |
int i; |
|
2f9920a…
|
drh
|
505 |
const char *zTail; |
|
2f9920a…
|
drh
|
506 |
const char *zDot; |
|
2f9920a…
|
drh
|
507 |
int n; |
|
2f9920a…
|
drh
|
508 |
if( g.url.isFile ){ |
|
2f9920a…
|
drh
|
509 |
zTail = file_tail(g.url.name); |
|
2f9920a…
|
drh
|
510 |
}else{ |
|
2f9920a…
|
drh
|
511 |
zTail = file_tail(g.url.path); |
|
2f9920a…
|
drh
|
512 |
} |
|
2f9920a…
|
drh
|
513 |
zDot = strchr(zTail,'.'); |
|
2f9920a…
|
drh
|
514 |
if( zDot==0 ) zDot = zTail+strlen(zTail); |
|
2f9920a…
|
drh
|
515 |
n = (int)(zDot - zTail); |
|
2f9920a…
|
drh
|
516 |
zDest = mprintf("%.*s-%s", n, zTail, zVers); |
|
2f9920a…
|
drh
|
517 |
for(i=0; zDest[i]; i++){ |
|
2f9920a…
|
drh
|
518 |
char c = zDest[i]; |
|
2f9920a…
|
drh
|
519 |
if( !fossil_isalnum(c) && c!='-' && c!='^' && c!='~' && c!='_' ){ |
|
2f9920a…
|
drh
|
520 |
zDest[i] = '-'; |
|
2f9920a…
|
drh
|
521 |
} |
|
2f9920a…
|
drh
|
522 |
} |
|
2f9920a…
|
drh
|
523 |
} |
|
2f9920a…
|
drh
|
524 |
if( bDebug ){ |
|
2f9920a…
|
drh
|
525 |
fossil_print("dest = %s\n", zDest); |
|
2f9920a…
|
drh
|
526 |
} |
|
2f9920a…
|
drh
|
527 |
|
|
2f9920a…
|
drh
|
528 |
/* Error checking */ |
|
2f9920a…
|
drh
|
529 |
if( zDest!=file_tail(zDest) ){ |
|
2f9920a…
|
drh
|
530 |
fossil_fatal("--dest must be a simple directory name, not a path"); |
|
2f9920a…
|
drh
|
531 |
} |
|
2f9920a…
|
drh
|
532 |
if( zVers!=file_tail(zVers) ){ |
|
196cb77…
|
andybradford
|
533 |
fossil_fatal("The \"fossil get\" command does not currently work with" |
|
2f9920a…
|
drh
|
534 |
" version names that contain \"/\". This will be fixed in" |
|
2f9920a…
|
drh
|
535 |
" a future release."); |
|
2f9920a…
|
drh
|
536 |
} |
|
2f9920a…
|
drh
|
537 |
/* To relax the restrictions above, change the subpath URL formula below |
|
2f9920a…
|
drh
|
538 |
** to use query parameters. Ex: /sqlar?r=%t&name=%t */ |
|
2f9920a…
|
drh
|
539 |
|
|
2f9920a…
|
drh
|
540 |
if( !forceFlag ){ |
|
2f9920a…
|
drh
|
541 |
if( zSqlArchive ){ |
|
2f9920a…
|
drh
|
542 |
if( file_isdir(zSqlArchive, ExtFILE)>0 ){ |
|
2f9920a…
|
drh
|
543 |
fossil_fatal("file already exists: \"%s\"", zSqlArchive); |
|
2f9920a…
|
drh
|
544 |
} |
|
2f9920a…
|
drh
|
545 |
}else if( file_isdir(zDest, ExtFILE)>0 ){ |
|
2f9920a…
|
drh
|
546 |
if( fossil_strcmp(zDest,".")==0 ){ |
|
ff7fe39…
|
drh
|
547 |
if( file_directory_list(zDest,0,1,1,0) ){ |
|
2f9920a…
|
drh
|
548 |
fossil_fatal("current directory is not empty"); |
|
2f9920a…
|
drh
|
549 |
} |
|
2f9920a…
|
drh
|
550 |
}else{ |
|
2f9920a…
|
drh
|
551 |
fossil_fatal("\"%s\" already exists", zDest); |
|
2f9920a…
|
drh
|
552 |
} |
|
2f9920a…
|
drh
|
553 |
} |
|
2f9920a…
|
drh
|
554 |
} |
|
2f9920a…
|
drh
|
555 |
|
|
2f9920a…
|
drh
|
556 |
/* Construct a subpath on the URL if necessary */ |
|
be76a57…
|
drh
|
557 |
if( g.url.isFile ){ |
|
2f9920a…
|
drh
|
558 |
g.url.subpath = mprintf("/sqlar/%t/%t.sqlar", zVers, zDest); |
|
2f9920a…
|
drh
|
559 |
}else{ |
|
2f9920a…
|
drh
|
560 |
g.url.subpath = mprintf("%s/sqlar/%t/%t.sqlar", g.url.path, zVers, zDest); |
|
2f9920a…
|
drh
|
561 |
} |
|
2f9920a…
|
drh
|
562 |
|
|
2f9920a…
|
drh
|
563 |
if( bDebug ){ |
|
2f9920a…
|
drh
|
564 |
urlparse_print(0); |
|
2f9920a…
|
drh
|
565 |
} |
|
2f9920a…
|
drh
|
566 |
|
|
2f9920a…
|
drh
|
567 |
/* Fetch the ZIP archive for the requested check-in */ |
|
2f9920a…
|
drh
|
568 |
blob_init(&in, 0, 0); |
|
2f9920a…
|
drh
|
569 |
blob_init(&out, 0, 0); |
|
2f9920a…
|
drh
|
570 |
if( bDebug ) mHttpFlags |= HTTP_VERBOSE; |
|
2f9920a…
|
drh
|
571 |
if( bQuiet ) mHttpFlags |= HTTP_QUIET; |
|
2f9920a…
|
drh
|
572 |
rc = http_exchange(&in, &out, mHttpFlags, 4, 0); |
|
2f9920a…
|
drh
|
573 |
if( rc |
|
2f9920a…
|
drh
|
574 |
|| out.nUsed<512 |
|
2f9920a…
|
drh
|
575 |
|| (out.nUsed%512)!=0 |
|
2f9920a…
|
drh
|
576 |
|| memcmp(out.aData,"SQLite format 3",16)!=0 |
|
2f9920a…
|
drh
|
577 |
){ |
|
2f9920a…
|
drh
|
578 |
fossil_fatal("Server did not return the requested check-in."); |
|
2f9920a…
|
drh
|
579 |
} |
|
2f9920a…
|
drh
|
580 |
|
|
2f9920a…
|
drh
|
581 |
if( zSqlArchive ){ |
|
2f9920a…
|
drh
|
582 |
blob_write_to_file(&out, zSqlArchive); |
|
2f9920a…
|
drh
|
583 |
if( bVerbose ) fossil_print("%s\n", zSqlArchive); |
|
2f9920a…
|
drh
|
584 |
return; |
|
2f9920a…
|
drh
|
585 |
} |
|
2f9920a…
|
drh
|
586 |
|
|
2f9920a…
|
drh
|
587 |
rc = sqlite3_open(":memory:", &db); |
|
2f9920a…
|
drh
|
588 |
if( rc==SQLITE_OK ){ |
|
2f9920a…
|
drh
|
589 |
int sz = blob_size(&out); |
|
2f9920a…
|
drh
|
590 |
rc = sqlite3_deserialize(db, 0, (unsigned char*)blob_buffer(&out), sz, sz, |
|
2f9920a…
|
drh
|
591 |
SQLITE_DESERIALIZE_READONLY); |
|
2f9920a…
|
drh
|
592 |
} |
|
2f9920a…
|
drh
|
593 |
if( rc!=SQLITE_OK ){ |
|
2f9920a…
|
drh
|
594 |
fossil_fatal("Cannot create an in-memory database: %s", |
|
2f9920a…
|
drh
|
595 |
sqlite3_errmsg(db)); |
|
2f9920a…
|
drh
|
596 |
} |
|
2a387c9…
|
drh
|
597 |
zSql = mprintf("SELECT name, mode, sz, data, mtime FROM sqlar" |
|
2f9920a…
|
drh
|
598 |
" WHERE name GLOB '%q*'", zDest); |
|
2f9920a…
|
drh
|
599 |
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); |
|
2f9920a…
|
drh
|
600 |
fossil_free(zSql); |
|
2f9920a…
|
drh
|
601 |
if( rc!=0 ){ |
|
2f9920a…
|
drh
|
602 |
fossil_fatal("SQL error: %s\n", sqlite3_errmsg(db)); |
|
2f9920a…
|
drh
|
603 |
} |
|
2f9920a…
|
drh
|
604 |
blob_init(&file, 0, 0); |
|
2f9920a…
|
drh
|
605 |
while( sqlite3_step(pStmt)==SQLITE_ROW ){ |
|
2f9920a…
|
drh
|
606 |
const char *zFilename = (const char*)sqlite3_column_text(pStmt, 0); |
|
2f9920a…
|
drh
|
607 |
int mode = sqlite3_column_int(pStmt, 1); |
|
2f9920a…
|
drh
|
608 |
int sz = sqlite3_column_int(pStmt, 2); |
|
2f9920a…
|
drh
|
609 |
if( bList ){ |
|
2f9920a…
|
drh
|
610 |
fossil_print("%s\n", zFilename); |
|
2f9920a…
|
drh
|
611 |
}else if( mode & 0x4000 ){ |
|
2f9920a…
|
drh
|
612 |
/* A directory name */ |
|
2f9920a…
|
drh
|
613 |
nDir++; |
|
2f9920a…
|
drh
|
614 |
file_mkdir(zFilename, ExtFILE, 1); |
|
2f9920a…
|
drh
|
615 |
}else{ |
|
2f9920a…
|
drh
|
616 |
/* A file */ |
|
2f9920a…
|
drh
|
617 |
unsigned char *inBuf = (unsigned char*)sqlite3_column_blob(pStmt,3); |
|
2f9920a…
|
drh
|
618 |
unsigned int nIn = (unsigned int)sqlite3_column_bytes(pStmt,3); |
|
2f9920a…
|
drh
|
619 |
unsigned long int nOut2 = (unsigned long int)sz; |
|
2f9920a…
|
drh
|
620 |
nFile++; |
|
2f9920a…
|
drh
|
621 |
nByte += sz; |
|
2f9920a…
|
drh
|
622 |
blob_resize(&file, sz); |
|
2f9920a…
|
drh
|
623 |
if( nIn<sz ){ |
|
2f9920a…
|
drh
|
624 |
rc = uncompress((unsigned char*)blob_buffer(&file), &nOut2, |
|
2f9920a…
|
drh
|
625 |
inBuf, nIn); |
|
2f9920a…
|
drh
|
626 |
if( rc!=Z_OK ){ |
|
2f9920a…
|
drh
|
627 |
fossil_fatal("Failed to uncompress file %s", zFilename); |
|
2f9920a…
|
drh
|
628 |
} |
|
2f9920a…
|
drh
|
629 |
}else{ |
|
2f9920a…
|
drh
|
630 |
memcpy(blob_buffer(&file), inBuf, sz); |
|
2f9920a…
|
drh
|
631 |
} |
|
2f9920a…
|
drh
|
632 |
blob_write_to_file(&file, zFilename); |
|
2f9920a…
|
drh
|
633 |
if( mode & 0x40 ){ |
|
2f9920a…
|
drh
|
634 |
file_setexe(zFilename, 1); |
|
2f9920a…
|
drh
|
635 |
} |
|
2f9920a…
|
drh
|
636 |
blob_zero(&file); |
|
2a387c9…
|
drh
|
637 |
file_set_mtime(zFilename, sqlite3_column_int64(pStmt,4)); |
|
2f9920a…
|
drh
|
638 |
if( bVerbose ){ |
|
2f9920a…
|
drh
|
639 |
fossil_print("%s\n", zFilename); |
|
2f9920a…
|
drh
|
640 |
} |
|
2f9920a…
|
drh
|
641 |
} |
|
2f9920a…
|
drh
|
642 |
} |
|
2f9920a…
|
drh
|
643 |
sqlite3_finalize(pStmt); |
|
2f9920a…
|
drh
|
644 |
sqlite3_close(db); |
|
2f9920a…
|
drh
|
645 |
blob_zero(&out); |
|
2f9920a…
|
drh
|
646 |
if( !bVerbose && !bQuiet && nFile>0 && zDest ){ |
|
2f9920a…
|
drh
|
647 |
fossil_print("%d files (%,lld bytes) written into %s", |
|
2f9920a…
|
drh
|
648 |
nFile, nByte, zDest); |
|
2f9920a…
|
drh
|
649 |
if( nDir>1 ){ |
|
2f9920a…
|
drh
|
650 |
fossil_print(" and %d subdirectories\n", nDir-1); |
|
2f9920a…
|
drh
|
651 |
}else{ |
|
2f9920a…
|
drh
|
652 |
fossil_print("\n"); |
|
2f9920a…
|
drh
|
653 |
} |
|
2f9920a…
|
drh
|
654 |
} |
|
dbda8d6…
|
drh
|
655 |
} |