1 /*
2  * ME3D 3-D Modeler Program
3  * Copyright (C) 1998 Sam Revitch
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  */
19 
20 /* file utility functions */
21 
22 /* (this program was written with basic portability in mind) */
23 
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <sys/mman.h>
32 #include <stdarg.h>
33 
34 #include "file_utils.h"
35 
36 #ifdef MEMWATCH
37 #include "memwatch.h"
38 #endif
39 
40 
41 gint fu_pointers_equal(gconstpointer p1, gconstpointer p2);
42 
fu_pointers_equal(gconstpointer p1,gconstpointer p2)43 gint fu_pointers_equal(gconstpointer p1, gconstpointer p2)
44 { if(p1 == p2) return TRUE; return FALSE; }
45 
46 
fu_open(const gchar * name,gint create)47 struct fu_file *fu_open(const gchar *name, gint create)
48 {
49   struct fu_file *file;
50   int fd;
51 
52   g_return_val_if_fail(name != NULL, NULL);
53 
54   if(create)
55     fd = open(name, O_RDWR | O_CREAT, 0644);
56   else
57     fd = open(name, O_RDONLY);
58 
59   if(fd == -1)
60     return NULL;
61 
62   file = (struct fu_file*) malloc(sizeof(struct fu_file));
63   file->fd = fd;
64 
65 
66   if(create)
67     file->fp = fdopen( fd, "a+" );
68   else
69     file->fp = fdopen( fd, "r" );
70 
71   if( file->fp == NULL ) {
72       printf( "%s: fdopen failed.  errno is %i\n", __FUNCTION__, errno );
73       if( errno == EINVAL )
74           printf( "\terrno is EINVAL - invalid 'mode' arg\n" );
75   }
76 
77 
78   file->len_ht = g_hash_table_new(g_direct_hash, fu_pointers_equal);
79   return file;
80 }
81 
fu_close(struct fu_file * file)82 void fu_close(struct fu_file *file)
83 {
84   g_return_if_fail(file != NULL);
85 
86   fflush( file->fp );
87   close(file->fd);
88 
89   g_hash_table_destroy(file->len_ht);
90   free(file);
91 }
92 
fu_file_size(struct fu_file * file)93 guint fu_file_size(struct fu_file *file)
94 {
95   struct stat fu_stat;
96 
97   g_return_val_if_fail(file != NULL, 0);
98   fstat(file->fd, &fu_stat);
99   return fu_stat.st_size;
100 }
101 
fu_map_block(struct fu_file * file,guint start,guint len)102 guchar *fu_map_block(struct fu_file *file, guint start, guint len)
103 {
104   guchar *r;
105 
106   g_return_val_if_fail(file != NULL, NULL);
107   r = (guchar*) mmap(NULL, (size_t)len, PROT_READ,
108 		     MAP_PRIVATE, file->fd, (off_t)start);
109   g_return_val_if_fail(r != (guchar*) -1, NULL);
110 
111   g_hash_table_insert(file->len_ht, r, (gpointer)len);
112   return r;
113 }
114 
fu_unmap_block(struct fu_file * file,guchar * block)115 void fu_unmap_block(struct fu_file *file, guchar *block)
116 {
117   gpointer tmp;
118   guint len;
119 
120   g_return_if_fail(file != NULL);
121 
122   /* just doing some casting, to silence compiler warnings */
123   tmp = g_hash_table_lookup(file->len_ht, block);
124   len = (guint)tmp;
125   g_return_if_fail(len != 0);
126 
127   g_hash_table_remove(file->len_ht, block);
128   munmap(block, len);
129 }
130 
fu_write_block(struct fu_file * file,guchar * block,guint len)131 void fu_write_block(struct fu_file *file, guchar *block, guint len)
132 {
133   g_return_if_fail(file != NULL);
134 
135   write(file->fd, block, (size_t)len);
136 }
137 
fu_truncate(struct fu_file * file,guint size)138 void fu_truncate(struct fu_file *file, guint size)
139 {
140   g_return_if_fail(file != NULL);
141 
142   ftruncate(file->fd, size);
143 }
144 
fu_seek(struct fu_file * file,gint pos)145 void fu_seek(struct fu_file *file, gint pos)
146 {
147   g_return_if_fail(file != NULL);
148 
149   lseek(file->fd, (off_t) pos, SEEK_SET);
150 }
151 
fu_gets(struct fu_file * file,gchar * buf,guint len)152 gint fu_gets(struct fu_file *file, gchar *buf, guint len)
153 {
154   guint pos = 0;
155   off_t offset;
156 
157   g_return_val_if_fail(file != NULL, 0);
158   g_return_val_if_fail(buf != NULL, 0);
159   g_return_val_if_fail(len > 0, 0);
160 
161   offset = lseek(file->fd, 0, SEEK_CUR);
162 
163   /* this is a cool yet inefficient one */
164   pos = read(file->fd, buf, len);
165   if(pos <= 0)
166     return -1;
167 
168   if(pos < len)
169     len = pos;
170 
171   pos = 0;
172   while(pos < len)
173   {
174     if(buf[pos] == '\n') {
175       buf[pos] = '\0';
176       lseek(file->fd, (off_t) (offset + pos + 1), SEEK_SET);
177       return pos;
178     }
179     pos++;
180   }
181 
182   buf[len - 1] = '\0';
183   return (len - 1);
184 }
185 
fu_puts(struct fu_file * file,gchar * src)186 gint fu_puts(struct fu_file *file, gchar *src)
187 {
188   gint len;
189 
190   g_return_val_if_fail(file != NULL, 0);
191 
192   len = strlen(src);
193   return (gint) write(file->fd, src, len);
194 }
195 
fu_printf(struct fu_file * file,gchar * fmt,...)196 gint fu_printf(struct fu_file *file, gchar *fmt, ...)
197 {
198   va_list ap;
199   gchar buf[1024];		/* bigger is better */
200   gint length;
201 
202   g_return_val_if_fail(file != NULL, 0);
203 
204   va_start(ap, fmt);
205   length = vsnprintf(buf, 1024, fmt, ap);
206 
207   return (gint) write(file->fd, buf, length);
208 }
209