]> mj.ucw.cz Git - libucw.git/blob - ucw/fb-temp.c
4d924d504928fc10b0a9c3d83947f8c3349dca6d
[libucw.git] / ucw / fb-temp.c
1 /*
2  *      UCW Library -- Temporary Fastbufs
3  *
4  *      (c) 2002--2007 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include "ucw/lib.h"
11 #include "ucw/conf.h"
12 #include "ucw/fastbuf.h"
13 #include "ucw/threads.h"
14
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <sys/fcntl.h>
18 #include <stdlib.h>
19 #include <sys/time.h>
20 #include <errno.h>
21
22 static char *temp_prefix;
23 static int public_dir = 1;
24
25 static struct cf_section temp_config = {
26   CF_ITEMS {
27     CF_STRING("Prefix", &temp_prefix),
28     CF_INT("PublicDir", &public_dir),
29     CF_END
30   }
31 };
32
33 static void CONSTRUCTOR temp_global_init(void)
34 {
35   cf_declare_section("Tempfiles", &temp_config, 0);
36 }
37
38 void
39 temp_file_name(char *name_buf, int *open_flags)
40 {
41   char *prefix;
42   int free_prefix = 0;
43   if (temp_prefix)
44     prefix = temp_prefix;
45   else
46     {
47       char *env = getenv("TMPDIR");
48       if (env)
49         {
50           prefix = xmalloc(strlen(env) + 6);
51           sprintf(prefix, "%s/temp", env);
52           free_prefix = 1;
53         }
54       else
55         prefix = "/tmp/temp";
56     }
57   if (public_dir)
58     {
59       struct timeval tv;
60       if (gettimeofday(&tv, NULL))
61         die("Could not generate temp file name: %m");
62       sprintf(name_buf, "%s-%u", prefix, (uns) tv.tv_usec);
63       if (open_flags)
64         *open_flags = O_EXCL;
65     }
66   else
67     {
68       struct ucwlib_context *ctx = ucwlib_thread_context();
69       int cnt = ++ctx->temp_counter;
70       int pid = getpid();
71       if (ctx->thread_id == pid)
72         sprintf(name_buf, "%s%d-%d", temp_prefix, pid, cnt);
73       else
74         sprintf(name_buf, "%s%d-%d-%d", temp_prefix, pid, ctx->thread_id, cnt);
75       if (open_flags)
76         *open_flags = 0;
77     }
78   if (free_prefix)
79     xfree(prefix);
80 }
81
82 struct fastbuf *
83 bopen_tmp_file(struct fb_params *params)
84 {
85   char name[TEMP_FILE_NAME_LEN];
86   int fd = open_tmp(name, O_RDWR | O_CREAT | O_TRUNC, 0600);
87   struct fastbuf *fb = bopen_fd_name(fd, params, name);
88   bconfig(fb, BCONFIG_IS_TEMP_FILE, 1);
89   return fb;
90 }
91
92 int
93 open_tmp(char *name_buf, int open_flags, int mode)
94 {
95   int create_flags, fd, retry = 10;
96   do
97     {
98       temp_file_name(name_buf, &create_flags);
99       fd = open(name_buf, open_flags | create_flags, mode);
100     }
101   while (fd < 0 && errno == EEXIST && retry --);
102   if (fd < 0)
103     die("Unable to create temp file %s: %m", name_buf);
104   return fd;
105 }
106
107 struct fastbuf *
108 bopen_tmp(uns buflen)
109 {
110   return bopen_tmp_file(&(struct fb_params){ .type = FB_STD, .buffer_size = buflen });
111 }
112
113 void bfix_tmp_file(struct fastbuf *fb, const char *name)
114 {
115   int was_temp = bconfig(fb, BCONFIG_IS_TEMP_FILE, 0);
116   ASSERT(was_temp == 1);
117   if (rename(fb->name, name))
118     die("Cannot rename %s to %s: %m", fb->name, name);
119   bclose(fb);
120 }
121
122 #ifdef TEST
123
124 #include "ucw/getopt.h"
125
126 int main(int argc, char **argv)
127 {
128   log_init(NULL);
129   if (cf_getopt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) >= 0)
130     die("Hey, whaddya want?");
131
132   struct fastbuf *f = bopen_tmp(65536);
133   bputsn(f, "Hello, world!");
134   bclose(f);
135   return 0;
136 }
137
138 #endif