Ejemplo n.º 1
0
// renameFile attempts to rename an existing file to a destination
// and set the right attributes on it.
func (p *rwFolder) renameFile(source, target protocol.FileInfo) {
	var err error
	events.Default.Log(events.ItemStarted, map[string]string{
		"folder": p.folder,
		"item":   source.Name,
		"type":   "file",
		"action": "delete",
	})
	events.Default.Log(events.ItemStarted, map[string]string{
		"folder": p.folder,
		"item":   target.Name,
		"type":   "file",
		"action": "update",
	})
	defer func() {
		events.Default.Log(events.ItemFinished, map[string]interface{}{
			"folder": p.folder,
			"item":   source.Name,
			"error":  events.Error(err),
			"type":   "file",
			"action": "delete",
		})
		events.Default.Log(events.ItemFinished, map[string]interface{}{
			"folder": p.folder,
			"item":   target.Name,
			"error":  events.Error(err),
			"type":   "file",
			"action": "update",
		})
	}()

	l.Debugln(p, "taking rename shortcut", source.Name, "->", target.Name)

	from := filepath.Join(p.dir, source.Name)
	to := filepath.Join(p.dir, target.Name)

	if p.versioner != nil {
		err = osutil.Copy(from, to)
		if err == nil {
			err = osutil.InWritableDir(p.versioner.Archive, from)
		}
	} else {
		err = osutil.TryRename(from, to)
	}

	if err == nil {
		// The file was renamed, so we have handled both the necessary delete
		// of the source and the creation of the target. Fix-up the metadata,
		// and update the local index of the target file.

		p.dbUpdates <- dbUpdateJob{source, dbUpdateDeleteFile}

		err = p.shortcutFile(target)
		if err != nil {
			l.Infof("Puller (folder %q, file %q): rename from %q metadata: %v", p.folder, target.Name, source.Name, err)
			p.newError(target.Name, err)
			return
		}

		p.dbUpdates <- dbUpdateJob{target, dbUpdateHandleFile}
	} else {
		// We failed the rename so we have a source file that we still need to
		// get rid of. Attempt to delete it instead so that we make *some*
		// progress. The target is unhandled.

		err = osutil.InWritableDir(osutil.Remove, from)
		if err != nil {
			l.Infof("Puller (folder %q, file %q): delete %q after failed rename: %v", p.folder, target.Name, source.Name, err)
			p.newError(target.Name, err)
			return
		}

		p.dbUpdates <- dbUpdateJob{source, dbUpdateDeleteFile}
	}
}
Ejemplo n.º 2
0
func alterFiles(dir string) error {
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if os.IsNotExist(err) {
			// Something we deleted. Never mind.
			return nil
		}

		info, err = os.Stat(path)
		if err != nil {
			// Something we deleted while walking. Ignore.
			return nil
		}

		if strings.HasPrefix(filepath.Base(path), "test-") {
			return nil
		}

		switch filepath.Base(path) {
		case ".stfolder":
			return nil
		case ".stversions":
			return nil
		}

		// File structure is base/x/xy/xyz12345...
		// comps == 1: base (don't touch)
		// comps == 2: base/x (must be dir)
		// comps == 3: base/x/xy (must be dir)
		// comps  > 3: base/x/xy/xyz12345... (can be dir or file)

		comps := len(strings.Split(path, string(os.PathSeparator)))

		r := rand.Intn(10)
		switch {
		case r == 0 && comps > 2:
			// Delete every tenth file or directory, except top levels
			return removeAll(path)

		case r == 1 && info.Mode().IsRegular():
			if info.Mode()&0200 != 0200 {
				// Not owner writable. Fix.
				if err = os.Chmod(path, 0644); err != nil {
					return err
				}
			}

			// Overwrite a random kilobyte of every tenth file
			fd, err := os.OpenFile(path, os.O_RDWR, 0644)
			if err != nil {
				return err
			}
			if info.Size() > 1024 {
				_, err = fd.Seek(rand.Int63n(info.Size()), os.SEEK_SET)
				if err != nil {
					return err
				}
			}
			_, err = io.Copy(fd, io.LimitReader(cr.Reader, 1024))
			if err != nil {
				return err
			}
			return fd.Close()

		// Change capitalization
		case r == 2 && comps > 3 && rand.Float64() < 0.2:
			if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
				// Syncthing is currently broken for case-only renames on case-
				// insensitive platforms.
				// https://github.com/hernad/syncthing/issues/1787
				return nil
			}

			base := []rune(filepath.Base(path))
			for i, r := range base {
				if rand.Float64() < 0.5 {
					base[i] = unicode.ToLower(r)
				} else {
					base[i] = unicode.ToUpper(r)
				}
			}
			newPath := filepath.Join(filepath.Dir(path), string(base))
			if newPath != path {
				return osutil.TryRename(path, newPath)
			}

			/*
				This doesn't in fact work. Sometimes it appears to. We need to get this sorted...

				// Switch between files and directories
				case r == 3 && comps > 3 && rand.Float64() < 0.2:
					if !info.Mode().IsRegular() {
						err = removeAll(path)
						if err != nil {
							return err
						}
						d1 := []byte("I used to be a dir: " + path)
						err := ioutil.WriteFile(path, d1, 0644)
						if err != nil {
							return err
						}
					} else {
						err := osutil.Remove(path)
						if err != nil {
							return err
						}
						err = os.MkdirAll(path, 0755)
						if err != nil {
							return err
						}
						generateFiles(path, 10, 20, "../LICENSE")
					}
					return err
			*/

			/*
				This fails. Bug?

					// Rename the file, while potentially moving it up in the directory hierarchy
					case r == 4 && comps > 2 && (info.Mode().IsRegular() || rand.Float64() < 0.2):
						rpath := filepath.Dir(path)
						if rand.Float64() < 0.2 {
							for move := rand.Intn(comps - 1); move > 0; move-- {
								rpath = filepath.Join(rpath, "..")
							}
						}
						return osutil.TryRename(path, filepath.Join(rpath, randomName()))
			*/
		}

		return nil
	})
	if err != nil {
		return err
	}

	return generateFiles(dir, 25, 20, "../LICENSE")
}