13 |
#include <h/tws.h> |
#include <h/tws.h> |
14 |
#include <fcntl.h> |
#include <fcntl.h> |
15 |
#include <errno.h> |
#include <errno.h> |
16 |
|
#include <utime.h> |
17 |
|
|
18 |
|
|
19 |
/* |
/* |
21 |
*/ |
*/ |
22 |
static int annosbr (int, char *, char *, char *, int, int, int, int); |
static int annosbr (int, char *, char *, char *, int, int, int, int); |
23 |
|
|
24 |
|
/* |
25 |
|
* This "local" global and the annopreserve() function are a hack that allows additional |
26 |
|
* functionality to be added to anno without piling on yet another annotate() argument. |
27 |
|
*/ |
28 |
|
|
29 |
|
static int preserve_actime_and_modtime = 0; /* set to preserve access and modification times on annotated message */ |
30 |
|
|
31 |
int |
int |
32 |
annotate (char *file, char *comp, char *text, int inplace, int datesw, int delete, int append) |
annotate (char *file, char *comp, char *text, int inplace, int datesw, int delete, int append) |
33 |
{ |
{ |
34 |
int i, fd; |
int i, fd; |
35 |
|
struct utimbuf b; |
36 |
|
struct stat s; |
37 |
|
|
38 |
/* open and lock the file to be annotated */ |
/* open and lock the file to be annotated */ |
39 |
if ((fd = lkopen (file, O_RDWR, 0)) == NOTOK) { |
if ((fd = lkopen (file, O_RDWR, 0)) == NOTOK) { |
48 |
return 1; |
return 1; |
49 |
} |
} |
50 |
|
|
51 |
|
if (stat(file, &s) == -1) { |
52 |
|
advise("can't get access and modification times for %s", file); |
53 |
|
preserve_actime_and_modtime = 0; |
54 |
|
} |
55 |
|
|
56 |
|
b.actime = s.st_atime; |
57 |
|
b.modtime = s.st_mtime; |
58 |
|
|
59 |
i = annosbr (fd, file, comp, text, inplace, datesw, delete, append); |
i = annosbr (fd, file, comp, text, inplace, datesw, delete, append); |
60 |
|
|
61 |
|
if (preserve_actime_and_modtime && utime(file, &b) == -1) |
62 |
|
advise("can't set access and modification times for %s", file); |
63 |
|
|
64 |
lkclose (fd, file); |
lkclose (fd, file); |
65 |
return i; |
return i; |
66 |
} |
} |
159 |
return; |
return; |
160 |
} |
} |
161 |
|
|
162 |
|
/* |
163 |
|
* Set the preserve-times flag. This hack eliminates the need for an additional argument to annotate(). |
164 |
|
*/ |
165 |
|
|
166 |
|
void |
167 |
|
annopreserve(int preserve) |
168 |
|
{ |
169 |
|
preserve_actime_and_modtime = preserve; |
170 |
|
return; |
171 |
|
} |
172 |
|
|
173 |
static int |
static int |
174 |
annosbr (int fd, char *file, char *comp, char *text, int inplace, int datesw, int delete, int append) |
annosbr (int fd, char *file, char *comp, char *text, int inplace, int datesw, int delete, int append) |
204 |
* as they're read in. This buffer is grown as needed later. |
* as they're read in. This buffer is grown as needed later. |
205 |
*/ |
*/ |
206 |
|
|
207 |
if (delete >= 0 || append != 0) { |
if (delete >= -1 || append != 0) { |
208 |
if ((fp = fdopen(fd, "r")) == (FILE *)0) |
if ((fp = fdopen(fd, "r")) == (FILE *)0) |
209 |
adios(NULL, "unable to fdopen file."); |
adios(NULL, "unable to fdopen file."); |
210 |
|
|
214 |
|
|
215 |
/* |
/* |
216 |
* We're trying to delete a header field (annotation )if the delete flag is |
* We're trying to delete a header field (annotation )if the delete flag is |
217 |
* non-negative. A value greater than zero means that we're deleting the |
* not -2 or less. A value greater than zero means that we're deleting the |
218 |
* nth header field that matches the field (component) name. A value of |
* nth header field that matches the field (component) name. A value of |
219 |
* zero means that we're deleting the first field in which both the field |
* zero means that we're deleting the first field in which both the field |
220 |
* name matches the component name and the field body matches the text. |
* name matches the component name and the field body matches the text. |
223 |
* the last slash. This allows matching of both absolute and relative path |
* the last slash. This allows matching of both absolute and relative path |
224 |
* names. This is because this functionality was added to support attachments. |
* names. This is because this functionality was added to support attachments. |
225 |
* It might be worth having a separate flag to indicate path name matching to |
* It might be worth having a separate flag to indicate path name matching to |
226 |
* make it more general. |
* make it more general. A value of -1 means to delete all matching fields. |
227 |
*/ |
*/ |
228 |
|
|
229 |
if (delete >= 0) { |
if (delete >= -1) { |
230 |
/* |
/* |
231 |
* Get the length of the field name since we use it often. |
* Get the length of the field name since we use it often. |
232 |
*/ |
*/ |
265 |
if (++n >= field_size - 1) { |
if (++n >= field_size - 1) { |
266 |
if ((field = (char *)realloc((void *)field, field_size *= 2)) == (char *)0) |
if ((field = (char *)realloc((void *)field, field_size *= 2)) == (char *)0) |
267 |
adios(NULL, "can't grow field buffer."); |
adios(NULL, "can't grow field buffer."); |
268 |
|
|
269 |
cp = field + n - 1; |
cp = field + n - 1; |
270 |
} |
} |
271 |
} |
} |
291 |
* field, the text does not begin with a / meaning that we're looking for the |
* field, the text does not begin with a / meaning that we're looking for the |
292 |
* last path name component, and the last path name component matches the text. |
* last path name component, and the last path name component matches the text. |
293 |
* |
* |
294 |
* o The delete flag is non-zero meaning that we're going to delete the nth field |
* o The delete flag is positive meaning that we're going to delete the nth field |
295 |
* with a matching field name, and this is the nth matching field name. |
* with a matching field name, and this is the nth matching field name. |
296 |
|
* |
297 |
|
* o The delete flag is -1 meaning that we're going to delete all fields with a |
298 |
|
* matching field name. |
299 |
*/ |
*/ |
300 |
|
|
301 |
if (strncasecmp(field, comp, length) == 0 && field[length] == ':') { |
if (strncasecmp(field, comp, length) == 0 && field[length] == ':') { |
319 |
} |
} |
320 |
} |
} |
321 |
|
|
322 |
|
else if (delete == -1) |
323 |
|
continue; |
324 |
|
|
325 |
else if (++count == delete) |
else if (++count == delete) |
326 |
break; |
break; |
327 |
} |
} |
345 |
else { |
else { |
346 |
/* |
/* |
347 |
* Find the end of the headers before adding the annotations if we're |
* Find the end of the headers before adding the annotations if we're |
348 |
* appending instead of the default prepending. |
* appending instead of the default prepending. A special check for |
349 |
|
* no headers is needed if appending. |
350 |
*/ |
*/ |
351 |
|
|
352 |
if (append) { |
if (append) { |
355 |
* reach the end of the headers. |
* reach the end of the headers. |
356 |
*/ |
*/ |
357 |
|
|
358 |
while ((c = getc(fp)) != EOF) { |
if ((c = getc(fp)) == '\n') |
359 |
(void)putc(c, tmp); |
rewind(fp); |
360 |
|
|
361 |
if (c == '\n') { |
else { |
362 |
(void)ungetc(c = getc(fp), fp); |
(void)putc(c, tmp); |
363 |
|
|
364 |
if (c == '\n' || c == '-') |
while ((c = getc(fp)) != EOF) { |
365 |
break; |
(void)putc(c, tmp); |
366 |
|
|
367 |
|
if (c == '\n') { |
368 |
|
(void)ungetc(c = getc(fp), fp); |
369 |
|
|
370 |
|
if (c == '\n' || c == '-') |
371 |
|
break; |
372 |
|
} |
373 |
} |
} |
374 |
} |
} |
375 |
} |
} |
399 |
* copying routine uses the descriptor, not the pointer. |
* copying routine uses the descriptor, not the pointer. |
400 |
*/ |
*/ |
401 |
|
|
402 |
if (append || delete >= 0) { |
if (append || delete >= -1) { |
403 |
if (lseek(fd, (off_t)ftell(fp), SEEK_SET) == (off_t)-1) |
if (lseek(fd, (off_t)ftell(fp), SEEK_SET) == (off_t)-1) |
404 |
adios(NULL, "can't seek."); |
adios(NULL, "can't seek."); |
405 |
} |
} |
418 |
* so the file has to be truncated or it will contain garbage. |
* so the file has to be truncated or it will contain garbage. |
419 |
*/ |
*/ |
420 |
|
|
421 |
if (delete >= 0 && ftruncate(fd, 0) == -1) |
if (delete >= -1 && ftruncate(fd, 0) == -1) |
422 |
adios(tmpfil, "unable to truncate."); |
adios(tmpfil, "unable to truncate."); |
423 |
|
|
424 |
cpydata (tmpfd, fd, tmpfil, file); |
cpydata (tmpfd, fd, tmpfil, file); |
450 |
* lkclose() fail, but that failure is ignored so it's not a problem. |
* lkclose() fail, but that failure is ignored so it's not a problem. |
451 |
*/ |
*/ |
452 |
|
|
453 |
if (delete >= 0) |
if (delete >= -1) |
454 |
(void)fclose(fp); |
(void)fclose(fp); |
455 |
|
|
456 |
return 0; |
return 0; |