xref: /plan9/sys/src/ape/cmd/pax/fileio.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 /* $Source: /u/mark/src/pax/RCS/fileio.c,v $
2  *
3  * $Revision: 1.2 $
4  *
5  * fileio.c - file I/O functions for all archive interfaces
6  *
7  * DESCRIPTION
8  *
9  *	These function all do I/O of some form or another.  They are
10  *	grouped here mainly for convienence.
11  *
12  * AUTHOR
13  *
14  *	Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
15  *
16  * Sponsored by The USENIX Association for public distribution.
17  *
18  * Copyright (c) 1989 Mark H. Colburn.
19  * All rights reserved.
20  *
21  * Redistribution and use in source and binary forms are permitted
22  * provided that the above copyright notice is duplicated in all such
23  * forms and that any documentation, advertising materials, and other
24  * materials related to such distribution and use acknowledge that the
25  * software was developed * by Mark H. Colburn and sponsored by The
26  * USENIX Association.
27  *
28  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31  *
32  * $Log:	fileio.c,v $
33  * Revision 1.2  89/02/12  10:04:31  mark
34  * 1.2 release fixes
35  *
36  * Revision 1.1  88/12/23  18:02:09  mark
37  * Initial revision
38  *
39  */
40 
41 #ifndef lint
42 static char *ident = "$Id: fileio.c,v 1.2 89/02/12 10:04:31 mark Exp $";
43 static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
44 #endif /* ! lint */
45 
46 
47 /* Headers */
48 
49 #include "pax.h"
50 
51 
52 /* open_archive -  open an archive file.
53  *
54  * DESCRIPTION
55  *
56  *	Open_archive will open an archive file for reading or writing,
57  *	setting the proper file mode, depending on the "mode" passed to
58  *	it.  All buffer pointers are reset according to the mode
59  *	specified.
60  *
61  * PARAMETERS
62  *
63  * 	int	mode 	- specifies whether we are reading or writing.
64  *
65  * RETURNS
66  *
67  *	Returns a zero if successfull, or -1 if an error occured during
68  *	the open.
69  */
70 
71 #ifdef __STDC__
72 
open_archive(int mode)73 int open_archive(int mode)
74 
75 #else
76 
77 int open_archive(mode)
78 int             mode;
79 
80 #endif
81 {
82     if (ar_file[0] == '-' && ar_file[1] == '\0') {
83 	if (mode == AR_READ) {
84 	    archivefd = STDIN;
85 	    bufend = bufidx = bufstart;
86 	} else {
87 	    archivefd = STDOUT;
88 	}
89     } else if (mode == AR_READ) {
90 	archivefd = open(ar_file, O_RDONLY | O_BINARY);
91 	bufend = bufidx = bufstart;	/* set up for initial read */
92     } else if (mode == AR_WRITE) {
93 	archivefd = open(ar_file, O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, 0666);
94     } else if (mode == AR_APPEND) {
95 	archivefd = open(ar_file, O_RDWR | O_BINARY, 0666);
96 	bufend = bufidx = bufstart;	/* set up for initial read */
97     }
98 
99     if (archivefd < 0) {
100 	warnarch(strerror(), (OFFSET) 0);
101 	return (-1);
102     }
103     ++arvolume;
104     return (0);
105 }
106 
107 
108 /* close_archive - close the archive file
109  *
110  * DESCRIPTION
111  *
112  *	Closes the current archive and resets the archive end of file
113  *	marker.
114  */
115 
116 #ifdef __STDC__
117 
close_archive(void)118 void close_archive(void)
119 
120 #else
121 
122 void close_archive()
123 
124 #endif
125 {
126     if (archivefd != STDIN && archivefd != STDOUT) {
127 	close(archivefd);
128     }
129     areof = 0;
130 }
131 
132 
133 /* openout - open an output file
134  *
135  * DESCRIPTION
136  *
137  *	Openo opens the named file for output.  The file mode and type are
138  *	set based on the values stored in the stat structure for the file.
139  *	If the file is a special file, then no data will be written, the
140  *	file/directory/Fifo, etc., will just be created.  Appropriate
141  *	permission may be required to create special files.
142  *
143  * PARAMETERS
144  *
145  *	char 	*name		- The name of the file to create
146  *	Stat	*asb		- Stat structure for the file
147  *	Link	*linkp;		- pointer to link chain for this file
148  *	int	 ispass		- true if we are operating in "pass" mode
149  *
150  * RETURNS
151  *
152  * 	Returns the output file descriptor, 0 if no data is required or -1
153  *	if unsuccessful. Note that UNIX open() will never return 0 because
154  *	the standard input is in use.
155  */
156 
157 #ifdef __STDC__
158 
openout(char * name,Stat * asb,Link * linkp,int ispass)159 int openout(char *name, Stat *asb, Link *linkp, int ispass)
160 
161 #else
162 
163 int openout(name, asb, linkp, ispass)
164 char           *name;
165 Stat           *asb;
166 Link           *linkp;
167 int             ispass;
168 
169 #endif
170 {
171     int             exists;
172     int             fd;
173     ushort          perm;
174     ushort          operm = 0;
175     Stat            osb;
176 #ifdef	S_IFLNK
177     int             ssize;
178     char            sname[PATH_MAX + 1];
179 #endif	/* S_IFLNK */
180 
181     if (exists = (LSTAT(name, &osb) == 0)) {
182 	if (ispass && osb.sb_ino == asb->sb_ino && osb.sb_dev == asb->sb_dev) {
183 	    warn(name, "Same file");
184 	    return (-1);
185 	} else if ((osb.sb_mode & S_IFMT) == (asb->sb_mode & S_IFMT)) {
186 	    operm = osb.sb_mode & S_IPERM;
187 	} else if (REMOVE(name, &osb) < 0) {
188 	    warn(name, strerror());
189 	    return (-1);
190 	} else {
191 	    exists = 0;
192 	}
193     }
194     if (linkp) {
195 	if (exists) {
196 	    if (asb->sb_ino == osb.sb_ino && asb->sb_dev == osb.sb_dev) {
197 		return (0);
198 	    } else if (unlink(name) < 0) {
199 		warn(name, strerror());
200 		return (-1);
201 	    } else {
202 		exists = 0;
203 	    }
204 	}
205 	if (link(linkp->l_name, name) != 0) {
206 	    if (errno == ENOENT) {
207 		if (f_dir_create) {
208 		    if (dirneed(name) != 0 ||
209 			    link(linkp->l_name, name) != 0) {
210 			    warn(name, strerror());
211 			return (-1);
212 		    }
213 		} else {
214 		    warn(name,
215 			     "Directories are not being created (-d option)");
216 		}
217 		return(0);
218 	    } else if (errno != EXDEV) {
219 		warn(name, strerror());
220 		return (-1);
221 	    }
222 	} else {
223 	    return(0);
224 	}
225     }
226     perm = asb->sb_mode & S_IPERM;
227     switch (asb->sb_mode & S_IFMT) {
228     case S_IFBLK:
229     case S_IFCHR:
230 #ifdef _POSIX_SOURCE
231 	warn(name, "Can't create special files");
232 	return (-1);
233 #else
234 	fd = 0;
235 	if (exists) {
236 	    if (asb->sb_rdev == osb.sb_rdev) {
237 		if (perm != operm && chmod(name, (int) perm) < 0) {
238 		    warn(name, strerror());
239 		    return (-1);
240 		} else {
241 		    break;
242 		}
243 	    } else if (REMOVE(name, &osb) < 0) {
244 		warn(name, strerror());
245 		return (-1);
246 	    } else {
247 		exists = 0;
248 	    }
249 	}
250 	if (mknod(name, (int) asb->sb_mode, (int) asb->sb_rdev) < 0) {
251 	    if (errno == ENOENT) {
252 		if (f_dir_create) {
253 		    if (dirneed(name) < 0 || mknod(name, (int) asb->sb_mode,
254 			   (int) asb->sb_rdev) < 0) {
255 			warn(name, strerror());
256 			return (-1);
257 		    }
258 		} else {
259 		    warn(name, "Directories are not being created (-d option)");
260 		}
261 	    } else {
262 		warn(name, strerror());
263 		return (-1);
264 	    }
265 	}
266 	return(0);
267 #endif /* _POSIX_SOURCE */
268 	break;
269     case S_IFDIR:
270 	if (exists) {
271 	    if (perm != operm && chmod(name, (int) perm) < 0) {
272 		warn(name, strerror());
273 		return (-1);
274 	    }
275 	} else if (f_dir_create) {
276 	    if (dirmake(name, asb) < 0 || dirneed(name) < 0) {
277 		warn(name, strerror());
278 		return (-1);
279 	    }
280 	} else {
281 	    warn(name, "Directories are not being created (-d option)");
282 	}
283 	return (0);
284 #ifndef _POSIX_SOURCE
285 #ifdef	S_IFIFO
286     case S_IFIFO:
287 	fd = 0;
288 	if (exists) {
289 	    if (perm != operm && chmod(name, (int) perm) < 0) {
290 		warn(name, strerror());
291 		return (-1);
292 	    }
293 	} else if (mknod(name, (int) asb->sb_mode, 0) < 0) {
294 	    if (errno == ENOENT) {
295 		if (f_dir_create) {
296 		    if (dirneed(name) < 0
297 		       || mknod(name, (int) asb->sb_mode, 0) < 0) {
298 			warn(name, strerror());
299 			return (-1);
300 		    }
301 		} else {
302 		    warn(name, "Directories are not being created (-d option)");
303 		}
304 	    } else {
305 		warn(name, strerror());
306 		return (-1);
307 	    }
308 	}
309 	return(0);
310 	break;
311 #endif				/* S_IFIFO */
312 #endif				/* _POSIX_SOURCE */
313 #ifdef	S_IFLNK
314     case S_IFLNK:
315 	if (exists) {
316 	    if ((ssize = readlink(name, sname, sizeof(sname))) < 0) {
317 		warn(name, strerror());
318 		return (-1);
319 	    } else if (strncmp(sname, asb->sb_link, ssize) == 0) {
320 		return (0);
321 	    } else if (REMOVE(name, &osb) < 0) {
322 		warn(name, strerror());
323 		return (-1);
324 	    } else {
325 		exists = 0;
326 	    }
327 	}
328 	if (symlink(asb->sb_link, name) < 0) {
329 	    if (errno == ENOENT) {
330 		if (f_dir_create) {
331 		    if (dirneed(name) < 0 || symlink(asb->sb_link, name) < 0) {
332 			warn(name, strerror());
333 			return (-1);
334 		    }
335 		} else {
336 		    warn(name, "Directories are not being created (-d option)");
337 		}
338 	    } else {
339 		warn(name, strerror());
340 		return (-1);
341 	    }
342 	}
343 	return (0);		/* Can't chown()/chmod() a symbolic link */
344 #endif				/* S_IFLNK */
345     case S_IFREG:
346 	if (exists) {
347 	    if (!f_unconditional && osb.sb_mtime > asb->sb_mtime) {
348 		warn(name, "Newer file exists");
349 		return (-1);
350 	    } else if (unlink(name) < 0) {
351 		warn(name, strerror());
352 		return (-1);
353 	    } else {
354 		exists = 0;
355 	    }
356 	}
357 	if ((fd = creat(name, (int) perm)) < 0) {
358 	    if (errno == ENOENT) {
359 		if (f_dir_create) {
360 		    if (dirneed(name) < 0 ||
361 			    (fd = creat(name, (int) perm)) < 0) {
362 			warn(name, strerror());
363 			return (-1);
364 		    }
365 		} else {
366 		    /*
367 		     * the file requires a directory which does not exist
368 		     * and which the user does not want created, so skip
369 		     * the file...
370 		     */
371 		    warn(name, "Directories are not being created (-d option)");
372 		    return(0);
373 		}
374 	    } else {
375 		warn(name, strerror());
376 		return (-1);
377 	    }
378 	}
379 	break;
380     default:
381 	warn(name, "Unknown filetype");
382 	return (-1);
383     }
384     if (f_owner) {
385 	if (!exists || asb->sb_uid != osb.sb_uid || asb->sb_gid != osb.sb_gid) {
386 	    chown(name, (int) asb->sb_uid, (int) asb->sb_gid);
387 	}
388     }
389     return (fd);
390 }
391 
392 
393 /* openin - open the next input file
394  *
395  * DESCRIPTION
396  *
397  *	Openi will attempt to open the next file for input.  If the file is
398  *	a special file, such as a directory, FIFO, link, character- or
399  *	block-special file, then the file size field of the stat structure
400  *	is zeroed to make sure that no data is written out for the file.
401  *	If the file is a special file, then a file descriptor of 0 is
402  *	returned to the caller, which is handled specially.  If the file
403  *	is a regular file, then the file is opened and a file descriptor
404  *	to the open file is returned to the caller.
405  *
406  * PARAMETERS
407  *
408  *	char   *name	- pointer to the name of the file to open
409  *	Stat   *asb	- pointer to the stat block for the file to open
410  *
411  * RETURNS
412  *
413  * 	Returns a file descriptor, 0 if no data exists, or -1 at EOF. This
414  *	kludge works because standard input is in use, preventing open() from
415  *	returning zero.
416  */
417 
418 #ifdef __STDC__
419 
openin(char * name,Stat * asb)420 int openin(char *name, Stat *asb)
421 
422 #else
423 
424 int openin(name, asb)
425 char           *name;		/* name of file to open */
426 Stat           *asb;		/* pointer to stat structure for file */
427 
428 #endif
429 {
430     int             fd;
431 
432     switch (asb->sb_mode & S_IFMT) {
433     case S_IFDIR:
434 	asb->sb_nlink = 1;
435 	asb->sb_size = 0;
436 	return (0);
437 #ifdef	S_IFLNK
438     case S_IFLNK:
439 	if ((asb->sb_size = readlink(name,
440 			     asb->sb_link, sizeof(asb->sb_link) - 1)) < 0) {
441 	    warn(name, strerror());
442 	    return(0);
443 	}
444 	asb->sb_link[asb->sb_size] = '\0';
445 	return (0);
446 #endif				/* S_IFLNK */
447     case S_IFREG:
448 	if (asb->sb_size == 0) {
449 	    return (0);
450 	}
451 	if ((fd = open(name, O_RDONLY | O_BINARY)) < 0) {
452 	    warn(name, strerror());
453 	}
454 	return (fd);
455     default:
456 	asb->sb_size = 0;
457 	return (0);
458     }
459 }
460