fileBrowser.py 8.1 KB
Newer Older
1
# -*- coding: utf-8 -*-
Marco Mariani's avatar
Marco Mariani committed
2
# vim: set et sts=2:
Marco Mariani's avatar
Marco Mariani committed
3
# pylint: disable-msg=W0311,C0301,C0103,C0111
4 5

import datetime
Marco Mariani's avatar
Marco Mariani committed
6
import md5
Marco Mariani's avatar
Marco Mariani committed
7
import os
8
import re
Marco Mariani's avatar
Marco Mariani committed
9 10
import shutil
import urllib
11 12
import zipfile

Marco Mariani's avatar
Marco Mariani committed
13 14 15 16
import werkzeug
from slapos.runner.utils import realpath, tail, isText


Marco Mariani's avatar
Marco Mariani committed
17
class FileBrowser(object):
18 19 20 21 22
  """This class contain all bases function for file browser"""

  def __init__(self, config):
    self.config = config

Marco Mariani's avatar
Marco Mariani committed
23 24
  def _realdir(self, dir):
    realdir = realpath(self.config, urllib.unquote(dir))
25 26
    if not realdir:
      raise NameError('Could not load directory %s: Permission denied' % dir)
Marco Mariani's avatar
Marco Mariani committed
27 28 29 30
    return realdir

  def listDirs(self, dir, all=False):
    """List elements of directory 'dir' taken"""
Marco Mariani's avatar
Marco Mariani committed
31 32 33
    html = 'var gsdirs = [], gsfiles = [];'

    dir = urllib.unquote(dir)
Marco Mariani's avatar
Marco Mariani committed
34
    # XXX-Marco 'dir' and 'all' should not shadow builtin names
Marco Mariani's avatar
Marco Mariani committed
35 36 37
    realdir = realpath(self.config, dir)
    if not realdir:
      raise NameError('Could not load directory %s: Permission denied' % dir)
38 39 40

    ldir = sorted(os.listdir(realdir), key=str.lower)
    for f in ldir:
Marco Mariani's avatar
Marco Mariani committed
41
      if f.startswith('.') and not all:  # do not display this file/folder
42
        continue
Marco Mariani's avatar
Marco Mariani committed
43
      ff = os.path.join(dir, f)
44 45
      realfile = os.path.join(realdir, f)
      mdate = datetime.datetime.fromtimestamp(os.path.getmtime(realfile)
Marco Mariani's avatar
Marco Mariani committed
46
                                              ).strftime("%Y-%d-%m %I:%M")
Marco Mariani's avatar
Marco Mariani committed
47
      md5sum = md5.md5(realfile).hexdigest()
48 49
      if not os.path.isdir(realfile):
        size = os.path.getsize(realfile)
Marco Mariani's avatar
Marco Mariani committed
50 51 52 53 54 55 56
        regex = re.compile("(^.*)\.(.*)", re.VERBOSE)
        ext = regex.sub(r'\2', f)
        if ext == f:
          ext = "unknow"
        else:
          ext = str.lower(ext)
        html += 'gsfiles.push(new gsItem("1", "' + f + '", "' + \
Marco Mariani's avatar
Marco Mariani committed
57
                  ff + '", "' + str(size) + '", "' + md5sum + \
Marco Mariani's avatar
Marco Mariani committed
58
                  '", "' + ext + '", "' + mdate + '"));'
59 60
      else:
        html += 'gsdirs.push(new gsItem("2", "' + f + '", "' + \
Marco Mariani's avatar
Marco Mariani committed
61
                  ff + '", "0", "' + md5sum + '", "dir", "' + mdate + '"));'
62 63 64 65
    return html

  def makeDirectory(self, dir, filename):
    """Create a directory"""
Marco Mariani's avatar
Marco Mariani committed
66
    realdir = self._realdir(dir)
67 68 69 70 71 72 73 74 75
    folder = os.path.join(realdir, filename)
    if not os.path.exists(folder):
      os.mkdir(folder, 0744)
      return '{result: \'1\'}'
    else:
      return '{result: \'0\'}'

  def makeFile(self, dir, filename):
    """Create a file in a directory dir taken"""
