3 * Thorsten Glaser <tg@mirbsd.org>
5 * Provided that these terms and disclaimer and all copyright notices
6 * are retained or reproduced in an accompanying document, permission
7 * is granted to deal in this work without restriction, including un-
8 * limited rights to use, publicly perform, distribute, sell, modify,
9 * merge, give away, or sublicence.
11 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
12 * the utmost extent permitted by applicable law, neither express nor
13 * implied; without malicious intent or gross negligence. In no event
14 * may a licensor, author or contributor be held liable for indirect,
15 * direct, other damage, loss, or other issues arising in any way out
16 * of dealing in the work, even if advised of the possibility of such
17 * damage or existence of a defect, except proven that it results out
18 * of said person's immediate fault when using the work as intended.
20 * Download a ,v file from the repository
33 #define MAP_FAILED ((void *)-1)
37 static const char * const suck_usage[] = {
38 "Usage: %s %s module/filename\n",
43 suck(int argc, char *argv[])
56 if (current_parsed_root->isremote) {
59 if (!supported_request("suck"))
60 error(1, 0, "server does not support %s", "suck");
63 send_to_server("suck\012", 0);
65 return (get_responses_and_close());
69 /* check for ../ attack */
70 if (pathname_levels(argv[1]) > 0)
71 error(1, 0, "path %s outside of repository", argv[1]);
73 /* repo + / + module/file */
74 cp = Xasprintf("%s/%s", current_parsed_root->directory, argv[1]);
77 if ((fn = cp + (last_component(cp) - cp)) == cp)
80 /* repo/module + file */
83 /* check if it's a valid RCS file, not /etc/passwd or somesuch */
84 if ((rcs = RCS_parse(fn, cp)) == NULL) {
85 error(1, 0, "not a valid RCS file: %s/%s", cp, fn);
89 /* save the real pathname of the RCS file for later */
90 fn = xstrdup(rcs->path);
92 /* free up resources allocated until now */
96 /* attempt to open the file ourselves */
97 if ((fp = CVS_FOPEN(fn, FOPEN_BINARY_READ)) == NULL)
98 error(1, errno, "Could not open RCS archive %s", fn);
99 if (fstat(fd = fileno(fp), &sb) < 0)
100 error(1, errno, "Could not stat RCS archive %s", fn);
102 /*XXX this code will fail for large files */
104 /* attempt to slurp entire file into memory */
106 buf = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
107 if (buf == NULL || buf == MAP_FAILED) {
108 error(0, errno, "Could not map memory to RCS archive %s", fn);
110 /* backup: just read */
111 cp = buf = xmalloc(n = sb.st_size);
116 "Could not read RCS archive %s", fn);
124 /* write real pathname plus newline as text */
125 cvs_output(fn + strlen(current_parsed_root->directory) + 1, 0);
128 /* write file content as binary */
129 cvs_output_binary(buf, sb.st_size);
131 /* release all resources allocated */
133 munmap(buf, sb.st_size);