156 } else if(!strcasecmp(cmd, "get")) { |
157 } else if(!strcasecmp(cmd, "get")) { |
157 ret = cmd_get(args, FALSE); |
158 ret = cmd_get(args, FALSE); |
158 } else if(!strcasecmp(cmd, "cat")) { |
159 } else if(!strcasecmp(cmd, "cat")) { |
159 ucx_map_cstr_put(args->options, "output", "-"); |
160 ucx_map_cstr_put(args->options, "output", "-"); |
160 ret = cmd_get(args, FALSE); |
161 ret = cmd_get(args, FALSE); |
|
162 } else if(!strcasecmp(cmd, "edit")) { |
|
163 ret = cmd_edit(args); |
161 } else if(!strcasecmp(cmd, "put")) { |
164 } else if(!strcasecmp(cmd, "put")) { |
162 ret = cmd_put(args, FALSE); |
165 ret = cmd_put(args, FALSE); |
163 } else if( |
166 } else if( |
164 !strcasecmp(cmd, "remove") || |
167 !strcasecmp(cmd, "remove") || |
165 !strcasecmp(cmd, "rm") || |
168 !strcasecmp(cmd, "rm") || |
245 |
248 |
246 static char *cmdusageinfo[] = { |
249 static char *cmdusageinfo[] = { |
247 "list [-altdepcR] [-u <date>] <url>", |
250 "list [-altdepcR] [-u <date>] <url>", |
248 "get [-pcRK] [-o <file>] [-u <date>] [-V <version>] <url>", |
251 "get [-pcRK] [-o <file>] [-u <date>] [-V <version>] <url>", |
249 "put [-pcR] [-k <key>] [-L <lock>] <url> <file...>", |
252 "put [-pcR] [-k <key>] [-L <lock>] <url> <file...>", |
|
253 "edit [-V <version>] <url>", |
250 "mkdir [-pc] [-k <key>] [-L <lock>] <url> [file...]", |
254 "mkdir [-pc] [-k <key>] [-L <lock>] <url> [file...]", |
251 "remove [-pc] [-L <lock>] <url> [file...]", |
255 "remove [-pc] [-L <lock>] <url> [file...]", |
252 "copy [-pcO] [-L <lock>] <url> <url>", |
256 "copy [-pcO] [-L <lock>] <url> <url>", |
253 "move [-pcO] [-L <lock>] <url> <url>", |
257 "move [-pcO] [-L <lock>] <url> <url>", |
254 "rename [-pcO] [-L <lock>] <url> <name>", |
258 "rename [-pcO] [-L <lock>] <url> <name>", |
1113 fclose(pdata.out); |
1117 fclose(pdata.out); |
1114 } |
1118 } |
1115 return ret; |
1119 return ret; |
1116 } |
1120 } |
1117 |
1121 |
|
1122 static int file_seek(FILE *f, curl_off_t offset, int origin) { |
|
1123 int ret = fseek(f, offset, origin); |
|
1124 return ret == 0 ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_CANTSEEK; |
|
1125 } |
|
1126 |
|
1127 int cmd_edit(CmdArgs *a) { |
|
1128 if(a->argc != 1) { |
|
1129 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few":"many"); |
|
1130 fprintf(stderr, "Usage: dav %s\n", find_usage_str("edit")); |
|
1131 return -1; |
|
1132 } |
|
1133 |
|
1134 char *url = a->argv[0]; |
|
1135 char *path = NULL; |
|
1136 Repository *repo = url2repo(url, &path); |
|
1137 DavSession *sn = connect_to_repo(repo, path, a); |
|
1138 |
|
1139 if(set_session_config(sn, a)) { |
|
1140 return -1; |
|
1141 } |
|
1142 |
|
1143 char *version = cmd_getoption(a, "version"); |
|
1144 DavResource *res; |
|
1145 |
|
1146 res = dav_resource_new(sn, path); |
|
1147 int fresh_resource = !dav_exists(res); |
|
1148 if(fresh_resource) { |
|
1149 // create the resource to check if the resource can be created |
|
1150 // we don't want the user to invest time in editing and fail afterwards |
|
1151 if(dav_create(res)) { |
|
1152 fprintf(stderr, "Resource does not exist and cannot be created.\n"); |
|
1153 return -1; |
|
1154 } |
|
1155 } else { |
|
1156 if(!res) { |
|
1157 print_resource_error(sn, path); |
|
1158 return -1; |
|
1159 } |
|
1160 if(res->iscollection) { |
|
1161 fprintf(stderr, "Resource %s is a collection " |
|
1162 "and cannot be opened in an editor.\n", res->path); |
|
1163 return -1; |
|
1164 } |
|
1165 |
|
1166 if(version) { |
|
1167 DavResource *vres = find_version(res, version); |
|
1168 if(!vres) { |
|
1169 fprintf(stderr, "Cannot find version '%s' for resource.\n", version); |
|
1170 return -1; |
|
1171 } |
|
1172 dav_resource_free_all(res); |
|
1173 res = vres; |
|
1174 } |
|
1175 } |
|
1176 |
|
1177 // open temporary file |
|
1178 // TODO: look up the location of the temp directory, maybe add sys_* funcs |
|
1179 char outfile[24]; |
|
1180 strncpy(outfile, ".dav-edit-XXXXXX", 24); |
|
1181 int tmp_fd = mkstemp(outfile); |
|
1182 if(tmp_fd < 0) { |
|
1183 perror("Cannot open temporary file"); |
|
1184 return -1; |
|
1185 } |
|
1186 |
|
1187 // get resource |
|
1188 if(!fresh_resource) { |
|
1189 FILE* tmp_stream = sys_fopen(outfile, "wb"); |
|
1190 if(!tmp_stream) { |
|
1191 perror("Cannot open temporary file"); |
|
1192 close(tmp_fd); |
|
1193 return -1; |
|
1194 } |
|
1195 if(dav_get_content(res, tmp_stream, (dav_write_func)fwrite)) { |
|
1196 print_resource_error(sn, path); |
|
1197 close(tmp_fd); |
|
1198 unlink(outfile); |
|
1199 return -1; |
|
1200 } |
|
1201 fclose(tmp_stream); |
|
1202 } |
|
1203 |
|
1204 // remember time s.t. we can later check if the file has changed |
|
1205 SYS_STAT tmp_stat; |
|
1206 // TODO: maybe add sys_fstat |
|
1207 if(sys_stat(outfile, &tmp_stat)) { |
|
1208 perror("Cannot stat temporary file"); |
|
1209 close(tmp_fd); |
|
1210 unlink(outfile); |
|
1211 return -1; |
|
1212 } |
|
1213 time_t dl_mtime = tmp_stat.st_mtime; |
|
1214 |
|
1215 // open in editor |
|
1216 char* default_editor = "vi"; |
|
1217 char* editor = getenv("EDITOR"); |
|
1218 if(!editor) editor = default_editor; |
|
1219 char* viargs[3] = {editor, outfile, NULL}; |
|
1220 |
|
1221 int ret = 0; |
|
1222 // TODO: solution for windows |
|
1223 pid_t pid = fork(); |
|
1224 if(pid < 0) { |
|
1225 perror("Cannot create process for editor"); |
|
1226 ret = 1; |
|
1227 } else if(pid == 0) { |
|
1228 if(execvp(viargs[0], viargs)) { |
|
1229 perror("Opening the editor failed"); |
|
1230 return 1; |
|
1231 } |
|
1232 } else { |
|
1233 int status = -1; |
|
1234 ret = waitpid(pid, &status, 0); |
|
1235 if(ret < 0) { |
|
1236 perror("Error waiting for editor"); |
|
1237 } else if(WEXITSTATUS(status)) { |
|
1238 fprintf(stderr, |
|
1239 "Editor closed abnormally - file will not be uploaded.\n"); |
|
1240 ret = 1; |
|
1241 } else { |
|
1242 // check if the file has changed |
|
1243 if (sys_stat(outfile, &tmp_stat)) { |
|
1244 perror("Cannot stat temporary file"); |
|
1245 ret = 1; |
|
1246 } else if (dl_mtime < tmp_stat.st_mtime) { |
|
1247 // upload changed file |
|
1248 FILE* tmp_stream = sys_fopen(outfile, "rb"); |
|
1249 if(!tmp_stream) { |
|
1250 perror("Cannot open temporary file"); |
|
1251 close(tmp_fd); |
|
1252 return -1; |
|
1253 } |
|
1254 dav_set_content(res, tmp_stream, |
|
1255 (dav_read_func)fread, |
|
1256 (dav_seek_func)file_seek); |
|
1257 dav_set_content_length(res, tmp_stat.st_size); |
|
1258 ret = dav_store(res); |
|
1259 fclose(tmp_stream); |
|
1260 if(ret) { |
|
1261 print_resource_error(sn, path); |
|
1262 } |
|
1263 } else { |
|
1264 printf("No changes by user - file will not be uploaded.\n"); |
|
1265 } |
|
1266 } |
|
1267 } |
|
1268 |
|
1269 close(tmp_fd); |
|
1270 unlink(outfile); |
|
1271 free(path); |
|
1272 |
|
1273 return ret; |
|
1274 } |
|
1275 |
1118 int get_resource(Repository *repo, GetResource *getres, CmdArgs *a, void *unused) { |
1276 int get_resource(Repository *repo, GetResource *getres, CmdArgs *a, void *unused) { |
1119 DavResource *res = getres->res; |
1277 DavResource *res = getres->res; |
1120 char *out = getres->path; |
1278 char *out = getres->path; |
1121 |
1279 |
1122 if(res->iscollection) { |
1280 if(res->iscollection) { |