libutil: add O_NOCTTY back to old pty open code
[minix.git] / servers / mfs / open.c
blob6358c520e95784460bf55a8ab0d29460d31e0df3
1 #include "fs.h"
2 #include <sys/stat.h>
3 #include <string.h>
4 #include <minix/com.h>
5 #include "buf.h"
6 #include "inode.h"
7 #include "super.h"
8 #include <minix/vfsif.h>
10 static struct inode *new_node(struct inode *ldirp, char *string, mode_t
11 bits, zone_t z0);
13 /*===========================================================================*
14 * fs_create *
15 *===========================================================================*/
16 int fs_create()
18 size_t len;
19 int r;
20 struct inode *ldirp;
21 struct inode *rip;
22 mode_t omode;
23 char lastc[MFS_NAME_MAX];
25 /* Read request message */
26 omode = (mode_t) fs_m_in.REQ_MODE;
27 caller_uid = (uid_t) fs_m_in.REQ_UID;
28 caller_gid = (gid_t) fs_m_in.REQ_GID;
30 /* Try to make the file. */
32 /* Copy the last component (i.e., file name) */
33 len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(lastc));
34 err_code = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
35 (vir_bytes) 0, (vir_bytes) lastc, len);
36 if (err_code != OK) return err_code;
37 NUL(lastc, len, sizeof(lastc));
39 /* Get last directory inode (i.e., directory that will hold the new inode) */
40 if ((ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
41 return(ENOENT);
43 /* Create a new inode by calling new_node(). */
44 rip = new_node(ldirp, lastc, omode, NO_ZONE);
45 r = err_code;
47 /* If an error occurred, release inode. */
48 if (r != OK) {
49 put_inode(ldirp);
50 put_inode(rip);
51 return(r);
54 /* Reply message */
55 fs_m_out.RES_INODE_NR = rip->i_num;
56 fs_m_out.RES_MODE = rip->i_mode;
57 fs_m_out.RES_FILE_SIZE_LO = rip->i_size;
59 /* These values are needed for the execution */
60 fs_m_out.RES_UID = rip->i_uid;
61 fs_m_out.RES_GID = rip->i_gid;
63 /* Drop parent dir */
64 put_inode(ldirp);
66 return(OK);
70 /*===========================================================================*
71 * fs_mknod *
72 *===========================================================================*/
73 int fs_mknod()
75 struct inode *ip, *ldirp;
76 char lastc[MFS_NAME_MAX];
77 phys_bytes len;
79 /* Copy the last component and set up caller's user and group id */
80 len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(lastc));
81 err_code = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
82 (vir_bytes) 0, (vir_bytes) lastc, (size_t) len);
83 if (err_code != OK) return err_code;
84 NUL(lastc, len, sizeof(lastc));
86 caller_uid = (uid_t) fs_m_in.REQ_UID;
87 caller_gid = (gid_t) fs_m_in.REQ_GID;
89 /* Get last directory inode */
90 if((ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
91 return(ENOENT);
93 /* Try to create the new node */
94 ip = new_node(ldirp, lastc, (mode_t) fs_m_in.REQ_MODE,
95 (zone_t) fs_m_in.REQ_DEV);
97 put_inode(ip);
98 put_inode(ldirp);
99 return(err_code);
103 /*===========================================================================*
104 * fs_mkdir *
105 *===========================================================================*/
106 int fs_mkdir()
108 int r1, r2; /* status codes */
109 ino_t dot, dotdot; /* inode numbers for . and .. */
110 struct inode *rip, *ldirp;
111 char lastc[MFS_NAME_MAX]; /* last component */
112 phys_bytes len;
114 /* Copy the last component and set up caller's user and group id */
115 len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(lastc));
116 err_code = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
117 (vir_bytes) 0, (vir_bytes) lastc, (size_t) len);
118 if(err_code != OK) return(err_code);
119 NUL(lastc, len, sizeof(lastc));
121 caller_uid = (uid_t) fs_m_in.REQ_UID;
122 caller_gid = (gid_t) fs_m_in.REQ_GID;
124 /* Get last directory inode */
125 if((ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
126 return(ENOENT);
128 /* Next make the inode. If that fails, return error code. */
129 rip = new_node(ldirp, lastc, (mode_t) fs_m_in.REQ_MODE, (zone_t) 0);
131 if(rip == NULL || err_code == EEXIST) {
132 put_inode(rip); /* can't make dir: it already exists */
133 put_inode(ldirp);
134 return(err_code);
137 /* Get the inode numbers for . and .. to enter in the directory. */
138 dotdot = ldirp->i_num; /* parent's inode number */
139 dot = rip->i_num; /* inode number of the new dir itself */
141 /* Now make dir entries for . and .. unless the disk is completely full. */
142 /* Use dot1 and dot2, so the mode of the directory isn't important. */
143 rip->i_mode = (mode_t) fs_m_in.REQ_MODE; /* set mode */
144 r1 = search_dir(rip, dot1, &dot, ENTER, IGN_PERM);/* enter . in the new dir*/
145 r2 = search_dir(rip, dot2, &dotdot, ENTER, IGN_PERM); /* enter .. in the new
146 dir */
148 /* If both . and .. were successfully entered, increment the link counts. */
149 if (r1 == OK && r2 == OK) {
150 /* Normal case. It was possible to enter . and .. in the new dir. */
151 rip->i_nlinks++; /* this accounts for . */
152 ldirp->i_nlinks++; /* this accounts for .. */
153 IN_MARKDIRTY(ldirp); /* mark parent's inode as dirty */
154 } else {
155 /* It was not possible to enter . or .. probably disk was full -
156 * links counts haven't been touched. */
157 if(search_dir(ldirp, lastc, NULL, DELETE, IGN_PERM) != OK)
158 panic("Dir disappeared: %ul", rip->i_num);
159 rip->i_nlinks--; /* undo the increment done in new_node() */
161 IN_MARKDIRTY(rip); /* either way, i_nlinks has changed */
163 put_inode(ldirp); /* return the inode of the parent dir */
164 put_inode(rip); /* return the inode of the newly made dir */
165 return(err_code); /* new_node() always sets 'err_code' */
169 /*===========================================================================*
170 * fs_slink *
171 *===========================================================================*/
172 int fs_slink()
174 phys_bytes len;
175 struct inode *sip; /* inode containing symbolic link */
176 struct inode *ldirp; /* directory containing link */
177 register int r; /* error code */
178 char string[MFS_NAME_MAX]; /* last component of the new dir's path name */
179 struct buf *bp; /* disk buffer for link */
181 caller_uid = (uid_t) fs_m_in.REQ_UID;
182 caller_gid = (gid_t) fs_m_in.REQ_GID;
184 /* Copy the link name's last component */
185 len = min( (unsigned) fs_m_in.REQ_PATH_LEN, sizeof(string));
186 r = sys_safecopyfrom(VFS_PROC_NR, (cp_grant_id_t) fs_m_in.REQ_GRANT,
187 (vir_bytes) 0, (vir_bytes) string, (size_t) len);
188 if (r != OK) return(r);
189 NUL(string, len, sizeof(string));
191 /* Temporarily open the dir. */
192 if( (ldirp = get_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
193 return(EINVAL);
195 /* Create the inode for the symlink. */
196 sip = new_node(ldirp, string, (mode_t) (I_SYMBOLIC_LINK | RWX_MODES),
197 (zone_t) 0);
199 /* Allocate a disk block for the contents of the symlink.
200 * Copy contents of symlink (the name pointed to) into first disk block. */
201 if( (r = err_code) == OK) {
202 bp = new_block(sip, (off_t) 0);
203 if (bp == NULL)
204 r = err_code;
205 else
206 r = sys_safecopyfrom(VFS_PROC_NR,
207 (cp_grant_id_t) fs_m_in.REQ_GRANT3,
208 (vir_bytes) 0, (vir_bytes) b_data(bp),
209 (size_t) fs_m_in.REQ_MEM_SIZE);
211 if(bp != NULL && r == OK) {
212 b_data(bp)[_MIN_BLOCK_SIZE-1] = '\0';
213 sip->i_size = (off_t) strlen(b_data(bp));
214 if(sip->i_size != fs_m_in.REQ_MEM_SIZE) {
215 /* This can happen if the user provides a buffer
216 * with a \0 in it. This can cause a lot of trouble
217 * when the symlink is used later. We could just use
218 * the strlen() value, but we want to let the user
219 * know he did something wrong. ENAMETOOLONG doesn't
220 * exactly describe the error, but there is no
221 * ENAMETOOWRONG.
223 r = ENAMETOOLONG;
227 put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NULL. */
229 if(r != OK) {
230 sip->i_nlinks = NO_LINK;
231 if(search_dir(ldirp, string, NULL, DELETE, IGN_PERM) != OK)
232 panic("Symbolic link vanished");
236 /* put_inode() accepts NULL as a noop, so the below are safe. */
237 put_inode(sip);
238 put_inode(ldirp);
240 return(r);
243 /*===========================================================================*
244 * new_node *
245 *===========================================================================*/
246 static struct inode *new_node(struct inode *ldirp,
247 char *string, mode_t bits, zone_t z0)
249 /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
250 * In all cases it allocates a new inode, makes a directory entry for it in
251 * the ldirp directory with string name, and initializes it.
252 * It returns a pointer to the inode if it can do this;
253 * otherwise it returns NULL. It always sets 'err_code'
254 * to an appropriate value (OK or an error code).
256 * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
257 * has to hold at least MFS_NAME_MAX bytes.
260 register struct inode *rip;
261 register int r;
263 if (ldirp->i_nlinks == NO_LINK) { /* Dir does not actually exist */
264 err_code = ENOENT;
265 return(NULL);
268 /* Get final component of the path. */
269 rip = advance(ldirp, string, IGN_PERM);
271 if (S_ISDIR(bits) && (ldirp->i_nlinks >= LINK_MAX)) {
272 /* New entry is a directory, alas we can't give it a ".." */
273 put_inode(rip);
274 err_code = EMLINK;
275 return(NULL);
278 if ( rip == NULL && err_code == ENOENT) {
279 /* Last path component does not exist. Make new directory entry. */
280 if ( (rip = alloc_inode((ldirp)->i_dev, bits)) == NULL) {
281 /* Can't creat new inode: out of inodes. */
282 return(NULL);
285 /* Force inode to the disk before making directory entry to make
286 * the system more robust in the face of a crash: an inode with
287 * no directory entry is much better than the opposite.
289 rip->i_nlinks++;
290 rip->i_zone[0] = z0; /* major/minor device numbers */
291 rw_inode(rip, WRITING); /* force inode to disk now */
293 /* New inode acquired. Try to make directory entry. */
294 if((r=search_dir(ldirp, string, &rip->i_num, ENTER, IGN_PERM)) != OK) {
295 rip->i_nlinks--; /* pity, have to free disk inode */
296 IN_MARKDIRTY(rip); /* dirty inodes are written out */
297 put_inode(rip); /* this call frees the inode */
298 err_code = r;
299 return(NULL);
302 } else if (err_code == EENTERMOUNT || err_code == ELEAVEMOUNT) {
303 r = EEXIST;
304 } else {
305 /* Either last component exists, or there is some problem. */
306 if (rip != NULL)
307 r = EEXIST;
308 else
309 r = err_code;
312 /* The caller has to return the directory inode (*ldirp). */
313 err_code = r;
314 return(rip);
318 /*===========================================================================*
319 * fs_inhibread *
320 *===========================================================================*/
321 int fs_inhibread()
323 struct inode *rip;
325 if((rip = find_inode(fs_dev, (ino_t) fs_m_in.REQ_INODE_NR)) == NULL)
326 return(EINVAL);
328 /* inhibit read ahead */
329 rip->i_seek = ISEEK;
331 return(OK);