xref: /plan9/sys/src/ape/cmd/pax/pathname.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 /* $Source: /u/mark/src/pax/RCS/pathname.c,v $
2  *
3  * $Revision: 1.2 $
4  *
5  * pathname.c - directory/pathname support functions
6  *
7  * DESCRIPTION
8  *
9  *	These functions provide directory/pathname support for PAX
10  *
11  * AUTHOR
12  *
13  *	Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
14  *
15  * Sponsored by The USENIX Association for public distribution.
16  *
17  * Copyright (c) 1989 Mark H. Colburn.
18  * All rights reserved.
19  *
20  * Redistribution and use in source and binary forms are permitted
21  * provided that the above copyright notice is duplicated in all such
22  * forms and that any documentation, advertising materials, and other
23  * materials related to such distribution and use acknowledge that the
24  * software was developed * by Mark H. Colburn and sponsored by The
25  * USENIX Association.
26  *
27  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
28  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
29  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * $Log:	pathname.c,v $
32  * Revision 1.2  89/02/12  10:05:13  mark
33  * 1.2 release fixes
34  *
35  * Revision 1.1  88/12/23  18:02:21  mark
36  * Initial revision
37  *
38  */
39 
40 #ifndef lint
41 static char *ident = "$Id: pathname.c,v 1.2 89/02/12 10:05:13 mark Exp $";
42 static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
43 #endif /* ! lint */
44 
45 
46 /* Headers */
47 
48 #include "pax.h"
49 
50 
51 /* dirneed  - checks for the existance of directories and possibly create
52  *
53  * DESCRIPTION
54  *
55  *	Dirneed checks to see if a directory of the name pointed to by name
56  *	exists.  If the directory does exist, then dirneed returns 0.  If
57  *	the directory does not exist and the f_dir_create flag is set,
58  *	then dirneed will create the needed directory, recursively creating
59  *	any needed intermediate directory.
60  *
61  *	If f_dir_create is not set, then no directories will be created
62  *	and a value of -1 will be returned if the directory does not
63  *	exist.
64  *
65  * PARAMETERS
66  *
67  *	name		- name of the directory to create
68  *
69  * RETURNS
70  *
71  *	Returns a 0 if the creation of the directory succeeded or if the
72  *	directory already existed.  If the f_dir_create flag was not set
73  *	and the named directory does not exist, or the directory creation
74  *	failed, a -1 will be returned to the calling routine.
75  */
76 
77 #ifdef __STDC__
78 
dirneed(char * name)79 int dirneed(char *name)
80 
81 #else
82 
83 int dirneed(name)
84 char           *name;
85 
86 #endif
87 {
88     char           *cp;
89     char           *last;
90     int             ok;
91     static Stat     sb;
92 
93     last = (char *)NULL;
94     for (cp = name; *cp;) {
95 	if (*cp++ == '/') {
96 	    last = cp;
97 	}
98     }
99     if (last == (char *)NULL) {
100 	return (STAT(".", &sb));
101     }
102     *--last = '\0';
103     ok = STAT(*name ? name : ".", &sb) == 0
104 	? ((sb.sb_mode & S_IFMT) == S_IFDIR)
105 	: (f_dir_create && dirneed(name) == 0 && dirmake(name, &sb) == 0);
106     *last = '/';
107     return (ok ? 0 : -1);
108 }
109 
110 
111 /* nameopt - optimize a pathname
112  *
113  * DESCRIPTION
114  *
115  * 	Confused by "<symlink>/.." twistiness. Returns the number of final
116  * 	pathname elements (zero for "/" or ".") or -1 if unsuccessful.
117  *
118  * PARAMETERS
119  *
120  *	char	*begin	- name of the path to optimize
121  *
122  * RETURNS
123  *
124  *	Returns 0 if successful, non-zero otherwise.
125  *
126  */
127 
128 #ifdef __STDC__
129 
nameopt(char * begin)130 int nameopt(char *begin)
131 
132 #else
133 
134 int nameopt(begin)
135 char           *begin;
136 
137 #endif
138 {
139     char           *name;
140     char           *item;
141     int             idx;
142     int             absolute;
143     char           *element[PATHELEM];
144 
145     absolute = (*(name = begin) == '/');
146     idx = 0;
147     for (;;) {
148 	if (idx == PATHELEM) {
149 	    warn(begin, "Too many elements");
150 	    return (-1);
151 	}
152 	while (*name == '/') {
153 	    ++name;
154 	}
155 	if (*name == '\0') {
156 	    break;
157 	}
158 	element[idx] = item = name;
159 	while (*name && *name != '/') {
160 	    ++name;
161 	}
162 	if (*name) {
163 	    *name++ = '\0';
164 	}
165 	if (strcmp(item, "..") == 0) {
166 	    if (idx == 0) {
167 		if (!absolute) {
168 		    ++idx;
169 		}
170 	    } else if (strcmp(element[idx - 1], "..") == 0) {
171 		++idx;
172 	    } else {
173 		--idx;
174 	    }
175 	} else if (strcmp(item, ".") != 0) {
176 	    ++idx;
177 	}
178     }
179     if (idx == 0) {
180 	element[idx++] = absolute ? "" : ".";
181     }
182     element[idx] = (char *)NULL;
183     name = begin;
184     if (absolute) {
185 	*name++ = '/';
186     }
187     for (idx = 0; item = element[idx]; ++idx, *name++ = '/') {
188 	while (*item) {
189 	    *name++ = *item++;
190 	}
191     }
192     *--name = '\0';
193     return (idx);
194 }
195 
196 
197 /* dirmake - make a directory
198  *
199  * DESCRIPTION
200  *
201  *	Dirmake makes a directory with the appropritate permissions.
202  *
203  * PARAMETERS
204  *
205  *	char 	*name	- Name of directory make
206  *	Stat	*asb	- Stat structure of directory to make
207  *
208  * RETURNS
209  *
210  * 	Returns zero if successful, -1 otherwise.
211  *
212  */
213 
214 #ifdef __STDC__
215 
dirmake(char * name,Stat * asb)216 int dirmake(char *name, Stat *asb)
217 
218 #else
219 
220 int dirmake(name, asb)
221 char           *name;
222 Stat           *asb;
223 
224 #endif
225 {
226     if (mkdir(name, (int) (asb->sb_mode & S_IPOPN)) < 0) {
227 	return (-1);
228     }
229     if (asb->sb_mode & S_IPEXE) {
230 	chmod(name, (int) (asb->sb_mode & S_IPERM));
231     }
232     if (f_owner) {
233 	chown(name, (int) asb->sb_uid, (int) asb->sb_gid);
234     }
235     return (0);
236 }
237