1433d6423SLionel Sambuc #include "fs.h" 2433d6423SLionel Sambuc #include <sys/stat.h> 3433d6423SLionel Sambuc #include <string.h> 4433d6423SLionel Sambuc #include "buf.h" 5433d6423SLionel Sambuc #include "inode.h" 6433d6423SLionel Sambuc #include "super.h" 7433d6423SLionel Sambuc 8433d6423SLionel Sambuc static struct inode *new_node(struct inode *ldirp, char *string, mode_t 9*ccaeedb2SDavid van Moolenbroek bits, uid_t uid, gid_t gid, zone_t z0); 10433d6423SLionel Sambuc 11433d6423SLionel Sambuc /*===========================================================================* 12433d6423SLionel Sambuc * fs_create * 13433d6423SLionel Sambuc *===========================================================================*/ 14*ccaeedb2SDavid van Moolenbroek int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid, 15*ccaeedb2SDavid van Moolenbroek struct fsdriver_node *node) 16433d6423SLionel Sambuc { 17433d6423SLionel Sambuc int r; 18433d6423SLionel Sambuc struct inode *ldirp; 19433d6423SLionel Sambuc struct inode *rip; 20433d6423SLionel Sambuc 21433d6423SLionel Sambuc /* Try to make the file. */ 22433d6423SLionel Sambuc 23433d6423SLionel Sambuc /* Get last directory inode (i.e., directory that will hold the new inode) */ 24*ccaeedb2SDavid van Moolenbroek if ((ldirp = get_inode(fs_dev, dir_nr)) == NULL) 25*ccaeedb2SDavid van Moolenbroek return(EINVAL); 26433d6423SLionel Sambuc 27433d6423SLionel Sambuc /* Create a new inode by calling new_node(). */ 28*ccaeedb2SDavid van Moolenbroek rip = new_node(ldirp, name, mode, uid, gid, NO_ZONE); 29433d6423SLionel Sambuc r = err_code; 30433d6423SLionel Sambuc 31433d6423SLionel Sambuc /* If an error occurred, release inode. */ 32433d6423SLionel Sambuc if (r != OK) { 33433d6423SLionel Sambuc put_inode(ldirp); 34433d6423SLionel Sambuc put_inode(rip); 35433d6423SLionel Sambuc return(r); 36433d6423SLionel Sambuc } 37433d6423SLionel Sambuc 38433d6423SLionel Sambuc /* Reply message */ 39*ccaeedb2SDavid van Moolenbroek node->fn_ino_nr = rip->i_num; 40*ccaeedb2SDavid van Moolenbroek node->fn_mode = rip->i_mode; 41*ccaeedb2SDavid van Moolenbroek node->fn_size = rip->i_size; 42*ccaeedb2SDavid van Moolenbroek node->fn_uid = rip->i_uid; 43*ccaeedb2SDavid van Moolenbroek node->fn_gid = rip->i_gid; 44*ccaeedb2SDavid van Moolenbroek node->fn_dev = NO_DEV; 45433d6423SLionel Sambuc 46433d6423SLionel Sambuc /* Drop parent dir */ 47433d6423SLionel Sambuc put_inode(ldirp); 48433d6423SLionel Sambuc 49433d6423SLionel Sambuc return(OK); 50433d6423SLionel Sambuc } 51433d6423SLionel Sambuc 52433d6423SLionel Sambuc 53433d6423SLionel Sambuc /*===========================================================================* 54433d6423SLionel Sambuc * fs_mknod * 55433d6423SLionel Sambuc *===========================================================================*/ 56*ccaeedb2SDavid van Moolenbroek int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid, 57*ccaeedb2SDavid van Moolenbroek dev_t dev) 58433d6423SLionel Sambuc { 59433d6423SLionel Sambuc struct inode *ip, *ldirp; 60433d6423SLionel Sambuc 61433d6423SLionel Sambuc /* Get last directory inode */ 62*ccaeedb2SDavid van Moolenbroek if((ldirp = get_inode(fs_dev, dir_nr)) == NULL) 63*ccaeedb2SDavid van Moolenbroek return(EINVAL); 64433d6423SLionel Sambuc 65433d6423SLionel Sambuc /* Try to create the new node */ 66*ccaeedb2SDavid van Moolenbroek ip = new_node(ldirp, name, mode, uid, gid, (zone_t) dev); 67433d6423SLionel Sambuc 68433d6423SLionel Sambuc put_inode(ip); 69433d6423SLionel Sambuc put_inode(ldirp); 70433d6423SLionel Sambuc return(err_code); 71433d6423SLionel Sambuc } 72433d6423SLionel Sambuc 73433d6423SLionel Sambuc 74433d6423SLionel Sambuc /*===========================================================================* 75433d6423SLionel Sambuc * fs_mkdir * 76433d6423SLionel Sambuc *===========================================================================*/ 77*ccaeedb2SDavid van Moolenbroek int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid) 78433d6423SLionel Sambuc { 79433d6423SLionel Sambuc int r1, r2; /* status codes */ 80433d6423SLionel Sambuc ino_t dot, dotdot; /* inode numbers for . and .. */ 81433d6423SLionel Sambuc struct inode *rip, *ldirp; 82433d6423SLionel Sambuc 83433d6423SLionel Sambuc /* Get last directory inode */ 84*ccaeedb2SDavid van Moolenbroek if((ldirp = get_inode(fs_dev, dir_nr)) == NULL) 85*ccaeedb2SDavid van Moolenbroek return(EINVAL); 86433d6423SLionel Sambuc 87433d6423SLionel Sambuc /* Next make the inode. If that fails, return error code. */ 88*ccaeedb2SDavid van Moolenbroek rip = new_node(ldirp, name, mode, uid, gid, (zone_t) 0); 89433d6423SLionel Sambuc 90433d6423SLionel Sambuc if(rip == NULL || err_code == EEXIST) { 91433d6423SLionel Sambuc put_inode(rip); /* can't make dir: it already exists */ 92433d6423SLionel Sambuc put_inode(ldirp); 93433d6423SLionel Sambuc return(err_code); 94433d6423SLionel Sambuc } 95433d6423SLionel Sambuc 96433d6423SLionel Sambuc /* Get the inode numbers for . and .. to enter in the directory. */ 97433d6423SLionel Sambuc dotdot = ldirp->i_num; /* parent's inode number */ 98433d6423SLionel Sambuc dot = rip->i_num; /* inode number of the new dir itself */ 99433d6423SLionel Sambuc 100433d6423SLionel Sambuc /* Now make dir entries for . and .. unless the disk is completely full. */ 101*ccaeedb2SDavid van Moolenbroek r1 = search_dir(rip, ".", &dot, ENTER); /* enter . in the new dir */ 102*ccaeedb2SDavid van Moolenbroek r2 = search_dir(rip, "..", &dotdot, ENTER); /* enter .. in the new dir */ 103433d6423SLionel Sambuc 104433d6423SLionel Sambuc /* If both . and .. were successfully entered, increment the link counts. */ 105433d6423SLionel Sambuc if (r1 == OK && r2 == OK) { 106433d6423SLionel Sambuc /* Normal case. It was possible to enter . and .. in the new dir. */ 107433d6423SLionel Sambuc rip->i_nlinks++; /* this accounts for . */ 108433d6423SLionel Sambuc ldirp->i_nlinks++; /* this accounts for .. */ 109433d6423SLionel Sambuc IN_MARKDIRTY(ldirp); /* mark parent's inode as dirty */ 110433d6423SLionel Sambuc } else { 111433d6423SLionel Sambuc /* It was not possible to enter . or .. probably disk was full - 112433d6423SLionel Sambuc * links counts haven't been touched. */ 113*ccaeedb2SDavid van Moolenbroek if(search_dir(ldirp, name, NULL, DELETE) != OK) 114433d6423SLionel Sambuc panic("Dir disappeared: %llu", rip->i_num); 115433d6423SLionel Sambuc rip->i_nlinks--; /* undo the increment done in new_node() */ 116433d6423SLionel Sambuc } 117433d6423SLionel Sambuc IN_MARKDIRTY(rip); /* either way, i_nlinks has changed */ 118433d6423SLionel Sambuc 119433d6423SLionel Sambuc put_inode(ldirp); /* return the inode of the parent dir */ 120433d6423SLionel Sambuc put_inode(rip); /* return the inode of the newly made dir */ 121433d6423SLionel Sambuc return(err_code); /* new_node() always sets 'err_code' */ 122433d6423SLionel Sambuc } 123433d6423SLionel Sambuc 124433d6423SLionel Sambuc 125433d6423SLionel Sambuc /*===========================================================================* 126433d6423SLionel Sambuc * fs_slink * 127433d6423SLionel Sambuc *===========================================================================*/ 128*ccaeedb2SDavid van Moolenbroek int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid, 129*ccaeedb2SDavid van Moolenbroek struct fsdriver_data *data, size_t bytes) 130433d6423SLionel Sambuc { 131433d6423SLionel Sambuc struct inode *sip; /* inode containing symbolic link */ 132433d6423SLionel Sambuc struct inode *ldirp; /* directory containing link */ 133433d6423SLionel Sambuc register int r; /* error code */ 134433d6423SLionel Sambuc struct buf *bp; /* disk buffer for link */ 135433d6423SLionel Sambuc 136433d6423SLionel Sambuc /* Temporarily open the dir. */ 137*ccaeedb2SDavid van Moolenbroek if( (ldirp = get_inode(fs_dev, dir_nr)) == NULL) 138433d6423SLionel Sambuc return(EINVAL); 139433d6423SLionel Sambuc 140433d6423SLionel Sambuc /* Create the inode for the symlink. */ 141*ccaeedb2SDavid van Moolenbroek sip = new_node(ldirp, name, (I_SYMBOLIC_LINK | RWX_MODES), uid, gid, 0); 142433d6423SLionel Sambuc 143433d6423SLionel Sambuc /* Allocate a disk block for the contents of the symlink. 144433d6423SLionel Sambuc * Copy contents of symlink (the name pointed to) into first disk block. */ 145433d6423SLionel Sambuc if( (r = err_code) == OK) { 146433d6423SLionel Sambuc bp = new_block(sip, (off_t) 0); 147433d6423SLionel Sambuc if (bp == NULL) 148433d6423SLionel Sambuc r = err_code; 149433d6423SLionel Sambuc else { 150*ccaeedb2SDavid van Moolenbroek if(get_block_size(sip->i_dev) <= bytes) { 151433d6423SLionel Sambuc r = ENAMETOOLONG; 152433d6423SLionel Sambuc } else { 153*ccaeedb2SDavid van Moolenbroek r = fsdriver_copyin(data, 0, b_data(bp), bytes); 154*ccaeedb2SDavid van Moolenbroek b_data(bp)[bytes] = '\0'; 155433d6423SLionel Sambuc } 156433d6423SLionel Sambuc } 157433d6423SLionel Sambuc 158433d6423SLionel Sambuc if(bp != NULL && r == OK) { 159433d6423SLionel Sambuc sip->i_size = (off_t) strlen(b_data(bp)); 160*ccaeedb2SDavid van Moolenbroek if(sip->i_size != bytes) { 161433d6423SLionel Sambuc /* This can happen if the user provides a buffer 162433d6423SLionel Sambuc * with a \0 in it. This can cause a lot of trouble 163433d6423SLionel Sambuc * when the symlink is used later. We could just use 164433d6423SLionel Sambuc * the strlen() value, but we want to let the user 165433d6423SLionel Sambuc * know he did something wrong. ENAMETOOLONG doesn't 166433d6423SLionel Sambuc * exactly describe the error, but there is no 167433d6423SLionel Sambuc * ENAMETOOWRONG. 168433d6423SLionel Sambuc */ 169433d6423SLionel Sambuc r = ENAMETOOLONG; 170433d6423SLionel Sambuc } 171433d6423SLionel Sambuc } 172433d6423SLionel Sambuc 173433d6423SLionel Sambuc put_block(bp, DIRECTORY_BLOCK); /* put_block() accepts NULL. */ 174433d6423SLionel Sambuc 175433d6423SLionel Sambuc if(r != OK) { 176433d6423SLionel Sambuc sip->i_nlinks = NO_LINK; 177*ccaeedb2SDavid van Moolenbroek if(search_dir(ldirp, name, NULL, DELETE) != OK) 178433d6423SLionel Sambuc panic("Symbolic link vanished"); 179433d6423SLionel Sambuc } 180433d6423SLionel Sambuc } 181433d6423SLionel Sambuc 182433d6423SLionel Sambuc /* put_inode() accepts NULL as a noop, so the below are safe. */ 183433d6423SLionel Sambuc put_inode(sip); 184433d6423SLionel Sambuc put_inode(ldirp); 185433d6423SLionel Sambuc 186433d6423SLionel Sambuc return(r); 187433d6423SLionel Sambuc } 188433d6423SLionel Sambuc 189433d6423SLionel Sambuc /*===========================================================================* 190433d6423SLionel Sambuc * new_node * 191433d6423SLionel Sambuc *===========================================================================*/ 192433d6423SLionel Sambuc static struct inode *new_node(struct inode *ldirp, 193*ccaeedb2SDavid van Moolenbroek char *string, mode_t bits, uid_t uid, gid_t gid, zone_t z0) 194433d6423SLionel Sambuc { 195433d6423SLionel Sambuc /* New_node() is called by fs_open(), fs_mknod(), and fs_mkdir(). 196433d6423SLionel Sambuc * In all cases it allocates a new inode, makes a directory entry for it in 197433d6423SLionel Sambuc * the ldirp directory with string name, and initializes it. 198433d6423SLionel Sambuc * It returns a pointer to the inode if it can do this; 199433d6423SLionel Sambuc * otherwise it returns NULL. It always sets 'err_code' 200433d6423SLionel Sambuc * to an appropriate value (OK or an error code). 201433d6423SLionel Sambuc * 202433d6423SLionel Sambuc * The parsed path rest is returned in 'parsed' if parsed is nonzero. It 203433d6423SLionel Sambuc * has to hold at least MFS_NAME_MAX bytes. 204433d6423SLionel Sambuc */ 205433d6423SLionel Sambuc register struct inode *rip; 206433d6423SLionel Sambuc register int r; 207433d6423SLionel Sambuc 208433d6423SLionel Sambuc if (ldirp->i_nlinks == NO_LINK) { /* Dir does not actually exist */ 209433d6423SLionel Sambuc err_code = ENOENT; 210433d6423SLionel Sambuc return(NULL); 211433d6423SLionel Sambuc } 212433d6423SLionel Sambuc 213433d6423SLionel Sambuc if (S_ISDIR(bits) && (ldirp->i_nlinks >= LINK_MAX)) { 214433d6423SLionel Sambuc /* New entry is a directory, alas we can't give it a ".." */ 215433d6423SLionel Sambuc err_code = EMLINK; 216433d6423SLionel Sambuc return(NULL); 217433d6423SLionel Sambuc } 218433d6423SLionel Sambuc 219*ccaeedb2SDavid van Moolenbroek /* Get final component of the path. */ 220*ccaeedb2SDavid van Moolenbroek rip = advance(ldirp, string); 221*ccaeedb2SDavid van Moolenbroek 222433d6423SLionel Sambuc if ( rip == NULL && err_code == ENOENT) { 223433d6423SLionel Sambuc /* Last path component does not exist. Make new directory entry. */ 224*ccaeedb2SDavid van Moolenbroek if ( (rip = alloc_inode((ldirp)->i_dev, bits, uid, gid)) == NULL) { 225433d6423SLionel Sambuc /* Can't creat new inode: out of inodes. */ 226433d6423SLionel Sambuc return(NULL); 227433d6423SLionel Sambuc } 228433d6423SLionel Sambuc 229433d6423SLionel Sambuc /* Force inode to the disk before making directory entry to make 230433d6423SLionel Sambuc * the system more robust in the face of a crash: an inode with 231433d6423SLionel Sambuc * no directory entry is much better than the opposite. 232433d6423SLionel Sambuc */ 233433d6423SLionel Sambuc rip->i_nlinks++; 234433d6423SLionel Sambuc rip->i_zone[0] = z0; /* major/minor device numbers */ 235433d6423SLionel Sambuc rw_inode(rip, WRITING); /* force inode to disk now */ 236433d6423SLionel Sambuc 237433d6423SLionel Sambuc /* New inode acquired. Try to make directory entry. */ 238*ccaeedb2SDavid van Moolenbroek if((r=search_dir(ldirp, string, &rip->i_num, ENTER)) != OK) { 239433d6423SLionel Sambuc rip->i_nlinks--; /* pity, have to free disk inode */ 240433d6423SLionel Sambuc IN_MARKDIRTY(rip); /* dirty inodes are written out */ 241433d6423SLionel Sambuc put_inode(rip); /* this call frees the inode */ 242433d6423SLionel Sambuc err_code = r; 243433d6423SLionel Sambuc return(NULL); 244433d6423SLionel Sambuc } 245433d6423SLionel Sambuc 246433d6423SLionel Sambuc } else { 247433d6423SLionel Sambuc /* Either last component exists, or there is some problem. */ 248433d6423SLionel Sambuc if (rip != NULL) 249433d6423SLionel Sambuc r = EEXIST; 250433d6423SLionel Sambuc else 251433d6423SLionel Sambuc r = err_code; 252433d6423SLionel Sambuc } 253433d6423SLionel Sambuc 254433d6423SLionel Sambuc /* The caller has to return the directory inode (*ldirp). */ 255433d6423SLionel Sambuc err_code = r; 256433d6423SLionel Sambuc return(rip); 257433d6423SLionel Sambuc } 258433d6423SLionel Sambuc 259433d6423SLionel Sambuc 260433d6423SLionel Sambuc /*===========================================================================* 261*ccaeedb2SDavid van Moolenbroek * fs_seek * 262433d6423SLionel Sambuc *===========================================================================*/ 263*ccaeedb2SDavid van Moolenbroek void fs_seek(ino_t ino_nr) 264433d6423SLionel Sambuc { 265433d6423SLionel Sambuc struct inode *rip; 266433d6423SLionel Sambuc 267433d6423SLionel Sambuc /* inhibit read ahead */ 268*ccaeedb2SDavid van Moolenbroek if ((rip = find_inode(fs_dev, ino_nr)) != NULL) 269433d6423SLionel Sambuc rip->i_seek = ISEEK; 270433d6423SLionel Sambuc } 271