Marco Mariani's avatar
Marco Mariani committed
76
    realdir = self._realdir(dir)
Marco Mariani's avatar
Marco Mariani committed
77 78 79
    fout = os.path.join(realdir, filename)
    if not os.path.exists(fout):
      open(fout, 'w')
80 81 82 83 84 85
      return 'var responce = {result: \'1\'}'
    else:
      return '{result: \'0\'}'

  def deleteItem(self, dir, files):
    """Delete a list of files or directories"""
Marco Mariani's avatar
Marco Mariani committed
86
    # XXX-Marco do not shadow 'dir'
Marco Mariani's avatar
Marco Mariani committed
87
    realdir = self._realdir(dir)
88 89
    lfiles = urllib.unquote(files).split(',,,')
    try:
Marco Mariani's avatar
Marco Mariani committed
90
      # XXX-Marco do not shadow 'file'
91 92 93
      for file in lfiles:
        file = os.path.join(realdir, file)
        if not os.path.exists(file):
Marco Mariani's avatar
Marco Mariani committed
94
          continue  # silent skip file....
95
        details = file.split('/')
Marco Mariani's avatar
Marco Mariani committed
96
        last = details[-1]
97
        if last and last.startswith('.'):
Marco Mariani's avatar
Marco Mariani committed
98
          continue  # cannot delete this file/directory, to prevent security
99 100 101 102
        if os.path.isdir(file):
          shutil.rmtree(file)
        else:
          os.unlink(file)
Marco Mariani's avatar
Marco Mariani committed
103
    except Exception as e:
104 105 106 107 108
      return str(e)
    return '{result: \'1\'}'

  def copyItem(self, dir, files, del_source=False):
    """Copy a list of files or directory to dir"""
Marco Mariani's avatar
Marco Mariani committed
109
    realdir = self._realdir(dir)
110 111
    lfiles = urllib.unquote(files).split(',,,')
    try:
Marco Mariani's avatar
Marco Mariani committed
112
      # XXX-Marco do not shadow 'file'
113 114 115 116 117 118
      for file in lfiles:
        realfile = realpath(self.config, file)
        if not realfile:
          raise NameError('Could not load file or directory %s: Permission denied' % file)
        #prepare destination file
        details = realfile.split('/')
Marco Mariani's avatar
Marco Mariani committed
119
        dest = os.path.join(realdir, details[-1])
120 121 122 123 124 125 126 127 128 129
        if os.path.exists(dest):
          raise NameError('NOT ALLOWED OPERATION : File or directory already exist')
        if os.path.isdir(realfile):
          shutil.copytree(realfile, dest)
          if del_source:
            shutil.rmtree(realfile)
        else:
          shutil.copy(realfile, dest)
          if del_source:
            os.unlink(realfile)
Marco Mariani's avatar
Marco Mariani committed
130
    except Exception as e:
131 132 133 134 135
      return str(e)
    return '{result: \'1\'}'

  def rename(self, dir, filename, newfilename):
    """Rename file or directory to dir/filename"""
Marco Mariani's avatar
Marco Mariani committed
136
    realdir = self._realdir(dir)
137 138 139 140 141 142 143 144 145 146 147
    realfile = realpath(self.config, urllib.unquote(filename))
    if not realfile:
      raise NameError('Could not load directory %s: Permission denied' % filename)
    tofile = os.path.join(realdir, newfilename)
    if not os.path.exists(tofile):
      os.rename(realfile, tofile)
      return '{result: \'1\'}'
    raise NameError('NOT ALLOWED OPERATION : File or directory already exist')

  def copyAsFile(self, dir, filename, newfilename):
    """Copy file or directory to dir/filename"""
Marco Mariani's avatar
Marco Mariani committed
148
    realdir = self._realdir(dir)
