Remove building with NOCRYPTO option
[minix.git] / minix / fs / mfs / open.c
blob314a45917c841547c37b1d43dc03f259c0654f32
1 #include "fs.h"
2 #include <sys/stat.h>
3 #include <string.h>
4 #include "buf.h"
5 #include "inode.h"
6 #include "super.h"
8 static struct inode *new_node(struct inode *ldirp, char *string, mode_t
9 bits, uid_t uid, gid_t gid, zone_t z0);
11 /*===========================================================================*
12 * fs_create *
13 *===========================================================================*/
14 int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
15 struct fsdriver_node *node)
17 int r;
18 struct inode *ldirp;
19 struct inode *rip;
21 /* Try to make the file. */
23 /* Get last directory inode (i.e., directory that will hold the new inode) */
24 if ((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
25 return(EINVAL);
27 /* Create a new inode by calling new_node(). */
28 rip = new_node(ldirp, name, mode, uid, gid, NO_ZONE);
29 r = err_code;
31 /* If an error occurred, release inode. */
32 if (r != OK) {
33 put_inode(ldirp);
34 put_inode(rip);
35 return(r);
38 /* Reply message */
39 node->fn_ino_nr = rip->i_num;
40 node->fn_mode = rip->i_mode;
41 node->fn_size = rip->i_size;
42 node->fn_uid = rip->i_uid;
43 node->fn_gid = rip->i_gid;
44 node->fn_dev = NO_DEV;
46 /* Drop parent dir */
47 put_inode(ldirp);
49 return(OK);
53 /*===========================================================================*
54 * fs_mknod *
55 *===========================================================================*/
56 int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
57 dev_t dev)
59 struct inode *ip, *ldirp;
61 /* Get last directory inode */
62 if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
63 return(EINVAL);
65 /* Try to create the new node */
66 ip = new_node(ldirp, name, mode, uid, gid, (zone_t) dev);
68 put_inode(ip);
69 put_inode(ldirp);
70 return(err_code);
74 /*===========================================================================*
75 * fs_mkdir *
76 *===========================================================================*/
77 int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
79 int r1, r2; /* status codes */
80 ino_t dot, dotdot; /* inode numbers for . and .. */
81 struct inode *rip, *ldirp;
83 /* Get last directory inode */
84 if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
85 return(EINVAL);
87 /* Next make the inode. If that fails, return error code. */
88 rip = new_node(ldirp, name, mode, uid, gid, (zone_t) 0);
90 if(rip == NULL || err_code == EEXIST) {
91 put_inode(rip); /* can't make dir: it already exists */
92 put_inode(ldirp);
93 return(err_code);
96 /* Get the inode numbers for . and .. to enter in the directory. */
97 dotdot = ldirp->i_num; /* parent's inode number */
98 dot = rip->i_num; /* inode number of the new dir itself */
100 /* Now make dir entries for . and .. unless the disk is completely full. */
101 r1 = search_dir(rip, ".", &dot, ENTER); /* enter . in the new dir */
102 r2 = search_dir(rip, "..", &dotdot, ENTER); /* enter .. in the new dir */
104 /* If both . and .. were successfully entered, increment the link counts. */
105 if (r1 == OK && r2 == OK) {
106 /* Normal case. It was possible to enter . and .. in the new dir. */
107 rip->i_nlinks++; /* this accounts for . */
108 ldirp->i_nlinks++; /* this accounts for .. */
109 IN_MARKDIRTY(ldirp); /* mark parent's inode as dirty */
110 } else {
111 /* It was not possible to enter . or .. probably disk was full -
112 * links counts haven't been touched. */
113 if(search_dir(ldirp, name, NULL, DELETE) != OK)
114 panic("Dir disappeared: %llu", rip->i_num);
115 rip->i_nlinks--; /* undo the increment done in new_node() */
117 IN_MARKDIRTY(rip); /* either way, i_nlinks has changed */
119 put_inode(ldirp); /* return the inode of the parent dir */
120 put_inode(rip); /* return the inode of the newly made dir */
121 return(err_code); /* new_node() always sets 'err_code' */
125 /*===========================================================================*
126 * fs_slink *
127 *===========================================================================*/
128 int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
129 struct fsdriver_data *data, size_t bytes)
131 struct inode *sip; /* inode containing symbolic link */
132 struct inode *ldirp; /* directory containing link */
133 register int r; /* error code */
134 struct buf *bp; /* disk buffer for link */
136 /* Temporarily open the dir. */
137 if( (ldirp = get_inode(fs_dev, dir_nr)) == NULL)
138 return(EINVAL);
140 /* Create the inode for the symlink. */
141 sip = new_node(ldirp, name, (I_SYMBOLIC_LINK | RWX_MODES), uid, gid, 0);
143 /* Allocate a disk block for the contents of the symlink.
144 * Copy contents of symlink (the name pointed to) into first disk block. */
145 if( (r = err_code) == OK) {
146 bp = new_block(sip, (off_t) 0);
147 if (bp == NULL)
148 r = err_code;
149 else {
150 if(get_block_size(sip->i_dev) <= bytes) {
151 r = ENAMETOOLONG;
152 } else {
153 r = fsdriver_copyin(data, 0, b_data(bp), bytes);
154 b_data(bp)[bytes] = '\0';
158 if(bp != NULL && r == OK) {
159 sip->i_size = (off_t) strlen(b_data(bp));
160 if(sip->i_size != bytes) {
161 /* This can happen if the user provides a buffer
162 * with a \0 in it. This can cause a lot of trouble
163 * when the symlink is used later. We could just use
164 * the strlen() value, but we want to let the user
165 * know he did something wrong. ENAMETOOLONG doesn't
166 * exactly describe the error, but there is no
167 * ENAMETOOWRONG.
169 r = ENAMETOOLONG;
173 put_block(bp); /* put_block() accepts NULL. */
175 if(r != OK) {
176 sip->i_nlinks = NO_LINK;
177 if(search_dir(ldirp, name, NULL, DELETE) != OK)
178 panic("Symbolic link vanished");
182 /* put_inode() accepts NULL as a noop, so the below are safe. */
183 put_inode(sip);
184 put_inode(ldirp);
186 return(r);
189 /*===========================================================================*
190 * new_node *
191 *===========================================================================*/
192 static struct inode *new_node(struct inode *ldirp,
193 char *string, mode_t bits, uid_t uid, gid_t gid, zone_t z0)
195 /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
196 * In all cases it allocates a new inode, makes a directory entry for it in
197 * the ldirp directory with string name, and initializes it.
198 * It returns a pointer to the inode if it can do this;
199 * otherwise it returns NULL. It always sets 'err_code'
200 * to an appropriate value (OK or an error code).
202 * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
203 * has to hold at least MFS_NAME_MAX bytes.
205 register struct inode *rip;
206 register int r;
208 if (ldirp->i_nlinks == NO_LINK) { /* Dir does not actually exist */
209 err_code = ENOENT;
210 return(NULL);
213 if (S_ISDIR(bits) && (ldirp->i_nlinks >= LINK_MAX)) {
214 /* New entry is a directory, alas we can't give it a ".." */
215 err_code = EMLINK;
216 return(NULL);
219 /* Get final component of the path. */
220 rip = advance(ldirp, string);
222 if ( rip == NULL && err_code == ENOENT) {
223 /* Last path component does not exist. Make new directory entry. */
224 if ( (rip = alloc_inode((ldirp)->i_dev, bits, uid, gid)) == NULL) {
225 /* Can't creat new inode: out of inodes. */
226 return(NULL);
229 /* Force inode to the disk before making directory entry to make
230 * the system more robust in the face of a crash: an inode with
231 * no directory entry is much better than the opposite.
233 rip->i_nlinks++;
234 rip->i_zone[0] = z0; /* major/minor device numbers */
235 rw_inode(rip, WRITING); /* force inode to disk now */
237 /* New inode acquired. Try to make directory entry. */
238 if((r=search_dir(ldirp, string, &rip->i_num, ENTER)) != OK) {
239 rip->i_nlinks--; /* pity, have to free disk inode */
240 IN_MARKDIRTY(rip); /* dirty inodes are written out */
241 put_inode(rip); /* this call frees the inode */
242 err_code = r;
243 return(NULL);
246 } else {
247 /* Either last component exists, or there is some problem. */
248 if (rip != NULL)
249 r = EEXIST;
250 else
251 r = err_code;
254 /* The caller has to return the directory inode (*ldirp). */
255 err_code = r;
256 return(rip);
260 /*===========================================================================*
261 * fs_seek *
262 *===========================================================================*/
263 void fs_seek(ino_t ino_nr)
265 struct inode *rip;
267 /* inhibit read ahead */
268 if ((rip = find_inode(fs_dev, ino_nr)) != NULL)
269 rip->i_seek = ISEEK;