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