xref: /minix/minix/fs/mfs/open.c (revision 9f988b79)
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"
7 
8 static struct inode *new_node(struct inode *ldirp, char *string, mode_t
9 	bits, uid_t uid, gid_t gid, zone_t z0);
10 
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)
16 {
17   int r;
18   struct inode *ldirp;
19   struct inode *rip;
20 
21   /* Try to make the file. */
22 
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);
26 
27   /* Create a new inode by calling new_node(). */
28   rip = new_node(ldirp, name, mode, uid, gid, NO_ZONE);
29   r = err_code;
30 
31   /* If an error occurred, release inode. */
32   if (r != OK) {
33 	  put_inode(ldirp);
34 	  put_inode(rip);
35 	  return(r);
36   }
37 
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;
45 
46   /* Drop parent dir */
47   put_inode(ldirp);
48 
49   return(OK);
50 }
51 
52 
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)
58 {
59   struct inode *ip, *ldirp;
60 
61   /* Get last directory inode */
62   if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
63 	  return(EINVAL);
64 
65   /* Try to create the new node */
66   ip = new_node(ldirp, name, mode, uid, gid, (zone_t) dev);
67 
68   put_inode(ip);
69   put_inode(ldirp);
70   return(err_code);
71 }
72 
73 
74 /*===========================================================================*
75  *				fs_mkdir				     *
76  *===========================================================================*/
77 int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
78 {
79   int r1, r2;			/* status codes */
80   ino_t dot, dotdot;		/* inode numbers for . and .. */
81   struct inode *rip, *ldirp;
82 
83   /* Get last directory inode */
84   if((ldirp = get_inode(fs_dev, dir_nr)) == NULL)
85       return(EINVAL);
86 
87   /* Next make the inode. If that fails, return error code. */
88   rip = new_node(ldirp, name, mode, uid, gid, (zone_t) 0);
89 
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);
94   }
95 
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 */
99 
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 */
103 
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() */
116   }
117   IN_MARKDIRTY(rip);		/* either way, i_nlinks has changed */
118 
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' */
122 }
123 
124 
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)
130 {
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 */
135 
136   /* Temporarily open the dir. */
137   if( (ldirp = get_inode(fs_dev, dir_nr)) == NULL)
138 	  return(EINVAL);
139 
140   /* Create the inode for the symlink. */
141   sip = new_node(ldirp, name, (I_SYMBOLIC_LINK | RWX_MODES), uid, gid, 0);
142 
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';
155 		}
156 	}
157 
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.
168 			 */
169 			r = ENAMETOOLONG;
170 		}
171 	}
172 
173 	put_block(bp); /* put_block() accepts NULL. */
174 
175 	if(r != OK) {
176 		sip->i_nlinks = NO_LINK;
177 		if(search_dir(ldirp, name, NULL, DELETE) != OK)
178 			  panic("Symbolic link vanished");
179 	}
180   }
181 
182   /* put_inode() accepts NULL as a noop, so the below are safe. */
183   put_inode(sip);
184   put_inode(ldirp);
185 
186   return(r);
187 }
188 
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)
194 {
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).
201  *
202  * The parsed path rest is returned in 'parsed' if parsed is nonzero. It
203  * has to hold at least MFS_NAME_MAX bytes.
204  */
205   register struct inode *rip;
206   register int r;
207 
208   if (ldirp->i_nlinks == NO_LINK) {	/* Dir does not actually exist */
209   	err_code = ENOENT;
210   	return(NULL);
211   }
212 
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);
217   }
218 
219   /* Get final component of the path. */
220   rip = advance(ldirp, string);
221 
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);
227 	}
228 
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.
232 	 */
233 	rip->i_nlinks++;
234 	rip->i_zone[0] = z0;		/* major/minor device numbers */
235 	rw_inode(rip, WRITING);		/* force inode to disk now */
236 
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);
244 	}
245 
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;
252   }
253 
254   /* The caller has to return the directory inode (*ldirp).  */
255   err_code = r;
256   return(rip);
257 }
258 
259 
260 /*===========================================================================*
261  *				fs_seek					     *
262  *===========================================================================*/
263 void fs_seek(ino_t ino_nr)
264 {
265   struct inode *rip;
266 
267   /* inhibit read ahead */
268   if ((rip = find_inode(fs_dev, ino_nr)) != NULL)
269 	  rip->i_seek = ISEEK;
270 }
271