1 /* vu-utils.c - vu helper functions
2  *
3  ****************************************************************
4  * Copyright (C) 2000 Thomas Lord
5  *
6  * See the file "COPYING" for further information about
7  * the copyright and warranty status of this work.
8  */
9 
10 
11 
12 #include "hackerlab/os/errno.h"
13 #include "hackerlab/mem/must-malloc.h"
14 #include "hackerlab/char/str.h"
15 #include "hackerlab/vu/vu-utils.h"
16 
17 
18 /************************************************************************
19  *(h0 "VU Utilities")
20  *
21  * These functions provide higher-level abstractions that capture common
22  * ways of using the lower-level VU functions.
23  */
24 
25 
26 
27 /*(c vu_file_to_string)
28  * int vu_file_to_string (int * errn,
29  *                        t_uchar ** buf,
30  *                        size_t * len,
31  *                        int fd);
32  *
33  * Read the entire contents of `fd' into a newly allocated string.
34  *
35  * If no error occurs, return 0.  The new string is returned in `*buf';
36  * its length in `*len'.
37  *
38  * If an I/O error occurs, return -1 and fill `*errn'.
39  *
40  * If `vu_fstat' is able to report the length of the file, a single call to
41  * `vu_read_retry' is used to read its contents.  Otherwise, repeated calls
42  * to `vu_read_retry' are used.
43  */
44 int
vu_file_to_string(int * errn,t_uchar ** buf,size_t * len,int fd)45 vu_file_to_string (int * errn,
46 		   t_uchar ** buf,
47 		   size_t * len,
48 		   int fd)
49 {
50   struct stat sb;
51 
52   if (!vu_fstat (errn, fd, &sb))
53     {
54       *buf = (t_uchar *)must_malloc (sb.st_size);
55 
56       if (sb.st_size != vu_read_retry (errn, fd, *buf, sb.st_size))
57 	{
58 	  must_free (*buf);
59 	  return -1;
60 	}
61 
62       *len = sb.st_size;
63       return 0;
64     }
65   else
66     {
67 #define chunk 8192
68       size_t total;
69 
70       *buf = (t_uchar *)must_malloc (chunk);
71       total = 0;
72 
73       while (1)
74 	{
75 	  ssize_t amt;
76 
77 	  amt = vu_read_retry (errn, fd, *buf + total, chunk);
78 	  if (amt < 0)
79 	    {
80 	      must_free (*buf);
81 	      return -1;
82 	    }
83 	  if (amt == 0)
84 	    {
85 	      *buf = (t_uchar *)must_realloc ((void *)*buf, total);
86 	      *len = total;
87 	      return 0;
88 	    }
89           total += amt;
90 	  *buf = (t_uchar *)must_realloc ((void *)*buf, total + chunk);
91 	}
92     }
93 }
94 
95 
96 
97 
98 /*(c vu_move_fd)
99  * int vu_move_fd (int * errn, int fd, int newfd);
100  *
101  * Relocate `fd' to `newfd'.  `fd' must already be handled by VU.
102  *
103  * Thus function performs a `vu_dup' or `vu_dup2'
104  *
105  * This is useful when performing file redirections after `fork' and
106  * before `exec'.
107  *
108  */
109 int
vu_move_fd(int * errn,int fd,int newfd)110 vu_move_fd (int * errn, int fd, int newfd)
111 {
112   int ign;
113 
114   if (fd < 0)
115     {
116       if (errn) *errn = EINVAL;
117       return -1;
118     }
119   if (fd == newfd)
120     return 0;
121 
122   if (newfd == -1)
123     newfd = vu_dup (errn, fd);
124   else
125     newfd = vu_dup2 (errn, fd, newfd);
126 
127   if (newfd < 0)
128     return -1;
129 
130   if (0 > vu_move_state (errn, fd, newfd))
131     {
132       vu_close (&ign, newfd);
133       return -1;
134     }
135 
136   vu_close (&ign, fd);
137   return newfd;
138 }
139 
140 
141 
142 
143 /*(c vu_file_is_directory)
144  * int vu_file_is_directory (int * errn, const t_uchar * name);
145  *
146  * Return 1 if `name' names a directory, 0 if not, -1 on error.
147  *
148  * Non-existence of any file called `name' is not an error.
149  */
150 int
vu_file_is_directory(int * errn,const t_uchar * name)151 vu_file_is_directory (int * errn, const t_uchar * name)
152 {
153   int e;
154   struct stat sb;
155 
156   if (0 > vu_lstat (&e, name, &sb))
157     {
158       if (e == ENOENT)
159 	return 0;
160       if (errn) *errn = e;
161       return -1;
162     }
163 
164   return (S_ISDIR (sb.st_mode));
165 }
166 
167 
168 /*(c vu_file_is_directory_following)
169  * int vu_file_is_directory_following (int * errn, const t_uchar * name);
170  *
171  * Return 1 if `name' names a directory or symlink to a directory,
172  * 0 if not, -1 on error.
173  *
174  * Non-existence of any file called `name' is not an error.
175  */
176 int
vu_file_is_directory_following(int * errn,const t_uchar * name)177 vu_file_is_directory_following (int * errn, const t_uchar * name)
178 {
179   int e;
180   struct stat sb;
181 
182   if (0 > vu_stat (&e, name, &sb))
183     {
184       if (e == ENOENT)
185 	return 0;
186       if (errn) *errn = e;
187       return -1;
188     }
189 
190   return (S_ISDIR (sb.st_mode));
191 }
192