func rename(oldname, newname string) error { e := syscall.Rename(oldname, newname) if e != nil { return &LinkError{"rename", oldname, newname, e} } return nil }
func movePkg(pkg *archPkg) os.Error { filename := fmt.Sprintf("%s-%s-%s.%s", pkg.Name, pkg.Version, pkg.Arch, pkg.Ext) srcPath := fmt.Sprintf("%s/%s", *cachePath, filename) /* try to rename, first */ errno := syscall.Rename(srcPath, fmt.Sprintf("%s/%s", *destPath, filename)) switch errno { case syscall.EXDEV: src, err := os.Open(srcPath, os.O_RDONLY, 0666) if err != nil { fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err.String()) os.Exit(1) } defer src.Close() sfi, err := src.Stat() dst, err := os.Open(fmt.Sprintf("%s/%s", *destPath, filename), os.O_WRONLY|os.O_CREAT|os.O_TRUNC, sfi.Permission()) if err != nil { fmt.Fprintf(os.Stderr, "%s: %s\n", os.Args[0], err.String()) os.Exit(1) } defer dst.Close() err = copyFile(src, bufio.NewWriter(dst)) if err == nil { return os.Remove(srcPath) } return err /* different from err outside if */ } return os.Errno(errno) }
func ObjDeleteHandler(writer http.ResponseWriter, request *http.Request, vars map[string]string, config ServerConfig) { hash_dir := ObjHashDir(vars, config) if os.MkdirAll(hash_dir, 0770) != nil { ErrorResponse(writer, 500) return } file_name := fmt.Sprintf("%s/%s.ts", hash_dir, request.Header.Get("X-Timestamp")) data_file := PrimaryFile(hash_dir) temp_file, err := ioutil.TempFile(ObjTempDir(vars, config), "PUT") if err != nil { ErrorResponse(writer, 500) return } defer temp_file.Close() metadata := make(map[string]interface{}) metadata["X-Timestamp"] = request.Header.Get("X-Timestamp") metadata["name"] = fmt.Sprintf("/%s/%s/%s", vars["account"], vars["container"], vars["obj"]) WriteMetadata(int(temp_file.Fd()), metadata) syscall.Fsync(int(temp_file.Fd())) syscall.Rename(temp_file.Name(), file_name) UpdateContainer("DELETE", metadata, request, vars) go CleanupHashDir(hash_dir) go InvalidateHash(hash_dir) if !strings.HasSuffix(data_file, ".data") { ErrorResponse(writer, 404) } else { ErrorResponse(writer, 204) } }
// Poor man's Renameat func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) { chdirMutex.Lock() defer chdirMutex.Unlock() // Unless both paths are absolute we have to save the old working dir and // Chdir(oldWd) back to it in the end. If we error out before the first // chdir, Chdir(oldWd) is unneccassary but does no harm. if !filepath.IsAbs(oldpath) || !filepath.IsAbs(newpath) { oldWd, err := os.Getwd() if err != nil { return err } defer os.Chdir(oldWd) } // Make oldpath absolute oldpath, err = dirfdAbs(olddirfd, oldpath) if err != nil { return err } // Make newpath absolute newpath, err = dirfdAbs(newdirfd, newpath) if err != nil { return err } return syscall.Rename(oldpath, newpath) }
// Rename renames a file. func Rename(oldname, newname string) Error { e := syscall.Rename(oldname, newname) if e != 0 { return &LinkError{"rename", oldname, newname, Errno(e)} } return nil }
func rename(oldname, newname string) error { fi, err := Lstat(newname) if err == nil && fi.IsDir() { return &LinkError{"rename", oldname, newname, syscall.EEXIST} } e := syscall.Rename(oldname, newname) if e != nil { return &LinkError{"rename", oldname, newname, e} } return nil }
func ObjPutHandler(writer http.ResponseWriter, request *http.Request, vars map[string]string, config ServerConfig) { out_headers := writer.Header() hash_dir := ObjHashDir(vars, config) if os.MkdirAll(hash_dir, 0770) != nil || os.MkdirAll(ObjTempDir(vars, config), 0770) != nil { ErrorResponse(writer, 500) return } file_name := fmt.Sprintf("%s/%s.data", hash_dir, request.Header.Get("X-Timestamp")) temp_file, err := ioutil.TempFile(ObjTempDir(vars, config), "PUT") if err != nil { ErrorResponse(writer, 500) return } defer temp_file.Close() metadata := make(map[string]interface{}) metadata["name"] = fmt.Sprintf("/%s/%s/%s", vars["account"], vars["container"], vars["obj"]) metadata["X-Timestamp"] = request.Header.Get("X-Timestamp") metadata["Content-Type"] = request.Header.Get("Content-Type") var chunk [65536]byte total_size := uint64(0) hash := md5.New() for { read_len, err := request.Body.Read(chunk[0:len(chunk)]) if err != nil || read_len <= 0 { break } total_size += uint64(read_len) hash.Write(chunk[0:read_len]) temp_file.Write(chunk[0:read_len]) } metadata["Content-Length"] = strconv.FormatUint(total_size, 10) metadata["ETag"] = fmt.Sprintf("%x", hash.Sum(nil)) request_etag := request.Header.Get("ETag") if request_etag != "" && request_etag != metadata["ETag"].(string) { ErrorResponse(writer, 422) return } for key := range request.Header { if strings.HasPrefix(key, "X-Object-") { metadata[key] = request.Header.Get(key) } } out_headers.Set("ETag", metadata["ETag"].(string)) WriteMetadata(int(temp_file.Fd()), metadata) syscall.Fsync(int(temp_file.Fd())) syscall.Rename(temp_file.Name(), file_name) UpdateContainer("PUT", metadata, request, vars) go CleanupHashDir(hash_dir) go InvalidateHash(hash_dir) ErrorResponse(writer, 201) }
// Create and rename a file func testRename(t *testing.T, plainDir string) { file1 := plainDir + "rename1" file2 := plainDir + "rename2" err := ioutil.WriteFile(file1, []byte("content"), 0777) if err != nil { t.Fatal(err) } err = syscall.Rename(file1, file2) if err != nil { t.Fatal(err) } syscall.Unlink(file2) }
func (c *Host) updateWinHost() string { new := c.createNewHost() path := os.Getenv("SystemRoot") old := path + `\System32\drivers\etc\hosts` newFile := utf16.Encode([]rune(new + "\x00")) oldFile := utf16.Encode([]rune(old + "\x00")) syscall.Rename(old, old+time.Now().Format("-2006-01-02-15-04-05")+".bak") err := syscall.MoveFile(&newFile[0], &oldFile[0]) fmt.Println(err) time.Sleep(time.Second * 10) return "" }
// Import imports the source file into diskv under the destination key. If the // destination key already exists, it's overwritten. If move is true, the // source file is removed after a successful import. func (d *Diskv) Import(srcFilename, dstKey string, move bool) (err error) { if dstKey == "" { return errEmptyKey } if fi, err := os.Stat(srcFilename); err != nil { return err } else if fi.IsDir() { return errImportDirectory } d.mu.Lock() defer d.mu.Unlock() if err := d.ensurePathWithLock(dstKey); err != nil { return fmt.Errorf("ensure path: %s", err) } if move { if err := syscall.Rename(srcFilename, d.completeFilename(dstKey)); err == nil { d.bustCacheWithLock(dstKey) return nil } else if err != syscall.EXDEV { // If it failed due to being on a different device, fall back to copying return err } } f, err := os.Open(srcFilename) if err != nil { return err } defer f.Close() err = d.writeStreamWithLock(dstKey, f, false) if err == nil && move { err = os.Remove(srcFilename) } return err }
func WriteFileAtomic(filename string, data []byte, perm os.FileMode) error { partDir := filepath.Dir(filename) tmpFile, err := ioutil.TempFile(partDir, ".tmp-o-file") if err != nil { return err } defer tmpFile.Close() defer os.RemoveAll(tmpFile.Name()) if err = tmpFile.Chmod(perm); err != nil { return err } if _, err = tmpFile.Write(data); err != nil { return err } if err = tmpFile.Sync(); err != nil { return err } if err = syscall.Rename(tmpFile.Name(), filename); err != nil { return err } return nil }
func (file *File) rename( fs *Fs, orig_path string, new_path string) error { fs.filesLock.Lock() defer fs.filesLock.Unlock() other_file, ok := fs.files[new_path] if ok && other_file.exists() { return Eexist } // Drop the original reference. // (We've not replaced it atomically). if other_file != nil { defer other_file.DecRef(fs, "") } if file.write_exists && file.write_deleted { // Is it just marked deleted? err := file.unlink() if err != nil { return err } } // Try the rename. orig_read_path := file.read_path orig_write_path := file.write_path file.findPaths(fs, new_path) err := syscall.Rename(orig_write_path, file.write_path) if err != nil { if err == syscall.EXDEV { // TODO: The file cannot be renamed across file system. // This is a simple matter of copying the file across when // this happens. For now, we just return not implemented. err = Enotimpl } file.read_path = orig_read_path file.write_path = orig_write_path return err } // We've moved this file. // It didn't exist a moment ago, but it does now. file.write_exists = true file.write_deleted = false // Update our fids. // This is a bit messy, but since we are // holding a writeLock on this file, this // atomic should be reasonably atomic. for _, fid := range fs.Pool { if fid.file == file { fid.Path = new_path } else if other_file != nil && fid.file == other_file { // Since we hold at least one reference // to other_file, this should never trigger // a full cleanup of other_file. It's safe // to call DecRef here while locking the lock. file.IncRef(fs) fid.file = file other_file.DecRef(fs, "") } } // Perform the swaperoo. fs.files[new_path] = file delete(fs.files, orig_path) // Ensure the original file is deleted. // This is done at the very end, since there's // really nothing we can do at this point. We // even explicitly ignore the result. Ugh. setdelattr(orig_write_path) return nil }
func Handler(c http.ResponseWriter, r *http.Request) { c.Header().Set("Content-Type", "application/json") api_key := r.FormValue("api_key") //base_url := r.FormValue("base_url") if api_key != Cfg.ApiKey { write(c, jsonError("failed", "Invalid api key")) return } requested_url := r.FormValue("u") if requested_url == "" { r.ParseForm() file_name := r.FormValue("file_name") if file_name == "" { write(c, jsonError("failed", "no `file_name` parameter")) return } fmt.Printf("file_name: %v\n", file_name) file, err := r.MultipartReader() if err != nil { write(c, jsonError("failed", "cannot get multipart reader")) return } part, err := file.NextPart() if err != nil { write(c, jsonError("failed", "no `u` nor `file`")) return } var data [1000]byte var i int = 0 var data_size int64 = 0 md5ed := hmac.NewMD5([]byte("cdnized-2194")) abs_path := "/tmp/" + RandStrings(100) dst_file, err := os.OpenFile(abs_path, os.O_WRONLY|os.O_CREATE, 0755) if err != nil { anlog.Error("Cannot create file `%s`. error: %s\n", abs_path, err.String()) write(c, jsonError("failed", fmt.Sprintf("cannot create temporary data. %v\n", err))) return } for data_size < r.ContentLength { i, err = part.Read(data[0:999]) if err != nil { break } _, err := md5ed.Write(data[0:i]) if err != nil { anlog.Error("Cannot calculate MD5 hash") write(c, jsonError("failed", "cannot calculate checksum")) break } _, err = dst_file.Write(data[0:i]) if err != nil { anlog.Error("Cannot write %d bytes data in file `%s`. error: %s\n", data_size, abs_path, err.String()) } data_size += int64(i) } dst_file.Close() //fmt.Printf("content-length: %v, file: %v, file-length: %v, i: %v\n", r.ContentLength, string(data[0:]), i, i) hash := fmt.Sprintf("%x", md5ed.Sum()) file_ext := path.Ext(file_name) file_name = hash + RandStrings(9) + file_ext new_path, err := os.Getwd() new_path = path.Join(new_path, Cfg.StoreDir[2:], Cfg.ApiStorePrefix, file_name) if err != nil { anlog.Error("Cannot getwd\n") write(c, jsonError("failed", "internal error")) return } //fmt.Printf("abs_path: %v, new_path: %v\n", abs_path, new_path) if err := syscall.Rename(abs_path, new_path); err != 0 { anlog.Error("Cannot move from file `%s` to `%s`. %v.\n", abs_path, new_path, err) write(c, jsonError("failed", "internal error")) return } cdnized_url := fmt.Sprintf("http://%s/%s/%s/%s", Cfg.CdnServerName, Cfg.StoreDir[2:], Cfg.ApiStorePrefix, file_name) anlog.Info("cdnized_url: %s\n", cdnized_url) os.Remove(abs_path) type success struct { Status string Size int64 Cdnized_url string } write(c, Jsonize(&success{"ok", data_size, cdnized_url})) return } //write(c, fmt.Sprintf("{Status: 'ok', url_path: '%s', gen: '%s'}", requested_url, x)) file_ext := path.Ext(requested_url) abs_path, _ := os.Getwd() abs_path = path.Join(abs_path, Cfg.StoreDir[2:], Cfg.ApiStorePrefix, RandStrings(64)+file_ext) fmt.Printf("abs_path: %s\n", abs_path) var data []byte rv, lm, tsize := downloader.Download(requested_url, abs_path, true, &data) if rv != true { write(c, jsonError("failed", "Cannot fetch from source url")) return } md5ed := hmac.NewMD5([]byte("cdnized-2194")) for { brw, err := md5ed.Write(data) if err != nil { anlog.Error("Cannot calculate MD5 hash") write(c, jsonError("failed", "Internal error")) return } if brw >= tsize { break } } hash := fmt.Sprintf("%x", md5ed.Sum()) dir, _ := path.Split(abs_path) file_name := hash + RandStrings(8) + file_ext new_path := path.Join(dir, file_name) if err := syscall.Rename(abs_path, new_path); err != 0 { anlog.Error("Cannot rename from file `%s` to `%s`", abs_path, new_path) write(c, jsonError("failed", "Internal error")) return } cdnized_url := fmt.Sprintf("http://%s/%s/%s/%s", Cfg.CdnServerName, Cfg.StoreDir[2:], Cfg.ApiStorePrefix, file_name) anlog.Info("cdnized_url: %s", cdnized_url) type success struct { Status string Lm string Size int Original string Cdnized_url string } write(c, Jsonize(&success{"ok", lm, tsize, requested_url, cdnized_url})) }
func (u *Ufs) Wstat(req *SrvReq) { fid := req.Fid.Aux.(*ufsFid) err := fid.stat() if err != nil { req.RespondError(err) return } dir := &req.Tc.Dir if dir.Mode != 0xFFFFFFFF { mode := dir.Mode & 0777 if req.Conn.Dotu { if dir.Mode&DMSETUID > 0 { mode |= syscall.S_ISUID } if dir.Mode&DMSETGID > 0 { mode |= syscall.S_ISGID } } e := os.Chmod(fid.path, os.FileMode(mode)) if e != nil { req.RespondError(toError(e)) return } } uid, gid := NOUID, NOUID if req.Conn.Dotu { uid = dir.Uidnum gid = dir.Gidnum } // Try to find local uid, gid by name. if (dir.Uid != "" || dir.Gid != "") && !req.Conn.Dotu { uid, err = lookup(dir.Uid, false) if err != nil { req.RespondError(err) return } // BUG(akumar): Lookup will never find gids // corresponding to group names, because // it only operates on user names. gid, err = lookup(dir.Gid, true) if err != nil { req.RespondError(err) return } } if uid != NOUID || gid != NOUID { e := os.Chown(fid.path, int(uid), int(gid)) if e != nil { req.RespondError(toError(e)) return } } if dir.Name != "" { fmt.Printf("Rename %s to %s\n", fid.path, dir.Name) // if first char is / it is relative to root, else relative to // cwd. var destpath string if dir.Name[0] == '/' { destpath = path.Join(u.Root, dir.Name) fmt.Printf("/ results in %s\n", destpath) } else { fiddir, _ := path.Split(fid.path) destpath = path.Join(fiddir, dir.Name) fmt.Printf("rel results in %s\n", destpath) } err := syscall.Rename(fid.path, destpath) fmt.Printf("rename %s to %s gets %v\n", fid.path, destpath, err) if err != nil { req.RespondError(toError(err)) return } fid.path = destpath } if dir.Length != 0xFFFFFFFFFFFFFFFF { e := os.Truncate(fid.path, int64(dir.Length)) if e != nil { req.RespondError(toError(e)) return } } // If either mtime or atime need to be changed, then // we must change both. if dir.Mtime != ^uint32(0) || dir.Atime != ^uint32(0) { mt, at := time.Unix(int64(dir.Mtime), 0), time.Unix(int64(dir.Atime), 0) if cmt, cat := (dir.Mtime == ^uint32(0)), (dir.Atime == ^uint32(0)); cmt || cat { st, e := os.Stat(fid.path) if e != nil { req.RespondError(toError(e)) return } switch cmt { case true: mt = st.ModTime() default: //at = time.Time(0)//atime(st.Sys().(*syscall.Stat_t)) } } e := os.Chtimes(fid.path, at, mt) if e != nil { req.RespondError(toError(e)) return } } req.RespondRwstat() }
func TestRotatableFileWriter(t *testing.T) { dirs := make([]string, 0, 10) defer func() { if !t.Failed() { for _, dir := range dirs { os.RemoveAll(dir) } } }() for _, test := range rotateTests { dir, err := ioutil.TempDir("/tmp", "rfw") if err != nil { t.Fatal(err) } t.Logf("Test directory: %s\n", dir) dirs = append(dirs, dir) rotates := 0 path := filepath.Join(dir, "log_test.log") rfw, err := NewRotatableFileWriter(path, os.O_CREATE|os.O_RDWR|os.O_APPEND, os.FileMode(0644), test.checkFreq) if err != nil { t.Error(err) continue } files := make(map[string][]string) files[path] = make([]string, 0, 10) ignoreLines := false TEST_LOOP: for _, event := range test.events { switch event.eventType { case logEventType: t.Logf("Writing: %s", event.message) _, err = rfw.Write([]byte(event.message + "\n")) if err != nil { if err == NilFileHandleErr { t.Log(err) } else { t.Error(err) break TEST_LOOP } } if !ignoreLines { files[path] = append(files[path], event.message) } case rotateEventType: t.Log("rotating") movePath := fmt.Sprintf("%s.%d", path, rotates) err = syscall.Rename(path, movePath) files[movePath] = files[path] files[path] = make([]string, 0, 10) ignoreLines = false rotates++ case nilHandleType: t.Log("niling handle") rfw.fileHandle.Close() ignoreLines = true rfw.fileHandle = nil } time.Sleep(event.delay) } actualFiles, err := ioutil.ReadDir(dir) if err != nil { t.Error(err) continue } for _, fi := range actualFiles { if filepath.Base(fi.Name()) == "." || filepath.Base(fi.Name()) == ".." { continue } t.Logf("File: %s", fi.Name()) file := filepath.Join(dir, fi.Name()) var fileLines []string if d, ok := files[file]; ok { fileLines = d } else { t.Error("unexpected file", file) } fh, err := os.Open(file) if err != nil { t.Error(err) continue } data, err := ioutil.ReadAll(fh) if err != nil { t.Error(err) continue } lines := strings.Split(string(data), "\n") lines = lines[0 : len(lines)-1] if len(lines) != len(fileLines) { t.Errorf("Expected line count to match: %d != %d", len(lines), len(fileLines)) } for i, line := range lines { if i >= len(fileLines) { break } if line != fileLines[i] { t.Errorf("Expected '%s' == '%s'", line, fileLines[i]) } } } } }
func (u *Ufs) Wstat(req *srv.Req) { var changed bool fid := req.Fid.Aux.(*Fid) err := fid.stat() if err != nil { req.RespondError(err) return } dir := &req.Tc.Dir if dir.Mode != 0xFFFFFFFF { changed = true mode := dir.Mode & 0777 if req.Conn.Dotu { if dir.Mode&ninep.DMSETUID > 0 { mode |= syscall.S_ISUID } if dir.Mode&ninep.DMSETGID > 0 { mode |= syscall.S_ISGID } } e := os.Chmod(fid.path, os.FileMode(mode)) if e != nil { req.RespondError(toError(e)) return } } uid, gid := ninep.NOUID, ninep.NOUID if req.Conn.Dotu { uid = dir.Uidnum gid = dir.Gidnum } // Try to find local uid, gid by name. if (dir.Uid != "" || dir.Gid != "") && !req.Conn.Dotu { changed = true uid, err = lookup(dir.Uid, false) if err != nil { req.RespondError(err) return } // BUG(akumar): Lookup will never find gids // corresponding to group names, because // it only operates on user names. gid, err = lookup(dir.Gid, true) if err != nil { req.RespondError(err) return } } if uid != ninep.NOUID || gid != ninep.NOUID { changed = true e := os.Chown(fid.path, int(uid), int(gid)) if e != nil { req.RespondError(toError(e)) return } } if dir.Name != "" { changed = true // If we path.Join dir.Name to / before adding it to // the fid path, that ensures nobody gets to walk out of the // root of this server. newname := path.Join(path.Dir(fid.path), path.Join("/", dir.Name)) // absolute renaming. Ufs can do this, so let's support it. // We'll allow an absolute path in the Name and, if it is, // we will make it relative to root. This is a gigantic performance // improvement in systems that allow it. if filepath.IsAbs(dir.Name) { newname = path.Join(u.Root, dir.Name) } err := syscall.Rename(fid.path, newname) if err != nil { req.RespondError(toError(err)) return } fid.path = newname } if dir.Length != 0xFFFFFFFFFFFFFFFF { changed = true e := os.Truncate(fid.path, int64(dir.Length)) if e != nil { req.RespondError(toError(e)) return } } // If either mtime or atime need to be changed, then // we must change both. if dir.Mtime != ^uint32(0) || dir.Atime != ^uint32(0) { changed = true mt, at := time.Unix(int64(dir.Mtime), 0), time.Unix(int64(dir.Atime), 0) if cmt, cat := (dir.Mtime == ^uint32(0)), (dir.Atime == ^uint32(0)); cmt || cat { st, e := os.Stat(fid.path) if e != nil { req.RespondError(toError(e)) return } switch cmt { case true: mt = st.ModTime() default: at = atime(st.Sys().(*syscall.Stat_t)) } } e := os.Chtimes(fid.path, at, mt) if e != nil { req.RespondError(toError(e)) return } } if !changed && fid.file != nil { fid.file.Sync() } req.RespondRwstat() }
func (u *VuFs) Wstat(req *srv.Req) { fid := req.Fid.Aux.(*Fid) _, err := os.Stat(fid.path) if err != nil { req.RespondError(toError(err)) return } dir := &req.Tc.Dir if dir.Mode != 0xFFFFFFFF { mode := dir.Mode & 0777 e := os.Chmod(fid.path, os.FileMode(mode)) if e != nil { req.RespondError(toError(e)) return } } /* // BUG(mbucc) implement chown uid, gid := p.NOUID, p.NOUID uid, err = lookup(dir.Uid, false) if err != nil { req.RespondError(err) return } gid, err = lookup(dir.Gid, true) if err != nil { req.RespondError(err) return } if uid != p.NOUID || gid != p.NOUID { e := os.Chown(fid.path, int(uid), int(gid)) if e != nil { req.RespondError(toError(e)) return } } */ if dir.Name != "" { // If we path.Join dir.Name to / before adding it to // the fid path, that ensures nobody gets to walk out of the // root of this server. newname := path.Join(path.Dir(fid.path), path.Join("/", dir.Name)) // absolute renaming. VuFs can do this, so let's support it. // We'll allow an absolute path in the Name and, if it is, // we will make it relative to root. This is a gigantic performance // improvement in systems that allow it. if filepath.IsAbs(dir.Name) { newname = path.Join(fid.path, dir.Name) } err := syscall.Rename(fid.path, newname) if err != nil { req.RespondError(toError(err)) return } fid.path = newname } if dir.Length != 0xFFFFFFFFFFFFFFFF { e := os.Truncate(fid.path, int64(dir.Length)) if e != nil { req.RespondError(toError(e)) return } } // If either mtime or atime need to be changed, then // we must change both. if dir.Mtime != ^uint32(0) || dir.Atime != ^uint32(0) { mt, at := time.Unix(int64(dir.Mtime), 0), time.Unix(int64(dir.Atime), 0) if cmt, cat := (dir.Mtime == ^uint32(0)), (dir.Atime == ^uint32(0)); cmt || cat { st, e := os.Stat(fid.path) if e != nil { req.RespondError(toError(e)) return } switch cmt { case true: mt = st.ModTime() default: at = atime(st.Sys().(*syscall.Stat_t)) } } e := os.Chtimes(fid.path, at, mt) if e != nil { req.RespondError(toError(e)) return } } req.RespondRwstat() }
func (*Ufs) Wstat(req *srv.Req) { fid := req.Fid.Aux.(*Fid) err := fid.stat() if err != nil { req.RespondError(err) return } dir := &req.Tc.Dir if dir.Mode != 0xFFFFFFFF { mode := dir.Mode & 0777 if req.Conn.Dotu { if dir.Mode&p.DMSETUID > 0 { mode |= syscall.S_ISUID } if dir.Mode&p.DMSETGID > 0 { mode |= syscall.S_ISGID } } e := os.Chmod(fid.path, os.FileMode(mode)) if e != nil { req.RespondError(toError(e)) return } } uid, gid := p.NOUID, p.NOUID if req.Conn.Dotu { uid = dir.Uidnum gid = dir.Gidnum } // Try to find local uid, gid by name. if (dir.Uid != "" || dir.Gid != "") && !req.Conn.Dotu { uid, err = lookup(dir.Uid, false) if err != nil { req.RespondError(err) return } // BUG(akumar): Lookup will never find gids // corresponding to group names, because // it only operates on user names. gid, err = lookup(dir.Gid, true) if err != nil { req.RespondError(err) return } } if uid != p.NOUID || gid != p.NOUID { e := os.Chown(fid.path, int(uid), int(gid)) if e != nil { req.RespondError(toError(e)) return } } if dir.Name != "" { path := fid.path[0:strings.LastIndex(fid.path, "/")+1] + "/" + dir.Name err := syscall.Rename(fid.path, path) if err != nil { req.RespondError(toError(err)) return } fid.path = path } if dir.Length != 0xFFFFFFFFFFFFFFFF { e := os.Truncate(fid.path, int64(dir.Length)) if e != nil { req.RespondError(toError(e)) return } } // If either mtime or atime need to be changed, then // we must change both. if dir.Mtime != ^uint32(0) || dir.Atime != ^uint32(0) { mt, at := time.Unix(int64(dir.Mtime), 0), time.Unix(int64(dir.Atime), 0) if cmt, cat := (dir.Mtime == ^uint32(0)), (dir.Atime == ^uint32(0)); cmt || cat { st, e := os.Stat(fid.path) if e != nil { req.RespondError(toError(e)) return } switch cmt { case true: mt = st.ModTime() default: at = atime(st.Sys().(*syscall.Stat_t)) } } e := os.Chtimes(fid.path, at, mt) if e != nil { req.RespondError(toError(e)) return } } req.RespondRwstat() }
func (constor *Constor) Rename(input *fuse.RenameIn, oldName string, newName string) (code fuse.Status) { var unhashDentry *Dentry oldParent := input.NodeId newParent := input.Newdir oldpath, err := constor.dentrymap.getPathName(oldParent, oldName) if err != nil { constor.error("%s", err) return fuse.ToStatus(err) } newpath, err := constor.dentrymap.getPathName(newParent, newName) if err != nil { constor.error("%s", err) return fuse.ToStatus(err) } // newdirpath, err := constor.dentrymap.getPath(newParent) // if err != nil { // constor.error("%s", err) // return fuse.ToStatus(err) // } // remove dst file oldli := constor.getLayer(oldpath) if oldli == -1 { constor.error("oldli == -1") return fuse.ENOENT } oldstat := syscall.Stat_t{} newstat := syscall.Stat_t{} err = constor.Lstat(oldpath, &oldstat) if err != nil { constor.error("%s", err) return fuse.ToStatus(err) } if oldstat.Mode&syscall.S_IFDIR != 0 { allow := true for i, l := range constor.layers { if i == 0 { continue } pathl := Path.Join(l, oldpath) if constor.isdeleted(pathl) { break } if _, err := os.Lstat(pathl); err == nil { allow = false break } } if !allow { // FIXME: allow renaming of directories constor.error("rename of directory %s %d %d %d", oldpath, oldstat.Ino, oldstat.Mode, oldstat.Mode|syscall.S_IFDIR) return fuse.EIO } } err = constor.Lstat(newpath, &newstat) if err == nil { unhashDentry, _ = constor.dentrymap.findDentry(newParent, newstat.Ino) } oldpathl := Path.Join(constor.layers[0], oldpath) newpathl := Path.Join(constor.layers[0], newpath) if oldli == 0 { err = syscall.Rename(oldpathl, newpathl) if err != nil { constor.error("%s", err) return fuse.ToStatus(err) } lowerli := constor.getLayer(oldpath) if lowerli != -1 { constor.setdeleted(oldpathl) } } else if oldli > 0 { inode, err := constor.inodemap.findInode(oldstat.Ino) if err != nil { constor.error("%s", err) return fuse.ToStatus(err) } err = constor.copyup(inode) if err != nil { constor.error("%s", err) return fuse.ToStatus(err) } err = syscall.Rename(oldpathl, newpathl) if err != nil { constor.error("%s", err) return fuse.ToStatus(err) } constor.setdeleted(oldpathl) } if unhashDentry != nil { constor.dentrymap.unhashDentry(unhashDentry) } err = constor.dentrymap.dentryChangeparent(oldstat.Ino, oldParent, newParent, oldName, newName) if err != nil { constor.error("%s", err) return fuse.ToStatus(err) } return fuse.OK }
// sad news. If I concat the Go cpio with the other cpios, for reasons I don't understand, // the kernel can't unpack it. Don't know why, don't care. Need to create one giant cpio and unpack that. // It's not size related: if the go archive is first or in the middle it still fails. func main() { flag.BoolVar(&config.Debug, "d", false, "Debugging") flag.BoolVar(&config.TestChroot, "test", false, "test the directory by chrooting to it") flag.BoolVar(&config.UseExistingInit, "useinit", false, "If there is an existing init, don't replace it") flag.BoolVar(&config.RemoveDir, "removedir", true, "remove the directory when done -- cleared if test fails") flag.StringVar(&config.InitialCpio, "cpio", "", "An initial cpio image to build on") flag.StringVar(&config.TempDir, "tmpdir", "", "tmpdir to use instead of ioutil.TempDir") flag.Parse() if config.Debug { debug = log.Printf } var err error Dirs = make(map[string]bool) Deps = make(map[string]bool) GorootFiles = make(map[string]bool) UrootFiles = make(map[string]bool) guessgoarch() config.Go = "" config.Goos = "linux" guessgoroot() guessgopath() if config.Fail { log.Fatal("Setup failed") } if err := addGoFiles(); err != nil { log.Fatalf("%v", err) } if config.TempDir == "" { config.TempDir, err = ioutil.TempDir("", "u-root") if err != nil { log.Fatalf("%v", err) } } defer func() { if config.RemoveDir { log.Printf("Removing %v\n", config.TempDir) // Wow, this one is *scary* cmd := exec.Command("sudo", "rm", "-rf", config.TempDir) cmd.Stderr, cmd.Stdout = os.Stderr, os.Stdout err = cmd.Run() if err != nil { log.Fatalf("%v", err) } } }() buildToolChain() if config.InitialCpio != "" { f, err := ioutil.ReadFile(config.InitialCpio) if err != nil { log.Fatalf("%v", err) } cmd := exec.Command("sudo", "cpio", "-i", "-v") cmd.Dir = config.TempDir // Note: if you print Cmd out with %v after assigning cmd.Stdin, it will print // the whole cpio; so don't do that. if config.Debug { cmd.Stdout = os.Stdout } debug("Run %v @ %v", cmd, cmd.Dir) // There's a bit of a tough problem here. There's lots of stuff owned by root in // these directories. They probably have to stay that way. But how do we create init // and do other things? For now, we're going to set the modes of select places to // 666 and remove a few things we know need to be removed. // It's hard to say what else to do. cmd.Stdin = bytes.NewBuffer(f) cmd.Stderr = os.Stderr err = cmd.Run() if err != nil { log.Printf("Unpacking %v: %v", config.InitialCpio, err) } } if !config.UseExistingInit { init := path.Join(config.TempDir, "init") // Must move config.TempDir/init to inito if one is not there. inito := path.Join(config.TempDir, "inito") if _, err := os.Stat(inito); err != nil { // WTF? did Ron forget about rename? Yuck! if err := syscall.Rename(init, inito); err != nil { log.Printf("%v", err) } } else { log.Printf("Not replacing %v because there is already one there.", inito) } // Build init cmd := exec.Command("go", "build", "-x", "-a", "-installsuffix", "cgo", "-ldflags", "'-s'", "-o", init, ".") cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout cmd.Dir = path.Join(config.Urootpath, "cmds/init") err = cmd.Run() if err != nil { log.Fatalf("%v\n", err) } } // These produce arrays of strings, the first element being the // directory to walk from. cpio := []string{ goList, urootList, } for _, c := range cpio { if err := cpiop(c); err != nil { log.Printf("Things went south. TempDir is %v", config.TempDir) log.Fatalf("Bailing out near line 666") } } debug("Done all cpio operations") r, w, err := os.Pipe() if err != nil { log.Fatalf("%v\n", err) } // First create the archive and put the device cpio in it. dev, err := ioutil.ReadFile(path.Join(config.Urootpath, devcpio)) if err != nil { log.Fatalf("%v %v\n", dev, err) } debug("Creating initramf file") oname := fmt.Sprintf("/tmp/initramfs.%v_%v.cpio", config.Goos, config.Arch) if err := ioutil.WriteFile(oname, dev, 0600); err != nil { log.Fatalf("%v\n", err) } // Now use the append option for cpio to append to it. // That way we get one cpio. // We need sudo as there may be files created from an initramfs that // can only be read by root. cmd := exec.Command("sudo", "cpio", "-H", "newc", "-o", "-A", "-F", oname) cmd.Dir = config.TempDir cmd.Stdin = r cmd.Stderr = os.Stderr cmd.Stdout = os.Stdout debug("Run %v @ %v", cmd, cmd.Dir) err = cmd.Start() if err != nil { log.Fatalf("%v\n", err) } if err := lsr(config.TempDir, w); err != nil { log.Fatalf("%v\n", err) } w.Close() debug("Finished sending file list for initramfs cpio") err = cmd.Wait() if err != nil { log.Printf("%v\n", err) } debug("cpio for initramfs is done") defer func() { log.Printf("Output file is in %v\n", oname) }() if !config.TestChroot { return } // We need to populate the temp directory with dev.cpio. It's a chicken and egg thing; // we can't run init without, e.g., /dev/console and /dev/null. cmd = exec.Command("sudo", "cpio", "-i") cmd.Dir = config.TempDir // We have it in memory. Get a better way to do this! r, err = os.Open(path.Join(config.Urootpath, devcpio)) if err != nil { log.Fatalf("%v", err) } // OK, at this point, we know we can run as root. And, we're going to create things // we can only remove as root. So, we'll have to remove the directory with // extreme measures. reallyRemoveDir := config.RemoveDir config.RemoveDir = false cmd.Stdin, cmd.Stderr, cmd.Stdout = r, os.Stderr, os.Stdout debug("Run %v @ %v", cmd, cmd.Dir) err = cmd.Run() if err != nil { log.Fatalf("%v", err) } // Arrange to start init in the directory in a new namespace. // That should make all mounts go away when we're done. // On real kernels you can unshare without being root. Not on Linux. cmd = exec.Command("sudo", "unshare", "-m", "chroot", config.TempDir, "/init") cmd.Dir = config.TempDir cmd.Stdin, cmd.Stderr, cmd.Stdout = os.Stdin, os.Stderr, os.Stdout debug("Run %v @ %v", cmd, cmd.Dir) err = cmd.Run() if err != nil { log.Fatalf("Test failed, not removing %v: %v", config.TempDir, err) config.RemoveDir = false } config.RemoveDir = reallyRemoveDir }
// Wstat updates file info. func (fs *fileSystem) Wstat(req *go9p.SrvReq) { aux := req.Fid.Aux.(*Aux) if err := aux.stat(); err != nil { req.RespondError(err) return } // Add to writeset. fs.addToWriteset(aux.rootID, aux.path) dir := &req.Tc.Dir if dir.Mode != 0xFFFFFFFF { mode := dir.Mode & 0777 if req.Conn.Dotu { if dir.Mode&go9p.DMSETUID > 0 { mode |= syscall.S_ISUID } if dir.Mode&go9p.DMSETGID > 0 { mode |= syscall.S_ISGID } } err := os.Chmod(aux.path, os.FileMode(mode)) if err != nil { req.RespondError(toError(err)) return } } uid, gid := go9p.NOUID, go9p.NOUID if req.Conn.Dotu { uid = dir.Uidnum gid = dir.Gidnum } // Try to find local uid, gid by name. if (dir.Uid != "" || dir.Gid != "") && !req.Conn.Dotu { var err error uid, err = lookupUser(dir.Uid) if err != nil { req.RespondError(err) return } gid, err = lookupGroup(dir.Gid) if err != nil { req.RespondError(err) return } } if uid != go9p.NOUID || gid != go9p.NOUID { err := os.Chown(aux.path, int(uid), int(gid)) if err != nil { req.RespondError(toError(err)) return } } if dir.Name != "" { // if first char is / it is relative to root, else relative to cwd. var destpath string if dir.Name[0] == '/' { destpath = path.Join(fs.path, dir.Name) fmt.Printf("/ results in %s\n", destpath) } else { auxdir, _ := path.Split(aux.path) destpath = path.Join(auxdir, dir.Name) fmt.Printf("rel results in %s\n", destpath) } err := syscall.Rename(aux.path, destpath) fmt.Printf("rename %s to %s gets %v\n", aux.path, destpath, err) if err != nil { req.RespondError(toError(err)) return } aux.path = destpath } // Set file size, if specified. if dir.Length != 0xFFFFFFFFFFFFFFFF { if err := os.Truncate(aux.path, int64(dir.Length)); err != nil { req.RespondError(toError(err)) return } } // If either mtime or atime need to be changed, then we must change both. if dir.Mtime != ^uint32(0) || dir.Atime != ^uint32(0) { mtime := time.Unix(int64(dir.Mtime), 0) atime := time.Unix(int64(dir.Atime), 0) mtimeChanged := (dir.Mtime == ^uint32(0)) atimeChanged := (dir.Atime == ^uint32(0)) if mtimeChanged || atimeChanged { st, err := os.Stat(aux.path) if err != nil { req.RespondError(toError(err)) return } else if mtimeChanged { mtime = st.ModTime() } } if err := os.Chtimes(aux.path, atime, mtime); err != nil { req.RespondError(toError(err)) return } } req.RespondRwstat() }