Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / fs / ext2 / open.c
blob31145d59947351cc45de9c208f50932ea3aa8563
1 /* Created (MFS based):
2 * February 2010 (Evgeniy Ivanov)
3 */
5 #include "fs.h"
6 #include <sys/stat.h>
7 #include <string.h>
8 #include <assert.h>
9 #include "buf.h"
10 #include "inode.h"
11 #include "super.h"
13 static struct inode *new_node(struct inode *ldirp, char *string, mode_t
14 bits, uid_t uid, gid_t gid, block_t z0);
17 /*===========================================================================*
18 * fs_create *
19 *===========================================================================*/
20 int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
21 struct fsdriver_node *node)
23 int r;
24 struct inode *ldirp;
25 struct inode *rip;
27 /* Try to make the file. */
29 /* Get last directory inode (i.e., directory that will hold the new inode) */
30 if ((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
31 return(ENOENT);
33 /* Create a new inode by calling new_node(). */
34 rip = new_node(ldirp, name, mode, uid, gid, NO_BLOCK);
35 r = err_code;
37 /* If an error occurred, release inode. */
38 if (r != OK) {
39 put_inode(ldirp);
40 put_inode(rip);
41 return(r);
44 /* Reply message */
45 node->fn_ino_nr = rip->i_num;
46 node->fn_mode = rip->i_mode;
47 node->fn_size = rip->i_size;
48 node->fn_uid = rip->i_uid;
49 node->fn_gid = rip->i_gid;
50 node->fn_dev = NO_DEV;
52 /* Drop parent dir */
53 put_inode(ldirp);
55 return(OK);
59 /*===========================================================================*
60 * fs_mknod *
61 *===========================================================================*/
62 int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
63 dev_t dev)
65 struct inode *ip, *ldirp;
67 /* Get last directory inode */
68 if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
69 return(ENOENT);
71 /* Try to create the new node */
72 ip = new_node(ldirp, name, mode, uid, gid, (block_t) dev);
74 put_inode(ip);
75 put_inode(ldirp);
76 return(err_code);
80 /*===========================================================================*
81 * fs_mkdir *
82 *===========================================================================*/
83 int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
85 int r1, r2; /* status codes */
86 ino_t dot, dotdot; /* inode numbers for . and .. */
87 struct inode *rip, *ldirp;
89 /* Get last directory inode */
90 if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
91 return(ENOENT);
93 /* Next make the inode. If that fails, return error code. */
94 rip = new_node(ldirp, name, mode, uid, gid, (block_t) 0);
96 if(rip == NULL || err_code == EEXIST) {
97 put_inode(rip); /* can't make dir: it already exists */
98 put_inode(ldirp);
99 return(err_code);
102 /* Get the inode numbers for . and .. to enter in the directory. */
103 dotdot = ldirp->i_num; /* parent's inode number */
104 dot = rip->i_num; /* inode number of the new dir itself */
106 /* Now make dir entries for . and .. unless the disk is completely full. */
107 /* enter . in the new dir*/
108 r1 = search_dir(rip, ".", &dot, ENTER, I_DIRECTORY);
109 /* enter .. in the new dir */
110 r2 = search_dir(rip, "..", &dotdot, ENTER, I_DIRECTORY);
112 /* If both . and .. were successfully entered, increment the link counts. */
113 if (r1 == OK && r2 == OK) {
114 /* Normal case. It was possible to enter . and .. in the new dir. */
115 rip->i_links_count++; /* this accounts for . */
116 ldirp->i_links_count++; /* this accounts for .. */
117 ldirp->i_dirt = IN_DIRTY; /* mark parent's inode as dirty */
118 } else {
119 /* It was not possible to enter . or .. probably disk was full -
120 * links counts haven't been touched. */
121 if (search_dir(ldirp, name, NULL, DELETE, 0) != OK)
122 panic("Dir disappeared: %d ", (int) rip->i_num);
123 rip->i_links_count--; /* undo the increment done in new_node() */
125 rip->i_dirt = IN_DIRTY; /* either way, i_links_count has changed */
127 put_inode(ldirp); /* return the inode of the parent dir */
128 put_inode(rip); /* return the inode of the newly made dir */
129 return(err_code); /* new_node() always sets 'err_code' */
133 /*===========================================================================*
134 * fs_slink *
135 *===========================================================================*/
136 int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
137 struct fsdriver_data *data, size_t bytes)
139 struct inode *sip; /* inode containing symbolic link */
140 struct inode *ldirp; /* directory containing link */
141 register int r; /* error code */
142 char* link_target_buf = NULL; /* either sip->i_block or bp->b_data */
143 struct buf *bp = NULL; /* disk buffer for link */
145 /* Temporarily open the dir. */
146 if( (ldirp = get_inode(fs_dev, dir_nr)) == NULL)
147 return(EINVAL);
149 /* Create the inode for the symlink. */
150 sip = new_node(ldirp, name, (I_SYMBOLIC_LINK | RWX_MODES), uid, gid, 0);
152 /* If we can then create fast symlink (store it in inode),
153 * Otherwise allocate a disk block for the contents of the symlink and
154 * copy contents of symlink (the name pointed to) into first disk block. */
155 if( (r = err_code) == OK) {
156 if (bytes + 1 > sip->i_sp->s_block_size) {
157 r = ENAMETOOLONG;
158 } else if ((bytes + 1) <= MAX_FAST_SYMLINK_LENGTH) {
159 r = fsdriver_copyin(data, 0, (char *) sip->i_block, bytes);
160 sip->i_dirt = IN_DIRTY;
161 link_target_buf = (char*) sip->i_block;
162 } else {
163 if ((bp = new_block(sip, (off_t) 0)) != NULL) {
164 r = fsdriver_copyin(data, 0, b_data(bp), bytes);
165 lmfs_markdirty(bp);
166 link_target_buf = b_data(bp);
167 } else {
168 r = err_code;
171 if (r == OK) {
172 assert(link_target_buf);
173 link_target_buf[bytes] = '\0';
174 sip->i_size = (off_t) strlen(link_target_buf);
175 if (sip->i_size != bytes) {
176 /* This can happen if the user provides a buffer
177 * with a \0 in it. This can cause a lot of trouble
178 * when the symlink is used later. We could just use
179 * the strlen() value, but we want to let the user
180 * know he did something wrong. ENAMETOOLONG doesn't
181 * exactly describe the error, but there is no
182 * ENAMETOOWRONG.
184 r = ENAMETOOLONG;
188 put_block(bp); /* put_block() accepts NULL. */
190 if(r != OK) {
191 sip->i_links_count = NO_LINK;
192 if (search_dir(ldirp, name, NULL, DELETE, 0) != OK)
193 panic("Symbolic link vanished");
197 /* put_inode() accepts NULL as a noop, so the below are safe. */
198 put_inode(sip);
199 put_inode(ldirp);
201 return(r);
204 /*===========================================================================*
205 * new_node *
206 *===========================================================================*/
207 static struct inode *new_node(struct inode *ldirp,
208 char *string, mode_t bits, uid_t uid, gid_t gid, block_t b0)
210 /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
211 * In all cases it allocates a new inode, makes a directory entry for it in
212 * the ldirp directory with string name, and initializes it.
213 * It returns a pointer to the inode if it can do this;
214 * otherwise it returns NULL. It always sets 'err_code'
215 * to an appropriate value (OK or an error code).
218 register struct inode *rip;
219 register int r;
221 if (ldirp->i_links_count == NO_LINK) { /* Dir does not actually exist */
222 err_code = ENOENT;
223 return(NULL);
226 if (S_ISDIR(bits) && (ldirp->i_links_count >= USHRT_MAX ||
227 ldirp->i_links_count >= LINK_MAX)) {
228 /* New entry is a directory, alas we can't give it a ".." */
229 err_code = EMLINK;
230 return(NULL);
233 /* Get final component of the path. */
234 rip = advance(ldirp, string);
236 if ( rip == NULL && err_code == ENOENT) {
237 /* Last path component does not exist. Make new directory entry. */
238 if ( (rip = alloc_inode(ldirp, bits, uid, gid)) == NULL) {
239 /* Can't creat new inode: out of inodes. */
240 return(NULL);
243 /* Force inode to the disk before making directory entry to make
244 * the system more robust in the face of a crash: an inode with
245 * no directory entry is much better than the opposite.
247 rip->i_links_count++;
248 rip->i_block[0] = b0; /* major/minor device numbers */
249 rw_inode(rip, WRITING); /* force inode to disk now */
251 /* New inode acquired. Try to make directory entry. */
252 if ((r=search_dir(ldirp, string, &rip->i_num, ENTER,
253 rip->i_mode & I_TYPE)) != OK) {
254 rip->i_links_count--; /* pity, have to free disk inode */
255 rip->i_dirt = IN_DIRTY; /* dirty inodes are written out */
256 put_inode(rip); /* this call frees the inode */
257 err_code = r;
258 return(NULL);
261 } else {
262 /* Either last component exists, or there is some problem. */
263 if (rip != NULL)
264 r = EEXIST;
265 else
266 r = err_code;
269 /* The caller has to return the directory inode (*ldirp). */
270 err_code = r;
271 return(rip);
275 /*===========================================================================*
276 * fs_seek *
277 *===========================================================================*/
278 void fs_seek(ino_t ino_nr)
280 struct inode *rip;
282 /* inhibit read ahead */
283 if ((rip = find_inode(fs_dev, ino_nr)) != NULL)
284 rip->i_seek = ISEEK;