1 /* Created (MFS based):
2 * February 2010 (Evgeniy Ivanov)
13 #include <minix/vfsif.h>
15 static struct inode
*new_node(struct inode
*ldirp
, char *string
, mode_t
19 /*===========================================================================*
21 *===========================================================================*/
29 char lastc
[NAME_MAX
+ 1];
31 /* Read request message */
32 omode
= (mode_t
) fs_m_in
.REQ_MODE
;
33 caller_uid
= (uid_t
) fs_m_in
.REQ_UID
;
34 caller_gid
= (gid_t
) fs_m_in
.REQ_GID
;
36 /* Try to make the file. */
38 /* Copy the last component (i.e., file name) */
39 len
= fs_m_in
.REQ_PATH_LEN
; /* including trailing '\0' */
40 if (len
> NAME_MAX
+ 1 || len
> EXT2_NAME_MAX
+ 1)
43 err_code
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) fs_m_in
.REQ_GRANT
,
44 (vir_bytes
) 0, (vir_bytes
) lastc
, (size_t) len
);
45 if (err_code
!= OK
) return err_code
;
46 NUL(lastc
, len
, sizeof(lastc
));
48 /* Get last directory inode (i.e., directory that will hold the new inode) */
49 if ((ldirp
= get_inode(fs_dev
, (ino_t
) fs_m_in
.REQ_INODE_NR
)) == NULL
)
52 /* Create a new inode by calling new_node(). */
53 rip
= new_node(ldirp
, lastc
, omode
, NO_BLOCK
);
56 /* If an error occurred, release inode. */
64 fs_m_out
.RES_INODE_NR
= rip
->i_num
;
65 fs_m_out
.RES_MODE
= rip
->i_mode
;
66 fs_m_out
.RES_FILE_SIZE_LO
= rip
->i_size
;
68 /* This values are needed for the execution */
69 fs_m_out
.RES_UID
= rip
->i_uid
;
70 fs_m_out
.RES_GID
= rip
->i_gid
;
79 /*===========================================================================*
81 *===========================================================================*/
84 struct inode
*ip
, *ldirp
;
85 char lastc
[NAME_MAX
+ 1];
88 /* Copy the last component and set up caller's user and group id */
89 len
= fs_m_in
.REQ_PATH_LEN
; /* including trailing '\0' */
90 if (len
> NAME_MAX
+ 1 || len
> EXT2_NAME_MAX
+ 1)
93 err_code
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) fs_m_in
.REQ_GRANT
,
94 (vir_bytes
) 0, (vir_bytes
) lastc
, (size_t) len
);
95 if (err_code
!= OK
) return err_code
;
96 NUL(lastc
, len
, sizeof(lastc
));
98 caller_uid
= (uid_t
) fs_m_in
.REQ_UID
;
99 caller_gid
= (gid_t
) fs_m_in
.REQ_GID
;
101 /* Get last directory inode */
102 if((ldirp
= get_inode(fs_dev
, (ino_t
) fs_m_in
.REQ_INODE_NR
)) == NULL
)
105 /* Try to create the new node */
106 ip
= new_node(ldirp
, lastc
, (mode_t
) fs_m_in
.REQ_MODE
,
107 (block_t
) fs_m_in
.REQ_DEV
);
115 /*===========================================================================*
117 *===========================================================================*/
120 int r1
, r2
; /* status codes */
121 ino_t dot
, dotdot
; /* inode numbers for . and .. */
122 struct inode
*rip
, *ldirp
;
123 char lastc
[NAME_MAX
+ 1]; /* last component */
126 /* Copy the last component and set up caller's user and group id */
127 len
= fs_m_in
.REQ_PATH_LEN
; /* including trailing '\0' */
128 if (len
> NAME_MAX
+ 1 || len
> EXT2_NAME_MAX
+ 1)
129 return(ENAMETOOLONG
);
131 err_code
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) fs_m_in
.REQ_GRANT
,
132 (vir_bytes
) 0, (vir_bytes
) lastc
, (phys_bytes
) len
);
133 if(err_code
!= OK
) return(err_code
);
134 NUL(lastc
, len
, sizeof(lastc
));
136 caller_uid
= (uid_t
) fs_m_in
.REQ_UID
;
137 caller_gid
= (gid_t
) fs_m_in
.REQ_GID
;
139 /* Get last directory inode */
140 if((ldirp
= get_inode(fs_dev
, (ino_t
) fs_m_in
.REQ_INODE_NR
)) == NULL
)
143 /* Next make the inode. If that fails, return error code. */
144 rip
= new_node(ldirp
, lastc
, (ino_t
) fs_m_in
.REQ_MODE
, (block_t
) 0);
146 if(rip
== NULL
|| err_code
== EEXIST
) {
147 put_inode(rip
); /* can't make dir: it already exists */
152 /* Get the inode numbers for . and .. to enter in the directory. */
153 dotdot
= ldirp
->i_num
; /* parent's inode number */
154 dot
= rip
->i_num
; /* inode number of the new dir itself */
156 /* Now make dir entries for . and .. unless the disk is completely full. */
157 /* Use dot1 and dot2, so the mode of the directory isn't important. */
158 rip
->i_mode
= (mode_t
) fs_m_in
.REQ_MODE
; /* set mode */
159 /* enter . in the new dir*/
160 r1
= search_dir(rip
, dot1
, &dot
, ENTER
, IGN_PERM
, I_DIRECTORY
);
161 /* enter .. in the new dir */
162 r2
= search_dir(rip
, dot2
, &dotdot
, ENTER
, IGN_PERM
, I_DIRECTORY
);
164 /* If both . and .. were successfully entered, increment the link counts. */
165 if (r1
== OK
&& r2
== OK
) {
166 /* Normal case. It was possible to enter . and .. in the new dir. */
167 rip
->i_links_count
++; /* this accounts for . */
168 ldirp
->i_links_count
++; /* this accounts for .. */
169 ldirp
->i_dirt
= IN_DIRTY
; /* mark parent's inode as dirty */
171 /* It was not possible to enter . or .. probably disk was full -
172 * links counts haven't been touched. */
173 if (search_dir(ldirp
, lastc
, NULL
, DELETE
, IGN_PERM
, 0) != OK
)
174 panic("Dir disappeared ", rip
->i_num
);
175 rip
->i_links_count
--; /* undo the increment done in new_node() */
177 rip
->i_dirt
= IN_DIRTY
; /* either way, i_links_count has changed */
179 put_inode(ldirp
); /* return the inode of the parent dir */
180 put_inode(rip
); /* return the inode of the newly made dir */
181 return(err_code
); /* new_node() always sets 'err_code' */
185 /*===========================================================================*
187 *===========================================================================*/
191 struct inode
*sip
; /* inode containing symbolic link */
192 struct inode
*ldirp
; /* directory containing link */
193 register int r
; /* error code */
194 char string
[NAME_MAX
]; /* last component of the new dir's path name */
195 char* link_target_buf
= NULL
; /* either sip->i_block or bp->b_data */
196 struct buf
*bp
= NULL
; /* disk buffer for link */
198 caller_uid
= (uid_t
) fs_m_in
.REQ_UID
;
199 caller_gid
= (gid_t
) fs_m_in
.REQ_GID
;
201 /* Copy the link name's last component */
202 len
= fs_m_in
.REQ_PATH_LEN
;
203 if (len
> NAME_MAX
|| len
> EXT2_NAME_MAX
)
204 return(ENAMETOOLONG
);
206 r
= sys_safecopyfrom(VFS_PROC_NR
, (cp_grant_id_t
) fs_m_in
.REQ_GRANT
,
207 (vir_bytes
) 0, (vir_bytes
) string
, (size_t) len
);
208 if (r
!= OK
) return(r
);
209 NUL(string
, len
, sizeof(string
));
211 /* Temporarily open the dir. */
212 if( (ldirp
= get_inode(fs_dev
, (ino_t
) fs_m_in
.REQ_INODE_NR
)) == NULL
)
215 /* Create the inode for the symlink. */
216 sip
= new_node(ldirp
, string
, (mode_t
) (I_SYMBOLIC_LINK
| RWX_MODES
),
219 /* If we can then create fast symlink (store it in inode),
220 * Otherwise allocate a disk block for the contents of the symlink and
221 * copy contents of symlink (the name pointed to) into first disk block. */
222 if( (r
= err_code
) == OK
) {
223 if ( (fs_m_in
.REQ_MEM_SIZE
+ 1) > sip
->i_sp
->s_block_size
) {
225 } else if ((fs_m_in
.REQ_MEM_SIZE
+ 1) <= MAX_FAST_SYMLINK_LENGTH
) {
226 r
= sys_safecopyfrom(VFS_PROC_NR
,
227 (cp_grant_id_t
) fs_m_in
.REQ_GRANT3
,
228 (vir_bytes
) 0, (vir_bytes
) sip
->i_block
,
229 (vir_bytes
) fs_m_in
.REQ_MEM_SIZE
);
230 sip
->i_dirt
= IN_DIRTY
;
231 link_target_buf
= (char*) sip
->i_block
;
233 if ((bp
= new_block(sip
, (off_t
) 0)) != NULL
) {
234 sys_safecopyfrom(VFS_PROC_NR
,
235 (cp_grant_id_t
) fs_m_in
.REQ_GRANT3
,
236 (vir_bytes
) 0, (vir_bytes
) b_data(bp
),
237 (vir_bytes
) fs_m_in
.REQ_MEM_SIZE
);
239 link_target_buf
= b_data(bp
);
245 assert(link_target_buf
);
246 link_target_buf
[fs_m_in
.REQ_MEM_SIZE
] = '\0';
247 sip
->i_size
= (off_t
) strlen(link_target_buf
);
248 if (sip
->i_size
!= fs_m_in
.REQ_MEM_SIZE
) {
249 /* This can happen if the user provides a buffer
250 * with a \0 in it. This can cause a lot of trouble
251 * when the symlink is used later. We could just use
252 * the strlen() value, but we want to let the user
253 * know he did something wrong. ENAMETOOLONG doesn't
254 * exactly describe the error, but there is no
261 put_block(bp
, DIRECTORY_BLOCK
); /* put_block() accepts NULL. */
264 sip
->i_links_count
= NO_LINK
;
265 if (search_dir(ldirp
, string
, NULL
, DELETE
, IGN_PERM
, 0) != OK
)
266 panic("Symbolic link vanished");
270 /* put_inode() accepts NULL as a noop, so the below are safe. */
277 /*===========================================================================*
279 *===========================================================================*/
280 static struct inode
*new_node(struct inode
*ldirp
,
281 char *string
, mode_t bits
, block_t b0
)
283 /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir().
284 * In all cases it allocates a new inode, makes a directory entry for it in
285 * the ldirp directory with string name, and initializes it.
286 * It returns a pointer to the inode if it can do this;
287 * otherwise it returns NULL. It always sets 'err_code'
288 * to an appropriate value (OK or an error code).
291 register struct inode
*rip
;
294 if (ldirp
->i_links_count
== NO_LINK
) { /* Dir does not actually exist */
299 /* Get final component of the path. */
300 rip
= advance(ldirp
, string
, IGN_PERM
);
302 if (S_ISDIR(bits
) && (ldirp
->i_links_count
>= USHRT_MAX
||
303 ldirp
->i_links_count
>= LINK_MAX
)) {
304 /* New entry is a directory, alas we can't give it a ".." */
310 if ( rip
== NULL
&& err_code
== ENOENT
) {
311 /* Last path component does not exist. Make new directory entry. */
312 if ( (rip
= alloc_inode(ldirp
, bits
)) == NULL
) {
313 /* Can't creat new inode: out of inodes. */
317 /* Force inode to the disk before making directory entry to make
318 * the system more robust in the face of a crash: an inode with
319 * no directory entry is much better than the opposite.
321 rip
->i_links_count
++;
322 rip
->i_block
[0] = b0
; /* major/minor device numbers */
323 rw_inode(rip
, WRITING
); /* force inode to disk now */
325 /* New inode acquired. Try to make directory entry. */
326 if ((r
=search_dir(ldirp
, string
, &rip
->i_num
, ENTER
, IGN_PERM
,
327 rip
->i_mode
& I_TYPE
)) != OK
) {
328 rip
->i_links_count
--; /* pity, have to free disk inode */
329 rip
->i_dirt
= IN_DIRTY
; /* dirty inodes are written out */
330 put_inode(rip
); /* this call frees the inode */
335 } else if (err_code
== EENTERMOUNT
|| err_code
== ELEAVEMOUNT
) {
338 /* Either last component exists, or there is some problem. */
345 /* The caller has to return the directory inode (*ldirp). */
351 /*===========================================================================*
353 *===========================================================================*/
358 if((rip
= find_inode(fs_dev
, (ino_t
) fs_m_in
.REQ_INODE_NR
)) == NULL
)
361 /* inhibit read ahead */