File: form-file.c

package info (click to toggle)
netrik 1.16.1-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,288 kB
  • sloc: ansic: 6,657; sh: 994; makefile: 120
file content (208 lines) | stat: -rw-r--r-- 4,644 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
   netrik -- The ANTRIK Internet Viewer
   Copyright (C) Olaf D. Buddenhagen AKA antrik, et al (see AUTHORS)
   Published under the GNU GPL; see LICENSE for details.
*/

/*
 * form-file.c -- file handling for "textarea" and "file" form controls
 *
 * (C) 2003 antrik
 */

#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "form-file.h"

enum File_err {
   ERR_NO=0,
   ERR_OPEN,
   ERR_SIZE,
   ERR_READ
};

static enum File_err read_file(const char *file_name, struct Data_string *value);

/* 
 * Read file into memory.
 *
 * The file file_named "file_name" is opened and its content read into a newly
 * malloced buffer; this buffer is stored in the "value" data string.
 *
 * If some error occured while reading the file, an appropriate error code is
 * returned.
 */

static enum File_err read_file(file_name, value)
const char		*file_name;
struct Data_string	*value;
{
   int		fildes;
   struct stat	stat_buf;

   int		size;
   char		*data;

   fildes=open(file_name, O_RDONLY);
   if(fildes==-1) {
      unlink(file_name);
      return ERR_OPEN;
   }

   if(fstat(fildes, &stat_buf)==-1) {
      close(fildes);
      unlink(file_name);
      return ERR_SIZE;
   }
   size=stat_buf.st_size;

   data=malloc(size);
   if(read(fildes, data, size)!=size) {
      close(fildes);
      unlink(file_name);
      free(data);
      return ERR_READ;
   }

   close(fildes);

   /* store new data */
   free(value->data);
   value->data=data;
   value->size=size;

   return ERR_NO;
}    /* read file */

/*
 * Use external editor to edit the value of a "textarea" form input field.
 *
 * Creates a temporary file with the old contents of the input field, launches
 * editor on that file, and reads new contents back.
 *
 * If some error occured in the system calls, a string describing the error is
 * returned; NULL means no error.
 */

char *edit_textarea(value, name)
struct Data_string	*value;
char			*name;
{
   /* external editor to use */
   char	*editor;
   editor=getenv("EDITOR");
   if(editor==NULL)
      editor="vi";

   if(!name)
      name="";

   /* write file/edit/read file */
   {
      /* get temp file name */
      static const char	format[]="netrik-textarea-%s-XXXXXX";
      const int		size=sizeof(format)+strlen(name);
      char		temp_name[size];
      snprintf(temp_name, size, format, name);

      /* make sure we get a proper filename */
      {
	 char	*chr;
	 for(chr=temp_name; *chr; ++chr)
	    if(!isalnum(*chr))    /* not safe filename char -> replace */
	       *chr='_';
      }

      /* write temporary file */
      {
	 int	fildes;
	 
	 fildes=mkstemp(temp_name);
	 if(fildes==-1) {
	    return "failed to create temporary file";
	 }

	 if(write(fildes, value->data, value->size)!=value->size) {
	    close(fildes);
	    unlink(temp_name);
	    return "failed to write to temporary file";
	 }

	 if(close(fildes)==-1) {
	    unlink(temp_name);
	    return "failed to close temporary file after writing";
	 }
      }

      /* edit/read file */
      {
	 /* get edit command */
	 static const char	format[]="%s %s";
	 const int		size=sizeof(format)+strlen(temp_name)+strlen(editor);
	 char			edit_cmd[size];
	 snprintf(edit_cmd, size, format, editor, temp_name);

	 /* edit */
	 if(system(edit_cmd)!=0) {
	    unlink(temp_name);
	    return "invoking editor failed";
	 }

	 /* read temporary file */
	 {
	    enum File_err	error;

	    error=read_file(temp_name, value);
	    switch(error) {
	       case ERR_NO: break;
	       case ERR_OPEN: return "failed to reopen temporary file";
	       case ERR_SIZE: return "failed to get file size";
	       case ERR_READ: return "failed to read from temporary file";
	    }
	 }    /* read file */

      }    /* edit/read file */

      unlink(temp_name);
   }    /* write file/edit/read file */

   return NULL;    /* no error */
}

/* 
 * Read a file into memory.
 *
 * The file contents is stored in a data string which is returned to the
 * caller.
 *
 * If some error occured while reading the file, the "size" attribute of the
 * data string is set to -1 to indicate no valid data.
 */

struct Data_string form_read_file(file_name)
const char		*file_name;
{
   struct Data_string	value={NULL, 0};
   enum File_err	error;

   error=read_file(file_name, &value);
   if(error!=ERR_NO) {
      static const char	*err_str[]={
	 "",    /* ERR_NO */
	 "open",
	 "get size of",
	 "read from"
      };
      
      fprintf(stderr, "\n\nfailed to %s file \"%s\" (to be submitted with form)\n", err_str[error], file_name);
      value.size=-1;
   }

   return value;
}