149 150 151 152 153 154 155 156 157 158 159
    fromfile = os.path.join(realdir, filename)
    tofile = os.path.join(realdir, newfilename)
    if not os.path.exists(fromfile):
      raise NameError('NOT ALLOWED OPERATION : File or directory not exist')
    if not os.path.exists(tofile):
      shutil.copy(fromfile, tofile)
      return '{result: \'1\'}'
    raise NameError('NOT ALLOWED OPERATION : File or directory already exist')

  def uploadFile(self, dir, files):
    """Upload a list of file in directory dir"""
Marco Mariani's avatar
Marco Mariani committed
160
    realdir = self._realdir(dir)
161 162
    for file in files:
      if files[file]:
Marco Mariani's avatar
Marco Mariani committed
163
        filename = werkzeug.secure_filename(files[file].filename)
164 165 166 167 168 169
        if not os.path.exists(os.path.join(dir, filename)):
          files[file].save(os.path.join(realdir, filename))
    return '{result: \'1\'}'

  def downloadFile(self, dir, filename):
    """Download file dir/filename"""
Marco Mariani's avatar
Marco Mariani committed
170
    realdir = self._realdir(dir)
171 172 173 174 175 176 177 178
    file = os.path.join(realdir, urllib.unquote(filename))
    if not os.path.exists(file):
      raise NameError('NOT ALLOWED OPERATION : File or directory does not exist %s'
                      % os.path.join(dir, filename))
    return file

  def zipFile(self, dir, filename, newfilename):
    """Add filename to archive as newfilename"""
Marco Mariani's avatar
Marco Mariani committed
179
    realdir = self._realdir(dir)
180 181 182 183 184 185 186 187
    tozip = os.path.join(realdir, newfilename)
    fromzip = os.path.join(realdir, filename)
    if not os.path.exists(fromzip):
      raise NameError('NOT ALLOWED OPERATION : File or directory not exist')
    if not os.path.exists(tozip):
      zip = zipfile.ZipFile(tozip, 'w', zipfile.ZIP_DEFLATED)
      if os.path.isdir(fromzip):
        rootlen = len(fromzip) + 1
Marco Mariani's avatar
Marco Mariani committed
188 189 190 191
        for base, _, files in os.walk(fromzip):
          for filename in files:
            fn = os.path.join(base, filename).encode("utf-8")
            zip.write(fn, fn[rootlen:])       # XXX can fail if 'fromzip' contains multibyte characters
192 193 194 195 196 197 198 199
      else:
        zip.write(fromzip)
      zip.close()
      return '{result: \'1\'}'
    raise NameError('NOT ALLOWED OPERATION : File or directory already exist')

  def unzipFile(self, dir, filename, newfilename):
    """Extract a zipped archive"""
Marco Mariani's avatar
Marco Mariani committed
200
    realdir = self._realdir(dir)
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
    target = os.path.join(realdir, newfilename)
    archive = os.path.join(realdir, filename)
    if not os.path.exists(archive):
      raise NameError('NOT ALLOWED OPERATION : File or directory not exist')
    if not os.path.exists(target):
      zip = zipfile.ZipFile(archive)
      #member = zip.namelist()
      zip.extractall(target)
      #if len(member) > 1:
      #  zip.extractall(target)
      #else:
      #  zip.extract(member[0], newfilename)
      return '{result: \'1\'}'
    raise NameError('NOT ALLOWED OPERATION : File or directory already exist')

Alain Takoudjou's avatar
Alain Takoudjou committed
216
  def readFile(self, dir, filename, truncate=False):
217 218 219 220 221 222 223
    """Read file dir/filename and return content"""
    realfile = realpath(self.config, os.path.join(urllib.unquote(dir),
                        urllib.unquote(filename)))
    if not realfile:
      raise NameError('Could not load directory %s: Permission denied' % dir)
    if not isText(realfile):
      return "FILE ERROR: Cannot display binary file, please open a text file only!"
Alain Takoudjou's avatar
Alain Takoudjou committed
224
    if not truncate:
225 226
      return open(realfile, 'r').read()
    else:
Alain Takoudjou's avatar
Alain Takoudjou committed
227
      return tail(open(realfile, 'r'), 0)