copyout.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9// Author: Jens-S. V?ckler <voeckler@rvs.uni-hannover.de>
10//
11// File: copyout.cc
12// Tue Jun 15 1999
13//
14// (c) 1999 Lehrgebiet Rechnernetze und Verteilte Systeme
15// Universit?t Hannover, Germany
16//
17// Permission to use, copy, modify, distribute, and sell this software
18// and its documentation for any purpose is hereby granted without fee,
19// provided that (i) the above copyright notices and this permission
20// notice appear in all copies of the software and related documentation,
21// and (ii) the names of the Lehrgebiet Rechnernetze und Verteilte
22// Systeme and the University of Hannover may not be used in any
23// advertising or publicity relating to the software without the
24// specific, prior written permission of Lehrgebiet Rechnernetze und
25// Verteilte Systeme and the University of Hannover.
26//
27// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
28// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
29// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
30//
31// IN NO EVENT SHALL THE LEHRGEBIET RECHNERNETZE UND VERTEILTE SYSTEME OR
32// THE UNIVERSITY OF HANNOVER BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
33// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
34// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
35// ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
36// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
37// SOFTWARE.
38//
39// Revision 1.2 1999/06/16 13:05:26 voeckler
40// mmap file copying on Solaris.
41//
42// Revision 1.1 1999/06/15 21:10:47 voeckler
43// Initial revision
44//
45//
46#include "squid.h"
47#include "copyout.hh"
48
49#include <sys/stat.h>
50#include <cerrno>
51#include <cstring>
52#include <fcntl.h>
53#include <unistd.h>
54#include <sys/mman.h>
55
56#ifndef MAP_FILE
57#define MAP_FILE 0
58#endif // MAP_FILE
59
60int
61assert_copydir( const char* copydir )
62// purpose: check, if copydir is a directory and that we can write into it.
63// paramtr: copydir (IN): name of directory for copying bodies.
64// returns: 0 if ok, -1 otherwise.
65// further: errors are handled within. If the directory does not exist,
66// the assertion function will try to create it.
67{
68 struct stat st;
69 int status = stat( copydir, &st );
70
71 // check, if either "copydir" points to a valid directory,
72 // or if copydir can be created.
73 if ( status == 0 && ! S_ISDIR(st.st_mode) ) {
74 // stat() returned true, but did not point to a directory
75 fprintf( stderr, "copy dir \"%s\" is a file!\n", copydir );
76 return -1;
77 } else if ( S_ISDIR(st.st_mode) &&
78 !( (st.st_uid == geteuid() && ( (st.st_mode & S_IWUSR) > 0 )) ||
79 (st.st_gid == getegid() && ( (st.st_mode & S_IWGRP) > 0 )) ||
80 ((st.st_mode & S_IWOTH) > 0) ) ) {
81 fprintf( stderr, "copy dir \"%s\" is not accessible to me\n", copydir );
82 return -1;
83 }
84 if ( status == -1 ) {
85 // stat() returned with an error. 'File not found' is a legal error.
86 if ( errno != ENOENT ) {
87 // not a 'file not found' error, so this is hard error.
88 fprintf( stderr, "accessing copy-out dir \"%s\": %s\n",
89 copydir, strerror(errno) );
90 return -1;
91 } else {
92 // directory does not exist. Try to create it.
93 if ( mkdir( copydir, 0750 ) == -1 ) {
94 fprintf( stderr, "mkdir(%s): %s\n", copydir, strerror(errno) );
95 return -1;
96 }
97 }
98 }
99
100 // postcondition: copydir exists and is a directory.
101 return 0;
102}
103
104inline
105unsigned
106xlate( char ch )
107{
108 if ( ch == '\r' ) return 0u;
109 else if ( ch == '\n' ) return 1u;
110 else return 2u;
111}
112
113// shortcut for monotoneous typings...
114#define BAUTZ(x) delete[] filename; close(input); close(out); return (x)
115
116bool
117copy_out( size_t filesize, size_t metasize, unsigned debug,
118 const char* fn, const char* url, const char* copydir,
119 bool copyHdr )
120// purpose: copy content from squid disk file into separate file
121// paramtr: metasize (IN): size of metadata to skip
122// fn (IN): current filename of squid disk file
123// url (IN): currently looked at URL to generate separate file
124// copydir (IN): base directory where to generate the file
125// copyHdr (IN): copy HTTP header, too, if set to true.
126// returns: true, if successful, false otherwise.
127{
128 static const char* index = "index.html";
129
130 // find hostname part after the scheme (okok, not counting port, etc.)
131 const char* ptr = strstr( url, "://" );
132 if ( ptr == nullptr || strlen(ptr) < 4 ) return false;
133
134 // create filename to store contents into
135 // NP: magic extra 5 bytes for the component delimiter and termination octets
136 char *filename = new char[ strlen(ptr) + strlen(copydir) + strlen(index) +5 ];
137 assert( filename != nullptr );
138 strcpy( filename, copydir );
139 strcat( filename, "/" );
140 char* here = filename + strlen(filename);
141 strcat( filename, ptr+3 );
142
143 // handle server root (e.g. "http://www.focus.de" )
144 if ( strchr( ptr+3, '/' ) == nullptr ) strcat( filename, "/" );
145
146 // handle directories (e.g. "http://www.focus.de/A/" )
147 if ( filename[strlen(filename)-1] == '/' ) strcat( filename, index );
148
149 // create subdirectory structure
150 for ( char* t = strchr(here,'/'); t; t = strchr(t,'/') ) {
151 *t = 0;
152 if ( mkdir( filename, 0775 ) == -1 && errno != EEXIST ) {
153 fprintf( stderr, "mkdir(%s): %s\n", filename, strerror(errno) );
154 delete[] filename;
155 return false;
156 } else if ( debug & 0x02 ) {
157 fprintf( stderr, "# creating %s\n", filename );
158 }
159 *t = '/';
160 ++t;
161 }
162
163 // create file
164 int out = open( filename, O_CREAT | O_RDWR | O_TRUNC, 0664 );
165 if ( out == -1 ) {
166 fprintf( stderr, "open(%s,RDWR): %s\n", filename, strerror(errno) );
167 delete[] filename;
168 return false;
169 } else if ( debug & 0x02 ) {
170 fprintf( stderr, "# creating %s\n", filename );
171 }
172
173 // (re)open cache file
174 int input = open( fn, O_RDONLY );
175 if ( input == -1 ) {
176 fprintf( stderr, "open(%s,RDONLY): %s\n", fn, strerror(errno) );
177 delete[] filename;
178 close(out);
179 return false;
180 }
181
182 // find double CRLF sequence (actually, look at the FSM below)
183 // XXX: this only looks at the already known buffer read previously,
184 // which is globally passed (yuck)! As a limitation, the content data
185 // *must* begin within the buffer size (that is: 16k)!
186 if ( ! copyHdr ) {
187 extern char* linebuffer; // import from purge.cc
188 extern size_t buffersize; // import from purge.cc
189
190 unsigned state = 0;
191 char* s = linebuffer + metasize;
192 while ( s < linebuffer + buffersize && state < 4 ) {
193 // state transition machine
194 static unsigned table[4][3] = { {3,2,0}, {0,4,0}, {1,4,0}, {4,2,0} };
195 // old || \r | \n |else|
196 // =====++====+====+====+
197 // 0 || 3 | 2 | 0 |
198 // 1 || 0 | 4 | 0 |
199 // 2 || 1 | 4 | 0 |
200 // 3 || 4 | 2 | 0 |
201 state = table[ state ][ xlate(*s) ];
202 ++s;
203 }
204
205 if ( state < 4 )
206 // complain bitterly, if the HTTP header was too large ( > 16k ).
207 fprintf( stderr, "WARNING: %s will contain partial HTTP header data!\n",
208 filename );
209
210 // adjust to different seek size
211 metasize = s - linebuffer;
212 }
213
214 // no need to copy zero content files
215 if ( filesize - metasize <= 0 ) {
216 BAUTZ( filesize-metasize == 0 );
217 }
218
219#ifdef USE_REGULAR_COPY
220 // position input at start of server answer (contains HTTP headers)
221 if ( lseek( input, metasize, SEEK_SET ) == -1 ) {
222 fprintf( stderr, "lseek(%s,%lu): %s\n", fn, metasize, strerror(errno) );
223 BAUTZ(false);
224 }
225
226 // file copy input into output via buffer (regular io)
227 char buffer[32768];
228 int rsize, wsize;
229 while ( (rsize=read(input,buffer,sizeof(buffer))) > 0 ) {
230 if ( (wsize=write(out,buffer,rsize)) <= 0 ) break;
231 }
232 if ( rsize < 0 || wsize < 0 ) perror( "while copying" );
233#else // use mmap copy (compare: Stevens APUE 12.9)
234 // precondition: filesize-metasize > 0
235 // seek end of output file ...
236 off_t position = lseek( out, filesize-metasize-1, SEEK_SET );
237 if ( position == -1 ) {
238 fprintf( stderr, "lseek(%s,%lu): %s\n", filename,
239 (unsigned long)filesize-metasize,
240 strerror(errno) );
241 BAUTZ(false);
242 } else if ( debug & 0x02 ) {
243 fprintf( stderr, "# filesize=%lu, metasize=%lu, filepos=%ld\n",
244 (unsigned long)filesize, (unsigned long)metasize,
245 (long)position );
246 }
247
248 // ...and write 1 byte there (create a file that length)
249 if ( write( out, "", 1 ) != 1 ) {
250 perror( "write to output" );
251 BAUTZ(false);
252 }
253
254 // create source mmap to copy from (mmap complete file)
255 const auto src = static_cast<char *>(mmap(nullptr, filesize, PROT_READ, MAP_FILE | MAP_SHARED, input, 0));
256 if (src == reinterpret_cast<const char *>(-1)) {
257 perror( "mmap input" );
258 BAUTZ(false);
259 }
260
261 // create destination mmap to copy into (mmap data portion)
262 auto dst = static_cast<char *>(mmap(nullptr, filesize-metasize, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, out, 0));
263 if (dst == reinterpret_cast<char *>(-1)) {
264 perror( "mmap output" );
265 munmap( src, filesize );
266 BAUTZ(false);
267 }
268
269 // copy file (beware of offset into wanted data, skip meta data)
270 memcpy( dst, src+metasize, filesize-metasize );
271
272 // clean up
273 munmap( dst, filesize-metasize );
274 munmap( src, filesize );
275#endif // USE_REGULAR_COPY
276
277 BAUTZ(true);
278}
279
#define assert(EX)
Definition: assert.h:17
void debug(const char *format,...)
Definition: debug.cc:19
#define MAP_FILE
Definition: copyout.cc:57
unsigned xlate(char ch)
Definition: copyout.cc:106
#define BAUTZ(x)
Definition: copyout.cc:114
int assert_copydir(const char *copydir)
Definition: copyout.cc:61
bool copy_out(size_t filesize, size_t metasize, unsigned debug, const char *fn, const char *url, const char *copydir, bool copyHdr)
Definition: copyout.cc:117
char * linebuffer
Definition: purge.cc:145
static char * copydir
Definition: purge.cc:147
size_t buffersize
Definition: purge.cc:146
char * strerror(int ern)
Definition: strerror.c:22

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors