Obsolete option --no-sig-create-check.
[gnupg.git] / util / fileutil.c
1 /* fileutil.c -  file utilities
2  * Copyright (C) 1998, 2003, 2005, 2007 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #ifdef HAVE_PWD_H
29 #include <pwd.h>
30 #endif
31 #include <ctype.h>
32 #ifdef HAVE_W32_SYSTEM
33 # define WIN32_LEAN_AND_MEAN
34 # include <windows.h>
35 #else /*!HAVE_W32_SYSTEM*/
36 # include <sys/types.h>
37 # include <sys/stat.h>
38 # include <unistd.h>
39 #endif /*!HAVE_W32_SYSTEM*/
40
41
42 #include "util.h"
43 #include "memory.h"
44 #include "ttyio.h"
45
46
47 /***************
48  * Extract from a given path the filename component.
49  *
50  */
51 char *
52 make_basename(const char *filepath, const char *inputpath)
53 {
54 #ifdef __riscos__
55     return riscos_make_basename(filepath, inputpath);
56 #endif
57
58     char *p;
59
60     if ( !(p=strrchr(filepath, DIRSEP_C)) )
61 #ifdef HAVE_DRIVE_LETTERS
62         if ( !(p=strrchr(filepath, '\\')) )
63             if ( !(p=strrchr(filepath, ':')) )
64 #endif
65               {
66                 return xstrdup(filepath);
67               }
68
69     return xstrdup(p+1);
70 }
71
72
73
74 /***************
75  * Extract from a given filename the path prepended to it.
76  * If their isn't a path prepended to the filename, a dot
77  * is returned ('.').
78  *
79  */
80 char *
81 make_dirname(const char *filepath)
82 {
83     char *dirname;
84     int  dirname_length;
85     char *p;
86
87     if ( !(p=strrchr(filepath, DIRSEP_C)) )
88 #ifdef HAVE_DRIVE_LETTERS
89         if ( !(p=strrchr(filepath, '\\')) )
90             if ( !(p=strrchr(filepath, ':')) )
91 #endif
92               {
93                 return xstrdup(EXTSEP_S);
94               }
95
96     dirname_length = p-filepath;
97     dirname = xmalloc(dirname_length+1);
98     strncpy(dirname, filepath, dirname_length);
99     dirname[dirname_length] = 0;
100
101     return dirname;
102 }
103
104 /* Expand tildes.  Handles both the ~/foo and ~username/foo cases.
105    Returns what the tilde expands to.  *name is advanced to be past
106    the tilde expansion. */
107 static char *
108 untilde(const char **name)
109 {
110   char *home=NULL;
111
112   assert((*name)[0]=='~');
113
114   if((*name)[1]==DIRSEP_C || (*name)[1]=='\0')
115     {
116       /* This is the "~/foo" or "~" case. */
117       char *tmp=getenv("HOME");
118       if(tmp)
119         home=xstrdup(tmp);
120
121 #ifdef HAVE_GETPWUID
122       if(!home)
123         {
124           struct passwd *pwd;
125
126           pwd=getpwuid(getuid());
127           if(pwd)
128             home=xstrdup(pwd->pw_dir);
129         }
130 #endif
131       if(home)
132         (*name)++;
133     }
134 #ifdef HAVE_GETPWNAM
135   else
136     {
137       /* This is the "~username" case. */
138       char *user,*sep;
139       struct passwd *pwd;
140
141       user=xstrdup((*name)+1);
142
143       sep=strchr(user,DIRSEP_C);
144       if(sep)
145         *sep='\0';
146
147       pwd=getpwnam(user);
148       if(pwd)
149         {
150           home=xstrdup(pwd->pw_dir);
151           (*name)+=1+strlen(user);
152         }
153
154       xfree(user);
155     }
156 #endif
157
158   return home;
159 }
160
161 /*
162   Construct a filename from the NULL terminated list of parts.  Tilde
163   expansion is done here.  Note that FIRST_PART must never be NULL and
164   that this function is guaranteed to return an allocated string.  */
165 char *
166 make_filename( const char *first_part, ... )
167 {
168     va_list arg_ptr ;
169     size_t n;
170     const char *s;
171     char *name, *p, *home=NULL;
172
173     va_start( arg_ptr, first_part ) ;
174     n = strlen(first_part)+1;
175     while( (s=va_arg(arg_ptr, const char *)) )
176         n += strlen(s) + 1;
177     va_end(arg_ptr);
178
179 #ifndef __riscos__
180     if(*first_part=='~')
181       {
182         home=untilde(&first_part);
183         if(home)
184           n+=strlen(home);
185       }
186 #endif
187     name = xmalloc(n);
188     p = home ? stpcpy(stpcpy(name,home), first_part)
189              : stpcpy(name, first_part);
190     va_start( arg_ptr, first_part ) ;
191     while( (s=va_arg(arg_ptr, const char *)) )
192         p = stpcpy(stpcpy(p, DIRSEP_S), s);
193     va_end(arg_ptr);
194     xfree(home);
195
196 #ifndef __riscos__
197     return name;
198 #else /* __riscos__ */
199     p = riscos_gstrans(name);
200     xfree(name);
201     return p;
202 #endif /* __riscos__ */
203 }
204
205
206 /* Compare whether the filenames are identical.  This is a
207    special version of strcmp() taking the semantics of filenames in
208    account.  Note that this function works only on the supplied names
209    without considereing any context like the current directory.  See
210    also same_file_p(). */
211 int
212 compare_filenames (const char *a, const char *b)
213 {
214 #ifdef __riscos__
215   int c = 0;
216   char *abuf, *bbuf;
217   
218   abuf = riscos_gstrans(a);
219   bbuf = riscos_gstrans(b);
220   c = ascii_strcasecmp (abuf, bbuf);
221   xfree(abuf);
222   xfree(bbuf);
223   
224   return c;
225 #elif defined (HAVE_DRIVE_LETTERS)
226   for ( ; *a && *b; a++, b++ ) 
227     {
228       if (*a != *b 
229           && (toupper (*(const unsigned char*)a)
230               != toupper (*(const unsigned char*)b) )
231           && !((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/')))
232         break;
233     }
234   if ((*a == '/' && *b == '\\') || (*a == '\\' && *b == '/'))
235     return 0;
236   else
237     return (toupper (*(const unsigned char*)a) 
238             - toupper (*(const unsigned char*)b));
239 #else /*!HAVE_DRIVE_LETTERS*/
240   return strcmp (a,b);
241 #endif
242 }
243
244 /* Check whether the files NAME1 and NAME2 are identical.  This is for
245    example achieved by comparing the inode numbers of the files.  */
246 int
247 same_file_p (const char *name1, const char *name2)
248 {
249   int yes;
250       
251   /* First try a shortcut.  */
252   if (!compare_filenames (name1, name2))
253     yes = 1;
254   else
255     {
256 #ifdef HAVE_W32_SYSTEM  
257       HANDLE file1, file2;
258       BY_HANDLE_FILE_INFORMATION info1, info2;
259       
260       file1 = CreateFile (name1, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
261       if (file1 == INVALID_HANDLE_VALUE)
262         yes = 0; /* If we can't open the file, it is not the same.  */
263       else
264         {
265           file2 = CreateFile (name2, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
266           if (file1 == INVALID_HANDLE_VALUE)
267             yes = 0; /* If we can't open the file, it is not the same.  */
268           else
269             {
270               yes = (GetFileInformationByHandle (file1, &info1)
271                      && GetFileInformationByHandle (file2, &info2)
272                      && info1.dwVolumeSerialNumber==info2.dwVolumeSerialNumber
273                      && info1.nFileIndexHigh == info2.nFileIndexHigh
274                      && info1.nFileIndexLow == info2.nFileIndexLow);
275               CloseHandle (file2);
276             }
277           CloseHandle (file1);
278         }
279 #else /*!HAVE_W32_SYSTEM*/
280       struct stat info1, info2;
281       
282       yes = (!stat (name1, &info1) && !stat (name2, &info2)
283              && info1.st_dev == info2.st_dev && info1.st_ino == info2.st_ino);
284 #endif /*!HAVE_W32_SYSTEM*/
285     }
286   return yes;
287 }
288
289
290 /****************
291  * A simple function to decide whether the filename is stdout
292  * or a real filename.
293  */
294 const char *
295 print_fname_stdout( const char *s )
296 {
297     if( !s || (*s == '-' && !s[1]) )
298         return "[stdout]";
299     return s;
300 }
301
302
303 const char *
304 print_fname_stdin( const char *s )
305 {
306     if( !s || (*s == '-' && !s[1]) )
307         return "[stdin]";
308     return s;
309 }
310
311 /****************
312  * Check if the file is compressed.
313  **/
314 int
315 is_file_compressed( const char *s, int *ret_rc )
316 {
317     IOBUF a;
318     byte buf[4];
319     int i, rc = 0;
320     int overflow;
321
322     struct magic_compress_s {
323         size_t len;
324         byte magic[4];
325     } magic[] = {
326         { 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
327         { 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
328         { 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
329     };
330     
331     if ( iobuf_is_pipe_filename (s) || !ret_rc )
332         return 0; /* We can't check stdin or no file was given */
333
334     a = iobuf_open( s );
335     if ( a == NULL ) {
336         *ret_rc = G10ERR_OPEN_FILE;
337         return 0;
338     }
339
340     if ( iobuf_get_filelength( a, &overflow ) < 4 && !overflow) {
341         *ret_rc = 0;
342         goto leave;
343     }
344
345     if ( iobuf_read( a, buf, 4 ) == -1 ) {
346         *ret_rc = G10ERR_READ_FILE;
347         goto leave;
348     }
349
350     for ( i = 0; i < DIM( magic ); i++ ) {
351         if ( !memcmp( buf, magic[i].magic, magic[i].len ) ) {
352             *ret_rc = 0;
353             rc = 1;
354             break;
355         }
356     }
357
358 leave:    
359     iobuf_close( a );
360     return rc;
361 }